├── .gitignore ├── Doxyfile ├── LICENSE ├── Makefile ├── README.md ├── Xmega_Bootloader ├── .gitattributes ├── .gitignore ├── CCP_Write.s ├── LICENSE ├── README ├── Xmega_Bootloader.atsln ├── Xmega_Bootloader.c ├── Xmega_Bootloader.componentinfo.xml ├── Xmega_Bootloader.cproj ├── Xmega_Bootloader.h ├── Xmega_Bootloader_6_1.atsln ├── Xmega_Bootloader_6_1.cproj ├── avr_compiler.h ├── config_macros.h ├── eeprom_driver.c ├── eeprom_driver.h ├── makefile ├── serial.c ├── serial.h ├── sp_driver.h └── sp_driver.s ├── eeprom └── jtag-eeprom.conf ├── hal-avr ├── adc.c ├── definitions.h ├── hal-avr.c ├── jtag.c ├── nand.c ├── nor.c ├── sevenseg.c ├── spi.c ├── timer.c ├── uart.c └── uart_scanner.c ├── hal-test ├── definitions.h └── hal-test.c ├── hal.h ├── main.c ├── modules ├── jtag.c ├── nand.c ├── nor.c ├── spi.c └── uart_scanner.c ├── reset_device.py ├── secxtractor.c ├── secxtractor.h ├── shell.c ├── shell.h └── tools ├── nand ├── nandsplit.py └── stripspare.py └── xtractorterminal.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.hex 3 | *.bin 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SELF_TEST=0 2 | 3 | CC=avr-gcc 4 | CCFLAGS=-mmcu=atxmega128a1 -Os -std=gnu99 -DXTRACTOR_ARCH_AVR -DF_CPU=32000000 -DSELF_TEST=$(SELF_TEST) 5 | 6 | CC_TEST=gcc 7 | CCFLAGS_TEST=-Os -std=gnu99 -DXTRACTOR_ARCH_TEST 8 | 9 | SRC_FILES=*.c *.h modules/*.c 10 | SRC_FILES_AVR=$(SRC_FILES) hal-avr/*.c hal-avr/*.h 11 | SRC_FILES_TEST=$(SRC_FILES) hal-test/*.c hal-test/*.h 12 | 13 | OBJECTS=*.o 14 | 15 | LDFLAGS=-mmcu=atxmega128a1 -g 16 | 17 | PLATFORM=x128a1 18 | 19 | SERIAL_PORT=/dev/ttyUSB3 20 | BAUD=4000000 21 | 22 | AVRDUDE_USB=avrdude -p $(PLATFORM) -P usb -c atmelice_pdi 23 | AVRDUDE_SERIAL=avrdude -p $(PLATFORM) -P $(SERIAL_PORT) -b 115200 -c avr911 24 | 25 | # fuses 26 | FUSE0=0xFF 27 | FUSE1=0x00 28 | # BOOTRST set 29 | FUSE2=0x9F 30 | FUSE4=0xFE 31 | FUSE5=0xFF 32 | 33 | ################################################################################ 34 | ## Test for Flags ## 35 | ## -e Enable ANSI Escape Sequence Support ## 36 | ################################################################################ 37 | consume_flags: 38 | ifneq ($(findstring e, $(MAKEFLAGS)),) 39 | CCFLAGS+= -DESCAPE_CODE_SUPPORTED 40 | endif 41 | 42 | ################################################################################ 43 | ## GENERAL/MISC ## 44 | ################################################################################ 45 | all: main.hex 46 | 47 | clean: 48 | rm *.hex *.o *.bin *.elf main-test bootloader.compiled || true 49 | cd Xmega_Bootloader/ && make clean 50 | 51 | test: main-test 52 | ./main-test 53 | 54 | 55 | ################################################################################ 56 | ## AVR DEVICE ## 57 | ################################################################################ 58 | 59 | main.hex: main.bin 60 | avr-objcopy -j .text -j .data -O ihex $^ $@ 61 | 62 | main.bin: consume_flags $(SRC_FILES_AVR) 63 | $(CC) $(CCFLAGS) main.c -o $@ 64 | 65 | main.o: consume_flags $(SRC_FILES_AVR) 66 | $(CC) $(CCFLAGS) -c main.c -o $@ 67 | 68 | hal-avr: consume_flags $(SRC_FILES_AVR) 69 | $(CC) $(CCFLAGS) -c $(SRC_FILES_AVR) -o $^ 70 | 71 | main.elf: $(OBJECTS) 72 | $(CC) $(LDFLAGS) -o $@ $^ 73 | 74 | bootloader.bin: bootloader.c 75 | $(CC) $(CCFLAGS) bootloader.c -o $@ 76 | 77 | # bootloader 78 | bootloader.compiled: Xmega_Bootloader/* 79 | cd Xmega_Bootloader && touch Xmega_Bootloader.c && make 80 | touch $@ 81 | 82 | # flashing 83 | programmer-alive: 84 | $(AVRDUDE_USB) 85 | 86 | reset-device: 87 | echo "!!!!! NOW PRESS AND HOLD THE BUTTON LABELED 'BOOT' TO ENTER BOOTLOADER !!!" 88 | sleep 2 89 | python reset_device.py $(SERIAL_PORT) $(BAUD) 90 | # wait for bootloader 91 | sleep 1 92 | 93 | bootloader-alive: reset-device 94 | $(AVRDUDE_SERIAL) 95 | 96 | flash-main-programmer: main.hex programmer-alive 97 | $(AVRDUDE_USB) -U flash:w:main.hex 98 | 99 | flash-main-serial: main.hex bootloader-alive 100 | # avrdude does not support flash-erase for avr911 101 | # there seems to be a problem with verification, as some bytes appear to not arrive 102 | $(AVRDUDE_SERIAL) -e -D -V -U flash:w:main.hex 103 | 104 | flash-fuses: 105 | $(AVRDUDE_USB) -U fuse0:w:$(FUSE0):m -U fuse1:w:$(FUSE1):m -U fuse2:w:$(FUSE2):m 106 | -U fuse4:w:$(FUSE4):m -U fuse5:w:$(FUSE5):m 107 | 108 | flash-bootloader: bootloader.compiled 109 | $(AVRDUDE_USB) -U flash:w:Xmega_Bootloader/Xmega_Bootloader.hex -U eeprom:w:Xmega_Bootloader/Xmega_Bootloader.eep 110 | 111 | flash-all: programmer-alive flash-fuses flash-bootloader flash-main-programmer 112 | 113 | debug: 114 | $(CC) -ggdb -mmcu=atxmega128a1u -o main.elf main.o 115 | 116 | ################################################################################ 117 | ## TEST ## 118 | ################################################################################ 119 | main-test: $(SRC_FILES_TEST) 120 | $(CC_TEST) $(CCFLAGS_TEST) main.c -o $@ 121 | 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SEC Xtractor (Firmware) 2 | A tool for directly dumping memory chips and identifying on-chip debugging/programming interfaces. Can act as UART-to-USB converter and JTAG adapter. 3 | 4 | # Documentation 5 | A short documentation for the usage of the SEC Xtractor can be found in the [hardware repository][9] under the folder *documentation*. 6 | 7 | # Dependencies 8 | *For compiling and programming the SEC Xtractor* 9 | avr-binutils 10 | avr-gcc 11 | avr-libc 12 | avrdude 13 | *For configuring the FT2232HQ* 14 | ftdi_eeprom 15 | 16 | # Programming 17 | To update the main program of the SEC Xtractor, no additional programmer is needed. This is only required for changing the bootloader. 18 | ## Serial 19 | Connect the device with a USB cable to your PC. Navigate into the root of the directory and compile the program with "make". Afterwards, type "make flash-main-serial" to burn the main program to the flash memory. 20 | ## PDI 21 | To program the device with PDI, an additional programmer like the AVRISPMKII or the ATMELICE is needed. The command "make flash-main-programmer" can be used to flash the bootloader (this is only possible with a programmer). 22 | ## FT2232HQ EEPROM 23 | The EEPROM of the FTDI chip can be changed with "ftdi_eeprom --flash-eeprom ". This can be done to change the manufacturer, the product name and the serial string. 24 | # Authors 25 | Initial version: 26 | * Thomas Weber of [SEC Consult][1] 27 | 28 | Rolling relase: 29 | * Thomas Weber of [SEC Consult][1] 30 | * [Steffen Robertz][4] of [SEC Consult][1] 31 | # Author Emeritus 32 | * [Wolfgang Ettlinger][2] 33 | 34 | # Other Used Projects 35 | The firmware of SEC Xtractor was written from scratch with two exceptions: 36 | * JTAG brute forcing code was used from [JTAGenum][5] [Nathan Andrew Fain][6] 37 | * The [Xmega_bootloader][7] from [Anthony Andriano][8] was directly used 38 | 39 | ## License 40 | The SEC Xtractor source code is distributed under a [Mozilla Public License 2.0][3] copyleft license. This means that it requires modifications to be shared. 41 | 42 | [1]: https://www.sec-consult.com 43 | [2]: https://twitter.com/ettisan 44 | [3]: https://www.mozilla.org/en-US/MPL/2.0/ 45 | [4]: https://www.linkedin.com/in/shr70/ 46 | [5]: https://github.com/cyphunk/JTAGenum 47 | [6]: https://twitter.com/cyphunk 48 | [7]: https://github.com/bandtank/Xmega_Bootloader 49 | [8]: https://github.com/bandtank 50 | [9]: https://github.com/sec-consult/SEC-Xtractor_Hardware 51 | -------------------------------------------------------------------------------- /Xmega_Bootloader/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /Xmega_Bootloader/.gitignore: -------------------------------------------------------------------------------- 1 | *.atsuo 2 | Xmega_Bootloader.eep 3 | Xmega_Bootloader.elf 4 | Xmega_Bootloader.hex 5 | Xmega_Bootloader.lss 6 | Xmega_Bootloader.map 7 | *.o 8 | *.d 9 | -------------------------------------------------------------------------------- /Xmega_Bootloader/CCP_Write.s: -------------------------------------------------------------------------------- 1 | /* 2 | * CCP_Write.c 3 | * 4 | * Created: 12/9/2011 10:59:46 PM 5 | * Author: Tony 6 | * 7 | * CCP_CLK is a routine that allows the clock source to be changed. 8 | * The architecture requires that the CLK_CTRL register is updated 9 | * within 4 cycles of writing the unlock value (CCP_SIGN) into the 10 | * CCP register. After the value passed into the function in r24 11 | * is written into CLK_CTRL, c functions are capable of modifying 12 | * the clock source for the core (e.g. from a cystal to a PLL). 13 | * 14 | * CCP_RST is pretty much the same as the above comment. The core 15 | * can be reset via software by writing a 1 into the RST_CTRL 16 | * register. The same constraint applies to this register as the 17 | * CLK_CTRL register, though. It must be written within 4 cycles 18 | * of writing the unlock value into the CCP register. After the sts 19 | * instruction executes, the stack pointer jumps to the reset 20 | * vector and the core and all peripherals are initialized the same 21 | * way as a power-on reset. 22 | */ 23 | 24 | #include 25 | 26 | #define _SFR_ASM_COMPAT 1 27 | #define _SFR_OFFSET 0 28 | #define CCP_SIGN 0xD8 29 | 30 | .global CCP_CLK 31 | .global CCP_RST 32 | 33 | .func CCP_CLK 34 | CCP_CLK: 35 | ldi r20, CCP_SIGN 36 | out CCP, r20 37 | sts CLK_CTRL, r24 //1 uint8_t gets passed via r24 38 | ret 39 | 40 | .endfunc 41 | 42 | .func CCP_RST 43 | CCP_RST: 44 | ldi r20, CCP_SIGN 45 | out CCP, r20 46 | ldi r20, 1 47 | sts RST_CTRL, r20 48 | ret 49 | 50 | .endfunc -------------------------------------------------------------------------------- /Xmega_Bootloader/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014 Anthony Andriano 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /Xmega_Bootloader/README: -------------------------------------------------------------------------------- 1 | Welcome to the XmegaBl. This bootloader implements the AVR911 protocol and is 2 | purposefully stripped of the unnecessary bloat in an effort to keep it simple 3 | and efficient. 4 | 5 | Please see these threads for helpful tips and information: 6 | 1. http://www.avrfreaks.net/forum/tutsoft-xmega-bootloader-available 7 | 2. http://www.avrfreaks.net/forum/xmega-serial-bootloader 8 | 9 | !!!!!!!!!! 10 | NOTE - the xmega E series does not work properly with the master branch of this 11 | repository. Use the xmegaE branch, which has a temporary workaround. I will 12 | update the main repository to handle xmega E series microcontrollers at some 13 | point. 14 | !!!!!!!!!! 15 | 16 | Bootloader information: 17 | 1. It works with all Xmegas, but may require you to add support if it isn't 18 | already in the makefile. Note: AVR-GCC has to support the particular 19 | Xmega you want to use as well. AVRDUDE 5.10 lacks support for many, many 20 | Xmegas, so you may need to acquire a newer version if you're simply using 21 | the bundled version that came with Winavr. 22 | 2. It requires AVR-GCC to build. 23 | 3. It uses the AVR911 protocol. 24 | 4. It works with avrdude version 5.10 and Avr-OSP II version .549. 25 | 5. Compilation size should be 2600-3000 bytes depending on the size of your 26 | AVR (>64k flash = bigger code). 27 | 6. Unless you are adding support for unsupported baud rates or Xmegas, you 28 | do NOT need to edit any source code. 29 | 30 | Bootloader Instructions (configure each setting in the makefile): 31 | 1. It checks a pin (Active high/low and Pin/Port are configurable) for 32 | bootloader entry or application entry. 33 | 2. An LED can be turned on when the bootloader is entered. Active high/low 34 | and Pin/Port are configurable. 35 | 3. The default baud rate is 115200, but this can be set to anything you want. 36 | 37 | How to configure: 38 | In the makefile, you will see the following block of text at the top of the 39 | file. You should not need to edit anything other than this block of code 40 | unless you are adding support for additional baud rates or devices. 41 | 42 | ############################################################################### 43 | # User modification section 44 | ############################################################################### 45 | # Choose one of the following MCUs: 46 | # If you have a different MCU, you will have to define these values: 47 | # Name in makefile Name in ioxxxx.h 48 | # --------------------------- ----------------------------- 49 | # BOOT_SECTION_START_IN_BYTES BOOT_SECTION_START 50 | # BOOT_PAGE_SIZE BOOT_SECTION_PAGE_SIZE 51 | # APP_PAGE_SIZE APP_SECTION_PAGE_SIZE 52 | # 53 | # You can find these files in the include path for your compiler. Examples: 54 | # 1) Winavr: C:\WinAVR-20100110\avr\include\avr\ioxxxx.h 55 | # 2) Atmel 3.4.2: C:\Program Files (x86)\Atmel\Atmel Toolchain\AVR8 GCC\ 56 | # Native\3.4.2.1002\avr8-gnu-toolchain\avr\include\avr\ioxxxx.h 57 | 58 | # MCU = atxmega128a1 59 | # MCU = atxmega64a3 60 | MCU = atxmega64a3u 61 | # MCU = atxmega32a4 62 | # MCU = atxmega16a4 63 | # MCU = atxmega16d4 64 | 65 | # Choose a baud rate for the UART. 66 | # If you need a baud rate that is not listed in this makefile, you must add 67 | # new configuration statements in config.macros.h. Remember, Xmegas start-up 68 | # with a 2MHz clock. 69 | # BAUD_RATE = 9600 70 | # BAUD_RATE = 38400 71 | # BAUD_RATE = 57600 72 | BAUD_RATE = 115200 73 | 74 | # Specify a pin to check for entry into the bootloader. The notation is 75 | # PORT,PIN. For example, if you wanted to use PIN 3 on PORTC, you would set 76 | # the option as C,3. Then specifiy the logic value required to enable the 77 | # bootloader code (1 = enable the bootloader if the pin is VCC, 0 = enable 78 | # the bootloader if the pin is GND). 79 | BOOTLOADER_PIN = B,2 80 | BOOTLOADER_PIN_ON = 0 81 | 82 | # Specify a pin to control an LED. The notation is PORT,PIN. For example, if 83 | # you wanted to use PIN 6 on PORTA, you would set the option as A,6. Then 84 | # specifiy the logic value required to enable the LED (1 = output VCC to turn 85 | # on the LED, 0 = output GND to turn on the LED). 86 | LED_PIN = D,2 87 | LED_ON = 0 88 | 89 | # Specify which UART to use with PORT,NUM notation. For example, UART1 on 90 | # PORTD would be D,1. 91 | UART = C,0 92 | 93 | ############################################################################### 94 | # End user modification section 95 | ############################################################################### 96 | 97 | Please email me (anthonyandriano@gmail.com) if you have any questions or comments 98 | about the code. I will respond as quickly as possible. 99 | 100 | If you use or fork this repository, please let me know how you're using it only 101 | because I'm curious. Also, if you want to modify or improve the code, submit a 102 | pull request and I'd be happy to investigate the changes. 103 | -------------------------------------------------------------------------------- /Xmega_Bootloader/Xmega_Bootloader.atsln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Atmel Studio Solution File, Format Version 11.00 4 | Project("{54F91283-7BC4-4236-8FF9-10F437C3AD48}") = "Xmega_Bootloader", "Xmega_Bootloader.cproj", "{4605BE32-0E97-4C9A-AAFC-10D26E32DE03}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|AVR = Debug|AVR 9 | Release|AVR = Release|AVR 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {4605BE32-0E97-4C9A-AAFC-10D26E32DE03}.Debug|AVR.ActiveCfg = Debug|AVR 13 | {4605BE32-0E97-4C9A-AAFC-10D26E32DE03}.Debug|AVR.Build.0 = Debug|AVR 14 | {4605BE32-0E97-4C9A-AAFC-10D26E32DE03}.Release|AVR.ActiveCfg = Release|AVR 15 | {4605BE32-0E97-4C9A-AAFC-10D26E32DE03}.Release|AVR.Build.0 = Release|AVR 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /Xmega_Bootloader/Xmega_Bootloader.componentinfo.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Device 8 | Startup 9 | 10 | 11 | Atmel 12 | 1.0.0 13 | C:/Program Files (x86)\Atmel\Studio\7.0\Packs 14 | 15 | 16 | 17 | 18 | C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\XMEGAD_DFP\1.0.33\include 19 | 20 | include 21 | C 22 | 23 | 24 | include 25 | 26 | 27 | 28 | 29 | C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\XMEGAD_DFP\1.0.33\include\avr\iox16d4.h 30 | 31 | header 32 | C 33 | wDz7wmVDq01ckoVVGR8mGA== 34 | 35 | include/avr/iox16d4.h 36 | 37 | 38 | 39 | 40 | C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\XMEGAD_DFP\1.0.33\templates\main.c 41 | template 42 | source 43 | C Exe 44 | GD1k8YYhulqRs6FD1B2Hog== 45 | 46 | templates/main.c 47 | Main file (.c) 48 | 49 | 50 | 51 | C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\XMEGAD_DFP\1.0.33\templates\main.cpp 52 | template 53 | source 54 | C Exe 55 | YXFphlh0CtZJU+ebktABgQ== 56 | 57 | templates/main.cpp 58 | Main file (.cpp) 59 | 60 | 61 | 62 | C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\XMEGAD_DFP\1.0.33\gcc\dev\atxmega16d4 63 | 64 | libraryPrefix 65 | GCC 66 | 67 | 68 | gcc/dev/atxmega16d4 69 | 70 | 71 | 72 | 73 | XMEGAD_DFP 74 | C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/XMEGAD_DFP/1.0.33/Atmel.XMEGAD_DFP.pdsc 75 | 1.0.33 76 | true 77 | ATxmega16D4 78 | 79 | 80 | 81 | Resolved 82 | Fixed 83 | true 84 | 85 | 86 | -------------------------------------------------------------------------------- /Xmega_Bootloader/Xmega_Bootloader.cproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 2.0 5 | 7.0 6 | com.Atmel.AVRGCC8.C 7 | 4605be32-0e97-4c9a-aafc-10d26e32de03 8 | ATxmega16D4 9 | none 10 | Executable 11 | C 12 | $(MSBuildProjectName) 13 | .elf 14 | $(MSBuildProjectDirectory)\$(Configuration) 15 | Xmega_Bootloader 16 | Xmega_Bootloader 17 | Xmega_Bootloader 18 | Native 19 | true 20 | false 21 | true 22 | true 23 | 24 | 25 | 26 | 2 27 | 0 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -mmcu=atxmega16d4 -B "%24(PackRepoDir)\atmel\XMEGAD_DFP\1.0.33\gcc\dev\atxmega16d4" 45 | True 46 | True 47 | True 48 | True 49 | False 50 | True 51 | True 52 | 53 | 54 | NDEBUG 55 | 56 | 57 | 58 | 59 | %24(PackRepoDir)\atmel\XMEGAD_DFP\1.0.33\include 60 | 61 | 62 | Optimize for size (-Os) 63 | True 64 | True 65 | True 66 | 67 | 68 | libm 69 | 70 | 71 | 72 | 73 | %24(PackRepoDir)\atmel\XMEGAD_DFP\1.0.33\include 74 | 75 | 76 | 77 | 78 | True 79 | 80 | makefile 81 | all 82 | 83 | 84 | 85 | 86 | -mmcu=atxmega16d4 -B "%24(PackRepoDir)\atmel\XMEGAD_DFP\1.0.33\gcc\dev\atxmega16d4" 87 | True 88 | True 89 | True 90 | True 91 | False 92 | True 93 | True 94 | 95 | 96 | DEBUG 97 | 98 | 99 | 100 | 101 | %24(PackRepoDir)\atmel\XMEGAD_DFP\1.0.33\include 102 | 103 | 104 | Optimize (-O1) 105 | True 106 | True 107 | Default (-g2) 108 | True 109 | 110 | 111 | libm 112 | 113 | 114 | 115 | 116 | %24(PackRepoDir)\atmel\XMEGAD_DFP\1.0.33\include 117 | 118 | 119 | Default (-Wa,-g) 120 | 121 | 122 | True 123 | 124 | makefile 125 | all 126 | 127 | 128 | 129 | 130 | compile 131 | 132 | 133 | compile 134 | 135 | 136 | compile 137 | 138 | 139 | compile 140 | 141 | 142 | compile 143 | 144 | 145 | 146 | 147 | compile 148 | 149 | 150 | -------------------------------------------------------------------------------- /Xmega_Bootloader/Xmega_Bootloader.h: -------------------------------------------------------------------------------- 1 | #ifndef XMEGA_BOOTLOADER_H 2 | #define XMEGA_BOOTLOADER_H 3 | 4 | //////////////////////////////// 5 | /* COMMANDS */ 6 | //////////////////////////////// 7 | // 'a' = Check auto-increment status 8 | // 'A' = Set address, two parameters: , 9 | // 'e' = Erase Application Section and EEPROM 10 | // 'b' = Check block load support, returns BLOCKSIZE (2 bytes) 11 | // 'B' = Start block load, three parameters: block size (,),memtype 12 | // 'g' = Start block read, three parameters: block size (,),memtype 13 | // 'R' = Read program memory, returns high byte then low byte of flash word 14 | // 'c' = Write program memory, one parameter: low byte, returns '\r' 15 | // 'C' = Write program memory, one parameter: high byte, returns '\r' 16 | // 'm' = Write page, returns '?' if page is protected, returns '\r' if done 17 | // 'D' = Write EEPROM, one parameter: byte to write 18 | // 'd' = Read EEPROM, returns one byte 19 | // 'l' = Write lock bits, returns '\r' 20 | // 'r' = Read lock bits 21 | // 'F' = Read low fuse bits 22 | // 'N' = Read high fuse bits 23 | // 'Q' = Read extended fuse bits 24 | // 'P' = Enter and leave programming mode, returns '\r' 25 | // 'L' = Enter and leave programming mode, returns '\r' 26 | // 'E' = Exit bootloader, returns '\r', jumps to 0x0000 27 | // 'p' = Get programmer type, returns 'S' 28 | // 't' = Return supported device codes, returns PARTCODE and 0 29 | // 'x' = Turn on LED0, returns '\r' 30 | // 'y' = Turn off LED0, returns '\r' 31 | // 'T' = Set device type, one parameter: device byte, returns '\r' 32 | // 'S' = Returns Xmega_Bootloader 33 | // 'V' = Returns version number 34 | // 's' = Return signature bytes, returns 3 bytes (sig3, sig2, sig1) 35 | // 0x1b = ESC 36 | // Unknown = '?' 37 | 38 | #include 39 | #include "config_macros.h" 40 | #include "serial.h" 41 | #include "eeprom_driver.h" 42 | #include "sp_driver.h" 43 | 44 | #define COMMAND_CHECK_AUTOINC 'a' 45 | #define COMMAND_SET_ADDRESS 'A' 46 | #define COMMAND_CHIP_ERASE 'e' 47 | #define COMMAND_CHECK_BLOCKLOAD 'b' 48 | #define COMMAND_START_BLOCKLOAD 'B' 49 | #define COMMAND_START_BLOCKREAD 'g' 50 | #define COMMAND_READ_PROGMEM 'R' 51 | #define COMMAND_WRITE_PROGMEML 'c' 52 | #define COMMAND_WRITE_PROGMEMH 'C' 53 | #define COMMAND_WRITE_PAGE 'm' 54 | #define COMMAND_WRITE_EEPROMBYTE 'D' 55 | #define COMMAND_READ_EEPROMBYTE 'd' 56 | #define COMMAND_WRITE_LOCKBITS 'l' 57 | #define COMMAND_READ_LOCKBITS 'r' 58 | #define COMMAND_READ_FUSEL 'F' 59 | #define COMMAND_READ_FUSEH 'N' 60 | #define COMMAND_READ_FUSEE 'Q' 61 | #define COMMAND_PROGMODE_ENTLV0 'P' 62 | #define COMMAND_PROGMODE_ENTLV1 'L' 63 | #define COMMAND_EXIT_BOOTLOADER 'E' 64 | #define COMMAND_READ_PROGTYPE 'p' 65 | #define COMMAND_READ_DEVCODES 't' 66 | #define COMMAND_LED_ON 'x' 67 | #define COMMAND_LED_OFF 'y' 68 | #define COMMAND_SET_DEVTYPE 'T' 69 | #define COMMAND_READ_BOOTLOADNAME 'S' 70 | #define COMMAND_READ_BOOTLOADVER 'V' 71 | #define COMMAND_READ_SIGBYTES 's' 72 | #define COMMAND_ESCAPE 0x1b 73 | #define COMMAND_UNKNOWN '?' 74 | 75 | #define RESPONSE_OKAY '\r' 76 | #define RESPONSE_YES 'Y' 77 | #define RESPONSE_NO 'N' 78 | #define RESPONSE_UNKNOWN '?' 79 | 80 | extern void CCP_RST( void ); 81 | 82 | #endif -------------------------------------------------------------------------------- /Xmega_Bootloader/Xmega_Bootloader_6_1.atsln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Atmel Studio Solution File, Format Version 11.00 4 | Project("{54F91283-7BC4-4236-8FF9-10F437C3AD48}") = "Xmega_Bootloader", "Xmega_Bootloader_6_1.cproj", "{4605BE32-0E97-4C9A-AAFC-10D26E32DE03}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|AVR = Debug|AVR 9 | Release|AVR = Release|AVR 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {4605BE32-0E97-4C9A-AAFC-10D26E32DE03}.Debug|AVR.ActiveCfg = Debug|AVR 13 | {4605BE32-0E97-4C9A-AAFC-10D26E32DE03}.Debug|AVR.Build.0 = Debug|AVR 14 | {4605BE32-0E97-4C9A-AAFC-10D26E32DE03}.Release|AVR.ActiveCfg = Release|AVR 15 | {4605BE32-0E97-4C9A-AAFC-10D26E32DE03}.Release|AVR.Build.0 = Release|AVR 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /Xmega_Bootloader/Xmega_Bootloader_6_1.cproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 2.0 5 | 6.1 6 | com.Atmel.AVRGCC8.C 7 | 4605be32-0e97-4c9a-aafc-10d26e32de03 8 | ATxmega16D4 9 | none 10 | Executable 11 | C 12 | $(MSBuildProjectName) 13 | .elf 14 | $(MSBuildProjectDirectory)\$(Configuration) 15 | Xmega_Bootloader 16 | Xmega_Bootloader 17 | Xmega_Bootloader 18 | Native 19 | true 20 | false 21 | true 22 | true 23 | 24 | 25 | 26 | 2 27 | 0 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | True 45 | True 46 | True 47 | True 48 | True 49 | True 50 | 51 | 52 | NDEBUG 53 | 54 | 55 | Optimize for size (-Os) 56 | True 57 | True 58 | True 59 | 60 | 61 | libm 62 | 63 | 64 | 65 | 66 | True 67 | 68 | makefile 69 | all 70 | 71 | 72 | 73 | 74 | True 75 | True 76 | True 77 | True 78 | True 79 | True 80 | 81 | 82 | DEBUG 83 | 84 | 85 | Optimize (-O1) 86 | True 87 | True 88 | Default (-g2) 89 | True 90 | 91 | 92 | libm 93 | 94 | 95 | Default (-Wa,-g) 96 | 97 | 98 | True 99 | 100 | makefile 101 | all 102 | 103 | 104 | 105 | 106 | compile 107 | 108 | 109 | compile 110 | 111 | 112 | compile 113 | 114 | 115 | compile 116 | 117 | 118 | compile 119 | 120 | 121 | 122 | 123 | compile 124 | 125 | 126 | -------------------------------------------------------------------------------- /Xmega_Bootloader/avr_compiler.h: -------------------------------------------------------------------------------- 1 | /* This file has been prepared for Doxygen automatic documentation generation.*/ 2 | /*! \file ********************************************************************* 3 | * 4 | * \brief This file implements some macros that makes the IAR C-compiler and 5 | * avr-gcc work with the same code base for the AVR architecture. 6 | * 7 | * \par Documentation 8 | * For comprehensive code documentation, supported compilers, compiler 9 | * settings and supported devices see readme.html 10 | * 11 | * \author 12 | * Atmel Corporation: http://www.atmel.com \n 13 | * Support email: avr@atmel.com 14 | * 15 | * $Revision: 613 $ 16 | * $Date: 2006-04-07 14:40:07 +0200 (fr, 07 apr 2006) $ \n 17 | * 18 | * Copyright (c) 2008, Atmel Corporation All rights reserved. 19 | * 20 | * Redistribution and use in source and binary forms, with or without 21 | * modification, are permitted provided that the following conditions are met: 22 | * 23 | * 1. Redistributions of source code must retain the above copyright notice, 24 | * this list of conditions and the following disclaimer. 25 | * 26 | * 2. Redistributions in binary form must reproduce the above copyright notice, 27 | * this list of conditions and the following disclaimer in the documentation 28 | * and/or other materials provided with the distribution. 29 | * 30 | * 3. The name of ATMEL may not be used to endorse or promote products derived 31 | * from this software without specific prior written permission. 32 | * 33 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED 34 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 35 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND 36 | * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, 37 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 38 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 39 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 41 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 42 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 43 | ******************************************************************************/ 44 | 45 | #ifndef COMPILER_AVR_H 46 | #define COMPILER_AVR_H 47 | 48 | #ifndef F_CPU 49 | /*! \brief Define default CPU frequency, if this is not already defined. */ 50 | #define F_CPU 7372800UL 51 | #endif 52 | 53 | #include 54 | #include 55 | #include 56 | 57 | /*! \brief This macro will protect the following code from interrupts. */ 58 | #define AVR_ENTER_CRITICAL_REGION( ) uint8_t volatile saved_sreg = SREG; \ 59 | cli(); 60 | 61 | /*! \brief This macro must always be used in conjunction with AVR_ENTER_CRITICAL_REGION 62 | * so the interrupts are enabled again. 63 | */ 64 | #define AVR_LEAVE_CRITICAL_REGION( ) SREG = saved_sreg; 65 | 66 | #if defined( __ICCAVR__ ) 67 | 68 | #include 69 | #include 70 | #include 71 | #include 72 | 73 | #ifndef __HAS_ELPM__ 74 | #define _MEMATTR __flash 75 | #else /* __HAS_ELPM__ */ 76 | #define _MEMATTR __farflash 77 | #endif /* __HAS_ELPM__ */ 78 | 79 | /*! \brief Perform a delay of \c us microseconds. 80 | * 81 | * The macro F_CPU is supposed to be defined to a constant defining the CPU 82 | * clock frequency (in Hertz). 83 | * 84 | * The maximal possible delay is 262.14 ms / F_CPU in MHz. 85 | * 86 | * \note For the IAR compiler, currently F_CPU must be a 87 | * multiple of 1000000UL (1 MHz). 88 | */ 89 | #define delay_us( us ) ( __delay_cycles( ( F_CPU / 1000000UL ) * ( us ) ) ) 90 | 91 | /*! \brief Preprocessor magic. 92 | * 93 | * Some preprocessor magic to allow for a header file abstraction of 94 | * interrupt service routine declarations for the IAR compiler. This 95 | * requires the use of the C99 _Pragma() directive (rather than the 96 | * old #pragma one that could not be used as a macro replacement), as 97 | * well as two different levels of preprocessor concetanations in 98 | * order to do both, assign the correct interrupt vector name, as well 99 | * as construct a unique function name for the ISR. 100 | * 101 | * \note Do *NOT* try to reorder the macros below, as this will only 102 | * work in the given order. 103 | */ 104 | #define PRAGMA(x) _Pragma( #x ) 105 | #define ISR(vec) PRAGMA( vector=vec ) __interrupt void handler_##vec(void) 106 | #define sei( ) (__enable_interrupt( )) 107 | #define cli( ) (__disable_interrupt( )) 108 | 109 | /*! \brief Define the no operation macro. */ 110 | #define nop( ) (__no_operation()) 111 | 112 | /*! \brief Define the watchdog reset macro. */ 113 | #define watchdog_reset( ) (__watchdog_reset( )) 114 | 115 | 116 | #define INLINE PRAGMA( inline=forced ) static 117 | 118 | #define FLASH_DECLARE(x) _MEMATTR x 119 | #define FLASH_STRING(x) ((_MEMATTR const char *)(x)) 120 | #define FLASH_STRING_T char const _MEMATTR * 121 | #define FLASH_BYTE_ARRAY_T uint8_t const _MEMATTR * 122 | #define PGM_READ_BYTE(x) *(x) 123 | #define PGM_READ_WORD(x) *(x) 124 | 125 | #define SHORTENUM /**/ 126 | 127 | #elif defined( __GNUC__ ) 128 | 129 | #include 130 | #include 131 | #include 132 | #include 133 | 134 | /*! \brief Define the delay_us macro for GCC. */ 135 | #define delay_us( us ) (_delay_us( us )) 136 | 137 | #define INLINE static inline 138 | 139 | /*! \brief Define the no operation macro. */ 140 | #define nop() do { __asm__ __volatile__ ("nop"); } while (0) 141 | 142 | #define MAIN_TASK_PROLOGUE int 143 | 144 | 145 | #define MAIN_TASK_EPILOGUE() return -1; 146 | 147 | #define SHORTENUM __attribute__ ((packed)) 148 | 149 | #else 150 | #error Compiler not supported. 151 | #endif 152 | 153 | #endif 154 | 155 | -------------------------------------------------------------------------------- /Xmega_Bootloader/config_macros.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CONFIG_MACROS_H 3 | #define CONFIG_MACROS_H 4 | 5 | 6 | #define xCAT2(a,b) a##b 7 | #define CAT2(a,b) xCAT2(a,b) 8 | 9 | #define xCAT3(a,b,c) a##b##c 10 | #define CAT3(a,b,c) xCAT3(a,b,c) 11 | 12 | 13 | #define CAT_PORT(a,b,c) xCAT2(a,b) 14 | #define Port(a) CAT_PORT(PORT,a) 15 | 16 | #define CAT_PIN_CTRL4a(a,b,c,d) xCAT3(a,c,d) 17 | #define Pin_control(a) CAT_PIN_CTRL4a(PIN,a,CTRL) 18 | 19 | #define xISOLATE_PIN_NUMBER(a, b) b 20 | #define ISOLATE_PIN_NUMBER(a, b) xISOLATE_PIN_NUMBER(a,b) 21 | #define Pin(a) ISOLATE_PIN_NUMBER(a) 22 | 23 | #define Shift_TX_PIN(a) (1 << (a*4 +3)) 24 | #define TX_Pin(my_uart) Shift_TX_PIN(ISOLATE_PIN_NUMBER(my_uart)) 25 | 26 | 27 | #define Make_Uart_Name(uart) CAT2(USART, uart) 28 | #define Uart(my_uart) Make_Uart_Name(CAT2(my_uart)) 29 | 30 | 31 | 32 | #if (BAUD_RATE == 9600) 33 | #define BRREG_VALUE 12 34 | #define SCALE_VALUE 0 35 | #endif 36 | 37 | #if (BAUD_RATE == 19200) 38 | #define BRREG_VALUE 11 39 | #define SCALE_VALUE -1 40 | #endif 41 | 42 | #if (BAUD_RATE == 38400) 43 | #define BRREG_VALUE 9 44 | #define SCALE_VALUE -2 45 | #endif 46 | 47 | #if (BAUD_RATE == 57600) 48 | #define BRREG_VALUE 75 49 | #define SCALE_VALUE -6 50 | #endif 51 | 52 | #if (BAUD_RATE == 115200) 53 | #define BRREG_VALUE 11 54 | #define SCALE_VALUE -7 55 | #endif 56 | 57 | 58 | // This probably only works with GCC 59 | // It gets values from iox.....h 60 | 61 | // SPM control 62 | #define APP_END (APP_SECTION_START + APP_SECTION_SIZE) 63 | 64 | #if(APP_SECTION_SIZE >= 0x10000) 65 | #define LARGE_MEMORY 66 | #endif 67 | 68 | // EEPROM_definitions 69 | #define EEPROM_BYTES_IN_PAGE EEPROM_PAGE_SIZE 70 | #define EEPROM_BYTE_ADDRESS_MASK (EEPROM_PAGE_SIZE -1) 71 | 72 | /* definitions for device recognition */ 73 | #define PARTCODE 0xFA // I guess all Xmegas are the same. It doesn't seem to matter what code is used. 74 | #define SIGNATURE_BYTE_1 SIGNATURE_0 75 | #define SIGNATURE_BYTE_2 SIGNATURE_1 76 | #define SIGNATURE_BYTE_3 SIGNATURE_2 77 | 78 | #endif 79 | 80 | -------------------------------------------------------------------------------- /Xmega_Bootloader/eeprom_driver.c: -------------------------------------------------------------------------------- 1 | /* This file has been prepared for Doxygen automatic documentation generation.*/ 2 | /*! \file ********************************************************************* 3 | * 4 | * \brief XMEGA EEPROM driver source file. 5 | * 6 | * This file contains the function implementations for the XMEGA EEPROM driver. 7 | * 8 | * The driver is not intended for size and/or speed critical code, since 9 | * most functions are just a few lines of code, and the function call 10 | * overhead would decrease code performance. The driver is intended for 11 | * rapid prototyping and documentation purposes for getting started with 12 | * the XMEGA EEPROM module. 13 | * 14 | * For size and/or speed critical code, it is recommended to copy the 15 | * function contents directly into your application instead of making 16 | * a function call. 17 | * 18 | * \par Application note: 19 | * AVR1315: Accessing the XMEGA EEPROM 20 | * 21 | * \par Documentation 22 | * For comprehensive code documentation, supported compilers, compiler 23 | * settings and supported devices see readme.html 24 | * 25 | * \author 26 | * Atmel Corporation: http://www.atmel.com \n 27 | * Support email: avr@atmel.com 28 | * 29 | * $Revision: 1 $ 30 | * $Date: 2009-04-22 13:03:43 +0200 (ti, 22 apr 2009) $ \n 31 | * 32 | * Copyright (c) 2009, Atmel Corporation All rights reserved. 33 | * 34 | * Redistribution and use in source and binary forms, with or without 35 | * modification, are permitted provided that the following conditions are met: 36 | * 37 | * 1. Redistributions of source code must retain the above copyright notice, 38 | * this list of conditions and the following disclaimer. 39 | * 40 | * 2. Redistributions in binary form must reproduce the above copyright notice, 41 | * this list of conditions and the following disclaimer in the documentation 42 | * and/or other materials provided with the distribution. 43 | * 44 | * 3. The name of ATMEL may not be used to endorse or promote products derived 45 | * from this software without specific prior written permission. 46 | * 47 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED 48 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 49 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND 50 | * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, 51 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 52 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 53 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 54 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 55 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 56 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57 | *****************************************************************************/ 58 | 59 | #include "eeprom_driver.h" 60 | 61 | /*! \brief Write one byte to EEPROM using IO mapping. 62 | * 63 | * This function writes one byte to EEPROM using IO-mapped access. 64 | * Please note that the memory mapped EERPROM can not be used when using this function. 65 | * This functiom will cancel all ongoing EEPROM page buffer loading 66 | * operations, if any. 67 | * 68 | * \param pageAddr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGESIZE 69 | * \param byteAddr EEPROM Byte address, between 0 and EEPROM_PAGESIZE. 70 | * \param value Byte value to write to EEPROM. 71 | */ 72 | void EEPROM_WriteByte( uint8_t pageAddr, uint8_t byteAddr, uint8_t value ) 73 | { 74 | /* Flush buffer to make sure no unintetional data is written and load 75 | * the "Page Load" command into the command register. 76 | */ 77 | EEPROM_FlushBuffer(); 78 | NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; 79 | 80 | /* Calculate address */ 81 | uint16_t address = (uint16_t)(pageAddr*EEPROM_PAGESIZE) 82 | |(byteAddr & (EEPROM_PAGESIZE-1)); 83 | 84 | /* Set address to write to. */ 85 | NVM.ADDR0 = address & 0xFF; 86 | NVM.ADDR1 = (address >> 8) & 0x1F; 87 | NVM.ADDR2 = 0x00; 88 | 89 | /* Load data to write, which triggers the loading of EEPROM page buffer. */ 90 | NVM.DATA0 = value; 91 | 92 | /* Issue EEPROM Atomic Write (Erase&Write) command. Load command, write 93 | * the protection signature and execute command. 94 | */ 95 | NVM.CMD = NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc; 96 | NVM_EXEC(); 97 | } 98 | 99 | 100 | /*! \brief Read one byte from EEPROM using IO mapping. 101 | * 102 | * This function reads one byte from EEPROM using IO-mapped access. 103 | * Please note that the memory mapped EERPROM can not be used when using this function. 104 | * 105 | * \param pageAddr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGESIZE 106 | * \param byteAddr EEPROM Byte address, between 0 and EEPROM_PAGESIZE. 107 | * 108 | * \return Byte value read from EEPROM. 109 | */ 110 | uint8_t EEPROM_ReadByte( uint8_t pageAddr, uint8_t byteAddr ) 111 | { 112 | /* Wait until NVM is not busy. */ 113 | EEPROM_WaitForNVM(); 114 | 115 | /* Calculate address */ 116 | uint16_t address = (uint16_t)(pageAddr*EEPROM_PAGESIZE) 117 | |(byteAddr & (EEPROM_PAGESIZE-1)); 118 | 119 | /* Set address to read from. */ 120 | NVM.ADDR0 = address & 0xFF; 121 | NVM.ADDR1 = (address >> 8) & 0x1F; 122 | NVM.ADDR2 = 0x00; 123 | 124 | /* Issue EEPROM Read command. */ 125 | NVM.CMD = NVM_CMD_READ_EEPROM_gc; 126 | NVM_EXEC(); 127 | 128 | return NVM.DATA0; 129 | } 130 | 131 | 132 | /*! \brief Wait for any NVM access to finish, including EEPROM. 133 | * 134 | * This function is blcoking and waits for any NVM access to finish, 135 | * including EEPROM. Use this function before any EEPROM accesses, 136 | * if you are not certain that any previous operations are finished yet, 137 | * like an EEPROM write. 138 | */ 139 | void EEPROM_WaitForNVM( void ) 140 | { 141 | do { 142 | /* Block execution while waiting for the NVM to be ready. */ 143 | } while ((NVM.STATUS & NVM_NVMBUSY_bm) == NVM_NVMBUSY_bm); 144 | } 145 | 146 | 147 | /*! \brief Flush temporary EEPROM page buffer. 148 | * 149 | * This function flushes the EEPROM page buffers. This function will cancel 150 | * any ongoing EEPROM page buffer loading operations, if any. 151 | * This function also works for memory mapped EEPROM access. 152 | * 153 | * \note The EEPROM write operations will automatically flush the buffer for you. 154 | */ 155 | void EEPROM_FlushBuffer( void ) 156 | { 157 | /* Wait until NVM is not busy. */ 158 | EEPROM_WaitForNVM(); 159 | 160 | /* Flush EEPROM page buffer if necessary. */ 161 | if ((NVM.STATUS & NVM_EELOAD_bm) != 0) { 162 | NVM.CMD = NVM_CMD_ERASE_EEPROM_BUFFER_gc; 163 | NVM_EXEC(); 164 | } 165 | } 166 | 167 | 168 | /*! \brief Load single byte into temporary page buffer. 169 | * 170 | * This function loads one byte into the temporary EEPROM page buffers. 171 | * If memory mapped EEPROM is enabled, this function will not work. 172 | * Make sure that the buffer is flushed before starting to load bytes. 173 | * Also, if multiple bytes are loaded into the same location, they will 174 | * be ANDed together, thus 0x55 and 0xAA will result in 0x00 in the buffer. 175 | * 176 | * \note Only one page buffer exist, thus only one page can be loaded with 177 | * data and programmed into one page. If data needs to be written to 178 | * different pages, the loading and writing needs to be repeated. 179 | * 180 | * \param byteAddr EEPROM Byte address, between 0 and EEPROM_PAGESIZE. 181 | * \param value Byte value to write to buffer. 182 | */ 183 | void EEPROM_LoadByte( uint8_t byteAddr, uint8_t value ) 184 | { 185 | /* Wait until NVM is not busy and prepare NVM command.*/ 186 | EEPROM_WaitForNVM(); 187 | NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; 188 | 189 | /* Set address. */ 190 | NVM.ADDR0 = byteAddr & 0xFF; 191 | NVM.ADDR1 = 0x00; 192 | NVM.ADDR2 = 0x00; 193 | 194 | /* Set data, which triggers loading of EEPROM page buffer. */ 195 | NVM.DATA0 = value; 196 | } 197 | 198 | 199 | /*! \brief Load entire page into temporary EEPROM page buffer. 200 | * 201 | * This function loads an entire EEPROM page from an SRAM buffer to 202 | * the EEPROM page buffers. Please note that the memory mapped EERPROM can not be used when using this function. 203 | * Make sure that the buffer is flushed before 204 | * starting to load bytes. 205 | * 206 | * \note Only the lower part of the address is used to address the buffer. 207 | * Therefore, no address parameter is needed. In the end, the data 208 | * is written to the EEPROM page given by the address parameter to the 209 | * EEPROM write page operation. 210 | * 211 | * \param values Pointer to SRAM buffer containing an entire page. 212 | */ 213 | void EEPROM_LoadPage( const uint8_t * values ) 214 | { 215 | /* Wait until NVM is not busy. */ 216 | EEPROM_WaitForNVM(); 217 | NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; 218 | 219 | /* Set address to zero, as only the lower bits matters. ADDR0 is 220 | * maintained inside the loop below. 221 | */ 222 | NVM.ADDR1 = 0x00; 223 | NVM.ADDR2 = 0x00; 224 | 225 | /* Load multible bytes into page buffer. */ 226 | for (uint8_t i = 0; i < EEPROM_PAGESIZE; ++i) { 227 | NVM.ADDR0 = i; 228 | NVM.DATA0 = *values; 229 | ++values; 230 | } 231 | } 232 | 233 | /*! \brief Write already loaded page into EEPROM. 234 | * 235 | * This function writes the contents of an already loaded EEPROM page 236 | * buffer into EEPROM memory. 237 | * 238 | * As this is an atomic write, the page in EEPROM will be erased 239 | * automatically before writing. Note that only the page buffer locations 240 | * that have been loaded will be used when writing to EEPROM. Page buffer 241 | * locations that have not been loaded will be left untouched in EEPROM. 242 | * 243 | * \param pageAddr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGESIZE 244 | */ 245 | void EEPROM_AtomicWritePage( uint8_t pageAddr ) 246 | { 247 | /* Wait until NVM is not busy. */ 248 | EEPROM_WaitForNVM(); 249 | 250 | /* Calculate page address */ 251 | uint16_t address = (uint16_t)(pageAddr*EEPROM_PAGESIZE); 252 | 253 | /* Set address. */ 254 | NVM.ADDR0 = address & 0xFF; 255 | NVM.ADDR1 = (address >> 8) & 0x1F; 256 | NVM.ADDR2 = 0x00; 257 | 258 | /* Issue EEPROM Atomic Write (Erase&Write) command. */ 259 | NVM.CMD = NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc; 260 | NVM_EXEC(); 261 | } 262 | 263 | 264 | /*! \brief Erase EEPROM page. 265 | * 266 | * This function erases one EEPROM page, so that every location reads 0xFF. 267 | * 268 | * \param pageAddr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGESIZE 269 | */ 270 | void EEPROM_ErasePage( uint8_t pageAddr ) 271 | { 272 | /* Wait until NVM is not busy. */ 273 | EEPROM_WaitForNVM(); 274 | 275 | /* Calculate page address */ 276 | uint16_t address = (uint16_t)(pageAddr*EEPROM_PAGESIZE); 277 | 278 | /* Set address. */ 279 | NVM.ADDR0 = address & 0xFF; 280 | NVM.ADDR1 = (address >> 8) & 0x1F; 281 | NVM.ADDR2 = 0x00; 282 | 283 | /* Issue EEPROM Erase command. */ 284 | NVM.CMD = NVM_CMD_ERASE_EEPROM_PAGE_gc; 285 | NVM_EXEC(); 286 | } 287 | 288 | 289 | /*! \brief Write (without erasing) EEPROM page. 290 | * 291 | * This function writes the contents of an already loaded EEPROM page 292 | * buffer into EEPROM memory. 293 | * 294 | * As this is a split write, the page in EEPROM will _not_ be erased 295 | * before writing. 296 | * 297 | * \param pageAddr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGESIZE 298 | */ 299 | void EEPROM_SplitWritePage( uint8_t pageAddr ) 300 | { 301 | /* Wait until NVM is not busy. */ 302 | EEPROM_WaitForNVM(); 303 | 304 | /* Calculate page address */ 305 | uint16_t address = (uint16_t)(pageAddr*EEPROM_PAGESIZE); 306 | 307 | /* Set address. */ 308 | NVM.ADDR0 = address & 0xFF; 309 | NVM.ADDR1 = (address >> 8) & 0x1F; 310 | NVM.ADDR2 = 0x00; 311 | 312 | /* Issue EEPROM Split Write command. */ 313 | NVM.CMD = NVM_CMD_WRITE_EEPROM_PAGE_gc; 314 | NVM_EXEC(); 315 | } 316 | 317 | /*! \brief Erase entire EEPROM memory. 318 | * 319 | * This function erases the entire EEPROM memory block to 0xFF. 320 | */ 321 | void EEPROM_EraseAll( void ) 322 | { 323 | /* Wait until NVM is not busy. */ 324 | EEPROM_WaitForNVM(); 325 | 326 | /* Issue EEPROM Erase All command. */ 327 | NVM.CMD = NVM_CMD_ERASE_EEPROM_gc; 328 | NVM_EXEC(); 329 | } 330 | 331 | -------------------------------------------------------------------------------- /Xmega_Bootloader/eeprom_driver.h: -------------------------------------------------------------------------------- 1 | /* This file has been prepared for Doxygen automatic documentation generation.*/ 2 | /*! \file ********************************************************************* 3 | * 4 | * \brief XMEGA EEPROM driver header file. 5 | * 6 | * This file contains the function prototypes and enumerator definitions 7 | * for various configuration parameters for the XMEGA EEPROM driver. 8 | * 9 | * The driver is not intended for size and/or speed critical code, since 10 | * most functions are just a few lines of code, and the function call 11 | * overhead would decrease code performance. The driver is intended for 12 | * rapid prototyping and documentation purposes for getting started with 13 | * the XMEGA EEPROM module. 14 | * 15 | * For size and/or speed critical code, it is recommended to copy the 16 | * function contents directly into your application instead of making 17 | * a function call. 18 | * 19 | * \par Application note: 20 | * AVR1315: Accessing the XMEGA EEPROM 21 | * 22 | * \par Documentation 23 | * For comprehensive code documentation, supported compilers, compiler 24 | * settings and supported devices see readme.html 25 | * 26 | * \author 27 | * Atmel Corporation: http://www.atmel.com \n 28 | * Support email: avr@atmel.com 29 | * 30 | * $Revision: 1 $ 31 | * $Date: 2009-04-22 13:03:43 +0200 (ti, 22 apr 2009) $ \n 32 | * 33 | * Copyright (c) 2009, Atmel Corporation All rights reserved. 34 | * 35 | * Redistribution and use in source and binary forms, with or without 36 | * modification, are permitted provided that the following conditions are met: 37 | * 38 | * 1. Redistributions of source code must retain the above copyright notice, 39 | * this list of conditions and the following disclaimer. 40 | * 41 | * 2. Redistributions in binary form must reproduce the above copyright notice, 42 | * this list of conditions and the following disclaimer in the documentation 43 | * and/or other materials provided with the distribution. 44 | * 45 | * 3. The name of ATMEL may not be used to endorse or promote products derived 46 | * from this software without specific prior written permission. 47 | * 48 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED 49 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 50 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND 51 | * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, 52 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 53 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 54 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 55 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 56 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 57 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 58 | *****************************************************************************/ 59 | #ifndef EEPROM_DRIVER_H 60 | #define EEPROM_DRIVER_H 61 | 62 | #include "avr_compiler.h" 63 | 64 | /* Definitions of macros. */ 65 | 66 | /*! \brief Defining EEPROM Start address and Page Size. 67 | * 68 | * This macro defines the starting address of EEPROM along with the Page Size for further pagewise updation of EEPROM. 69 | */ 70 | #ifndef MAPPED_EEPROM_START 71 | #define MAPPED_EEPROM_START 0x1000 72 | #endif 73 | 74 | #define EEPROM_PAGESIZE 32 75 | #define EEPROM(_pageAddr, _byteAddr) \ 76 | ((uint8_t *) MAPPED_EEPROM_START)[_pageAddr*EEPROM_PAGESIZE + _byteAddr] 77 | 78 | 79 | 80 | /* Definitions of macros. */ 81 | 82 | /*! \brief Enable EEPROM block sleep-when-not-used mode. 83 | * 84 | * This macro enables power reduction mode for EEPROM. 85 | * It means that the EEPROM block is disabled when not used. 86 | * Note that there will be a penalty of 6 CPU cycles if EEPROM 87 | * is accessed. 88 | */ 89 | #define EEPROM_EnablePowerReduction() ( NVM.CTRLB |= NVM_EPRM_bm ) 90 | 91 | /*! \brief Disable EEPROM block sleep-when-not-used mode. 92 | * 93 | * This macro disables power reduction mode for EEPROM. 94 | */ 95 | #define EEPROM_DisablePowerReduction() ( NVM.CTRLB &= ~NVM_EPRM_bm ) 96 | 97 | /*! \brief Enable EEPROM mapping into data space. 98 | * 99 | * This macro enables mapping of EEPROM into data space. 100 | * EEPROM starts at EEPROM_START in data memory. Read access 101 | * can be done similar to ordinary SRAM access. 102 | * 103 | * \note This disables IO-mapped access to EEPROM, although page erase and 104 | * write operations still needs to be done through IO register. 105 | */ 106 | #define EEPROM_EnableMapping() ( NVM.CTRLB |= NVM_EEMAPEN_bm ) 107 | 108 | /*! \brief Disable EEPROM mapping into data space. 109 | * 110 | * This macro disables mapping of EEPROM into data space. 111 | * IO mapped access is now enabled. 112 | */ 113 | #define EEPROM_DisableMapping() ( NVM.CTRLB &= ~NVM_EEMAPEN_bm ) 114 | 115 | /*! \brief Non-Volatile Memory Execute Command 116 | * 117 | * This macro set the CCP register before setting the CMDEX bit in the 118 | * NVM.CTRLA register. 119 | * 120 | * \note The CMDEX bit must be set within 4 clock cycles after setting the 121 | * protection byte in the CCP register. 122 | */ 123 | #define NVM_EXEC() asm("push r30" "\n\t" \ 124 | "push r31" "\n\t" \ 125 | "push r16" "\n\t" \ 126 | "push r18" "\n\t" \ 127 | "ldi r30, 0xCB" "\n\t" \ 128 | "ldi r31, 0x01" "\n\t" \ 129 | "ldi r16, 0xD8" "\n\t" \ 130 | "ldi r18, 0x01" "\n\t" \ 131 | "out 0x34, r16" "\n\t" \ 132 | "st Z, r18" "\n\t" \ 133 | "pop r18" "\n\t" \ 134 | "pop r16" "\n\t" \ 135 | "pop r31" "\n\t" \ 136 | "pop r30" "\n\t" \ 137 | ) 138 | 139 | /* Prototyping of functions. */ 140 | void EEPROM_WriteByte( uint8_t pageAddr, uint8_t byteAddr, uint8_t value ); 141 | uint8_t EEPROM_ReadByte( uint8_t pageAddr, uint8_t byteAddr ); 142 | void EEPROM_WaitForNVM( void ); 143 | void EEPROM_FlushBuffer( void ); 144 | void EEPROM_LoadByte( uint8_t byteAddr, uint8_t value ); 145 | void EEPROM_LoadPage( const uint8_t * values ); 146 | void EEPROM_AtomicWritePage( uint8_t pageAddr ); 147 | void EEPROM_ErasePage( uint8_t pageAddress ); 148 | void EEPROM_SplitWritePage( uint8_t pageAddr ); 149 | void EEPROM_EraseAll( void ); 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /Xmega_Bootloader/makefile: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Makefile for the project Xmega_Bootloader 3 | ############################################################################### 4 | 5 | ## General Flags 6 | PROJECT = Xmega_Bootloader 7 | 8 | ############################################################################### 9 | # User modification section 10 | ############################################################################### 11 | # Choose one of the following MCUs: 12 | # If you have a different MCU, you will have to define these values: 13 | # Name in makefile Name in ioxxxx.h 14 | # --------------------------- ----------------------------- 15 | # BOOT_SECTION_START_IN_BYTES BOOT_SECTION_START 16 | # BOOT_PAGE_SIZE BOOT_SECTION_PAGE_SIZE 17 | # APP_PAGE_SIZE APP_SECTION_PAGE_SIZE 18 | # 19 | # You can find these files in the include path for your compiler. Examples: 20 | # 1) Winavr: C:\WinAVR-20100110\avr\include\avr\ioxxxx.h 21 | # 2) Atmel 3.4.2: C:\Program Files (x86)\Atmel\Atmel Toolchain\AVR8 GCC\ 22 | # Native\3.4.2.1002\avr8-gnu-toolchain\avr\include\avr\ioxxxx.h 23 | 24 | # MCU = atxmega8e5 25 | # MCU = atxmega16a4 26 | # MCU = atxmega16a4u 27 | # MCU = atxmega16c4 28 | # MCU = atxmega16d4 29 | # MCU = atxmega16e5 30 | # MCU = atxmega32a4 31 | # MCU = atxmega32a4u 32 | # MCU = atxmega32c3 33 | # MCU = atxmega32c4 34 | # MCU = atxmega32d3 35 | # MCU = atxmega32d4 36 | # MCU = atxmega32e5 37 | # MCU = atxmega64a1 38 | # MCU = atxmega64a1u 39 | # MCU = atxmega64a3 40 | # MCU = atxmega64a3u 41 | # MCU = atxmega64a4u 42 | # MCU = atxmega64b1 43 | # MCU = atxmega64b3 44 | # MCU = atxmega64c3 45 | # MCU = atxmega64d3 46 | # MCU = atxmega64d4 47 | MCU = atxmega128a1 48 | # MCU = atxmega128a1u 49 | # MCU = atxmega128a3 50 | # MCU = atxmega128a3u 51 | # MCU = atxmega128a4u 52 | # MCU = atxmega128b1 53 | # MCU = atxmega128b3 54 | # MCU = atxmega128c3 55 | # MCU = atxmega128d3 56 | # MCU = atxmega128d4 57 | # MCU = atxmega192a3 58 | # MCU = atxmega192a3u 59 | # MCU = atxmega192c3 60 | # MCU = atxmega192d3 61 | # MCU = atxmega256a3 62 | # MCU = atxmega256a3b 63 | # MCU = atxmega256a3bu 64 | # MCU = atxmega256a3u 65 | # MCU = atxmega256c3 66 | # MCU = atxmega256d3 67 | # MCU = atxmega384c3 68 | # MCU = atxmega384d3 69 | 70 | # Choose a baud rate for the UART. 71 | # If you need a baud rate that is not listed in this makefile, you must add 72 | # new configuration statements in config.macros.h. Remember, Xmegas start-up 73 | # with a 2MHz clock. 74 | # BAUD_RATE = 9600 75 | # BAUD_RATE = 38400 76 | # BAUD_RATE = 57600 77 | BAUD_RATE = 115200 78 | 79 | # Specify a pin to check for entry into the bootloader. The notation is 80 | # PORT,PIN. For example, if you wanted to use PIN 3 on PORTC, you would set 81 | # the option as C,3. Then specifiy the logic value required to enable the 82 | # bootloader code (1 = enable the bootloader if the pin is VCC, 0 = enable 83 | # the bootloader if the pin is GND). 84 | BOOTLOADER_PIN = Q,2 85 | BOOTLOADER_PIN_ON = 1 86 | 87 | # Specify a pin to control an LED. The notation is PORT,PIN. For example, if 88 | # you wanted to use PIN 6 on PORTA, you would set the option as A,6. Then 89 | # specifiy the logic value required to enable the LED (1 = output VCC to turn 90 | # on the LED, 0 = output GND to turn on the LED). 91 | LED_PIN = Q,3 92 | LED_ON = 1 93 | 94 | # Specify which UART to use with PORT,NUM notation. For example, UART1 on 95 | # PORTD would be D,1. 96 | UART = E,0 97 | 98 | # Specifiy the SEC Xtractor color (with boot button = black, without=red) 99 | COLOR_BLACK=1 100 | COLOR_RED=2 101 | XTRACTOR_COLOR = COLOR_BLACK 102 | 103 | ############################################################################### 104 | # End user modification section 105 | ############################################################################### 106 | 107 | ## Set configuration options based on MCU model 108 | ifeq ($(MCU), atxmega8e5) 109 | BOOT_SECTION_START_IN_BYTES = 0x2000 110 | BOOT_PAGE_SIZE = 128 111 | APP_PAGE_SIZE = 128 112 | endif 113 | ifeq ($(MCU), atxmega16a4) 114 | BOOT_SECTION_START_IN_BYTES = 0x4000 115 | BOOT_PAGE_SIZE = 256 116 | APP_PAGE_SIZE = 256 117 | endif 118 | ifeq ($(MCU), atxmega16a4u) 119 | BOOT_SECTION_START_IN_BYTES = 0x4000 120 | BOOT_PAGE_SIZE = 256 121 | APP_PAGE_SIZE = 256 122 | endif 123 | ifeq ($(MCU), atxmega16c4) 124 | BOOT_SECTION_START_IN_BYTES = 0x4000 125 | BOOT_PAGE_SIZE = 256 126 | APP_PAGE_SIZE = 256 127 | endif 128 | ifeq ($(MCU), atxmega16d4) 129 | BOOT_SECTION_START_IN_BYTES = 0x4000 130 | BOOT_PAGE_SIZE = 256 131 | APP_PAGE_SIZE = 256 132 | endif 133 | ifeq ($(MCU), atxmega16e5) 134 | BOOT_SECTION_START_IN_BYTES = 0x4000 135 | BOOT_PAGE_SIZE = 128 136 | APP_PAGE_SIZE = 128 137 | endif 138 | ifeq ($(MCU), atxmega32a4) 139 | BOOT_SECTION_START_IN_BYTES = 0x8000 140 | BOOT_PAGE_SIZE = 256 141 | APP_PAGE_SIZE = 256 142 | endif 143 | ifeq ($(MCU), atxmega32a4u) 144 | BOOT_SECTION_START_IN_BYTES = 0x8000 145 | BOOT_PAGE_SIZE = 256 146 | APP_PAGE_SIZE = 256 147 | endif 148 | ifeq ($(MCU), atxmega32c3) 149 | BOOT_SECTION_START_IN_BYTES = 0x8000 150 | BOOT_PAGE_SIZE = 256 151 | APP_PAGE_SIZE = 256 152 | endif 153 | ifeq ($(MCU), atxmega32c4) 154 | BOOT_SECTION_START_IN_BYTES = 0x8000 155 | BOOT_PAGE_SIZE = 256 156 | APP_PAGE_SIZE = 256 157 | endif 158 | ifeq ($(MCU), atxmega32d3) 159 | BOOT_SECTION_START_IN_BYTES = 0x8000 160 | BOOT_PAGE_SIZE = 256 161 | APP_PAGE_SIZE = 256 162 | endif 163 | ifeq ($(MCU), atxmega32d4) 164 | BOOT_SECTION_START_IN_BYTES = 0x8000 165 | BOOT_PAGE_SIZE = 256 166 | APP_PAGE_SIZE = 256 167 | endif 168 | ifeq ($(MCU), atxmega32e5) 169 | BOOT_SECTION_START_IN_BYTES = 0x8000 170 | BOOT_PAGE_SIZE = 128 171 | APP_PAGE_SIZE = 128 172 | endif 173 | ifeq ($(MCU), atxmega64a1) 174 | BOOT_SECTION_START_IN_BYTES = 0x10000 175 | BOOT_PAGE_SIZE = 256 176 | APP_PAGE_SIZE = 256 177 | endif 178 | ifeq ($(MCU), atxmega64a1u) 179 | BOOT_SECTION_START_IN_BYTES = 0x10000 180 | BOOT_PAGE_SIZE = 256 181 | APP_PAGE_SIZE = 256 182 | endif 183 | ifeq ($(MCU), atxmega64a3) 184 | BOOT_SECTION_START_IN_BYTES = 0x10000 185 | BOOT_PAGE_SIZE = 256 186 | APP_PAGE_SIZE = 256 187 | endif 188 | ifeq ($(MCU), atxmega64a3u) 189 | BOOT_SECTION_START_IN_BYTES = 0x10000 190 | BOOT_PAGE_SIZE = 256 191 | APP_PAGE_SIZE = 256 192 | endif 193 | ifeq ($(MCU), atxmega64a4u) 194 | BOOT_SECTION_START_IN_BYTES = 0x10000 195 | BOOT_PAGE_SIZE = 256 196 | APP_PAGE_SIZE = 256 197 | endif 198 | ifeq ($(MCU), atxmega64b1) 199 | BOOT_SECTION_START_IN_BYTES = 0x10000 200 | BOOT_PAGE_SIZE = 256 201 | APP_PAGE_SIZE = 256 202 | endif 203 | ifeq ($(MCU), atxmega64b3) 204 | BOOT_SECTION_START_IN_BYTES = 0x10000 205 | BOOT_PAGE_SIZE = 256 206 | APP_PAGE_SIZE = 256 207 | endif 208 | ifeq ($(MCU), atxmega64c3) 209 | BOOT_SECTION_START_IN_BYTES = 0x10000 210 | BOOT_PAGE_SIZE = 256 211 | APP_PAGE_SIZE = 256 212 | endif 213 | ifeq ($(MCU), atxmega64d3) 214 | BOOT_SECTION_START_IN_BYTES = 0x10000 215 | BOOT_PAGE_SIZE = 256 216 | APP_PAGE_SIZE = 256 217 | endif 218 | ifeq ($(MCU), atxmega64d4) 219 | BOOT_SECTION_START_IN_BYTES = 0x10000 220 | BOOT_PAGE_SIZE = 256 221 | APP_PAGE_SIZE = 256 222 | endif 223 | ifeq ($(MCU), atxmega128a1) 224 | BOOT_SECTION_START_IN_BYTES = 0x20000 225 | BOOT_PAGE_SIZE = 512 226 | APP_PAGE_SIZE = 512 227 | endif 228 | ifeq ($(MCU), atxmega128a1u) 229 | BOOT_SECTION_START_IN_BYTES = 0x20000 230 | BOOT_PAGE_SIZE = 512 231 | APP_PAGE_SIZE = 512 232 | endif 233 | ifeq ($(MCU), atxmega128a3) 234 | BOOT_SECTION_START_IN_BYTES = 0x20000 235 | BOOT_PAGE_SIZE = 512 236 | APP_PAGE_SIZE = 512 237 | endif 238 | ifeq ($(MCU), atxmega128a3u) 239 | BOOT_SECTION_START_IN_BYTES = 0x20000 240 | BOOT_PAGE_SIZE = 512 241 | APP_PAGE_SIZE = 512 242 | endif 243 | ifeq ($(MCU), atxmega128a4u) 244 | BOOT_SECTION_START_IN_BYTES = 0x20000 245 | BOOT_PAGE_SIZE = 256 246 | APP_PAGE_SIZE = 256 247 | endif 248 | ifeq ($(MCU), atxmega128b1) 249 | BOOT_SECTION_START_IN_BYTES = 0x20000 250 | BOOT_PAGE_SIZE = 256 251 | APP_PAGE_SIZE = 256 252 | endif 253 | ifeq ($(MCU), atxmega128b3) 254 | BOOT_SECTION_START_IN_BYTES = 0x20000 255 | BOOT_PAGE_SIZE = 256 256 | APP_PAGE_SIZE = 256 257 | endif 258 | ifeq ($(MCU), atxmega128c3) 259 | BOOT_SECTION_START_IN_BYTES = 0x20000 260 | BOOT_PAGE_SIZE = 512 261 | APP_PAGE_SIZE = 512 262 | endif 263 | ifeq ($(MCU), atxmega128d3) 264 | BOOT_SECTION_START_IN_BYTES = 0x20000 265 | BOOT_PAGE_SIZE = 512 266 | APP_PAGE_SIZE = 512 267 | endif 268 | ifeq ($(MCU), atxmega128d4) 269 | BOOT_SECTION_START_IN_BYTES = 0x20000 270 | BOOT_PAGE_SIZE = 256 271 | APP_PAGE_SIZE = 256 272 | endif 273 | ifeq ($(MCU), atxmega192a3) 274 | BOOT_SECTION_START_IN_BYTES = 0x30000 275 | BOOT_PAGE_SIZE = 512 276 | APP_PAGE_SIZE = 512 277 | endif 278 | ifeq ($(MCU), atxmega192a3u) 279 | BOOT_SECTION_START_IN_BYTES = 0x30000 280 | BOOT_PAGE_SIZE = 512 281 | APP_PAGE_SIZE = 512 282 | endif 283 | ifeq ($(MCU), atxmega192c3) 284 | BOOT_SECTION_START_IN_BYTES = 0x30000 285 | BOOT_PAGE_SIZE = 512 286 | APP_PAGE_SIZE = 512 287 | endif 288 | ifeq ($(MCU), atxmega192d3) 289 | BOOT_SECTION_START_IN_BYTES = 0x30000 290 | BOOT_PAGE_SIZE = 512 291 | APP_PAGE_SIZE = 512 292 | endif 293 | ifeq ($(MCU), atxmega256a3) 294 | BOOT_SECTION_START_IN_BYTES = 0x40000 295 | BOOT_PAGE_SIZE = 512 296 | APP_PAGE_SIZE = 512 297 | endif 298 | ifeq ($(MCU), atxmega256a3b) 299 | BOOT_SECTION_START_IN_BYTES = 0x40000 300 | BOOT_PAGE_SIZE = 512 301 | APP_PAGE_SIZE = 512 302 | endif 303 | ifeq ($(MCU), atxmega256a3bu) 304 | BOOT_SECTION_START_IN_BYTES = 0x40000 305 | BOOT_PAGE_SIZE = 512 306 | APP_PAGE_SIZE = 512 307 | endif 308 | ifeq ($(MCU), atxmega256a3u) 309 | BOOT_SECTION_START_IN_BYTES = 0x40000 310 | BOOT_PAGE_SIZE = 512 311 | APP_PAGE_SIZE = 512 312 | endif 313 | ifeq ($(MCU), atxmega256c3) 314 | BOOT_SECTION_START_IN_BYTES = 0x40000 315 | BOOT_PAGE_SIZE = 512 316 | APP_PAGE_SIZE = 512 317 | endif 318 | ifeq ($(MCU), atxmega256d3) 319 | BOOT_SECTION_START_IN_BYTES = 0x40000 320 | BOOT_PAGE_SIZE = 512 321 | APP_PAGE_SIZE = 512 322 | endif 323 | ifeq ($(MCU), atxmega384c3) 324 | BOOT_SECTION_START_IN_BYTES = 0x60000 325 | BOOT_PAGE_SIZE = 512 326 | APP_PAGE_SIZE = 512 327 | endif 328 | ifeq ($(MCU), atxmega384d3) 329 | BOOT_SECTION_START_IN_BYTES = 0x60000 330 | BOOT_PAGE_SIZE = 512 331 | APP_PAGE_SIZE = 512 332 | endif 333 | 334 | TARGET = $(PROJECT).elf 335 | TARGET_BASE = $(PROJECT) 336 | 337 | CC = avr-gcc 338 | CPP = avr-g++ 339 | 340 | ## Compile options common for all C compilation units. 341 | CFLAGS += -mmcu=$(MCU) -Wall -gdwarf-2 -std=gnu99 -DF_CPU=2000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -DBOOT_PAGE_SIZE=$(BOOT_PAGE_SIZE) -DAPP_PAGE_SIZE=$(APP_PAGE_SIZE) -DMCU=$(MCU) -DBAUD_RATE=$(BAUD_RATE) -DMY_UART=$(UART) -DENTER_BOOTLOADER_PIN=$(BOOTLOADER_PIN) -DBOOTLOADER_PIN_EN=$(BOOTLOADER_PIN_ON) -DLED_PIN=$(LED_PIN) -DLED_ON=$(LED_ON) -DXTRACTOR_COLOR=$(XTRACTOR_COLOR) -DCOLOR_BLACK=$(COLOR_BLACK) -DCOLOR_RED=$(COLOR_RED) 342 | CFLAGS += -MD -MP -MT $(*F).o 343 | 344 | ## Assembly specific flags 345 | ASMFLAGS += $(CFLAGS) 346 | ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2 347 | 348 | ## Linker flags 349 | LDFLAGS = -mmcu=$(MCU) 350 | LDFLAGS += -Wl,-Map=$(PROJECT).map 351 | LDFLAGS += -Wl,-section-start=.text=$(BOOT_SECTION_START_IN_BYTES) 352 | 353 | ## Intel Hex file production flags 354 | HEX_FLASH_FLAGS = -R .eeprom -R .fuse -R .lock -R .signature 355 | HEX_EEPROM_FLAGS = -j .eeprom 356 | HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load" 357 | HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings 358 | 359 | ## Objects that must be built in order to link 360 | OBJECTS = eeprom_driver.o $(PROJECT).o serial.o sp_driver.o CCP_Write.o 361 | 362 | ## Objects explicitly added by the user 363 | LINKONLYOBJECTS = 364 | 365 | ## Build 366 | all: $(TARGET) $(PROJECT).hex $(PROJECT).eep $(PROJECT).lss 367 | # Uncomment if you want sizebefore and size after to execute 368 | #all: sizebefore $(TARGET) $(PROJECT).hex $(PROJECT).eep sizeafter $(PROJECT).lss 369 | eeprom_driver.o: eeprom_driver.c 370 | $(CC) $(INCLUDES) $(CFLAGS) -c $< 371 | 372 | $(PROJECT).o: $(PROJECT).c 373 | $(CC) $(INCLUDES) $(CFLAGS) -c $< 374 | 375 | serial.o: serial.c 376 | $(CC) $(INCLUDES) $(CFLAGS) -c $< 377 | 378 | sp_driver.o: sp_driver.s 379 | $(CC) $(INCLUDES) $(ASMFLAGS) -c $< 380 | 381 | CCP_Write.o: CCP_Write.s 382 | $(CC) $(INCLUDES) $(ASMFLAGS) -c $< 383 | 384 | ##Link 385 | $(TARGET): $(OBJECTS) 386 | $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET) 387 | 388 | %.hex: $(TARGET) 389 | avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@ 390 | 391 | %.eep: $(TARGET) 392 | avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0 393 | 394 | %.lss: $(TARGET) 395 | avr-objdump -h -S $< > $@ 396 | 397 | ## Clean target 398 | .PHONY: clean 399 | clean: 400 | -rm -rf $(OBJECTS) $(PROJECT).elf $(PROJECT).hex $(PROJECT).eep $(PROJECT).lss $(PROJECT).map $(PROJECT).d 401 | 402 | ## Other dependencies 403 | 404 | 405 | # Display size of file. 406 | FORMAT = ihex 407 | SIZE = avr-size 408 | MSG_SIZE_BEFORE = Size before: 409 | MSG_SIZE_AFTER = Size after: 410 | 411 | HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET_BASE).hex 412 | ELFSIZE = $(SIZE) -A $(TARGET_BASE).elf 413 | 414 | sizebefore: 415 | @if test -f $(TARGET); then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \ 416 | echo; fi 417 | 418 | sizeafter: 419 | @if test -f $(TARGET); then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \ 420 | echo; fi 421 | -------------------------------------------------------------------------------- /Xmega_Bootloader/serial.c: -------------------------------------------------------------------------------- 1 | #include "serial.h" 2 | 3 | /*! \brief Initializing UART communcation. 4 | * 5 | * This function initializes the UART communication with generic parameters as mentioned below. 6 | * Both Enabling both TRASMISSION and RECEPTION 7 | * BAUD RATE configured to BRREG_VALUE 8 | * As this is important function of initializing the UART, it has to be called prior to start the communication. 9 | * 10 | */ 11 | void initbootuart(void) 12 | { 13 | Port(MY_UART).DIRSET = TX_Pin(MY_UART); 14 | Uart(MY_UART).BAUDCTRLA = BRREG_VALUE; 15 | Uart(MY_UART).BAUDCTRLB = (SCALE_VALUE << USART_BSCALE_gp) & USART_BSCALE_gm; 16 | Uart(MY_UART).CTRLB = USART_RXEN_bm | USART_TXEN_bm; // enable receive and transmit 17 | } 18 | 19 | /*! \brief Transmitting a character UART communcation. 20 | * 21 | * This function takes the unsigned char input given to the function and transmits out in the UART communication. 22 | * 23 | * This function is called whenever a single character has to be transmitted in the UART communication. 24 | * \param c Character value to be transmitted. 25 | * 26 | */ 27 | void sendchar(unsigned char c) 28 | { 29 | Uart(MY_UART).DATA = c; // prepare transmission 30 | while (!(Uart(MY_UART).STATUS & (1 << USART_DREIF_bp))); 31 | } 32 | 33 | /*! \brief Receiving a character in UART communcation. 34 | * 35 | * This function confirms the reception of data in UART, receives that character and returns the received character to the called function. 36 | * 37 | * This function is called whenever a single charater has to be received from the UART communication. 38 | * 39 | * \return Character value received from UART communication. 40 | */ 41 | 42 | unsigned char recchar(void) 43 | { 44 | while(!(Uart(MY_UART).STATUS & USART_RXCIF_bm)); // wait for data 45 | return Uart(MY_UART).DATA; 46 | } 47 | 48 | unsigned int input_available( void ) 49 | { 50 | return (Uart(MY_UART).STATUS & USART_RXCIF_bm); 51 | } 52 | -------------------------------------------------------------------------------- /Xmega_Bootloader/serial.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * Atmel Corporation 4 | * 5 | * File : serial.h 6 | * Compiler : IAR C 3.10C Kickstart, AVR-GCC/avr-libc(>= 1.2.5) 7 | * Revision : $Revision: 1 $ 8 | * Date : $Date: Wednesday, April 22, 2009 $ 9 | * Updated by : $Author: raapeland $ 10 | * 11 | * Support mail : avr@atmel.com 12 | * 13 | * Target platform : All AVRs with bootloader support 14 | * 15 | * AppNote : AVR109 - Self-programming 16 | * 17 | * Description : Header file for serial.c 18 | ****************************************************************************/ 19 | 20 | #include "Xmega_Bootloader.h" 21 | 22 | /*! \brief Generate UART initialisation section. 23 | * 24 | * \retval None 25 | */ 26 | void initbootuart( void ); 27 | /*! \brief UART Transmitting section. 28 | * 29 | * \retval None 30 | */ 31 | void sendchar( unsigned char ); 32 | /*! \brief Generate UART initialisation section. 33 | * 34 | * \retval 8-bit(unsigned char) Received Character 35 | */ 36 | unsigned char recchar( void ); 37 | 38 | unsigned int input_available( void ); 39 | 40 | -------------------------------------------------------------------------------- /Xmega_Bootloader/sp_driver.h: -------------------------------------------------------------------------------- 1 | /* This file has been prepared for Doxygen automatic documentation generation.*/ 2 | /*! \file ********************************************************************* 3 | * 4 | * \brief XMEGA Self-programming driver header file. 5 | * 6 | * This file contains the function prototypes for the 7 | * XMEGA Self-programming driver. 8 | * If any SPM instructions are used, the linker file must define 9 | * a segment named BOOT which must be located in the device boot section. 10 | * 11 | * 12 | * None of these functions clean up the NVM Command Register after use. 13 | * It is therefore important to write NVMCMD_NO_OPERATION (0x00) to this 14 | * register when you are finished using any of the functions in this driver. 15 | * 16 | * For all functions, it is important that no interrupt handlers 17 | * perform any NVM operations. The user must implement a scheme for mutually 18 | * exclusive access to the NVM. However, the 4-cycle timeout will work fine, 19 | * since writing to the Configuration Change Protection register (CCP) 20 | * automatically disables interrupts for 4 instruction cycles. 21 | * 22 | * \par Application note: 23 | * AVR1316: XMEGA Self-programming 24 | * 25 | * \par Documentation 26 | * For comprehensive code documentation, supported compilers, compiler 27 | * settings and supported devices see readme.html 28 | * 29 | * \author 30 | * Atmel Corporation: http://www.atmel.com \n 31 | * Support email: avr@atmel.com 32 | * 33 | * $Revision: 1691 $ 34 | * $Date: 2008-07-29 13:25:40 +0200 (ti, 29 jul 2008) $ \n 35 | * 36 | * Copyright (c) 2008, Atmel Corporation All rights reserved. 37 | * 38 | * Redistribution and use in source and binary forms, with or without 39 | * modification, are permitted provided that the following conditions are met: 40 | * 41 | * 1. Redistributions of source code must retain the above copyright notice, 42 | * this list of conditions and the following disclaimer. 43 | * 44 | * 2. Redistributions in binary form must reproduce the above copyright notice, 45 | * this list of conditions and the following disclaimer in the documentation 46 | * and/or other materials provided with the distribution. 47 | * 48 | * 3. The name of ATMEL may not be used to endorse or promote products derived 49 | * from this software without specific prior written permission. 50 | * 51 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED 52 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 53 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND 54 | * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, 55 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 56 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 57 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 58 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 60 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61 | *****************************************************************************/ 62 | #ifndef SP_DRIVER_H 63 | #define SP_DRIVER_H 64 | 65 | #include "avr_compiler.h" 66 | 67 | /* Define the Start of the application table if not defined in the header files. */ 68 | #ifndef APPTABLE_SECTION_START 69 | #error APPTABLE_SECTION_START must be defined if not defined in header files. 70 | # //#define APPTABLE_SECTION_START 0x01E000 //APPTABLE address for ATxmega128A1 71 | #endif /*APPTABLE_SECTION_START*/ 72 | 73 | /*! \brief Read a byte from flash. 74 | * 75 | * This function reads one byte from the flash. 76 | * 77 | * \note Both IAR and GCC have functions to do this, but 78 | * we include the fucntions for easier use. 79 | * 80 | * \param address Address to the location of the byte to read. 81 | * 82 | * \retval Byte read from flash. 83 | */ 84 | #ifdef __cplusplus 85 | extern "C" { 86 | #endif 87 | uint8_t SP_ReadByte(uint32_t address); 88 | 89 | /*! \brief Read a word from flash. 90 | * 91 | * This function reads one word from the flash. 92 | * 93 | * \note Both IAR and GCC have functions to do this automatically, but 94 | * we include the fucntions for easier use. 95 | * 96 | * \param address Address to the location of the word to read. 97 | * 98 | * \retval word read from flash. 99 | */ 100 | uint16_t SP_ReadWord(uint32_t address); 101 | 102 | /*! \brief Read calibration byte at given index. 103 | * 104 | * This function reads one calibration byte from the Calibration signature row. 105 | * 106 | * \param index Index of the byte in the calibration signature row. 107 | * 108 | * \retval Calibration byte 109 | */ 110 | uint8_t SP_ReadCalibrationByte(uint8_t index); 111 | 112 | /*! \brief Read fuse byte from given index. 113 | * 114 | * This function reads the fuse byte at the given index. 115 | * 116 | * \param index Index of the fuse byte. 117 | * 118 | * \retval Fuse byte 119 | */ 120 | uint8_t SP_ReadFuseByte(uint8_t index); 121 | 122 | /*! \brief Write lock bits. 123 | * 124 | * This function changes the lock bits. 125 | * 126 | * \note It is only possible to change the lock bits to a higher security level. 127 | * 128 | * \param data The new value of the lock bits. 129 | */ 130 | void SP_WriteLockBits(uint8_t data); 131 | 132 | /*! \brief Read lock bits. 133 | * 134 | * This function reads the lock bits. 135 | * 136 | * \retval Lock bits 137 | */ 138 | uint8_t SP_ReadLockBits(void); 139 | 140 | /*! \brief Read user signature at given index. 141 | * 142 | * This function reads one byte from the user signature row. 143 | * 144 | * \param index Index of the byte in the user signature row. 145 | * 146 | * \retval User signature byte 147 | */ 148 | uint8_t SP_ReadUserSignatureByte(uint16_t index); 149 | 150 | /*! \brief Erase user signature row. 151 | * 152 | * This function erase the entire user signature row. 153 | */ 154 | void SP_EraseUserSignatureRow(void); 155 | 156 | /*! \brief Write user signature row. 157 | * 158 | * This function write the flash buffer in the user signature row. 159 | */ 160 | void SP_WriteUserSignatureRow(void); 161 | 162 | /*! \brief Erase entire application section. 163 | * 164 | * This function erases the entire application and application table section 165 | * 166 | * \note If the lock bits is set to not allow spm in the application or 167 | * application table section the erase is not done. 168 | */ 169 | void SP_EraseApplicationSections(void); 170 | 171 | /*! \brief Erase page at byte address in application or application table section. 172 | * 173 | * This function erase one page given by the byte address. 174 | * 175 | * \param address Byte address for flash page. 176 | */ 177 | void SP_EraseApplicationPage(uint32_t address); 178 | 179 | /*! \brief Erase and write page buffer to application or application table section at byte address. 180 | * 181 | * This function does a combined erase and write to a flash page in the application 182 | * or application table section. 183 | * 184 | * \param address Byte address for flash page. 185 | */ 186 | void SP_EraseWriteApplicationPage(uint32_t address); 187 | 188 | /*! \brief Write page buffer to application or application table section at byte address. 189 | * 190 | * This function writes the Flash page buffer to a page in the application or 191 | * application table section given by the byte address. 192 | * 193 | * \note The page that is written to must be erased before it is written to. 194 | * 195 | * \param address Byte address for flash page. 196 | */ 197 | void SP_WriteApplicationPage(uint32_t address); 198 | 199 | /*! \brief Load one word into Flash page buffer. 200 | * 201 | * This function Loads one word into the Flash page buffer. 202 | * 203 | * \param address Position in inside the flash page buffer. 204 | * \param data Value to be put into the buffer. 205 | */ 206 | void SP_LoadFlashWord(uint16_t address, uint16_t data); 207 | 208 | /*! \brief Load entire page from SRAM buffer into Flash page buffer. 209 | * 210 | * This function load an entire page from SRAM. 211 | * 212 | * \param data Pointer to the data to put in buffer. 213 | * 214 | * \note The __near keyword limits the pointer to two bytes which means that 215 | * only data up to 64K (internal SRAM) can be used. 216 | */ 217 | void SP_LoadFlashPage(const uint8_t * data); 218 | 219 | /*! \brief Read entire Flash page into SRAM buffer. 220 | * 221 | * This function reads an entire flash page and puts it to SRAM. 222 | * 223 | * \param data Pointer to where to store the data. 224 | * \param address Address to page to read from flash. 225 | */ 226 | void SP_ReadFlashPage(const uint8_t * data, uint32_t address); 227 | 228 | /*! \brief Flush Flash page buffer. 229 | * 230 | * This function flush the Flash page buffer. 231 | */ 232 | void SP_EraseFlashBuffer(void); 233 | 234 | /*! \brief Erase page at byte address in boot section. 235 | * 236 | * This function erase one page given by the byte address. 237 | * 238 | * \param address Byte address for flash page. 239 | */ 240 | void SP_EraseBootPage(uint32_t address); 241 | 242 | /*! \brief Erase and write page buffer to boot section at byte address. 243 | * 244 | * This function does a combined erase and write to a flash page in the boot 245 | * section. 246 | * 247 | * \param address Byte address for flash page. 248 | */ 249 | void SP_EraseWriteBootPage(uint32_t address); 250 | 251 | /*! \brief Write page buffer to boot section at byte address. 252 | * 253 | * This function writes the Flash page buffer to a page in the boot section 254 | * given by the byte address. 255 | * 256 | * \note The page that is written to must be erased before it is written to. 257 | * 258 | * \param address Byte address for flash page. 259 | */ 260 | void SP_WriteBootPage(uint32_t address); 261 | 262 | /*! \brief Generate CRC from application section. 263 | * 264 | * \retval 24-bit CRC value 265 | */ 266 | uint32_t SP_ApplicationCRC(void); 267 | 268 | /*! \brief Generate CRC from boot section. 269 | * 270 | * \retval 24-bit CRC value 271 | */ 272 | uint32_t SP_BootCRC(void); 273 | 274 | /*! \brief Lock SPM instruction. 275 | * 276 | * This function locks the SPM instruction, and will disable the use of 277 | * SPM until the next reset occurs. 278 | */ 279 | void SP_LockSPM(void); 280 | 281 | /*! \brief Wait for SPM to finish. 282 | * 283 | * This routine waits for the SPM to finish and clears the command register. 284 | */ 285 | void SP_WaitForSPM(void); 286 | 287 | #ifdef __cplusplus 288 | } 289 | #endif 290 | 291 | 292 | #endif /* SP_DRIVER_H */ 293 | -------------------------------------------------------------------------------- /eeprom/jtag-eeprom.conf: -------------------------------------------------------------------------------- 1 | vendor_id=0x0403 # Vendor ID 2 | product_id=0x6010 # Product ID 3 | 4 | max_power=500 # Max. power consumption: value * 2 mA. Use 0 if self_powered = true. 5 | 6 | ########### 7 | # Strings # 8 | ########### 9 | manufacturer="SEC Consult Group" # Manufacturer 10 | product="SEC Xtractor 1.31" # Product 11 | serial="BHEU2019" # Serial 12 | 13 | ########### 14 | # Options # 15 | ########### 16 | self_powered=false # Turn this off for bus powered 17 | remote_wakeup=false # Turn this on for remote wakeup feature 18 | use_serial=true # Use the serial number string 19 | 20 | # Normally out don't have to change one of these flags 21 | in_is_isochronous=false # In Endpoint is Isochronous 22 | out_is_isochronous=false # Out Endpoint is Isochronous 23 | suspend_pull_downs=false # Enable suspend pull downs for lower power 24 | change_usb_version=false # Change USB Version 25 | usb_version=0x0200 # Only used when change_usb_version is enabled 26 | 27 | #cha_vcp=false 28 | #cha_type=FIFO 29 | #chb_type=UART 30 | 31 | eeprom_type=0x46 32 | 33 | ######## 34 | # Misc # 35 | ######## 36 | 37 | filename="eeprom.bin" # Filename, leave empty to skip file writing 38 | -------------------------------------------------------------------------------- /hal-avr/adc.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file adc.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger 12 | */ 13 | 14 | static uint16_t adc_result; 15 | static uint8_t result_flag = 0; 16 | 17 | /** 18 | * @brief Interrupt service routine for analog/digital conversion on channel 0. 19 | */ 20 | ISR(ADCA_CH0_vect) 21 | { 22 | 23 | adc_result = ADCA.CH0.RES; 24 | result_flag = 1; 25 | } 26 | 27 | /** 28 | * @brief Function for initialization of the ADC. 29 | */ 30 | static inline void initADC(void) 31 | { 32 | ADCA.REFCTRL |= 0x10; 33 | /*Single ended */ 34 | ADCA.CH0.CTRL = ADC_CH_INPUTMODE0_bm; 35 | /* Set ADC Prescaler (32Mhz/64 = 500khz)*/ 36 | ADCA.PRESCALER = ADC_PRESCALER2_bm; 37 | /* Enable Conversion Complete Interrupt with high priority*/ 38 | ADCA.CH0.INTCTRL = ADC_CH_INTLVL1_bm | ADC_CH_INTLVL0_bm; 39 | /* Ensure the conversion complete flag is cleared */ 40 | ADCA.INTFLAGS = ADC_CH0IF_bm; 41 | /* Enable ADC */ 42 | ADCA.CTRLA = ADC_ENABLE_bm; 43 | /*ADC Pin as input*/ 44 | DEVICE_FUNCTION_PORT.DIRCLR = 0x01; 45 | /*Select CH0 Pin0 (no configuration needed here)*/ 46 | ADCA.CH0.MUXCTRL = 0x00; 47 | } 48 | 49 | static inline uint16_t readVoltage() 50 | { 51 | /*Start conversion*/ 52 | ADCA.CH0.CTRL |= 0x80; 53 | //for 2.7V voltage regulator 54 | return (adc_result * 14) / 10 + (adc_result / 61) * (adc_result / 123); 55 | } 56 | -------------------------------------------------------------------------------- /hal-avr/definitions.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file definitions.h 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger 12 | */ 13 | #ifndef _DEFINITIONS_H 14 | #define _DEFINITIONS_H 15 | 16 | #include 17 | 18 | typedef PORT_t xtractor_port_t; 19 | 20 | /*! @brief No operation inline assembly definition */ 21 | #define NOP do { __asm__ __volatile__ ("nop"); } while (0) 22 | 23 | #define DELAY_MS(ms) _delay_ms(ms) 24 | #define DELAY_US(us) _delay_us(us) 25 | 26 | /* port for voltage ADC and 7seg display */ 27 | #define DEVICE_FUNCTION_PORT PORTA 28 | 29 | /*! @brief NAND interface pin definitions. */ 30 | #define NAND_IO_PORT0 PORTH 31 | #define NAND_IO_PORT1 PORTJ 32 | #define NAND_CTRL_PORT PORTK 33 | 34 | /*! \brief NOR interface pin definitions. */ 35 | #define NOR_ADDR_PORT0 PORTB 36 | #define NOR_ADDR_PORT1 PORTC 37 | #define NOR_ADDR_PORT2 PORTD 38 | #define NOR_ADDR_PORT3 PORTF 39 | #define NOR_DATA_PORT0 PORTH 40 | #define NOR_DATA_PORT1 PORTJ 41 | #define NOR_CTRL_PORT PORTK 42 | 43 | #define DEBUG(x, ...) {} 44 | 45 | #define NL "\r\n" 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /hal-avr/hal-avr.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file hal-avr.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger, Steffen Robertz 12 | */ 13 | #include "../secxtractor.h" 14 | #include "../hal.h" 15 | #include 16 | /* 4 Megabit UART */ 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "adc.c" 23 | #include "jtag.c" 24 | #include "nand.c" 25 | #include "nor.c" 26 | #include "sevenseg.c" 27 | #include "spi.c" 28 | #include "uart.c" 29 | #include "uart_scanner.c" 30 | #include "timer.c" 31 | 32 | static inline void portOut(xtractor_port_t *port, uint8_t b) 33 | { 34 | port->OUT = b; 35 | } 36 | 37 | static inline void portSetDirection(xtractor_port_t *port, uint8_t mask) 38 | { 39 | port->DIR = mask; 40 | } 41 | 42 | static inline void activateInterrupts() 43 | { 44 | /* activate interrupt level "high" only */ 45 | PMIC.CTRL |= PMIC_HILVLEN_bm; 46 | sei(); 47 | } 48 | 49 | /** 50 | * @brief Function to disable the JTAG port. This prevents the JTAG brute forcer from detecting itself. 51 | */ 52 | static inline void disableJTAG() 53 | { 54 | CCP = CCP_IOREG_gc; 55 | MCU.MCUCR = MCU_JTAGD_bm; 56 | } 57 | 58 | /** 59 | * @brief Clock initialization for 32MHz internal oscillator. 60 | */ 61 | static inline void initSystemClock(void) 62 | { 63 | OSC.CTRL |= OSC_RC32MEN_bm; 64 | while (!(OSC.STATUS & OSC_RC32MRDY_bm)); 65 | CCP = CCP_IOREG_gc; 66 | CLK.CTRL = CLK_SCLKSEL_RC32M_gc; 67 | 68 | 69 | // OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc ; 70 | // OSC.CTRL |= OSC_XOSCEN_bm ; // enable it 71 | // while((OSC.STATUS & OSC_XOSCRDY_bm) == 0){} // wait until it's stable 72 | // OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 2 ; 73 | // OSC.CTRL |= OSC_PLLEN_bm ; // enable the PLL... 74 | // while( (OSC.STATUS & OSC_PLLRDY_bm) == 0 ){} // wait until it's stable 75 | // CCP = CCP_IOREG_gc; // protected write follows 76 | // CLK.CTRL = CLK_SCLKSEL_PLL_gc; // The System clock is now PLL (16Mhz * 2) 77 | 78 | // OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc; 79 | // OSC.CTRL |= OSC_XOSCEN_bm; 80 | // while (!(OSC.STATUS & OSC_XOSCRDY_bm)); 81 | // CCP = CCP_IOREG_gc; 82 | // CLK.CTRL = CLK_SCLKSEL_XOSC_gc; 83 | // OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 2; 84 | // OSC.CTRL |= OSC_PLLEN_bm; 85 | // while (!(OSC.STATUS & OSC_PLLRDY_bm)); 86 | // CCP = CCP_IOREG_gc; 87 | // CLK.CTRL = CLK_SCLKSEL_PLL_gc; 88 | // OSC.CTRL &= ~OSC_RC32MEN_bm; 89 | 90 | } 91 | 92 | static inline void resetDevice(void) 93 | { 94 | cli(); 95 | 96 | CCP = CCP_IOREG_gc; 97 | RST.CTRL = RST_SWRST_bm; 98 | } 99 | -------------------------------------------------------------------------------- /hal-avr/jtag.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file jtag.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * Notice: This code is based on the project JTAGenum from Nathan Andrew Fain\n 7 | * It is available under https://github.com/cyphunk/JTAGenum\n 8 | * This Source Code Form is subject to the terms of the Mozilla Public\n 9 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 10 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 11 | * 12 | * @authors Thomas Weber, Wolfgang Ettlinger 13 | */ 14 | 15 | static inline void setPinMode(uint8_t pin, uint8_t inout) //inout = 1 -> output enabled 16 | { 17 | if (pin < 8) 18 | { 19 | if (inout) 20 | { 21 | PORTB.DIRSET = (1 << pin); 22 | } 23 | else 24 | { 25 | PORTB.DIRCLR = (1 << pin); 26 | } 27 | } 28 | else if (pin < 16) 29 | { 30 | if (inout) 31 | { 32 | PORTC.DIRSET = (1 << (pin - 8)); 33 | } 34 | else 35 | { 36 | PORTC.DIRCLR = (1 << (pin - 8)); 37 | } 38 | } 39 | else if (pin < 24) 40 | { 41 | if (inout) 42 | { 43 | PORTD.DIRSET = (1 << (pin - 16)); 44 | } 45 | else 46 | { 47 | PORTD.DIRCLR = (1 << (pin - 16)); 48 | } 49 | } 50 | else if (pin < 32) 51 | { 52 | if (inout) 53 | { 54 | PORTF.DIRSET = (1 << (pin - 24)); 55 | } 56 | else 57 | { 58 | PORTF.DIRCLR = (1 << (pin - 24)); 59 | } 60 | } 61 | return; 62 | } 63 | 64 | static inline void jtagWritePin(uint8_t pin, uint8_t level) 65 | { 66 | if (pin < 8) 67 | { 68 | if (level) 69 | { 70 | PORTB.OUTSET = (1 << pin); 71 | } 72 | else 73 | { 74 | PORTB.OUTCLR = (1 << pin); 75 | } 76 | } 77 | else if (pin < 16) 78 | { 79 | if (level) 80 | { 81 | PORTC.OUTSET = (1 << (pin - 8)); 82 | } 83 | else 84 | { 85 | PORTC.OUTCLR = (1 << (pin - 8)); 86 | } 87 | } 88 | else if (pin < 24) 89 | { 90 | if (level) 91 | { 92 | PORTD.OUTSET = (1 << (pin - 16)); 93 | } 94 | else 95 | { 96 | PORTD.OUTCLR = (1 << (pin - 16)); 97 | } 98 | } 99 | else if (pin < 32) 100 | { 101 | if (level) 102 | { 103 | PORTF.OUTSET = (1 << (pin - 24)); 104 | } 105 | else 106 | { 107 | PORTF.OUTCLR = (1 << (pin - 24)); 108 | } 109 | } 110 | return; 111 | } 112 | 113 | static inline uint8_t jtagReadPin(uint8_t pin) 114 | { 115 | uint8_t value = 0; 116 | if (pin < 8) //porta 117 | { 118 | value = (PORTB.IN & (1 << pin)) >> pin; 119 | } 120 | else if (pin < 16) 121 | { 122 | value = (PORTC.IN & (1 << (pin - 8))) >> (pin - 8); 123 | } 124 | else if (pin < 24) 125 | { 126 | value = (PORTD.IN & (1 << (pin - 16))) >> (pin - 16); 127 | } 128 | else if (pin < 32) 129 | { 130 | value = (PORTF.IN & (1 << (pin - 24))) >> (pin - 24); 131 | } 132 | return value; 133 | } 134 | 135 | /***** JTAG Functionality from JTAGenum *****/ 136 | /* 137 | * Set the JTAG TAP state machine 138 | */ 139 | void jtagTapState(char jtagTapState[], int tck, int tms) 140 | { 141 | while (*jtagTapState) 142 | { // exit when string \0 terminator encountered 143 | if (jtagDelay) 144 | _delay_us(50); 145 | jtagWritePin(tck, 0); 146 | jtagWritePin(tms, *jtagTapState - '0'); // conv from ascii pattern 147 | jtagWritePin(tck, 1); // rising edge shifts in TMS 148 | *jtagTapState++; 149 | } 150 | } 151 | 152 | void jtagInitPins(int tck, int tms, int tdi, int ntrst, uint8_t pinslen) 153 | { 154 | // default all to INPUT state 155 | for (int i = 0; i < pinslen; i++) 156 | { 157 | setPinMode(i, 0); 158 | // internal pullups default to logic 1: 159 | // if (PULLUP) jtagWritePin(i, 1); 160 | } 161 | // TCK = output 162 | if (tck != IGNOREPIN) 163 | setPinMode(tck, 1); 164 | // TMS = output 165 | if (tms != IGNOREPIN) 166 | setPinMode(tms, 1); 167 | // tdi = output 168 | if (tdi != IGNOREPIN) 169 | setPinMode(tdi, 1); 170 | // ntrst = output, fixed to 1 171 | if (ntrst != IGNOREPIN) 172 | { 173 | setPinMode(ntrst, 1); 174 | jtagWritePin(ntrst, 1); 175 | } 176 | } 177 | 178 | static void jtagPrintPins(int tck, int tms, int tdo, int tdi, int ntrst) 179 | { 180 | uint8_t buffer[6]; 181 | if (ntrst != IGNOREPIN) 182 | { 183 | uartWriteString("ntrst:\tA"); 184 | snprintf(buffer, sizeof(buffer), "%d", ntrst); 185 | uartWriteString(buffer); 186 | uartWriteString("\n\r"); 187 | } 188 | uartWriteString("tck:\tA"); 189 | snprintf(buffer, sizeof(buffer), "%d", tck); 190 | uartWriteString(buffer); 191 | uartWriteString("\n\rtms:\tA"); 192 | snprintf(buffer, sizeof(buffer), "%d", tms); 193 | uartWriteString(buffer); 194 | uartWriteString("\n\rtdo:\tA"); 195 | snprintf(buffer, sizeof(buffer), "%d", tdo); 196 | uartWriteString(buffer); 197 | if (tdi != IGNOREPIN) 198 | { 199 | uartWriteString("\n\rtdi:\tA"); 200 | snprintf(buffer, sizeof(buffer), "%d", tdi); 201 | uartWriteString(buffer); 202 | uartWriteString("\n\r"); 203 | } 204 | } 205 | 206 | static void jtagPulseTms(int tck, int tms, int s_tms) 207 | { 208 | jtagWritePin(tck, 0); 209 | jtagWritePin(tms, s_tms); 210 | jtagWritePin(tck, 1); 211 | } 212 | 213 | static void jtagPulseTdi(int tck, int tdi, int s_tdi) 214 | { 215 | if (jtagDelay) 216 | _delay_us(50); 217 | if (tck != IGNOREPIN) 218 | jtagWritePin(tck, 0); 219 | jtagWritePin(tdi, s_tdi); 220 | if (tck != IGNOREPIN) 221 | jtagWritePin(tck, 1); 222 | } 223 | 224 | uint8_t jtagPulseTdo(int tck, int tdo) 225 | { 226 | uint8_t tdo_read; 227 | if (jtagDelay) 228 | _delay_us(50); 229 | jtagWritePin(tck, 0); // read in TDO on falling edge 230 | tdo_read = jtagReadPin(tdo); 231 | jtagWritePin(tck, 1); 232 | return tdo_read; 233 | } 234 | -------------------------------------------------------------------------------- /hal-avr/nand.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file nand.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger, Steffen Robertz 12 | */ 13 | #include "definitions.h" 14 | #include "../secxtractor.h" 15 | 16 | #define NAND_ALE_HIGH() { NAND_CTRL_PORT.OUTSET = NAND_ALE; } 17 | #define NAND_ALE_LOW() { NAND_CTRL_PORT.OUTCLR = NAND_ALE; } 18 | #define NAND_CLE_HIGH() { NAND_CTRL_PORT.OUTSET = NAND_CLE; } 19 | #define NAND_CLE_LOW() { NAND_CTRL_PORT.OUTCLR = NAND_CLE; } 20 | #define NAND_WP_HIGH() { NAND_CTRL_PORT.OUTSET = NAND_WP; } 21 | #define NAND_WP_LOW() { NAND_CTRL_PORT.OUTCLR = NAND_WP; } 22 | #define NAND_WE_HIGH() { NAND_CTRL_PORT.OUTSET = NAND_WE; } 23 | #define NAND_WE_LOW() { NAND_CTRL_PORT.OUTCLR = NAND_WE; } 24 | #define NAND_RE_HIGH() { NAND_CTRL_PORT.OUTSET = NAND_RE; } 25 | #define NAND_RE_LOW() { NAND_CTRL_PORT.OUTCLR = NAND_RE; } 26 | #define NAND_CE_HIGH() { NAND_CTRL_PORT.OUTSET = NAND_CE; } 27 | #define NAND_CE_LOW() { NAND_CTRL_PORT.OUTCLR = NAND_CE; } 28 | #define NAND_RB_PULLUP_HIGH() { NAND_CTRL_PORT.OUTSET = NAND_RB; } 29 | 30 | #define NAND_RB_READ() (((NAND_CTRL_PORT.IN & NAND_RB) == NAND_RB) ? 1 : 0) 31 | 32 | #define NAND_DELAY() {for(int i=0; ipages_per_block;\ 216 | tmp_pages_per_block != 0; tmp_pages_per_block>>=1){ 217 | page_bits++; 218 | } 219 | uint8_t row_cycles = params->address_cycles &0x0f; 220 | uint8_t col_cycles = params->address_cycles >> 4; 221 | uint32_t block=0; 222 | NAND_WP_HIGH(); 223 | while(blockblock_per_logic_unit){ 224 | onfiCommand(ONFI_CMD_BLOCK_ERASE_CYCLE_1); 225 | onfiAddressStart(); 226 | uint64_t row_address = (((uint64_t)block)<>(i*8))); 229 | } 230 | onfiAddressEnd(); 231 | onfiCommand(ONFI_CMD_BLOCK_ERASE_CYCLE_2); 232 | NOP3; 233 | while(!NAND_RB_READ()); 234 | if(enable_progress & block%20==0){ 235 | uartWriteChar('.'); 236 | } 237 | ++block; 238 | } 239 | NAND_WP_LOW(); 240 | } 241 | 242 | /** 243 | *@brief Writes a pattern throughout the whole NAND 244 | *@param params Pointer to the ONFI parameter page 245 | *@param pattern pattern to write 246 | *@param write_ecc If set to 1, will write through ECC block, otherwise ECC block will be skipped 247 | */ 248 | static inline void onfiWriteData(onfi_param_page_t *params, uint16_t pattern, uint8_t write_ecc) 249 | { 250 | uint8_t supports_x16 = params->feature_support & ONFI_FEATURE_16_BIT_BUS; 251 | uint8_t row_cycles = params->address_cycles &0x0f; 252 | uint8_t col_cycles = params->address_cycles >> 4; 253 | uint8_t page_bits = 255; //Loop counts one bit too much 254 | for(uint32_t tmp_pages_per_block = params->pages_per_block;\ 255 | tmp_pages_per_block != 0; tmp_pages_per_block>>=1){ 256 | page_bits++; 257 | } 258 | 259 | uint32_t block = 0x00; 260 | uint32_t page = 0x00; 261 | uint32_t pagesize = params->bytes_per_page +(write_ecc*params->spare_bytes_per_page); 262 | pagesize = pagesize / (supports_x16+1); 263 | 264 | onfiEraseAll(params, 0); 265 | 266 | while (block < params->block_per_logic_unit){ 267 | NAND_WP_HIGH(); 268 | onfiCommand(ONFI_CMD_PAGE_CACHE_PROGRAM_CYCLE_1); 269 | onfiAddressStart(); 270 | for(uint8_t i=0; i>(i*8))); 277 | } 278 | onfiAddressEnd(); 279 | NOP2; 280 | onfiDataInStart(); 281 | for (int i = 0; i < pagesize; i++) 282 | { 283 | if(supports_x16){ 284 | onfiDataIn((uint8_t) pattern,(uint8_t) (pattern >> 8)); 285 | }else{ 286 | if(i%2){ 287 | onfiDataIn((uint8_t) pattern, 0); 288 | }else{ 289 | onfiDataIn((uint8_t) pattern>>8, 0); 290 | } 291 | } 292 | } 293 | onfiCommand(ONFI_CMD_PAGE_CACHE_PROGRAM_CYCLE_2); 294 | _delay_us(10); 295 | while(!NAND_RB_READ()); 296 | onfiCommand(ONFI_CMD_READ_STATUS); 297 | uint8_t temp1, temp2; 298 | onfiDataOut(&temp1, &temp2); 299 | NAND_CE_HIGH(); 300 | NAND_WP_LOW(); 301 | page++; 302 | if (page == 64) 303 | { 304 | page = 0; 305 | block++; 306 | } 307 | if(page==0 && block%10==0){ 308 | uartWriteChar('.'); 309 | } 310 | } 311 | uartprintf("done"NL); 312 | } 313 | 314 | /** 315 | *@brief Reads the ONFI parameters 316 | *@param params Pointer to an empty full parameter page 317 | */ 318 | static inline int onfiReadAndCheckParameters(onfi_param_page_t *params) 319 | { 320 | uint8_t tmp; 321 | int result = 0; 322 | uint8_t *data = (uint8_t*) params; 323 | uint8_t waste; 324 | 325 | onfiCommand(ONFI_CMD_READ_PARAMETER_PAGE); 326 | onfiAddressStart(); 327 | onfiAddress(0x00); 328 | onfiAddressEnd(); 329 | onfiDataOutStart(); 330 | 331 | _delay_us(10); 332 | while(!NAND_RB_READ()); 333 | 334 | /* first: read params page */ 335 | for(uint16_t i = 0; i<256; i++){ 336 | onfiDataOut(&data[i], &waste); 337 | } 338 | 339 | /* then: verify using other copies */ 340 | for(uint16_t j = 0; j < 2; j++){ 341 | for(uint16_t i = 0; i<256; i++){ 342 | onfiDataOut(&tmp, &waste); 343 | if(tmp != data[i]){ 344 | result |= 1; 345 | } 346 | } 347 | } 348 | 349 | NAND_CE_HIGH(); 350 | 351 | if(!memcmp(¶ms->signature, "ONFI", 4) == 0){ 352 | result |= 2; 353 | } 354 | 355 | return result; 356 | } 357 | 358 | static inline uint32_t onfiDumpPage(uint32_t block, uint32_t page, uint8_t supports_x16, uint8_t row_cycles, 359 | uint8_t col_cycles, uint8_t page_bits, uint32_t bytes_to_read, uint8_t silent) 360 | { 361 | uint32_t checksum = 0; 362 | 363 | NAND_IO_PORT0.OUT = 0x00; 364 | NAND_IO_PORT1.OUT = 0x00; 365 | NAND_IO_PORT0.DIR = 0xFF; 366 | NAND_IO_PORT1.DIR = 0xFF; 367 | 368 | onfiCommand(ONFI_CMD_READ_CYCLE_1); 369 | 370 | onfiAddressStart(); 371 | 372 | /* column addressing */ 373 | for(uint8_t i=0; i>(i*8))); 383 | } 384 | 385 | onfiAddressEnd(); 386 | 387 | onfiCommand(ONFI_CMD_READ_CYCLE_2); 388 | NOP2; 389 | while(!NAND_RB_READ()); 390 | 391 | /* end of sending command, start reading the whole page */ 392 | onfiDataOutStart(); 393 | 394 | bytes_to_read = bytes_to_read / (supports_x16 + 1); 395 | 396 | for (int i = 0; i < bytes_to_read; ++i) 397 | { 398 | uint8_t temp_high = 0; 399 | uint8_t temp_low = 0; 400 | 401 | onfiDataOut(&temp_low, &temp_high); 402 | 403 | if(!silent){ 404 | if(supports_x16){ 405 | dumpByte(temp_high); 406 | } 407 | dumpByte(temp_low); 408 | } 409 | 410 | checksum += (temp_high << 8) + temp_low; 411 | } 412 | NAND_CE_HIGH(); 413 | 414 | NAND_DELAY(); 415 | 416 | return checksum; 417 | } 418 | 419 | /** 420 | *@brief Writes a pattern throughout the whole NAND 421 | *@param params Pointer to the ONFI parameter page 422 | *@param read_ecc If set to 1, will read with ECC block, otherwise ECC block will be skipped 423 | */ 424 | static inline void onfiReadData(onfi_param_page_t *params, uint8_t read_ecc, uint8_t verify_read_iterations) 425 | { 426 | uint8_t supports_x16 = params->feature_support & ONFI_FEATURE_16_BIT_BUS; 427 | uint8_t row_cycles = params->address_cycles &0x0f; 428 | uint8_t col_cycles = params->address_cycles >> 4; 429 | uint8_t page_bits = 255; //Loop counts one bit too much 430 | uint32_t block, page; 431 | int i; 432 | uint8_t abort = 0; 433 | uint32_t reference_checksum, test_checksum; 434 | uint32_t bytes_to_read = params->bytes_per_page + (read_ecc * params->spare_bytes_per_page); 435 | 436 | for(uint32_t tmp_pages_per_block = params->pages_per_block;\ 437 | tmp_pages_per_block != 0; tmp_pages_per_block>>=1){ 438 | page_bits++; 439 | } 440 | 441 | dumpStart(); 442 | 443 | for(block = 0; block < params->block_per_logic_unit; block++){ 444 | if(isOperationCanceled() || abort){ 445 | break; 446 | } 447 | 448 | for(page = 0; page < params->pages_per_block && !abort; page++){ 449 | reference_checksum = onfiDumpPage(block, page, supports_x16, row_cycles, col_cycles, page_bits, bytes_to_read, 0); 450 | 451 | for(i=0; i> 8); 114 | NOR_ADDR_PORT2.OUT = (uint8_t)((address & 0x00FF0000) >> 16); 115 | NOR_ADDR_PORT3.OUT = (uint8_t)((address & 0xFF000000) >> 24); 116 | NOP5; 117 | databyte = NOR_DATA_PORT0.IN; 118 | databyte |= (uint16_t)(NOR_DATA_PORT1.IN << 8); 119 | 120 | return databyte; 121 | } 122 | 123 | /** 124 | *@brief Reads a byte from the NOR 125 | *@return Databyte 126 | *@param address The address to read from 127 | */ 128 | static inline uint8_t norRead8DataBits(uint32_t address) 129 | { 130 | uint8_t databyte; 131 | 132 | NOR_CTRL_PORT.OUTSET = NOR_WE; 133 | 134 | NOR_DATA_PORT1.OUT = (uint8_t)((address & 0x00000001) << 7); // A-1/Q15 135 | 136 | /* apply address */ 137 | NOR_ADDR_PORT0.OUT = (uint8_t)((address & 0x000001FE) >> 1); 138 | NOR_ADDR_PORT1.OUT = (uint8_t)((address & 0x0001FE00) >> 9); 139 | NOR_ADDR_PORT2.OUT = (uint8_t)((address & 0x01FE0000) >> 17); 140 | NOR_ADDR_PORT3.OUT = (uint8_t)((address & 0xFE000000) >> 25); 141 | 142 | /* clear CE#, OE# */ 143 | NOR_CTRL_PORT.OUTCLR = NOR_CE; 144 | NOR_CTRL_PORT.OUTCLR = NOR_OE; 145 | 146 | NOP5; 147 | databyte = NOR_DATA_PORT0.IN; 148 | NOP; 149 | 150 | NOR_CTRL_PORT.OUTSET = NOR_OE | NOR_CE; 151 | 152 | return databyte; 153 | } 154 | 155 | ///TODO: Fix the Write and Erase Method 156 | // static inline void norWrite8DataBits(uint32_t address, uint8_t data) 157 | // { 158 | // NOR_CTRL_PORT.OUTSET = NOR_RESET; 159 | // NOR_CTRL_PORT.OUTSET = NOR_WP; 160 | // _delay_us(1); 161 | 162 | // NOR_CTRL_PORT.OUTSET = NOR_WE; 163 | // NOR_CTRL_PORT.OUTSET = NOR_OE; 164 | 165 | // /* apply address */ 166 | // NOR_DATA_PORT1.OUT = (uint8_t)((address & 0x00000001) << 7); // A-1/Q15 167 | // NOR_ADDR_PORT0.OUT = (uint8_t)((address & 0x000001FE) >> 1); 168 | // NOR_ADDR_PORT1.OUT = (uint8_t)((address & 0x0001FE00) >> 9); 169 | // NOR_ADDR_PORT2.OUT = (uint8_t)((address & 0x01FE0000) >> 17); 170 | // NOR_ADDR_PORT3.OUT = (uint8_t)((address & 0xFE000000) >> 25); 171 | 172 | // /* address fetched at falling WE flank */ 173 | // NOR_CTRL_PORT.OUTCLR = NOR_WE; 174 | // NOP2; 175 | // /* apply data */ 176 | // NOR_DATA_PORT0.OUT = data; 177 | // /*data fetched at rising WE flank */ 178 | // NOR_CTRL_PORT.OUTSET = NOR_WE; 179 | // NOP; 180 | // NOR_CTRL_PORT.OUTSET = NOR_CE; 181 | // NOR_CTRL_PORT.OUTCLR = NOR_WE; 182 | // } 183 | // 184 | // static inline void norEraseChip() 185 | // { 186 | // norWrite8DataBits(0x555, 0xaa); 187 | // norWrite8DataBits(0x2aa, 0x55); 188 | // norWrite8DataBits(0x555, 0x80); 189 | // norWrite8DataBits(0x555, 0xaa); 190 | // norWrite8DataBits(0x2aa, 0x55); 191 | // norWrite8DataBits(0x555, 0x10); 192 | 193 | 194 | 195 | // // norWrite8DataBits(0xaaa, 0xaa); 196 | // // norWrite8DataBits(0x555, 0x55); 197 | // // norWrite8DataBits(0xaaa, 0x80); 198 | // // norWrite8DataBits(0xaaa, 0xaa); 199 | // // norWrite8DataBits(0x555, 0x55); 200 | // // norWrite8DataBits(0xaaa, 0x10); 201 | 202 | // NOR_CTRL_PORT.DIRSET = NOR_RYBY; 203 | // NOR_CTRL_PORT.OUTCLR = NOR_RYBY; 204 | 205 | // while (!(NOR_CTRL_PORT.IN & NOR_RYBY)); 206 | // uartprintf("Chip Erased!" NL); 207 | // } 208 | -------------------------------------------------------------------------------- /hal-avr/sevenseg.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sevenseg.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger 12 | */ 13 | 14 | /** 15 | * @brief This function enables a segment and disables the others. 16 | */ 17 | 18 | static inline void enableSegment(int n) 19 | { 20 | PORTE.OUTSET = 0x13; 21 | switch (n) 22 | { 23 | case 0: 24 | PORTE.OUTCLR = 0x01; 25 | break; 26 | case 1: 27 | PORTE.OUTCLR = 0x02; 28 | break; 29 | case 2: 30 | PORTE.OUTCLR = 0x10; 31 | break; 32 | default: 33 | PORTE.OUTCLR = 0x00; 34 | break; 35 | } 36 | } 37 | 38 | /** 39 | * @brief This function depicts the known numbers on the 7-segment. 40 | * @param number The input variable number contains the number depicted on the 7-segment. 41 | */ 42 | static inline void sevensegShowDec(uint8_t number) 43 | { 44 | switch (number) 45 | { 46 | case 0: 47 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 48 | DEVICE_FUNCTION_PORT.OUTCLR = 0x7E; 49 | break; 50 | case 1: 51 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 52 | DEVICE_FUNCTION_PORT.OUTCLR = 0x0C; 53 | break; 54 | case 2: 55 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 56 | DEVICE_FUNCTION_PORT.OUTCLR = 0xB7; 57 | break; 58 | case 3: 59 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 60 | DEVICE_FUNCTION_PORT.OUTCLR = 0x9E; 61 | break; 62 | case 4: 63 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 64 | DEVICE_FUNCTION_PORT.OUTCLR = 0xCC; 65 | break; 66 | case 5: 67 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 68 | DEVICE_FUNCTION_PORT.OUTCLR = 0xDA; 69 | break; 70 | case 6: 71 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 72 | DEVICE_FUNCTION_PORT.OUTCLR = 0xFA; 73 | break; 74 | case 7: 75 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 76 | DEVICE_FUNCTION_PORT.OUTCLR = 0x0E; 77 | break; 78 | case 8: 79 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 80 | DEVICE_FUNCTION_PORT.OUTCLR = 0xFE; 81 | break; 82 | case 9: 83 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 84 | DEVICE_FUNCTION_PORT.OUTCLR = 0xDE; 85 | break; 86 | default: 87 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 88 | DEVICE_FUNCTION_PORT.OUTCLR = 0xFE; 89 | } 90 | } 91 | 92 | 93 | /** 94 | * @brief This function depicts the known characters on the displays. 95 | */ 96 | static inline void sevensegShowChar(char chr) 97 | { 98 | switch (chr) 99 | { 100 | case '0': 101 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 102 | DEVICE_FUNCTION_PORT.OUTCLR = 0x7E; 103 | break; 104 | case '1': 105 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 106 | DEVICE_FUNCTION_PORT.OUTCLR = 0x0C; 107 | break; 108 | case '2': 109 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 110 | DEVICE_FUNCTION_PORT.OUTCLR = 0xB7; 111 | break; 112 | case '3': 113 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 114 | DEVICE_FUNCTION_PORT.OUTCLR = 0x9E; 115 | break; 116 | case '4': 117 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 118 | DEVICE_FUNCTION_PORT.OUTCLR = 0xCC; 119 | break; 120 | case '5': 121 | case 'S': 122 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 123 | DEVICE_FUNCTION_PORT.OUTCLR = 0xDA; 124 | break; 125 | case '6': 126 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 127 | DEVICE_FUNCTION_PORT.OUTCLR = 0xFA; 128 | break; 129 | case '7': 130 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 131 | DEVICE_FUNCTION_PORT.OUTCLR = 0x0E; 132 | break; 133 | case '8': 134 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 135 | DEVICE_FUNCTION_PORT.OUTCLR = 0xFE; 136 | break; 137 | case '9': 138 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 139 | DEVICE_FUNCTION_PORT.OUTCLR = 0xDE; 140 | break; 141 | case 'A': 142 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 143 | DEVICE_FUNCTION_PORT.OUTCLR = 0xEE; 144 | break; 145 | case 'a': 146 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 147 | DEVICE_FUNCTION_PORT.OUTCLR = 0xEE; 148 | break; 149 | case 'B': 150 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 151 | DEVICE_FUNCTION_PORT.OUTCLR = 0xF8; 152 | break; 153 | case 'b': 154 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 155 | DEVICE_FUNCTION_PORT.OUTCLR = 0xF8; 156 | break; 157 | case 'C': 158 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 159 | DEVICE_FUNCTION_PORT.OUTCLR = 0x72; 160 | break; 161 | case 'c': 162 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 163 | DEVICE_FUNCTION_PORT.OUTCLR = 0x72; 164 | break; 165 | case 'D': 166 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 167 | DEVICE_FUNCTION_PORT.OUTCLR = 0xBC; 168 | break; 169 | case 'd': 170 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 171 | DEVICE_FUNCTION_PORT.OUTCLR = 0xBC; 172 | break; 173 | case 'E': 174 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 175 | DEVICE_FUNCTION_PORT.OUTCLR = 0xF2; 176 | break; 177 | case 'e': 178 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 179 | DEVICE_FUNCTION_PORT.OUTCLR = 0xF2; 180 | break; 181 | case 'F': 182 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 183 | DEVICE_FUNCTION_PORT.OUTCLR = 0xE2; 184 | break; 185 | case 'f': 186 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 187 | DEVICE_FUNCTION_PORT.OUTCLR = 0xE2; 188 | break; 189 | case 'L': 190 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 191 | DEVICE_FUNCTION_PORT.OUTCLR = 0x71; 192 | break; 193 | case 'l': 194 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 195 | DEVICE_FUNCTION_PORT.OUTCLR = 0x71; 196 | break; 197 | case 'O': 198 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 199 | DEVICE_FUNCTION_PORT.OUTCLR = 0xB8; 200 | break; 201 | case 'o': 202 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 203 | DEVICE_FUNCTION_PORT.OUTCLR = 0xB8; 204 | break; 205 | default: 206 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 207 | DEVICE_FUNCTION_PORT.OUTCLR = 0xFE; 208 | } 209 | } 210 | 211 | static inline void sevensegWriteNumber(uint16_t printed_value) 212 | { 213 | enableSegment(0); 214 | sevensegShowDec(printed_value / 1000); 215 | DELAY_MS(4); 216 | enableSegment(1); 217 | sevensegShowDec(printed_value / 100 - ((printed_value / 1000) * 10)); 218 | DELAY_MS(4); 219 | enableSegment(2); 220 | sevensegShowDec(printed_value / 10 - ((printed_value / 100) * 10)); 221 | DELAY_MS(4); 222 | } 223 | 224 | /** 225 | * @brief This function depicts a progress bar on the displays. 226 | */ 227 | static inline void sevensegShowProgressBar(void) 228 | { 229 | DEVICE_FUNCTION_PORT.OUTSET = 0xFE; 230 | DEVICE_FUNCTION_PORT.OUTCLR = 0xB8; 231 | 232 | PORTE.OUTSET = 0x13; 233 | PORTE.OUTCLR = 0x13; 234 | } 235 | 236 | /** 237 | * @brief This function initializes the 7 segment elements. 238 | * The direction is set to output for 7 of 8 pins (0xFE). 239 | * The last pin is used as measurement pin for the current output voltage. 240 | * @param selftest_flag This variable indicates whether a self test should be performed or not. 241 | */ 242 | static inline void sevensegInit() 243 | { 244 | DEVICE_FUNCTION_PORT.OUTCLR = 0xFE; 245 | DEVICE_FUNCTION_PORT.DIRSET = 0xFE; 246 | PORTE.OUTCLR = 0x13; 247 | PORTE.DIRSET = 0x13; 248 | 249 | #if SELF_TEST == 1 250 | /* self test */ 251 | 252 | sevensegShowChar('0'); _delay_ms(200); 253 | sevensegShowChar('1'); _delay_ms(200); 254 | sevensegShowChar('2'); _delay_ms(200); 255 | sevensegShowChar('3'); _delay_ms(200); 256 | sevensegShowChar('4'); _delay_ms(200); 257 | sevensegShowChar('5'); _delay_ms(200); 258 | sevensegShowChar('6'); _delay_ms(200); 259 | sevensegShowChar('7'); _delay_ms(200); 260 | sevensegShowChar('8'); _delay_ms(200); 261 | sevensegShowChar('9'); _delay_ms(200); 262 | sevensegShowChar('A'); _delay_ms(200); 263 | sevensegShowChar('B'); _delay_ms(200); 264 | sevensegShowChar('C'); _delay_ms(200); 265 | sevensegShowChar('D'); _delay_ms(200); 266 | sevensegShowChar('E'); _delay_ms(200); 267 | sevensegShowChar('F'); _delay_ms(200); 268 | #endif 269 | } 270 | -------------------------------------------------------------------------------- /hal-avr/spi.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file spi.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger 12 | */ 13 | /******************** SPI GD5F1GQ4U *********************/ 14 | /*DOES NOT WORK YET*/ 15 | volatile uint8_t spiTransferComplete; 16 | 17 | ISR(SPIC_INT_vect) 18 | { 19 | spiTransferComplete = 1; 20 | } 21 | /*DOES NOT WORK YET*/ 22 | void spiConfigurePins() 23 | { 24 | uint8_t rx_byte; 25 | PORTC.DIR = 0xB0; //output: mosi, sck, ss 26 | PORTC.OUTSET = 0x10; //spi master mode 0 27 | SPIC.CTRL = 0x53; // spi master, spi mode 0 and prescaler to [11] 28 | spiTransferComplete = 1; 29 | SPIC.INTCTRL = 0x03; // assign high priority to SPID interrupts 30 | 31 | while (SPIC.STATUS & 0x80) 32 | { // flush spi receive buffer 33 | rx_byte = SPIC.DATA; 34 | } 35 | 36 | uartWriteString("\n\rconfigure\n\r"); 37 | return; 38 | } 39 | 40 | /*DOES NOT WORK YET*/ 41 | uint8_t spiRead() 42 | { 43 | //uartWriteString("Read\n\r"); 44 | uint8_t byte = SPIC.DATA; 45 | return byte; 46 | } 47 | 48 | /*DOES NOT WORK YET*/ 49 | void spiWrite(uint8_t byte) 50 | { 51 | // uartWriteString("Write\n\r"); 52 | spiTransferComplete = 0; 53 | SPIC.DATA = byte; 54 | while (!spiTransferComplete) 55 | ; // wait for transmit complete 56 | spiTransferComplete = 0; 57 | return; 58 | } 59 | 60 | /*DOES NOT WORK YET*/ 61 | void spiGDreadID() 62 | { 63 | PORTC.OUTCLR = 0x10; // assert SS pin (active low) 64 | NOP; 65 | spiWrite(0x9F); 66 | spiWrite(0x00); 67 | uartprintf("%02X", spiRead()); 68 | uartprintf("%02X", spiRead()); 69 | uartWriteString(NL); 70 | PORTC.OUTSET = 0x10; // de-assert SS pin 71 | } 72 | -------------------------------------------------------------------------------- /hal-avr/timer.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file timer.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger, Steffen Robertz 12 | */ 13 | 14 | 15 | static volatile uint64_t overflow_val = 0; 16 | 17 | static inline void initTimer(void) 18 | { 19 | /*timer test block */ 20 | TCC0.CNTL = 0; 21 | TCC0.CNTH = 0; 22 | TCC0.INTCTRLA = TC_OVFINTLVL_MED_gc; 23 | PMIC.CTRL |= PMIC_MEDLVLEN_bm; 24 | TCC0.CTRLA = TC_CLKSEL_DIV1_gc; 25 | sei(); 26 | } 27 | 28 | static inline uint64_t getTime(void) 29 | { 30 | uint16_t cnt = (((uint16_t)TCC0.CNTH)<<8) | TCC0.CNTL; 31 | return overflow_val + cnt; 32 | } 33 | 34 | ISR(TCC0_OVF_vect) 35 | { 36 | overflow_val += 0x10000; 37 | } 38 | -------------------------------------------------------------------------------- /hal-avr/uart.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file uart.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger, Steffen Robertz 12 | */ 13 | #include 14 | 15 | /*! @brief Interrupt variable uart_rx_byte. When a byte is received via the main UART, uart_rx_byte is set to "1".*/ 16 | volatile uint8_t uart_rx_byte = 0; 17 | volatile uint8_t uart_has_input = 0; 18 | 19 | /*! @brief Interrupt variable terminal_output. When a characters are outputted via the main UART, terminal_output is set to "1".*/ 20 | volatile uint8_t terminal_output = 1; 21 | 22 | /** 23 | * @brief Interrupt service routine for receive complete on UARTE. 24 | */ 25 | ISR(USARTE0_RXC_vect) 26 | { 27 | uart_rx_byte = USARTE0.DATA; 28 | uart_has_input = 1; 29 | sevensegShowChar('A'); 30 | } 31 | 32 | /** 33 | * @brief Interrupt service routine for transmit complete on UARTE. 34 | */ 35 | ISR(USARTE0_TXC_vect) 36 | { 37 | terminal_output = 0; 38 | sevensegShowChar('B'); 39 | } 40 | 41 | static inline void checkUartFlowControl() 42 | { 43 | if(uart_has_input && uart_rx_byte == CHAR_XOFF){ 44 | uart_has_input = 0; // consume XOFF char 45 | 46 | // XOFF (or any other char) causes output to continue 47 | while(!uart_has_input) {} 48 | uart_has_input = 0; 49 | } 50 | } 51 | 52 | inline uint8_t uartHasInput() 53 | { 54 | uint8_t result = 0; 55 | if (uart_has_input && uart_rx_byte != CHAR_XOFF) 56 | { 57 | result = 1; 58 | } 59 | return result; 60 | } 61 | 62 | inline uint8_t uartGetInput(void) 63 | { 64 | uart_has_input = 0; 65 | return uart_rx_byte; 66 | } 67 | 68 | inline uint8_t uartPeekInput(void) 69 | { 70 | return uart_rx_byte; 71 | } 72 | 73 | /** 74 | * @brief This function initializes the main communication UART port. 75 | * This port is used as primary communication channel to the user and has a speed of 4 Megabaud. 76 | */ 77 | static inline void uartInit(void) 78 | { 79 | /*4M Baudrate */ 80 | USARTE0.BAUDCTRLB = 0x00; 81 | USARTE0.BAUDCTRLA = 0x00; 82 | 83 | /*activate send and receive and activate double speed*/ 84 | USARTE0.CTRLB = USART_TXEN_bm | USART_RXEN_bm | USART_CLK2X_bm; 85 | // USARTE0.BAUDCTRLB = 0xF0; 86 | // USARTE0.BAUDCTRLA = 0x21; //-> 9600 87 | // USARTE0.CTRLB = USART_TXEN_bm | USART_RXEN_bm; //activate send and receive 88 | USARTE0.CTRLC = USART_CHSIZE_8BIT_gc; //change size to 8 bit 89 | PORTE.DIR = 0xE8; //set pc3 to output 90 | /* Interrupt Section */ 91 | //USARTE0.STATUS = USART_RXCIF_bm | USART_TXCIF_bm; //set receive interrupt enable flag 92 | USARTE0.CTRLA = 0x30; //set receive complete interrupt level to 3 (high) 93 | } 94 | 95 | /** 96 | * @brief This function sends one character to be outputted on the main communication UART port. 97 | * @param c The variable c contains the character that is send to the output. 98 | */ 99 | static inline void uartWriteChar(char c) 100 | { 101 | // before writing data, check that receiver wants data 102 | checkUartFlowControl(); 103 | 104 | PORTQ.DIRSET = PIN3_bm; 105 | PORTQ.OUTSET = PIN3_bm; 106 | //while(!(USARTE0.STATUS & USART_DREIF_bm)); 107 | USARTE0.DATA = c; //send data to uart tx 108 | //terminal_output = 1; 109 | while(!(USARTE0.STATUS & USART_TXCIF_bm)); 110 | USARTE0.STATUS|= USART_TXCIF_bm; 111 | PORTQ.OUTCLR = PIN3_bm; 112 | //while (terminal_output); 113 | } 114 | 115 | 116 | /** 117 | * @brief This function is a prototype that can be used for man-in-the-middle UART attacks. 118 | */ 119 | static inline void uartMitMInit(void) 120 | { 121 | /* 9600 baud */ 122 | // USARTC0.BAUDCTRLA = 0xC; 123 | // USARTC0.BAUDCTRLB = 0x40; 124 | /* 115200 baud*/ 125 | USARTC0.BAUDCTRLA = 0x83; 126 | USARTC0.BAUDCTRLB = 0xD0; // -3 twos complement 127 | USARTC0.CTRLB = USART_TXEN_bm | USART_RXEN_bm; // //activate send and receive 128 | 129 | USARTC0.CTRLC = USART_CHSIZE_8BIT_gc; //change size to 8 bit 130 | PORTC.DIR = 0xFB; //set pc3 to output 131 | /* Interrupt Section */ 132 | USARTC0.STATUS = USART_RXCIF_bm | USART_TXCIF_bm; //set receive interrupt enable flag 133 | USARTC0.CTRLA = 0x3C; //set receive complete interrupt level to 3 (high) 134 | } 135 | 136 | static inline void uartMitMWriteChar(char c) 137 | { 138 | USARTC0.DATA = c; //send data to uart tx 139 | } 140 | 141 | static inline void uartMitMWriteString(char *s) 142 | { 143 | uint16_t len = (uint16_t)strlen((const char *)s); 144 | 145 | for (uint16_t i = 0; i < len; i++) 146 | { 147 | uartMitMWriteChar(s[i]); 148 | } 149 | } 150 | 151 | static inline void uartWriteString(char *s) 152 | { 153 | uint16_t len = (uint16_t)strlen((const char *)s); 154 | 155 | for (uint16_t i = 0; i < len; i++) 156 | { 157 | uartWriteChar(s[i]); 158 | } 159 | } 160 | 161 | static inline void uartprintf(char *fmt, ...) 162 | { 163 | va_list arglist; 164 | va_start(arglist, fmt); 165 | int size = vsnprintf(NULL, 0, fmt, arglist); 166 | char str[size + 1]; 167 | 168 | vsnprintf(str, size + 1, fmt, arglist); 169 | uartWriteString(str); 170 | 171 | va_end(arglist); 172 | } 173 | -------------------------------------------------------------------------------- /hal-avr/uart_scanner.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file uart_scanner.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Steffen Robertz 12 | */ 13 | 14 | /*! @brief When a pin change is triggered by an alternating edge on a pin, this var counts up.*/ 15 | volatile scanner_result_t results[SCANNER_MAX_PIN_CNT] = {0}; 16 | volatile uint32_t shortest_lowtime; 17 | 18 | volatile uint8_t port_b_old_in; 19 | volatile uint8_t port_c_old_in; 20 | volatile uint8_t pin_cnt=0; 21 | 22 | /** 23 | * @brief Function for initialization of the UART scanner interrupts. 24 | */ 25 | static inline void initScan(uint8_t pin_num) 26 | { 27 | /* init results struct */ 28 | for(uint8_t i=0; i8){ 37 | PORTC.DIRCLR = 0xFF; 38 | } 39 | 40 | /* enable interrupt 0 on all address ports */ 41 | PORTB.INT0MASK = 0x0f; 42 | if(pin_num >4){ 43 | PORTB.INT1MASK = 0xf0; 44 | } 45 | if(pin_num >8){ 46 | PORTC.INT0MASK = 0x0f; 47 | } 48 | if(pin_num >12){ 49 | PORTC.INT1MASK = 0xf0; 50 | } 51 | 52 | /* configure totem-pole on all address ports and sens both edges*/ 53 | PORTCFG.MPCMASK = 0xFF; 54 | PORTB.PIN0CTRL = 0x0; 55 | if(pin_num >8){ 56 | PORTCFG.MPCMASK = 0xFF; 57 | PORTC.PIN0CTRL = 0x0; 58 | } 59 | 60 | /* Set interrupt level to low for PORTB_INT0*/ 61 | if(pin_num >4){ 62 | PORTB.INTCTRL |= PORT_INT0LVL_LO_gc | PORT_INT1LVL_LO_gc; 63 | } 64 | if(pin_num >8){ 65 | PORTC.INTCTRL = PORT_INT0LVL_LO_gc | PORT_INT1LVL_LO_gc; 66 | } 67 | 68 | //low level interrupts freigeben 69 | PMIC.CTRL |= PMIC_LOLVLEN_bm; 70 | sei(); 71 | 72 | PORTD.DIRCLR = PIN0_bm; 73 | PORTD.INT0MASK = PIN0_bm; 74 | PORTD.INTCTRL |= PORT_INT0LVL_HI_gc; 75 | PORTD.PIN0CTRL |= PIN0_bm; 76 | shortest_lowtime = 0xffffffff; 77 | } 78 | 79 | /** 80 | * @brief Will test which of the 4 pins caused the interrupt and then increase the right result var 81 | */ 82 | static inline void count_change(volatile scanner_result_t* results, uint8_t port_value, uint8_t pin_mask) 83 | { 84 | uint64_t curr_time = getTime() + 6; 85 | if (port_value & pin_mask) { 86 | uint64_t low_time = curr_time - results->last_change; 87 | results->time_low += low_time; 88 | if(low_time < results->shortest_lowtime){ 89 | results->shortest_lowtime = low_time; 90 | } 91 | }else{ 92 | results->time_high += curr_time - results->last_change; 93 | } 94 | results->pin_changes++; 95 | results->last_change = curr_time; 96 | } 97 | 98 | /** 99 | * @brief Interrupt Service Routine for A0-A3 100 | */ 101 | ISR(PORTB_INT0_vect){ 102 | uint8_t new_in = PORTB.IN; 103 | for(uint8_t i=0; i<4; ++i ){ 104 | if((pin_cnt >=i+1) && ((port_b_old_in ^ new_in) & (1<=i+1) && ((port_b_old_in ^ new_in) & (1<=i+1) && ((port_c_old_in ^ new_in) & (1<=i+1) && ((port_c_old_in ^ new_in) & (1< 15 | #include 16 | 17 | #include "definitions.h" 18 | 19 | static inline uint8_t uartHasInput(void) 20 | { 21 | return 1; 22 | } 23 | 24 | static inline uint8_t uartGetInput(void) 25 | { 26 | int c = fgetc(stdin); 27 | if (c == 0x0A) 28 | { 29 | c = 0x0D; 30 | } 31 | return c; 32 | } 33 | 34 | static inline void uartWriteChar(char c) 35 | { 36 | putc(c, stdout); 37 | } 38 | 39 | static inline void uartMitMWriteChar(char c) 40 | { 41 | putc(c, stdout); 42 | } 43 | 44 | static inline void uartMitMWriteString(char *s) 45 | { 46 | puts(s); 47 | } 48 | 49 | static inline void uartWriteString(char *s) 50 | { 51 | puts(s); 52 | } 53 | 54 | static inline void uartprintf(char *fmt, ...) 55 | { 56 | va_list arglist; 57 | va_start(arglist, fmt); 58 | vprintf(fmt, arglist); 59 | va_end(arglist); 60 | } 61 | 62 | static inline void resetDevice(void) {} 63 | static inline uint16_t readVoltage(void) { return 0; } 64 | static inline void activateInterrupts() {} 65 | static inline void disableJTAG(void) {} 66 | static inline void initADC(void) {} 67 | static inline void initSystemClock(void) {} 68 | static inline uint8_t jtagReadPin(uint8_t pin) { return 0; } 69 | static inline void jtagWritePin(uint8_t pin, uint8_t level) {} 70 | static inline void portOut(xtractor_port_t port, uint8_t b) {} 71 | static inline void portSetDirection(xtractor_port_t port, uint8_t mask) 72 | { 73 | DEBUG("portSetDirection: %s %x", port, mask); 74 | } 75 | static inline void uartInit(void) {} 76 | static inline void uartMitMInit(void) {} 77 | static inline void sevensegWriteNumber(uint16_t printed_value) {} 78 | static inline void sevensegShowProgressBar(void) {} 79 | static inline void sevensegInit() {} 80 | void spiConfigurePins() {} 81 | uint8_t spiRead() { return 0; } 82 | void spiGDreadID() {} 83 | static inline void nandReset() {} 84 | static inline void nandInit() {} 85 | static inline void nandReadONFI(uint8_t result[]) {} 86 | static inline void nandReadChipID(uint8_t result[]) {} 87 | static inline void nandReadData16bit() {} 88 | static inline void nandWriteData16bitTest() {} 89 | static inline void nandReadData8bit() {} 90 | static inline void nandReadData8bitF59L1G81() {} 91 | void jtagTapState(char jtagTapState[], int tck, int tms) {} 92 | void jtagInitPins(int tck, int tms, int tdi, int ntrst, uint8_t pinslen) {} 93 | static void jtagPrintPins(int tck, int tms, int tdo, int tdi, int ntrst) {} 94 | static void jtagPulseTms(int tck, int tms, int s_tms) {} 95 | static void jtagPulseTdi(int tck, int tdi, int s_tdi) {} 96 | uint8_t jtagPulseTdo(int tck, int tdo) { return 0; } 97 | static void norResetFlash() {} 98 | static inline void norModeWord() {} 99 | static inline void norModeByte() {} 100 | static inline void norStartReadData() 101 | { 102 | usleep(100000); 103 | DEBUG("norStartReadData"); 104 | } 105 | static inline void norEndReadData() 106 | { 107 | DEBUG("norEndReadData"); 108 | } 109 | 110 | static inline uint8_t norRead8DataBits(uint32_t address) 111 | { 112 | return 0xAB; 113 | } 114 | 115 | static inline uint16_t norRead16DataBits(uint32_t address) 116 | { 117 | return 0xABCD; 118 | } 119 | -------------------------------------------------------------------------------- /hal.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file hal.h 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger, Steffen Robertz 12 | */ 13 | #ifndef _HAL_H 14 | #define _HAL_H 15 | 16 | #include 17 | 18 | #if defined(XTRACTOR_ARCH_TEST) 19 | #include "hal-test/definitions.h" 20 | #elif defined(XTRACTOR_ARCH_AVR) 21 | #include "hal-avr/definitions.h" 22 | #else 23 | #error "XTRACTOR_ARCH not defined" 24 | #endif 25 | 26 | #pragma region generic device functionality 27 | static inline uint16_t readVoltage(void); 28 | static inline void activateInterrupts(); 29 | static inline void disableJTAG(void); 30 | static inline void initADC(void); 31 | static inline void initSystemClock(void); 32 | static inline void resetDevice(void); 33 | #pragma endregion 34 | 35 | #pragma region GPIO 36 | static inline void portOut(xtractor_port_t *port, uint8_t b); 37 | static inline void portSetDirection(xtractor_port_t *port, uint8_t mask); 38 | #pragma endregion 39 | 40 | #pragma region UART functionality 41 | static inline uint8_t uartHasInput(void); 42 | static inline uint8_t uartPeekInput(void); 43 | static inline uint8_t uartGetInput(void); 44 | static inline void uartInit(void); 45 | static inline void uartprintf(char *fmt, ...); 46 | static inline void uartWriteChar(char c); 47 | static inline void uartMitMInit(void); 48 | static inline void uartMitMWriteChar(char c); 49 | static inline void uartMitMWriteString(char *s); 50 | static inline void uartWriteString(char *s); 51 | #pragma endregion 52 | 53 | #pragma region seven segment display 54 | static inline void sevensegWriteNumber(uint16_t printed_value); 55 | static inline void sevensegShowProgressBar(void); 56 | static inline void sevensegInit(); 57 | #pragma endregion 58 | 59 | #pragma region SPI 60 | void spiConfigurePins(); 61 | void spiGDreadID(); 62 | uint8_t spiRead(); 63 | #pragma endregion 64 | 65 | #pragma region NAND 66 | typedef struct { 67 | uint8_t signature[4]; 68 | uint16_t rev_num; 69 | uint16_t feature_support; 70 | uint16_t opt_cmd_support; 71 | uint8_t reserved1[22]; 72 | uint8_t vendor[12]; 73 | uint8_t model[20]; 74 | uint8_t vendor_jedec; 75 | uint16_t date; 76 | uint8_t reserved2[13]; 77 | uint32_t bytes_per_page; 78 | uint16_t spare_bytes_per_page; 79 | uint32_t data_bytes_per_partial_page; 80 | uint16_t spare_bytes_per_partial_page; 81 | uint32_t pages_per_block; 82 | uint32_t block_per_logic_unit; 83 | uint8_t logical_units; 84 | uint8_t address_cycles; 85 | uint8_t bits_per_cell; 86 | uint16_t max_bad_block_per_lun; 87 | uint16_t block_endurance; 88 | uint8_t guaranteed_valid_blocks_at_beginning; 89 | uint16_t block_endurance_for_guaranteed_valid_block; 90 | uint8_t num_of_programs_per_page; 91 | uint8_t partial_programming_attributes; 92 | uint8_t num_of_bits_ecc_correctability; 93 | uint8_t interleaved_addressing; 94 | uint8_t interleaved_operation_attributes; 95 | uint8_t reserved3[13]; 96 | uint8_t io_pin_capacitance; 97 | uint16_t timing_mode_support; 98 | uint16_t program_cache_timing_mode_support; 99 | uint16_t max_page_program_time; 100 | uint16_t max_block_erase_time; 101 | uint16_t max_page_read_time; 102 | uint16_t min_change_column_setup_time; 103 | uint8_t reserved4[23]; 104 | uint16_t vendor_rev_num; 105 | uint8_t vendor_specific[88]; 106 | uint16_t integrity_crc; 107 | } onfi_param_page_t; 108 | 109 | typedef struct { 110 | onfi_param_page_t params; 111 | char chipId[5]; 112 | } onfi_infos_t; 113 | 114 | static inline void nandReset(); 115 | static inline void nandInit(); 116 | static inline void nandReadONFI(uint8_t result[]); 117 | static inline void nandReadChipID(uint8_t result[]); 118 | static inline void onfiWriteData(onfi_param_page_t *params, uint16_t pattern,uint8_t write_ecc); 119 | static inline int onfiReadAndCheckParameters(onfi_param_page_t *params); 120 | static inline void onfiReadData(onfi_param_page_t *params, uint8_t read_ecc, uint8_t verify_read); 121 | static inline void initOnfiParam(); 122 | static inline void onfiEraseAll(onfi_param_page_t *params, uint8_t enable_progress); 123 | #pragma endregion 124 | 125 | #pragma region NOR 126 | static void norResetFlash(); 127 | static inline void norModeWord(); 128 | static inline void norModeByte(); 129 | static inline void norStartReadData(); 130 | static inline void norEndReadData(); 131 | static inline uint8_t norRead8DataBits(uint32_t address); 132 | static inline uint16_t norRead16DataBits(uint32_t address); 133 | //static inline void norWrite8DataBits(uint32_t address, uint8_t data); 134 | //static inline void norEraseChip(); 135 | #pragma endregion 136 | 137 | #pragma region UART_SCANNER 138 | typedef struct { 139 | uint32_t pin_changes; 140 | uint64_t last_change; 141 | uint64_t time_high; 142 | uint64_t time_low; 143 | uint32_t shortest_lowtime; 144 | }scanner_result_t; 145 | static inline void initScan(uint8_t pin_num); 146 | static volatile inline scanner_result_t* getChanges(void); 147 | static volatile inline uint32_t getShortestLowTime(void); 148 | #pragma endregion 149 | 150 | #pragma region TIMER 151 | static inline void initTimer(void); 152 | static inline uint64_t getTime(void); 153 | #pragma endregion 154 | 155 | #pragma region JTAG 156 | static inline uint8_t jtagReadPin(uint8_t pin); 157 | static inline void jtagWritePin(uint8_t pin, uint8_t level); 158 | void jtagInitPins(int tck, int tms, int tdi, int ntrst, uint8_t pinslen); 159 | void jtagTapState(char jtagTapState[], int tck, int tms); 160 | static void jtagPrintPins(int tck, int tms, int tdo, int tdi, int ntrst); 161 | static void jtagPulseTms(int tck, int tms, int s_tms); 162 | static void jtagPulseTdi(int tck, int tdi, int s_tdi); 163 | uint8_t jtagPulseTdo(int tck, int tdo); 164 | #pragma endregion 165 | 166 | #endif 167 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file main.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger 12 | */ 13 | #include "secxtractor.h" 14 | 15 | #if defined(XTRACTOR_ARCH_TEST) 16 | #include "hal-test/hal-test.c" 17 | #elif defined(XTRACTOR_ARCH_AVR) 18 | #include "hal-avr/hal-avr.c" 19 | #else 20 | #error "XTRACTOR_ARCH not defined" 21 | #endif 22 | 23 | #include "secxtractor.c" 24 | #include "shell.c" 25 | -------------------------------------------------------------------------------- /modules/nand.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file nand.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger, Steffen Robertz 12 | */ 13 | #include "../secxtractor.h" 14 | #include "../hal.h" 15 | 16 | onfi_infos_t onfi_infos; 17 | 18 | /** 19 | * @brief inits ONFI params to zero 20 | */ 21 | static void initOnfiParam() 22 | { 23 | memset(&onfi_infos.params, 0, sizeof(onfi_param_page_t)); 24 | } 25 | 26 | /** 27 | * @brief checks if the ONFI Parameters are initialized, otherwise prints error message 28 | * @returns 0 error 29 | * @returns 1 ONFI Parameters existent 30 | */ 31 | static uint8_t isOnfiParamConfigured() 32 | { 33 | if(memcmp(&onfi_infos.params.signature, "ONFI", 4) == 0){ 34 | return 1; 35 | } 36 | uartWriteString(NL"ONFI Parameters unknown. Try to run 'config onfi' first"NL); 37 | return 0; 38 | } 39 | 40 | 41 | /** 42 | * @brief Erases the whole Nand Flash 43 | */ 44 | static void cmdEraseNand() 45 | { 46 | if(isOnfiParamConfigured()) { 47 | uartWriteString(NL "Erasing Nand: " NL); 48 | nandInit(); 49 | nandReset(); 50 | onfiEraseAll(&onfi_infos.params,1); 51 | uartWriteString(NL "Operations finished successfully." NL); 52 | } 53 | } 54 | 55 | /** 56 | * @brief Writes a test pattern to the whole Nand 57 | */ 58 | static void cmdWriteNand() 59 | { 60 | if(isOnfiParamConfigured()){ 61 | nandInit(); 62 | nandReset(); 63 | uartWriteString(NL "Write through ECC Bytes? [Y/n]: " NL); 64 | while(!uartHasInput()); 65 | if(uartGetInput() != 'n'){ 66 | uartWriteString("Writing through ECC!"NL); 67 | onfiWriteData(&onfi_infos.params, 0xbeef, 1); 68 | }else{ 69 | uartWriteString("Skipping ECC!"NL); 70 | onfiWriteData(&onfi_infos.params, 0xbeef, 0); 71 | } 72 | uartWriteString(NL "Operations finished successfully." NL); 73 | } 74 | } 75 | 76 | /** 77 | * @brief Function to dump NAND flash memory. 78 | */ 79 | static void cmdDumpNand(char *arguments) 80 | { 81 | if(isOnfiParamConfigured()){ 82 | nandInit(); 83 | nandReset(); 84 | uartWriteString(NL "Dump with ECC Bytes? [Y/n]: " NL); 85 | while(!uartHasInput()); 86 | uint8_t dump_ecc = uartGetInput() != 'n'; 87 | 88 | uartWriteString(NL "Verify read operations? [Y/n]: " NL); 89 | while(!uartHasInput()); 90 | uint8_t verify_read = uartGetInput() != 'n'; 91 | 92 | if(dump_ecc){ 93 | uartWriteString("Dumping with ECC "); 94 | }else{ 95 | uartWriteString("Dumping without ECC "); 96 | } 97 | 98 | if(verify_read){ 99 | uartWriteString("with verification!"NL); 100 | }else{ 101 | uartWriteString("without verification!"NL); 102 | } 103 | 104 | onfiReadData(&onfi_infos.params, dump_ecc, verify_read); 105 | } 106 | } 107 | 108 | /** 109 | * @brief Prints some ONFI Parameters to the terminal 110 | */ 111 | static inline void onfiPrintParams(onfi_infos_t *infos) 112 | { 113 | onfi_param_page_t *params = &infos->params; 114 | onfi_feature_description_t *ft = &onfi_feature_descriptions[0]; 115 | 116 | uartprintf("Chip ID:\t\t\t%02x %02x %02x %02x %02x"NL, 117 | (unsigned char) infos->chipId[0], (unsigned char) infos->chipId[1], 118 | (unsigned char) infos->chipId[2], (unsigned char) infos->chipId[3], 119 | (unsigned char) infos->chipId[4]); 120 | uartprintf("Manufacturer:\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c"NL, 121 | params->vendor[0],params->vendor[1],params->vendor[2],params->vendor[3],params->vendor[4], 122 | params->vendor[5],params->vendor[6],params->vendor[7],params->vendor[8],params->vendor[9], 123 | params->vendor[10],params->vendor[11]); 124 | uartprintf("Model:\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"NL, 125 | params->model[0],params->model[1],params->model[2],params->model[3],params->model[4], 126 | params->model[5],params->model[6],params->model[7],params->model[8],params->model[9], 127 | params->model[10],params->model[11],params->model[12],params->model[13],params->model[14], 128 | params->model[15],params->model[16],params->model[17],params->model[18],params->model[19]); 129 | uartprintf("Date Code:\t\t\t0x%04x"NL, params->date); 130 | uartprintf("ONFI Revision:\t\t\t0x%04x"NL, params->rev_num); 131 | uartprintf("Features supported:\t\t0x%04x"NL, params->feature_support); 132 | 133 | while(ft->mask != 0){ 134 | if(ft->mask & params->feature_support){ 135 | uartprintf("\t\t\t\t* %s (0x%x)"NL, ft->description, ft->mask); 136 | } 137 | ft++; 138 | } 139 | 140 | uartprintf("Optional commands supported:\t0x%04x"NL, params->opt_cmd_support); 141 | uartprintf("Bytes per Page:\t\t\t%"PRIu32 NL, params->bytes_per_page); 142 | uartprintf("Spare bytes per Page:\t\t%u"NL, params->spare_bytes_per_page); 143 | uartprintf("Pages per Block:\t\t%"PRIu32 NL, params->pages_per_block); 144 | uartprintf("Blocks per LUN:\t\t\t%"PRIu32 NL, params->block_per_logic_unit); 145 | uartprintf("Number of LUNs:\t\t\t%u"NL, params->logical_units); 146 | } 147 | 148 | 149 | /** 150 | * @brief Function to return the chip ID and the ONFI string of a NAND flash memory. 151 | */ 152 | static inline void cmdInfoNand(char *arguments) 153 | { 154 | if(isOnfiParamConfigured()){ 155 | onfiPrintParams(&onfi_infos); 156 | } 157 | } 158 | 159 | 160 | /** 161 | * @brief configure the onfi params 162 | */ 163 | static void cmdConfigOnfi() 164 | { 165 | char signature[4]; 166 | 167 | uartWriteString("Configuring device with ONFI parameters"NL); 168 | nandInit(); 169 | nandReset(); 170 | nandReadONFI(signature); 171 | 172 | if(memcmp(signature, "ONFI", 4) != 0){ 173 | uartWriteString("NAND chip did not report to be ONFI compatible"NL); 174 | return; 175 | } 176 | 177 | nandReadChipID(onfi_infos.chipId); 178 | 179 | int res = onfiReadAndCheckParameters(&onfi_infos.params); 180 | 181 | if(res & 2){ 182 | uartWriteString("ONFI configuration failed! Please retry..."NL); 183 | return; 184 | } 185 | 186 | if(res & 1){ 187 | uartWriteString(NL"ONFI parameter page copys do not match. Further operation might be prone to errors!"NL); 188 | } 189 | 190 | uartWriteString("ONFI configuration successful!"NL); 191 | cmdInfoNand(""); 192 | } 193 | 194 | void cmdDelayNand(char *arguments) 195 | { 196 | 197 | if (*arguments != '\0') 198 | { 199 | nandDelayTime = atoi(arguments); 200 | } 201 | uartprintf("Nand chip delay: %ld iterations" NL, nandDelayTime); 202 | } -------------------------------------------------------------------------------- /modules/nor.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file nor.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger, Steffen Robertz 12 | */ 13 | 14 | #include "../secxtractor.h" 15 | #include "../hal.h" 16 | 17 | /* 18 | * PK0 = CE# 0x01 OUTPUT 19 | * PK1 = OE# 0x02 OUTPUT 20 | * PK2 = WE# 0x04 OUTPUT 21 | * PK3 = WP#/ACC 0x08 OUTPUT 22 | * PK4 = RESET# 0x10 OUTPUT 23 | * PK5 = BYTE# 0x20 OUTPUT 24 | * PK6 = RY#/BY# 0x40 INPUT 25 | * 26 | * control BIT0 = 16bit/1 8bit/0 27 | * control BIT1 = BigEndian/1 LittleEndian/0 28 | * */ 29 | 30 | /** 31 | * @brief Function to dump a NOR flash memory. 32 | * The content is directly redirected to the main UART in hexadecimal and can be recovered with "xxd -r". 33 | * @param endianess This varable indicates which endianess type should be set on the outputted firmware. 34 | * @param word_mode If set to one Word mode will be used during transfers, otherwise Byte Mode will be used 35 | */ 36 | static inline void norDump(uint8_t endianess, uint8_t word_mode) 37 | { 38 | DEBUG("Entering norDump"); 39 | uartprintf("endiness:%u, word: %u"NL, endianess, word_mode); 40 | 41 | /* NOR flash init */ 42 | portOut(&NOR_CTRL_PORT, NOR_CE | NOR_OE | NOR_RESET); 43 | portSetDirection(&NOR_CTRL_PORT, ~(NOR_RYBY | NOR_NC) & 0xFF); // set CE#, OE# and WE# to output, RY/BY# input 44 | 45 | /* set all address pins to output */ 46 | portSetDirection(&NOR_ADDR_PORT0, 0xFF); 47 | portSetDirection(&NOR_ADDR_PORT1, 0xFF); 48 | portSetDirection(&NOR_ADDR_PORT2, 0xFF); 49 | portSetDirection(&NOR_ADDR_PORT3, 0xFF); 50 | 51 | /* set all data pins to input */ 52 | portOut(&NOR_DATA_PORT0, 0x00); 53 | portOut(&NOR_DATA_PORT1, 0x00); 54 | portSetDirection(&NOR_DATA_PORT0, 0x00); 55 | portSetDirection(&NOR_DATA_PORT1, 0x00); 56 | 57 | norResetFlash(); 58 | 59 | dumpStart(); 60 | 61 | 62 | for (uint64_t address = 0x0; address < NOR_READ_LENGTH && !isOperationCanceled(); ++address) 63 | { 64 | uint16_t data; 65 | norStartReadData(); 66 | if(word_mode){ 67 | norModeWord(); 68 | data = norRead16DataBits(address); 69 | norEndReadData(); 70 | uint8_t data_byte1 = (uint8_t)((data & 0xFF00) >> 8); 71 | uint8_t data_byte2 = (uint8_t)(data & 0x00FF); 72 | if (endianess & 0x02 == 0x02) 73 | { 74 | dumpByte(data_byte2); 75 | dumpByte(data_byte1); 76 | } 77 | else 78 | { 79 | dumpByte(data_byte1); 80 | dumpByte(data_byte2); 81 | } 82 | }else{ 83 | norModeByte(); 84 | data = norRead8DataBits(address); 85 | norEndReadData(); 86 | dumpByte((uint8_t) data); 87 | } 88 | } 89 | dumpEnd(); 90 | } 91 | 92 | void cmdDumpNor(char *arguments) 93 | { 94 | if(*arguments == '\0'){ 95 | uartWriteString("Please supply and endianess and word-mode parameter"NL); 96 | uartWriteString("dump nor "NL" = 0 or 1"NL"=1 or 0"NL); 97 | return; 98 | } 99 | uint8_t word_mode = 1; 100 | uint8_t endianess = 1; 101 | int err = sscanf(arguments, "%u %u", &endianess, &word_mode); 102 | if (endianess < 2) 103 | { 104 | uartWriteString(NL "Starting nor flash dump: "); 105 | norDump(endianess, word_mode); 106 | } 107 | else 108 | { 109 | uartWriteString("Value too high. Max 1!" NL); 110 | } 111 | } 112 | 113 | ///TODO: Fix pattern write method 114 | /** 115 | * @brief Writes a pattern to a NOR Flash 116 | */ 117 | // void cmdNorPattern(char *arguments) 118 | // { 119 | // uartprintf("Writing NOR Pattern: %s", arguments); 120 | // uint16_t pattern = 0xff; 121 | // sscanf(arguments, "0x%x", &pattern); 122 | 123 | // /* NOR flash init */ 124 | // portOut(&NOR_CTRL_PORT, NOR_CE | NOR_OE | NOR_RESET); 125 | // portSetDirection(&NOR_CTRL_PORT, ~(NOR_RYBY | NOR_NC) & 0xFF); // set CE#, OE# and WE# to output, RY/BY# input 126 | 127 | // /* set all address pins to output */ 128 | // portSetDirection(&NOR_ADDR_PORT0, 0xFF); 129 | // portSetDirection(&NOR_ADDR_PORT1, 0xFF); 130 | // portSetDirection(&NOR_ADDR_PORT2, 0xFF); 131 | // portSetDirection(&NOR_ADDR_PORT3, 0xFF); 132 | 133 | // /* set all data pins to output */ 134 | // portSetDirection(&NOR_DATA_PORT0, 0xFF); 135 | // portSetDirection(&NOR_DATA_PORT1, 0xFF); 136 | 137 | // norResetFlash(); 138 | 139 | // norModeByte(); 140 | 141 | // norEraseChip(); 142 | 143 | // _delay_ms(10000); 144 | 145 | // for (uint64_t address = 0x0; address < NOR_READ_LENGTH; ++address) 146 | // { 147 | // norWrite8DataBits(0x0aaa, 0xaa); 148 | // norWrite8DataBits(0x0555, 0x55); 149 | // norWrite8DataBits(0x0aaa, 0xa0); 150 | // norWrite8DataBits(address, pattern); 151 | // uartWriteChar('.'); 152 | // } 153 | // uartWriteString(NL); 154 | // uartprintf("Pattern written. Pls verify!"); 155 | // } 156 | -------------------------------------------------------------------------------- /modules/spi.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file spi.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger 12 | */ 13 | 14 | void cmdSpiDump(char *arguments) 15 | { 16 | uartWriteString(NL "start spi nand dump"); 17 | spiConfigurePins(); 18 | spiGDreadID(); 19 | uartWriteString(NL); 20 | } 21 | -------------------------------------------------------------------------------- /modules/uart_scanner.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file uart_scanner.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger, Steffen Robertz 12 | */ 13 | 14 | #include "../secxtractor.h" 15 | #include "../hal.h" 16 | 17 | /** 18 | * @brief Executes the UART Scanner module and prints the results 19 | */ 20 | void cmdUartScanner(char *arguments) 21 | { 22 | #ifdef ESCAPE_CODE_SUPPORTED 23 | CLEAN_SCREEN() 24 | #endif 25 | 26 | //check for valid pinslen 27 | if(pinslen == 0){ 28 | uartWriteString("Please provide a pinlen first!"NL); 29 | return; 30 | } 31 | 32 | //PORTQ.DIRSET = PIN3_bm; 33 | initTimer(); 34 | initScan(pinslen); 35 | while(!isOperationCanceled()){ 36 | volatile scanner_result_t* result = getChanges(); 37 | 38 | //uartprintf("Pin:\tCnt:\tHigh(%%)\tBaud"NL); 39 | uartprintf("Pin:\tCnt:\tHigh(%%)"NL); 40 | uartWriteString(OUTPUT_BOUNDARY); 41 | for(uint8_t i=0; i> 4]); 47 | uartWriteChar(hexChars[b & 0xF]); 48 | dumpPosition++; 49 | } 50 | 51 | static inline void dumpEnd() 52 | { 53 | uartWriteString(NL DUMP_END_MARKER); 54 | } 55 | 56 | static inline int isOperationCanceled() 57 | { 58 | if(cancelCurrentOperation) 59 | { 60 | return 1; 61 | } 62 | 63 | if(uartHasInput() && uartGetInput() == CHAR_BREAK){ 64 | cancelCurrentOperation = 1; 65 | uartWriteString(NL OUTPUT_BOUNDARY_THICK "Cancelling..." NL); 66 | return 1; 67 | } 68 | return 0; 69 | } 70 | 71 | /** 72 | * @brief Main microcontroller loop. This is the main entry point of the SEC Xtractor firmware. 73 | */ 74 | int main(void) 75 | { 76 | DELAY_MS(100); //wait for possible voltage glitches 77 | //disable JTAG to make PORTB 4-7 usable 78 | disableJTAG(); 79 | initSystemClock(); 80 | uartInit(); 81 | activateInterrupts(); 82 | shellInit(); 83 | sevensegInit(); 84 | initADC(); 85 | initOnfiParam(); 86 | while (1) 87 | { 88 | if (uartHasInput()) 89 | { 90 | shell(uartGetInput()); 91 | } 92 | sevensegWriteNumber(readVoltage()); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /secxtractor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file secxtractor.h 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger, Steffen Robertz 12 | */ 13 | #ifndef _SECXTRACTOR_H 14 | #define _SECXTRACTOR_H 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define GLOBAL_VERSION_STRING "SEC Xtractor, version 1.31(0.5)" 22 | #define SHELL_STRING "[hacker@SEC Xtractor]# " 23 | 24 | #pragma region utility stuff 25 | #define OUTPUT_BOUNDARY "-----------------------" NL 26 | #define OUTPUT_BOUNDARY_THICK "=======================" NL 27 | #define DUMP_BEGIN_MARKER "---- BEGIN DUMP ----" NL 28 | #define DUMP_END_MARKER "---- END DUMP ----" NL 29 | 30 | #define NOP2 {NOP; NOP;} 31 | #define NOP3 {NOP; NOP; NOP;} 32 | #define NOP4 {NOP; NOP; NOP; NOP;} 33 | #define NOP5 {NOP; NOP; NOP; NOP; NOP;} 34 | #define NOP6 {NOP; NOP; NOP; NOP; NOP; NOP;} 35 | #define NOP7 {NOP; NOP; NOP; NOP; NOP; NOP; NOP;} 36 | #define NOP8 {NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;} 37 | #define NOP9 {NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;} 38 | #define NOP10 {NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;} 39 | #pragma endregion 40 | 41 | #pragma region UART_SCANNER 42 | #define SCANNER_MAX_PIN_CNT (16) 43 | #pragma endregion 44 | 45 | #pragma region NOR 46 | #define NOR_CE (1 << 0) 47 | #define NOR_OE (1 << 1) 48 | #define NOR_WE (1 << 2) 49 | #define NOR_WP (1 << 3) 50 | #define NOR_RESET (1 << 4) 51 | #define NOR_BYTE (1 << 5) 52 | #define NOR_RYBY (1 << 6) 53 | #define NOR_NC (1 << 7) 54 | 55 | #define NOR_READ_LENGTH 0x200000 56 | #pragma endregion 57 | 58 | #define CHAR_BELL 0x07 59 | #define CHAR_TAB 0x09 60 | #define CHAR_XOFF 0x13 61 | #define CHAR_XON 0x11 62 | #define CHAR_BREAK 0x03 63 | #define CHAR_BACKSPACE 0x08 64 | #define CHAR_DEL 0x7f 65 | #define CHAR_CR 0x0D 66 | #define CHAR_LF 0x0A 67 | 68 | #pragma region ID codes 69 | /*! \brief General chip detection mask table. */ 70 | #define IDCODE_MASK_GENERIC 0x7E 71 | 72 | #define IDCODE_MASK_AMD (0x01) 73 | #define IDCODE_MASK_AMI (0x02) 74 | #define IDCODE_MASK_FAIRCHILD (0x83) 75 | #define IDCODE_MASK_FUJITSU (0x04) 76 | #define IDCODE_MASK_GTE (0x85) 77 | #define IDCODE_MASK_HARRIS (0x86) 78 | #define IDCODE_MASK_HITACHI (0x07) 79 | #define IDCODE_MASK_INMOS (0x08) 80 | #define IDCODE_MASK_INTEL (0x89) 81 | #define IDCODE_MASK_ITT (0x8A) 82 | #define IDCODE_MASK_INTERSIL (0x0B) 83 | #define IDCODE_MASK_MONOLITHIC_MEMORIES (0x8C) 84 | #define IDCODE_MASK_MOSTEK (0x0D) 85 | #define IDCODE_MASK_FREESCALE (0x0E) 86 | #define IDCODE_MASK_NATIONAL (0x8F) 87 | #define IDCODE_MASK_NEC (0x10) 88 | #define IDCODE_MASK_RCA (0x91) 89 | #define IDCODE_MASK_RAYTHEON (0x92) 90 | #define IDCODE_MASK_CONEXANT (0x13) 91 | #define IDCODE_MASK_SEEQ (0x94) 92 | #define IDCODE_MASK_NXP (0x15) 93 | #define IDCODE_MASK_SYNERTEK (0x16) 94 | #define IDCODE_MASK_TEXAS_INSTRUMENTS (0x97) 95 | #define IDCODE_MASK_TOSHIBA (0x98) 96 | #define IDCODE_MASK_XICOR (0x19) 97 | #define IDCODE_MASK_ZILOG (0x1A) 98 | #define IDCODE_MASK_EUROTECHNIQUE (0x9B) 99 | #define IDCODE_MASK_MITSUBISHI (0x1C) 100 | #define IDCODE_MASK_LUCENT (0x9D) 101 | #define IDCODE_MASK_EXEL (0x9E) 102 | #define IDCODE_MASK_ATMEL (0x1F) 103 | #define IDCODE_MASK_STMICROELECTRONICS (0x20) 104 | #define IDCODE_MASK_LATTICE_SEM (0xA1) 105 | #define IDCODE_MASK_NCR (0xA2) 106 | #define IDCODE_MASK_WAFER_SCALE_INTEGRATION (0x23) 107 | #define IDCODE_MASK_IBM (0xA4) 108 | #define IDCODE_MASK_TRISTAR (0x25) 109 | #define IDCODE_MASK_VISIC (0x26) 110 | #define IDCODE_MASK_INTL_CMOS_TECHNOLOGY (0xA7) 111 | #define IDCODE_MASK_SSSI (0xA8) 112 | #define IDCODE_MASK_MICROCHIPTECHNOLOGY (0x29) 113 | #define IDCODE_MASK_RICOH_LTD (0x2A) 114 | #define IDCODE_MASK_VLSI (0xAB) 115 | #define IDCODE_MASK_MICRON_TECHNOLOGY (0x2C) 116 | #define IDCODE_MASK_MARVELL_SEMICONDUCTORS (0xE9) 117 | 118 | #pragma endregion 119 | 120 | #pragma region ONFI 121 | #define ONFI_CMD_READ_ID 0x90 122 | #define ONFI_CMD_RESET 0xFF 123 | #define ONFI_CMD_BLOCK_ERASE_CYCLE_1 0x60 124 | #define ONFI_CMD_BLOCK_ERASE_CYCLE_2 0xd0 125 | #define ONFI_CMD_PAGE_CACHE_PROGRAM_CYCLE_1 0x80 126 | #define ONFI_CMD_PAGE_CACHE_PROGRAM_CYCLE_2 0x10 127 | #define ONFI_CMD_READ_STATUS 0x70 128 | #define ONFI_CMD_READ_PARAMETER_PAGE 0xEC 129 | #define ONFI_CMD_READ_CYCLE_1 0x00 130 | #define ONFI_CMD_READ_CYCLE_2 0x30 131 | 132 | #define ONFI_FEATURE_16_BIT_BUS (1<<0) 133 | #define ONFI_FEATURE_MULTIPLE_LUNS (1<<1) 134 | #define ONFI_FEATURE_NON_SEQ_PAGE_PROG (1<<2) 135 | #define ONFI_FEATURE_MULTI_PLANE_PROG_ERASE (1<<3) 136 | #define ONFI_FEATURE_ODD_EVEN_PAGE_COPYBACK (1<<4) 137 | #define ONFI_FEATURE_NV_DDR (1<<5) 138 | #define ONFI_FEATURE_MULTI_PLANE_READ (1<<6) 139 | #define ONFI_FEATURE_EXTENDED_PARAMETER_PAGE (1<<7) 140 | #define ONFI_FEATURE_PROGRAM_PAGE_REGISTER_CLEAR_ENHANCEMENT (1<<8) 141 | #define ONFI_FEATURE_EZ_NAND (1<<9) 142 | #define ONFI_FEATURE_NV_DDR2 (1<<10) 143 | #define ONFI_FEATURE_VOLUME_ADDRESSING (1<<11) 144 | #define ONFI_FEATURE_EXT_VPP (1<<12) 145 | #define ONFI_FEATURE_NV_DDR3 (1<<13) 146 | #define ONFI_FEATURE_ZQ_CALIBRATION (1<<14) 147 | #define ONFI_FEATURE_PACKAGE_ELECTRICAL_SPEC (1<<15) 148 | 149 | typedef struct { 150 | uint16_t mask; 151 | char* description; 152 | } onfi_feature_description_t; 153 | 154 | onfi_feature_description_t onfi_feature_descriptions[] = { 155 | {ONFI_FEATURE_16_BIT_BUS, "16 bit bus"}, 156 | {ONFI_FEATURE_MULTIPLE_LUNS, "Multiple LUNs"}, 157 | {ONFI_FEATURE_NON_SEQ_PAGE_PROG, "Non-sequential page programming"}, 158 | {ONFI_FEATURE_ODD_EVEN_PAGE_COPYBACK, "Odd to even page Copyback"}, 159 | {ONFI_FEATURE_MULTI_PLANE_PROG_ERASE, "Multi-plane program and erase operations"}, 160 | {ONFI_FEATURE_MULTI_PLANE_READ, "Multi-plane read operations"}, 161 | {ONFI_FEATURE_NV_DDR, "NV-DDR"}, 162 | {ONFI_FEATURE_NV_DDR2, "NV-DDR2"}, 163 | {ONFI_FEATURE_NV_DDR3, "NV-DDR3"}, 164 | {ONFI_FEATURE_EXTENDED_PARAMETER_PAGE, "Extended parameter page"}, 165 | {ONFI_FEATURE_PROGRAM_PAGE_REGISTER_CLEAR_ENHANCEMENT, "Program page register clear enhancement"}, 166 | {ONFI_FEATURE_EZ_NAND, "EZ NAND"}, 167 | {ONFI_FEATURE_VOLUME_ADDRESSING, "Volume addressing"}, 168 | {ONFI_FEATURE_EXT_VPP, "External Vpp"}, 169 | {ONFI_FEATURE_ZQ_CALIBRATION, "ZQ Calibration"}, 170 | {ONFI_FEATURE_PACKAGE_ELECTRICAL_SPEC, "Package Electrical Specification"}, 171 | {0, NULL} 172 | }; 173 | 174 | #pragma endregion 175 | 176 | #pragma region dump methods 177 | static inline void dumpStart(); 178 | static inline void dumpByte(uint8_t b); 179 | static inline void dumpEnd(); 180 | static inline int isOperationCanceled(); 181 | #pragma endregion 182 | 183 | // Once you have found the JTAG pins you can define 184 | // the following to allow for the boundary scan and 185 | // irenum functions to be run. Define the values 186 | // as the index for the pins[] array of the found 187 | // jtag pin: 188 | //#define TCK 3 189 | //#define TMS 0 190 | //#define TDO 2 191 | //#define TDI 1 192 | //#define TRST 4 193 | 194 | // Pattern used for scan() and loopback() tests 195 | #define PATTERN_LEN 64 196 | // Use something random when trying find JTAG lines: 197 | static char pattern[PATTERN_LEN] = "0110011101001101101000010111001001"; 198 | // Use something more determinate when trying to find 199 | // length of the DR register: 200 | //static char pattern[PATTERN_LEN] = "1000000000000000000000000000000000"; 201 | 202 | // Max. number of JTAG enabled chips (MAX_DEV_NR) and length 203 | // of the DR register together define the number of 204 | // iterations to run for scan_idcode(): 205 | #define MAX_DEV_NR 8 206 | #define IDCODE_LEN 32 207 | 208 | // Target specific, check your documentation or guess 209 | #define SCAN_LEN 1890 // used for IR enum. bigger the better 210 | //#define IR_LEN 8 211 | // IR registers must be IR_LEN wide: 212 | #define IR_IDCODE "01100" // always 011 213 | #define IR_SAMPLE "10100" // always 101 214 | #define IR_PRELOAD IR_SAMPLE 215 | 216 | /* 217 | * END USER DEFINITIONS 218 | */ 219 | 220 | // TAP TMS states we care to use. NOTE: MSB sent first 221 | // Meaning ALL TAP and IR codes have their leftmost 222 | // bit sent first. This might be the reverse of what 223 | // documentation for your target(s) show. 224 | #define TAP_RESET "11111" // looping 1 will return \ 225 | // IDCODE if reg available 226 | #define TAP_SHIFTDR "111110100" 227 | #define TAP_SHIFTIR "1111101100" // -11111> Reset -0> Idle -1> SelectDR \ 228 | // -1> SelectIR -0> CaptureIR -0> ShiftIR 229 | 230 | // Ignore TCK, TMS use in loopback check: 231 | #define IGNOREPIN 0xFFFF 232 | // Flags configured by UI: 233 | uint8_t debug = 0; 234 | uint8_t jtagDelay = 0; 235 | long jtagDelayTime = 5000; // 5 Milliseconds 236 | long nandDelayTime = 0; 237 | uint8_t PULLUP = 0; 238 | uint8_t cancelCurrentOperation = 0; 239 | uint8_t dumpFast = 0; 240 | 241 | #define NAND_ALE (1 << 4) 242 | #define NAND_CLE (1 << 5) 243 | #define NAND_WP (1 << 3) 244 | #define NAND_WE (1 << 2) 245 | #define NAND_RE (1 << 1) 246 | #define NAND_CE (1 << 0) 247 | /*! \brief READY/BUSY input definition. */ 248 | #define NAND_RB (1 << 6) 249 | 250 | 251 | 252 | /* pin mapping: A31~A0 253 | * 1111 1111 1111 1111 1111 1111 1111 1111 254 | * PORTF| PORTD| PortC| PortB| 255 | * 0-7 -> B 256 | * 8-15 -> C 257 | * 16-23 -> D 258 | * 24-31 -> F 259 | * 260 | * pin mapping: DATA15~DATA0 261 | * 1111 1111 1111 1111 262 | * PortJ| PortH| 263 | * 0-7 -> H 264 | * 8-15 -> J 265 | * 266 | * pin mapping: Control 7~0 267 | * PK0 = CE# 268 | * PK1 = OE# 269 | * PK2 = WE# 270 | * PK3 = WP#/ACC 271 | * PK4 = RESET# 272 | * PK5 = BYTE# 273 | * PK6 = RY#/BY# 274 | * 275 | * 7SEG: 276 | * PA1 = A 277 | * PA2 = B 278 | * PA3 = C 279 | * PA4 = D 280 | * PA5 = E 281 | * PA6 = F 282 | * PA7 = G 283 | * 13-15, 16:30- */ 284 | 285 | #endif 286 | -------------------------------------------------------------------------------- /shell.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file shell.c 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger, Steffen Robertz 12 | */ 13 | #include "hal.h" 14 | #include "secxtractor.h" 15 | 16 | #include "modules/jtag.c" 17 | #include "modules/nand.c" 18 | #include "modules/nor.c" 19 | #include "modules/spi.c" 20 | #include "modules/uart_scanner.c" 21 | 22 | #define HELPNL NL " " 23 | 24 | /* shell variables */ 25 | static char commandinput[SHELL_LINE_MAX_LENGTH]; 26 | static uint8_t commandpointer = 0; 27 | 28 | static void showHelp(char* prefix, uint8_t details, uint8_t completeCommandInput); 29 | 30 | 31 | /** 32 | * @brief General help output for usage. 33 | **/ 34 | static void cmdHelp(char *arguments) 35 | { 36 | uartWriteString(NL); 37 | uartWriteString(GLOBAL_VERSION_STRING NL); 38 | uartWriteString( 39 | "The SEC Xtractor is designed as hardware testing tool by SEC Consult Unternehmensberatung GmbH." NL 40 | "Use `help detail' to find out more about all commands." NL 41 | NL); 42 | showHelp("", 0, 0); 43 | } 44 | 45 | /** 46 | * @brief Detailed help output for all functions. 47 | **/ 48 | static void cmdHelpDetail(char *arguments) 49 | { 50 | uartWriteString(NL); 51 | uartWriteString(GLOBAL_VERSION_STRING NL); 52 | uartWriteString( 53 | "The SEC Xtractor is designed as hardware testing tool by SEC Consult Unternehmensberatung GmbH." NL 54 | NL); 55 | showHelp("", 1, 0); 56 | } 57 | 58 | void cmdDebug(char *arguments) 59 | { 60 | debug = ~debug; 61 | if (debug) 62 | { 63 | uartWriteString("DEBUG ON" NL); 64 | } 65 | else 66 | { 67 | uartWriteString("DEBUG OFF" NL); 68 | } 69 | } 70 | 71 | void cmdReset(char *arguments) 72 | { 73 | resetDevice(); 74 | } 75 | 76 | void cmdFastdump(char *arguments) 77 | { 78 | if(arguments[0] == '1'){ 79 | dumpFast = 1; 80 | uartWriteString("FASTDUMP ON" NL); 81 | }else{ 82 | dumpFast = 0; 83 | uartWriteString("FASTDUMP OFF" NL); 84 | } 85 | } 86 | 87 | shell_command_t commands[] = { 88 | /* generic */ 89 | SHELL_COMMAND("help detail", cmdHelpDetail, "", 90 | "Prints the detailed help page."), 91 | SHELL_COMMAND("help", cmdHelp, "", 92 | "Prints the short help page."), 93 | SHELL_COMMAND("debug", cmdDebug, "", ""), 94 | SHELL_COMMAND("reset", cmdReset, "", ""), 95 | SHELL_COMMAND("fastdump", cmdFastdump, "<0|1>", 96 | "Enable or disable fast dumping (skip formating and dump 1K in every line)."), 97 | /* JTAG */ 98 | SHELL_COMMAND("pattern scan single", cmdPatternScanSingle, "", 99 | "Probe for a present JTAG port by using the pre-selected JTAG pin configuration"), 100 | SHELL_COMMAND("pattern scan", cmdPatternScan, "", 101 | "Scans for a present JTAG port on all activated A pins of the SEC Xtractor."), 102 | SHELL_COMMAND("idcode scan", cmdIdcodeScan, "", 103 | "Assumes IDCODE is default DR on reset. Ignores TDI." HELPNL 104 | "Sets TAP state to DR_SHIFT and prints TDO to console" HELPNL 105 | "when TDO appears active. Human examination required to" HELPNL 106 | "determine if actual IDCODE is present. Run several" HELPNL 107 | "times to check for consistancy or compare against" HELPNL 108 | "active tdo lines found with loopback test."), 109 | SHELL_COMMAND("bypass scan", cmdBypassScan, "", 110 | "Assumes BYPASS is default DR on reset. Ignores TMS and" NL 111 | "shifts pattern[] through TDI/TDO using TCK for clock." NL), 112 | SHELL_COMMAND("boundary scan", cmdBoundaryScan, "", 113 | "Checks code defined tdo for 4000+ bits."), 114 | SHELL_COMMAND("pattern set", cmdPatternSet, "[numbers_from_1_to_32]", ""), 115 | SHELL_COMMAND("pinlen set", cmdPinlenSet, "[number_in_the_range_from_1_to_32]", 116 | "Set length of pins for brute force JTAG."), 117 | SHELL_COMMAND("tck set", cmdTckSet, "[number_in_the_range_from_1_to_32]", ""), 118 | SHELL_COMMAND("tms set", cmdTmsSet, "[number_in_the_range_from_1_to_32]", ""), 119 | SHELL_COMMAND("tdi set", cmdTdiSet, "[number_in_the_range_from_1_to_32]", ""), 120 | SHELL_COMMAND("tdo set", cmdTdoSet, "[number_in_the_range_from_1_to_32]", ""), 121 | SHELL_COMMAND("trst set", cmdTrstSet, "[number_in_the_range_from_1_to_32]", ""), 122 | SHELL_COMMAND("loopback check", cmdLoopbackCheck, "", ""), 123 | SHELL_COMMAND("ir len set", cmdIrLenSet, "[number_in_the_range_from_1_to_40]", ""), 124 | SHELL_COMMAND("flashsize set", cmdFlashsizeSet, "", ""), 125 | SHELL_COMMAND("delay jtag", cmdDelayJtag, "[+/-]", 126 | "No arguments: Slows down the JTAG scan." HELPNL 127 | "With arguments + or -: Reduces or increases the scan delay by 1000us"), 128 | SHELL_COMMAND("irenum", cmdIrEnum, "", 129 | "Sets every possible Instruction Register and then checks the output of the Data Register."), 130 | /* NAND */ 131 | SHELL_COMMAND("info nand", cmdInfoNand, "", 132 | "Displays information about the NAND memory gathered from the ONFI parameter pages."), 133 | SHELL_COMMAND("write nand", cmdWriteNand, "", 134 | "Writes 0xbeef into the entire NAND memory. Choices can be made to include or exclude ECC bytes."), 135 | SHELL_COMMAND("dump nand", cmdDumpNand, "", 136 | "Dumps the content of the NAND memory. ECC bytes can be included or excluded."), 137 | SHELL_COMMAND("config onfi", cmdConfigOnfi, "", 138 | "Reads the ONFI parameter page of the NAND memory. These values are required for further communication with the flash memory."), 139 | SHELL_COMMAND("erase nand", cmdEraseNand, "", 140 | "Erases all content from the NAND memory."), 141 | SHELL_COMMAND("delay nand", cmdDelayNand, "[delay iterations]", 142 | "Allows waiting a specified amount of time before expecting NAND chip to have received a request." HELPNL 143 | "May improve reliability." HELPNL 144 | "No arguments: Shows current delay." HELPNL 145 | "With arguments: Sets delay [in loop iterations]"), 146 | /* NOR */ 147 | SHELL_COMMAND("dump nor", cmdDumpNor, "[endianess (1/0)] [enable word mode (1/0)]", ""), 148 | //SHELL_COMMAND("write nor pattern", cmdNorPattern), 149 | /* SPI */ 150 | SHELL_COMMAND("spi dump", cmdSpiDump, "", ""), 151 | /* UART */ 152 | SHELL_COMMAND("uart scanner", cmdUartScanner, "", 153 | "Scans for toggling pins which are hold high during idle times. This indicates the presence of a UART bus."), 154 | END_OF_COMMANDS() 155 | }; 156 | 157 | void shellInit(void) 158 | { 159 | memset(commandinput, 0, SHELL_LINE_MAX_LENGTH); 160 | uartWriteString(GLOBAL_VERSION_STRING NL); 161 | uartWriteString(SHELL_STRING); 162 | } 163 | 164 | static inline void executeCommand(void) 165 | { 166 | shell_command_t *commandPtr = &commands[0]; 167 | int tmp; 168 | 169 | cancelCurrentOperation = 0; 170 | 171 | sevensegShowProgressBar(); 172 | 173 | // remove trailing spaces 174 | while (commandpointer > 0 && commandinput[commandpointer] == ' ') 175 | { 176 | commandpointer--; 177 | } 178 | 179 | commandinput[commandpointer] = '\0'; 180 | 181 | if(commandinput[0] == '\0') 182 | { 183 | // no command -> nothing to do 184 | return; 185 | } 186 | 187 | while (!IS_END_OF_COMMANDS(commandPtr)) 188 | { 189 | tmp = strlen(commandPtr->commandPrefix); 190 | 191 | if (strncmp(commandinput, commandPtr->commandPrefix, tmp) == 0) 192 | { 193 | // remove spaces between command and arguments 194 | while (commandinput[tmp] == ' ') 195 | { 196 | tmp++; 197 | } 198 | commandPtr->callback(&commandinput[tmp]); 199 | return; 200 | } 201 | commandPtr++; 202 | } 203 | 204 | uartprintf("ERROR: Unknown Command '%s', try 'help'" NL, commandinput); 205 | } 206 | 207 | /** 208 | * @brief Main shell of the tool. 209 | * @param character The input character that gets processed. 210 | */ 211 | static void shell(char character) 212 | { 213 | if (commandpointer >= SHELL_LINE_MAX_LENGTH) 214 | { 215 | return; 216 | } 217 | switch (character) 218 | { 219 | case CHAR_BACKSPACE: // backspace 220 | case CHAR_DEL: // del (putty) 221 | if (commandpointer != 0) //delete one char in memory 222 | { 223 | uartWriteChar(CHAR_BACKSPACE); 224 | uartWriteChar(' '); 225 | uartWriteChar(CHAR_BACKSPACE); 226 | commandpointer--; 227 | commandinput[commandpointer] = '\0'; 228 | } 229 | break; 230 | case CHAR_CR: 231 | case CHAR_LF: 232 | uartWriteString(NL); 233 | commandinput[commandpointer] = '\0'; // NUL-terminate string 234 | executeCommand(); 235 | uartWriteString(SHELL_STRING); 236 | commandpointer = 0; 237 | commandinput[0] = '\0'; 238 | break; 239 | case CHAR_BREAK: 240 | uartWriteString(NL SHELL_STRING); 241 | commandpointer = 0; 242 | commandinput[0] = '\0'; 243 | break; 244 | case CHAR_TAB: 245 | commandinput[commandpointer] = '\0'; // NUL-terminate string 246 | uartWriteString(NL); 247 | showHelp(commandinput, 0, 1); 248 | uartWriteString(SHELL_STRING); 249 | uartWriteString(commandinput); 250 | break; 251 | default: //default char 252 | if(character < 32 || character >= 127){ 253 | // non-ASCII or other non-printable 254 | uartWriteChar(CHAR_BELL); 255 | }else{ 256 | uartWriteChar(character); 257 | commandinput[commandpointer] = character; 258 | commandpointer++; 259 | } 260 | break; 261 | } 262 | } 263 | 264 | static inline int countSameChars(const char *s1, const char *s2, int length){ 265 | int i = 0; 266 | while(i < length && s2[i] != '\0' && s2[i] != '\0' && s1[i] == s2[i]){ 267 | i++; 268 | } 269 | return i; 270 | } 271 | 272 | static void showHelp(char* prefix, uint8_t details, uint8_t completeCommandInput) 273 | { 274 | shell_command_t *commandPtr = &commands[0]; 275 | uint8_t prefixEndPointer = strlen(prefix); 276 | const char *matchingStrPtr = NULL; 277 | int matchingStrLen = 0; 278 | uint8_t matchingCommandCount = 0; 279 | 280 | // remove trailing spaces 281 | while (prefixEndPointer > 0 && prefix[prefixEndPointer] == ' ') 282 | { 283 | prefixEndPointer--; 284 | } 285 | 286 | while (!IS_END_OF_COMMANDS(commandPtr)) 287 | { 288 | if (strncmp(prefix, commandPtr->commandPrefix, prefixEndPointer) == 0) 289 | { 290 | matchingCommandCount++; 291 | if(matchingCommandCount == 1){ 292 | matchingStrPtr = commandPtr->commandPrefix; 293 | matchingStrLen = strlen(commandPtr->commandPrefix); 294 | }else{ 295 | matchingStrLen = countSameChars(matchingStrPtr, commandPtr->commandPrefix, matchingStrLen); 296 | } 297 | uartprintf("%s %s" NL, commandPtr->commandPrefix, commandPtr->usage); 298 | if(details){ 299 | uartprintf(" %s" NL, commandPtr->helptext); 300 | } 301 | } 302 | commandPtr++; 303 | } 304 | 305 | if(completeCommandInput && matchingStrLen > commandpointer){ 306 | strncpy(commandinput, matchingStrPtr, matchingStrLen); 307 | commandpointer = matchingStrLen; 308 | if(matchingCommandCount == 1){ 309 | commandinput[commandpointer++] = ' '; 310 | } 311 | commandinput[commandpointer] = '\0'; 312 | } 313 | } -------------------------------------------------------------------------------- /shell.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file shell.h 3 | * 4 | * Copyright (C): SEC Consult Unternehmensberatung GmbH, 2019 \n 5 | * Web: https://sec-consult.com/ \n 6 | * \n 7 | * This Source Code Form is subject to the terms of the Mozilla Public\n 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this\n 9 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 10 | * 11 | * @authors Thomas Weber, Wolfgang Ettlinger 12 | */ 13 | 14 | #ifndef _SHELL_H 15 | #define _SHELL_H 16 | 17 | #define SHELL_LINE_MAX_LENGTH 256 18 | 19 | void shellInit(void); 20 | static void shell(char character); 21 | 22 | typedef void (shell_command_callback_t)(char *arguments); 23 | 24 | typedef struct { 25 | char *commandPrefix; 26 | char *usage; 27 | char *helptext; 28 | shell_command_callback_t* callback; 29 | } shell_command_t; 30 | 31 | #define SHELL_COMMAND(prefix, callback, usage, helptext) {(prefix), (usage), (helptext), (&callback)} 32 | #define END_OF_COMMANDS() {(NULL), (NULL), (NULL), (NULL)} 33 | 34 | #define IS_END_OF_COMMANDS(sc) ((sc)->commandPrefix == NULL) 35 | 36 | #define CLEAN_SCREEN() {uartWriteChar(27);\ 37 | uartWriteString("[2J");\ 38 | uartWriteChar(27);\ 39 | uartWriteString("[H");} 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /tools/nand/nandsplit.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C): SEC Consult Unternehmensberatung GmbH, 2020 \n 3 | # Web: https://sec-consult.com/ \n 4 | # \n 5 | # This Source Code Form is subject to the terms of the Mozilla Public\n 6 | # License, v. 2.0. If a copy of the MPL was not distributed with this\n 7 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 8 | # 9 | # @authors Wolfgang Ettlinger 10 | # 11 | import sys 12 | 13 | 14 | def main(args): 15 | if len(args) < 4: 16 | print('USAGE: nandsplit.py [...]') 17 | return -1 18 | idx = 0 19 | fname = args[0] 20 | pagesize = int(args[1], 0) 21 | sparesize = int(args[2], 0) 22 | pages_per_block = int(args[3], 0) 23 | blocksize = pages_per_block * pagesize 24 | parts = [] 25 | 26 | with open(fname, 'rb') as f: 27 | for size in args[4:]: 28 | to_copy = int(size, 0) 29 | 30 | parts.append((idx, to_copy)) 31 | 32 | to_copy += int(to_copy/pagesize) * sparesize # add spare 33 | 34 | with open(fname + 'p'+str(idx), 'wb') as fout: 35 | while to_copy != 0: 36 | chunk = min(to_copy, 4096) 37 | data = f.read(chunk) 38 | if len(data) != chunk: 39 | raise Exception('Input file too small') 40 | fout.write(data) 41 | to_copy -= chunk 42 | 43 | idx += 1 44 | 45 | print("Parts: "+(','.join([hex(int(x[1] / blocksize)) for x in parts]))) 46 | 47 | print("nandwrite commands:") 48 | for partidx, _ in parts: 49 | print("nandwrite -o /dev/mtd{0} {1}p{0}".format(partidx, fname)) 50 | 51 | if __name__ == '__main__': 52 | sys.exit(main(sys.argv[1:])) 53 | -------------------------------------------------------------------------------- /tools/nand/stripspare.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C): SEC Consult Unternehmensberatung GmbH, 2020 \n 3 | # Web: https://sec-consult.com/ \n 4 | # \n 5 | # This Source Code Form is subject to the terms of the Mozilla Public\n 6 | # License, v. 2.0. If a copy of the MPL was not distributed with this\n 7 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 8 | # 9 | # @authors Wolfgang Ettlinger 10 | # 11 | import sys 12 | 13 | 14 | def main(args): 15 | if len(args) < 4: 16 | print('USAGE: stripspare.py ') 17 | return -1 18 | idx = 0 19 | infile = args[0] 20 | pagesize = int(args[1], 0) 21 | sparesize = int(args[2], 0) 22 | outfile = args[3] 23 | 24 | with open(infile, 'rb') as fin: 25 | with open(outfile, 'wb') as fout: 26 | while True: 27 | data = fin.read(pagesize+sparesize) 28 | if len(data) == 0: 29 | break 30 | fout.write(data[0:pagesize]) 31 | 32 | 33 | if __name__ == '__main__': 34 | sys.exit(main(sys.argv[1:])) 35 | -------------------------------------------------------------------------------- /tools/xtractorterminal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright (C): SEC Consult Unternehmensberatung GmbH, 2020 \n 4 | # Web: https://sec-consult.com/ \n 5 | # \n 6 | # This Source Code Form is subject to the terms of the Mozilla Public\n 7 | # License, v. 2.0. If a copy of the MPL was not distributed with this\n 8 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. \n 9 | # 10 | # @authors Wolfgang Ettlinger 11 | # 12 | import re 13 | import datetime 14 | import time 15 | import tempfile 16 | from binascii import unhexlify 17 | from serial.tools.miniterm import Miniterm, key_description, Transform 18 | import serial 19 | import sys 20 | 21 | BAUD = 4000000 22 | EOL = 'crlf' 23 | ENCODING = 'UTF-8' 24 | HEADER = r''' 25 | ### ### ### 26 | # # # \ / 27 | # ## # \/ ___ ___ _ ___ _ ___ 28 | # # # /\ | | | /\ | | | | | | 29 | ### ### ### / \ | | / \ |_ | |_| | 30 | 31 | ''' 32 | 33 | NL = '\n' 34 | OUTPUT_BOUNDARY = "-----------------------" 35 | OUTPUT_BOUNDARY_THICK = "=======================" 36 | DUMP_BEGIN_MARKER = "---- BEGIN DUMP ----" 37 | DUMP_END_MARKER = "---- END DUMP ----" 38 | KB = 1024 39 | 40 | 41 | class XtractorTransformation(Transform): 42 | def __init__(self): 43 | self.buf = '' 44 | self.destination_file = None 45 | self.byte_count = 0 46 | self.start_timestamp = None 47 | 48 | def rx(self, text): 49 | res = [] 50 | 51 | inputlines = (text).split(NL) 52 | 53 | for i in range(len(inputlines) - 1): 54 | line = inputlines[i] 55 | 56 | if i == 0: 57 | line = self.buf + line 58 | self.buf = '' 59 | 60 | if self.destination_file is None: 61 | res.append(inputlines[i]) 62 | 63 | process_out = self.process(line) 64 | 65 | if process_out is not None: 66 | res.append(process_out) 67 | 68 | self.buf += inputlines[-1] 69 | 70 | if self.destination_file is None: 71 | res.append(inputlines[-1]) 72 | elif len(res) != 0: 73 | res.append('') # force newline 74 | 75 | return NL.join(res) 76 | 77 | def process(self, line): 78 | line = line.strip(' \r\n') 79 | if self.destination_file is not None: 80 | if line in (OUTPUT_BOUNDARY, OUTPUT_BOUNDARY_THICK, DUMP_END_MARKER): 81 | fname = self.destination_file.name 82 | self.destination_file.close() 83 | self.destination_file = None 84 | return "Dump saved to '{0}' ({1}KB)".format(fname, self.byte_count / KB) 85 | else: 86 | data = unhexlify(line.replace(' ', '')) 87 | self.destination_file.write(data) 88 | old_byte_count = self.byte_count 89 | self.byte_count += len(data) 90 | 91 | if int(old_byte_count / 100 / KB) != int(self.byte_count / 100 / KB): 92 | return "Received {0:,.0f} KB at {1:.1f} KB/s".format( 93 | self.byte_count / KB, 94 | self.byte_count / KB / (time.time() - self.start_timestamp)) 95 | 96 | elif line == DUMP_BEGIN_MARKER: 97 | self.destination_file = tempfile.NamedTemporaryFile(delete=False, dir='.', 98 | prefix='dump_'+re.sub('[^0-9-]', '_', datetime.datetime.now().isoformat()), 99 | suffix='.xtractor') 100 | self.byte_count = 0 101 | self.start_timestamp = time.time() 102 | return "Receiving dump ('{0}')...".format(self.destination_file.name) 103 | 104 | 105 | class XtractorMiniterm(Miniterm): 106 | def update_transformations(self): 107 | super().update_transformations() 108 | 109 | self.rx_transformations.append(XtractorTransformation()) 110 | 111 | 112 | def main(args): 113 | if len(args) != 1: 114 | print('USAGE: xtractorterminal.py [serial device]') 115 | return -1 116 | 117 | device = args[0] 118 | 119 | serial_instance = serial.serial_for_url( 120 | device, BAUD, parity='N', rtscts=False, xonxoff=True) 121 | 122 | miniterm = XtractorMiniterm(serial_instance, echo=False, 123 | eol=EOL, filters=['default']) 124 | miniterm.exit_character = chr(0x1d) 125 | miniterm.menu_character = chr(0x14) 126 | miniterm.raw = False 127 | miniterm.set_rx_encoding(ENCODING) 128 | miniterm.set_tx_encoding(ENCODING) 129 | 130 | sys.stderr.write(HEADER) 131 | sys.stderr.write('--- Miniterm (XTractor) on {p.name} {p.baudrate},{p.bytesize},{p.parity},{p.stopbits} ---\n'.format( 132 | p=miniterm.serial)) 133 | sys.stderr.write('--- Quit: {} | Menu: {} | Help: {} followed by {} ---\n'.format( 134 | 'Ctrl+[Key next to return, en:"]", de:"+"]', 135 | key_description(miniterm.menu_character), 136 | key_description(miniterm.menu_character), 137 | key_description('\x08'))) 138 | 139 | miniterm.start() 140 | miniterm.serial.write(b'\x03') # send CTRL+C 141 | try: 142 | miniterm.join(True) 143 | except KeyboardInterrupt: 144 | pass 145 | sys.stderr.write('\n--- exit ---\n') 146 | miniterm.join() 147 | miniterm.close() 148 | 149 | 150 | if __name__ == '__main__': 151 | sys.exit(main(sys.argv[1:])) 152 | --------------------------------------------------------------------------------