Imported Upstream version 1
Bas Wijnen
9 years ago
0 | Version 1: | |
1 | ||
2 | * *: Fork from https://github.com/maniacbug/mighty-1284p/. | |
3 | * README.md: Update. | |
4 | * .gitignore: Update. | |
5 | * cores: Remove outdated copy of Arduino source tree. | |
6 | * bootloaders: Build from source. | |
7 | * variants: Remove alternative pinouts. | |
8 | * variants/standard/pins_arduino.h: Correct NUM_DIGITAL_PINS. |
0 | # Mighty 1284P: Platform files for Arduino to run on ATmega1284P | |
1 | ||
2 | ## What is it? | |
3 | ||
4 | Everything you need to run Arduino on ATmega1284P. | |
5 | ||
6 | ## Current state | |
7 | ||
8 | This is a fork of Maniacbug's work, which seems to have been abandoned. It uses upstream Arduino files as much as possible instead of (out of date) copies. It has been tested and is considered complete. Please report any bugs you may find. | |
9 | ||
10 | ## Installation | |
11 | ||
12 | Recommended method: on your Debian system, install the package from the repository. Alternatively: | |
13 | ||
14 | 1. Download the [ZIP File](https://github.com/wijnen/mighty-1284p/zipball/master) | |
15 | 2. Unzip it a folder called 'hardware' in your sketchbook directory, e.g. ~/Arduino/hardware/mighty-1284p | |
16 | 3. Restart the IDE | |
17 | 4. Select Tools > Board > Mighty 1284p 16MHz using Optiboot | |
18 | 5. To burn the bootloader, follow the Arduino [Bootloader](http://arduino.cc/en/Hacking/Bootloader) instructions. | |
19 | ||
20 | ## Requirements | |
21 | ||
22 | * Works only on Arduino >= 1.0 | |
23 | * Cannot be burned using [USBtinyISP](http://www.ladyada.net/make/usbtinyisp/). That programmer cannot flash to chips with >64k flash size. | |
24 | ||
25 | ## See also | |
26 | ||
27 | http://maniacbug.wordpress.com/2011/11/27/arduino-on-atmega1284p-4/ | |
28 | ||
29 | ## Supported Boards | |
30 | ||
31 | * 'Mighty 1284p using Optiboot'. | |
32 | * 'Original Mighty 1284p'. Uses a different booloader; if you have a board with this, burning optiboot is recommended. |
0 | ############################################################## | |
1 | ||
2 | mighty_opt.name=Mighty 1284p using Optiboot | |
3 | mighty_opt.upload.protocol=arduino | |
4 | mighty_opt.upload.maximum_size=130048 | |
5 | mighty_opt.upload.speed=115200 | |
6 | mighty_opt.bootloader.low_fuses=0xff | |
7 | mighty_opt.bootloader.high_fuses=0xde | |
8 | mighty_opt.bootloader.extended_fuses=0xfd | |
9 | mighty_opt.bootloader.path=optiboot | |
10 | mighty_opt.bootloader.file=optiboot_atmega1284p.hex | |
11 | mighty_opt.bootloader.unlock_bits=0x3F | |
12 | mighty_opt.bootloader.lock_bits=0x0F | |
13 | mighty_opt.build.mcu=atmega1284p | |
14 | mighty_opt.build.f_cpu=16000000L | |
15 | mighty_opt.build.core=arduino:arduino | |
16 | mighty_opt.build.variant=standard | |
17 | ||
18 | ############################################################## | |
19 | ||
20 | mighty.name=Original Mighty 1284p | |
21 | mighty.upload.protocol=stk500v1 | |
22 | mighty.upload.maximum_size=129024 | |
23 | mighty.upload.speed=57600 | |
24 | mighty.bootloader.low_fuses=0xff | |
25 | mighty.bootloader.high_fuses=0xdc | |
26 | mighty.bootloader.extended_fuses=0xfd | |
27 | mighty.bootloader.path=standard | |
28 | mighty.bootloader.file=ATmegaBOOT_1284P.hex | |
29 | mighty.bootloader.unlock_bits=0x3F | |
30 | mighty.bootloader.lock_bits=0x0F | |
31 | mighty.build.mcu=atmega1284p | |
32 | mighty.build.f_cpu=16000000L | |
33 | mighty.build.core=arduino:arduino | |
34 | mighty.build.variant=standard |
0 | # Makefile for ATmegaBOOT | |
1 | # E.Lins, 18.7.2005 | |
2 | # $Id$ | |
3 | # | |
4 | # Instructions | |
5 | # | |
6 | # To make bootloader .hex file: | |
7 | # make diecimila | |
8 | # make lilypad | |
9 | # make ng | |
10 | # etc... | |
11 | # | |
12 | # To burn bootloader .hex file: | |
13 | # make diecimila_isp | |
14 | # make lilypad_isp | |
15 | # make ng_isp | |
16 | # etc... | |
17 | ||
18 | # program name should not be changed... | |
19 | PROGRAM = optiboot | |
20 | ||
21 | # The default behavior is to build using tools that are in the users | |
22 | # current path variables, but we can also build using an installed | |
23 | # Arduino user IDE setup, or the Arduino source tree. | |
24 | # Uncomment this next lines to build within the arduino environment, | |
25 | # using the arduino-included avrgcc toolset (mac and pc) | |
26 | # ENV ?= arduino | |
27 | # ENV ?= arduinodev | |
28 | # OS ?= macosx | |
29 | # OS ?= windows | |
30 | ||
31 | # enter the parameters for the avrdude isp tool | |
32 | ISPTOOL = avrisp | |
33 | ISPPORT = /dev/ttyUSB0 | |
34 | ISPSPEED = -b 19200 | |
35 | ||
36 | MCU_TARGET = atmega168 | |
37 | LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffe | |
38 | ||
39 | # Build environments | |
40 | # Start of some ugly makefile-isms to allow optiboot to be built | |
41 | # in several different environments. See the README.TXT file for | |
42 | # details. | |
43 | ||
44 | # default | |
45 | fixpath = $(1) | |
46 | ||
47 | # the efuse should really be 0xf8; since, however, only the lower | |
48 | # three bits of that byte are used on the atmega168, avrdude gets | |
49 | # confused if you specify 1's for the higher bits, see: | |
50 | # http://tinker.it/now/2007/02/24/the-tale-of-avrdude-atmega168-and-extended-bits-fuses/ | |
51 | # | |
52 | # similarly, the lock bits should be 0xff instead of 0x3f (to | |
53 | # unlock the bootloader section) and 0xcf instead of 0x2f (to | |
54 | # lock it), but since the high two bits of the lock byte are | |
55 | # unused, avrdude would get confused. | |
56 | ||
57 | ISPFUSES = $(AVRDUDE_ROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \ | |
58 | -p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \ | |
59 | -e -u -U lock:w:0x3f:m -U efuse:w:0x$(EFUSE):m \ | |
60 | -U hfuse:w:0x$(HFUSE):m -U lfuse:w:0x$(LFUSE):m | |
61 | ISPFLASH = $(AVRDUDE_ROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \ | |
62 | -p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) -V \ | |
63 | -U flash:w:$(PROGRAM)_$(TARGET).hex -U lock:w:0x2f:m | |
64 | ||
65 | STK500 = "C:\Program Files\Atmel\AVR Tools\STK500\Stk500.exe" | |
66 | STK500-1 = $(STK500) -e -d$(MCU_TARGET) -pf -vf -if$(PROGRAM)_$(TARGET).hex \ | |
67 | -lFF -LFF -f$(HFUSE)$(LFUSE) -EF8 -ms -q -cUSB -I200kHz -s -wt | |
68 | STK500-2 = $(STK500) -d$(MCU_TARGET) -ms -q -lCF -LCF -cUSB -I200kHz -s -wt | |
69 | ||
70 | OBJ = $(PROGRAM).o | |
71 | OPTIMIZE = -Os -fno-inline-small-functions -fno-split-wide-types | |
72 | ||
73 | DEFS = | |
74 | LIBS = | |
75 | ||
76 | CC = $(GCCROOT)avr-gcc | |
77 | ||
78 | # Override is only needed by avr-lib build system. | |
79 | ||
80 | override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS) | |
81 | override LDFLAGS = $(LDSECTIONS) -Wl,--relax -Wl,--gc-sections -nostartfiles -nostdlib | |
82 | ||
83 | OBJCOPY = $(GCCROOT)avr-objcopy | |
84 | OBJDUMP = $(call fixpath,$(GCCROOT)avr-objdump) | |
85 | ||
86 | SIZE = $(GCCROOT)avr-size | |
87 | ||
88 | atmega1284: TARGET = atmega1284p | |
89 | atmega1284: MCU_TARGET = atmega1284p | |
90 | atmega1284: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200' '-DBIGBOOT' | |
91 | atmega1284: AVR_FREQ = 16000000L | |
92 | atmega1284: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 | |
93 | atmega1284: $(PROGRAM)_atmega1284p.hex | |
94 | atmega1284: $(PROGRAM)_atmega1284p.lst | |
95 | ||
96 | atmega1284_isp: atmega1284 | |
97 | atmega1284_isp: TARGET = atmega1284p | |
98 | atmega1284_isp: MCU_TARGET = atmega1284p | |
99 | # 1024 byte boot | |
100 | atmega1284_isp: HFUSE = DE | |
101 | # Low power xtal (16MHz) 16KCK/14CK+65ms | |
102 | atmega1284_isp: LFUSE = FF | |
103 | # 2.7V brownout | |
104 | atmega1284_isp: EFUSE = FD | |
105 | atmega1284_isp: isp | |
106 | ||
107 | atmega1284_slow: TARGET = atmega1284p_slow | |
108 | atmega1284_slow: MCU_TARGET = atmega1284p | |
109 | atmega1284_slow: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=19200' '-DBIGBOOT' | |
110 | atmega1284_slow: AVR_FREQ = 16000000L | |
111 | atmega1284_slow: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 | |
112 | atmega1284_slow: $(PROGRAM)_atmega1284p_slow.hex | |
113 | atmega1284_slow: $(PROGRAM)_atmega1284p_slow.lst | |
114 | ||
115 | atmega1284_slow_isp: atmega1284_slow | |
116 | atmega1284_slow_isp: TARGET = atmega1284p_slow | |
117 | atmega1284_slow_isp: MCU_TARGET = atmega1284p | |
118 | # 1024 byte boot | |
119 | atmega1284_slow_isp: HFUSE = DE | |
120 | # Low power xtal (16MHz) 16KCK/14CK+65ms | |
121 | atmega1284_slow_isp: LFUSE = FF | |
122 | # 2.7V brownout | |
123 | atmega1284_slow_isp: EFUSE = FD | |
124 | atmega1284_slow_isp: isp | |
125 | ||
126 | # | |
127 | # Generic build instructions | |
128 | # | |
129 | # | |
130 | ||
131 | isp: $(TARGET) | |
132 | $(ISPFUSES) | |
133 | $(ISPFLASH) | |
134 | ||
135 | isp-stk500: $(PROGRAM)_$(TARGET).hex | |
136 | $(STK500-1) | |
137 | $(STK500-2) | |
138 | ||
139 | %.elf: $(OBJ) | |
140 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) | |
141 | $(SIZE) $@ | |
142 | ||
143 | clean: | |
144 | rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex | |
145 | ||
146 | %.lst: %.elf | |
147 | $(OBJDUMP) -h -S $< > $@ | |
148 | ||
149 | %.hex: %.elf | |
150 | $(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex $< $@ | |
151 | ||
152 | %.srec: %.elf | |
153 | $(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O srec $< $@ | |
154 | ||
155 | %.bin: %.elf | |
156 | $(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O binary $< $@ |
0 | /* Modified to use out for SPM access | |
1 | ** Peter Knight, Optiboot project http://optiboot.googlecode.com | |
2 | ** | |
3 | ** Todo: Tidy up | |
4 | ** | |
5 | ** "_short" routines execute 1 cycle faster and use 1 less word of flash | |
6 | ** by using "out" instruction instead of "sts". | |
7 | ** | |
8 | ** Additional elpm variants that trust the value of RAMPZ | |
9 | */ | |
10 | ||
11 | /* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Eric B. Weddington | |
12 | All rights reserved. | |
13 | ||
14 | Redistribution and use in source and binary forms, with or without | |
15 | modification, are permitted provided that the following conditions are met: | |
16 | ||
17 | * Redistributions of source code must retain the above copyright | |
18 | notice, this list of conditions and the following disclaimer. | |
19 | * Redistributions in binary form must reproduce the above copyright | |
20 | notice, this list of conditions and the following disclaimer in | |
21 | the documentation and/or other materials provided with the | |
22 | distribution. | |
23 | * Neither the name of the copyright holders nor the names of | |
24 | contributors may be used to endorse or promote products derived | |
25 | from this software without specific prior written permission. | |
26 | ||
27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
30 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
31 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
32 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
33 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
34 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
35 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
36 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
37 | POSSIBILITY OF SUCH DAMAGE. */ | |
38 | ||
39 | /* $Id: boot.h,v 1.27.2.3 2008/09/30 13:58:48 arcanum Exp $ */ | |
40 | ||
41 | #ifndef _AVR_BOOT_H_ | |
42 | #define _AVR_BOOT_H_ 1 | |
43 | ||
44 | /** \file */ | |
45 | /** \defgroup avr_boot <avr/boot.h>: Bootloader Support Utilities | |
46 | \code | |
47 | #include <avr/io.h> | |
48 | #include <avr/boot.h> | |
49 | \endcode | |
50 | ||
51 | The macros in this module provide a C language interface to the | |
52 | bootloader support functionality of certain AVR processors. These | |
53 | macros are designed to work with all sizes of flash memory. | |
54 | ||
55 | Global interrupts are not automatically disabled for these macros. It | |
56 | is left up to the programmer to do this. See the code example below. | |
57 | Also see the processor datasheet for caveats on having global interrupts | |
58 | enabled during writing of the Flash. | |
59 | ||
60 | \note Not all AVR processors provide bootloader support. See your | |
61 | processor datasheet to see if it provides bootloader support. | |
62 | ||
63 | \todo From email with Marek: On smaller devices (all except ATmega64/128), | |
64 | __SPM_REG is in the I/O space, accessible with the shorter "in" and "out" | |
65 | instructions - since the boot loader has a limited size, this could be an | |
66 | important optimization. | |
67 | ||
68 | \par API Usage Example | |
69 | The following code shows typical usage of the boot API. | |
70 | ||
71 | \code | |
72 | #include <inttypes.h> | |
73 | #include <avr/interrupt.h> | |
74 | #include <avr/pgmspace.h> | |
75 | ||
76 | void boot_program_page (uint32_t page, uint8_t *buf) | |
77 | { | |
78 | uint16_t i; | |
79 | uint8_t sreg; | |
80 | ||
81 | // Disable interrupts. | |
82 | ||
83 | sreg = SREG; | |
84 | cli(); | |
85 | ||
86 | eeprom_busy_wait (); | |
87 | ||
88 | boot_page_erase (page); | |
89 | boot_spm_busy_wait (); // Wait until the memory is erased. | |
90 | ||
91 | for (i=0; i<SPM_PAGESIZE; i+=2) | |
92 | { | |
93 | // Set up little-endian word. | |
94 | ||
95 | uint16_t w = *buf++; | |
96 | w += (*buf++) << 8; | |
97 | ||
98 | boot_page_fill (page + i, w); | |
99 | } | |
100 | ||
101 | boot_page_write (page); // Store buffer in flash page. | |
102 | boot_spm_busy_wait(); // Wait until the memory is written. | |
103 | ||
104 | // Reenable RWW-section again. We need this if we want to jump back | |
105 | // to the application after bootloading. | |
106 | ||
107 | boot_rww_enable (); | |
108 | ||
109 | // Re-enable interrupts (if they were ever enabled). | |
110 | ||
111 | SREG = sreg; | |
112 | }\endcode */ | |
113 | ||
114 | #include <avr/eeprom.h> | |
115 | #include <avr/io.h> | |
116 | #include <inttypes.h> | |
117 | #include <limits.h> | |
118 | ||
119 | /* Check for SPM Control Register in processor. */ | |
120 | #if defined (SPMCSR) | |
121 | # define __SPM_REG SPMCSR | |
122 | #elif defined (SPMCR) | |
123 | # define __SPM_REG SPMCR | |
124 | #else | |
125 | # error AVR processor does not provide bootloader support! | |
126 | #endif | |
127 | ||
128 | ||
129 | /* Check for SPM Enable bit. */ | |
130 | #if defined(SPMEN) | |
131 | # define __SPM_ENABLE SPMEN | |
132 | #elif defined(SELFPRGEN) | |
133 | # define __SPM_ENABLE SELFPRGEN | |
134 | #else | |
135 | # error Cannot find SPM Enable bit definition! | |
136 | #endif | |
137 | ||
138 | /** \ingroup avr_boot | |
139 | \def BOOTLOADER_SECTION | |
140 | ||
141 | Used to declare a function or variable to be placed into a | |
142 | new section called .bootloader. This section and its contents | |
143 | can then be relocated to any address (such as the bootloader | |
144 | NRWW area) at link-time. */ | |
145 | ||
146 | #define BOOTLOADER_SECTION __attribute__ ((section (".bootloader"))) | |
147 | ||
148 | /* Create common bit definitions. */ | |
149 | #ifdef ASB | |
150 | #define __COMMON_ASB ASB | |
151 | #else | |
152 | #define __COMMON_ASB RWWSB | |
153 | #endif | |
154 | ||
155 | #ifdef ASRE | |
156 | #define __COMMON_ASRE ASRE | |
157 | #else | |
158 | #define __COMMON_ASRE RWWSRE | |
159 | #endif | |
160 | ||
161 | /* Define the bit positions of the Boot Lock Bits. */ | |
162 | ||
163 | #define BLB12 5 | |
164 | #define BLB11 4 | |
165 | #define BLB02 3 | |
166 | #define BLB01 2 | |
167 | ||
168 | /** \ingroup avr_boot | |
169 | \def boot_spm_interrupt_enable() | |
170 | Enable the SPM interrupt. */ | |
171 | ||
172 | #define boot_spm_interrupt_enable() (__SPM_REG |= (uint8_t)_BV(SPMIE)) | |
173 | ||
174 | /** \ingroup avr_boot | |
175 | \def boot_spm_interrupt_disable() | |
176 | Disable the SPM interrupt. */ | |
177 | ||
178 | #define boot_spm_interrupt_disable() (__SPM_REG &= (uint8_t)~_BV(SPMIE)) | |
179 | ||
180 | /** \ingroup avr_boot | |
181 | \def boot_is_spm_interrupt() | |
182 | Check if the SPM interrupt is enabled. */ | |
183 | ||
184 | #define boot_is_spm_interrupt() (__SPM_REG & (uint8_t)_BV(SPMIE)) | |
185 | ||
186 | /** \ingroup avr_boot | |
187 | \def boot_rww_busy() | |
188 | Check if the RWW section is busy. */ | |
189 | ||
190 | #define boot_rww_busy() (__SPM_REG & (uint8_t)_BV(__COMMON_ASB)) | |
191 | ||
192 | /** \ingroup avr_boot | |
193 | \def boot_spm_busy() | |
194 | Check if the SPM instruction is busy. */ | |
195 | ||
196 | #define boot_spm_busy() (__SPM_REG & (uint8_t)_BV(__SPM_ENABLE)) | |
197 | ||
198 | /** \ingroup avr_boot | |
199 | \def boot_spm_busy_wait() | |
200 | Wait while the SPM instruction is busy. */ | |
201 | ||
202 | #define boot_spm_busy_wait() do{}while(boot_spm_busy()) | |
203 | ||
204 | #define __BOOT_PAGE_ERASE (_BV(__SPM_ENABLE) | _BV(PGERS)) | |
205 | #define __BOOT_PAGE_WRITE (_BV(__SPM_ENABLE) | _BV(PGWRT)) | |
206 | #define __BOOT_PAGE_FILL _BV(__SPM_ENABLE) | |
207 | #define __BOOT_RWW_ENABLE (_BV(__SPM_ENABLE) | _BV(__COMMON_ASRE)) | |
208 | #define __BOOT_LOCK_BITS_SET (_BV(__SPM_ENABLE) | _BV(BLBSET)) | |
209 | ||
210 | #define __boot_page_fill_short(address, data) \ | |
211 | (__extension__({ \ | |
212 | __asm__ __volatile__ \ | |
213 | ( \ | |
214 | "movw r0, %3\n\t" \ | |
215 | "out %0, %1\n\t" \ | |
216 | "spm\n\t" \ | |
217 | "clr r1\n\t" \ | |
218 | : \ | |
219 | : "i" (_SFR_IO_ADDR(__SPM_REG)), \ | |
220 | "r" ((uint8_t)__BOOT_PAGE_FILL), \ | |
221 | "z" ((uint16_t)address), \ | |
222 | "r" ((uint16_t)data) \ | |
223 | : "r0" \ | |
224 | ); \ | |
225 | })) | |
226 | ||
227 | #define __boot_page_fill_normal(address, data) \ | |
228 | (__extension__({ \ | |
229 | __asm__ __volatile__ \ | |
230 | ( \ | |
231 | "movw r0, %3\n\t" \ | |
232 | "sts %0, %1\n\t" \ | |
233 | "spm\n\t" \ | |
234 | "clr r1\n\t" \ | |
235 | : \ | |
236 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
237 | "r" ((uint8_t)__BOOT_PAGE_FILL), \ | |
238 | "z" ((uint16_t)address), \ | |
239 | "r" ((uint16_t)data) \ | |
240 | : "r0" \ | |
241 | ); \ | |
242 | })) | |
243 | ||
244 | #define __boot_page_fill_alternate(address, data)\ | |
245 | (__extension__({ \ | |
246 | __asm__ __volatile__ \ | |
247 | ( \ | |
248 | "movw r0, %3\n\t" \ | |
249 | "sts %0, %1\n\t" \ | |
250 | "spm\n\t" \ | |
251 | ".word 0xffff\n\t" \ | |
252 | "nop\n\t" \ | |
253 | "clr r1\n\t" \ | |
254 | : \ | |
255 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
256 | "r" ((uint8_t)__BOOT_PAGE_FILL), \ | |
257 | "z" ((uint16_t)address), \ | |
258 | "r" ((uint16_t)data) \ | |
259 | : "r0" \ | |
260 | ); \ | |
261 | })) | |
262 | ||
263 | #define __boot_page_fill_extended(address, data) \ | |
264 | (__extension__({ \ | |
265 | __asm__ __volatile__ \ | |
266 | ( \ | |
267 | "movw r0, %4\n\t" \ | |
268 | "movw r30, %A3\n\t" \ | |
269 | "sts %1, %C3\n\t" \ | |
270 | "sts %0, %2\n\t" \ | |
271 | "spm\n\t" \ | |
272 | "clr r1\n\t" \ | |
273 | : \ | |
274 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
275 | "i" (_SFR_MEM_ADDR(RAMPZ)), \ | |
276 | "r" ((uint8_t)__BOOT_PAGE_FILL), \ | |
277 | "r" ((uint32_t)address), \ | |
278 | "r" ((uint16_t)data) \ | |
279 | : "r0", "r30", "r31" \ | |
280 | ); \ | |
281 | })) | |
282 | ||
283 | #define __boot_page_fill_extended_short(address, data) \ | |
284 | (__extension__({ \ | |
285 | __asm__ __volatile__ \ | |
286 | ( \ | |
287 | "movw r0, %4\n\t" \ | |
288 | "movw r30, %A3\n\t" \ | |
289 | "out %1, %C3\n\t" \ | |
290 | "out %0, %2\n\t" \ | |
291 | "spm\n\t" \ | |
292 | "clr r1\n\t" \ | |
293 | : \ | |
294 | : "i" (_SFR_IO_ADDR(__SPM_REG)), \ | |
295 | "i" (_SFR_IO_ADDR(RAMPZ)), \ | |
296 | "r" ((uint8_t)__BOOT_PAGE_FILL), \ | |
297 | "r" ((uint32_t)address), \ | |
298 | "r" ((uint16_t)data) \ | |
299 | : "r0", "r30", "r31" \ | |
300 | ); \ | |
301 | })) | |
302 | ||
303 | #define __boot_page_erase_short(address) \ | |
304 | (__extension__({ \ | |
305 | __asm__ __volatile__ \ | |
306 | ( \ | |
307 | "out %0, %1\n\t" \ | |
308 | "spm\n\t" \ | |
309 | : \ | |
310 | : "i" (_SFR_IO_ADDR(__SPM_REG)), \ | |
311 | "r" ((uint8_t)__BOOT_PAGE_ERASE), \ | |
312 | "z" ((uint16_t)address) \ | |
313 | ); \ | |
314 | })) | |
315 | ||
316 | ||
317 | #define __boot_page_erase_normal(address) \ | |
318 | (__extension__({ \ | |
319 | __asm__ __volatile__ \ | |
320 | ( \ | |
321 | "sts %0, %1\n\t" \ | |
322 | "spm\n\t" \ | |
323 | : \ | |
324 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
325 | "r" ((uint8_t)__BOOT_PAGE_ERASE), \ | |
326 | "z" ((uint16_t)address) \ | |
327 | ); \ | |
328 | })) | |
329 | ||
330 | #define __boot_page_erase_alternate(address) \ | |
331 | (__extension__({ \ | |
332 | __asm__ __volatile__ \ | |
333 | ( \ | |
334 | "sts %0, %1\n\t" \ | |
335 | "spm\n\t" \ | |
336 | ".word 0xffff\n\t" \ | |
337 | "nop\n\t" \ | |
338 | : \ | |
339 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
340 | "r" ((uint8_t)__BOOT_PAGE_ERASE), \ | |
341 | "z" ((uint16_t)address) \ | |
342 | ); \ | |
343 | })) | |
344 | ||
345 | #define __boot_page_erase_extended(address) \ | |
346 | (__extension__({ \ | |
347 | __asm__ __volatile__ \ | |
348 | ( \ | |
349 | "movw r30, %A3\n\t" \ | |
350 | "sts %1, %C3\n\t" \ | |
351 | "sts %0, %2\n\t" \ | |
352 | "spm\n\t" \ | |
353 | : \ | |
354 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
355 | "i" (_SFR_MEM_ADDR(RAMPZ)), \ | |
356 | "r" ((uint8_t)__BOOT_PAGE_ERASE), \ | |
357 | "r" ((uint32_t)address) \ | |
358 | : "r30", "r31" \ | |
359 | ); \ | |
360 | })) | |
361 | #define __boot_page_erase_extended_short(address) \ | |
362 | (__extension__({ \ | |
363 | __asm__ __volatile__ \ | |
364 | ( \ | |
365 | "movw r30, %A3\n\t" \ | |
366 | "out %1, %C3\n\t" \ | |
367 | "out %0, %2\n\t" \ | |
368 | "spm\n\t" \ | |
369 | : \ | |
370 | : "i" (_SFR_IO_ADDR(__SPM_REG)), \ | |
371 | "i" (_SFR_IO_ADDR(RAMPZ)), \ | |
372 | "r" ((uint8_t)__BOOT_PAGE_ERASE), \ | |
373 | "r" ((uint32_t)address) \ | |
374 | : "r30", "r31" \ | |
375 | ); \ | |
376 | })) | |
377 | ||
378 | #define __boot_page_write_short(address) \ | |
379 | (__extension__({ \ | |
380 | __asm__ __volatile__ \ | |
381 | ( \ | |
382 | "out %0, %1\n\t" \ | |
383 | "spm\n\t" \ | |
384 | : \ | |
385 | : "i" (_SFR_IO_ADDR(__SPM_REG)), \ | |
386 | "r" ((uint8_t)__BOOT_PAGE_WRITE), \ | |
387 | "z" ((uint16_t)address) \ | |
388 | ); \ | |
389 | })) | |
390 | ||
391 | #define __boot_page_write_normal(address) \ | |
392 | (__extension__({ \ | |
393 | __asm__ __volatile__ \ | |
394 | ( \ | |
395 | "sts %0, %1\n\t" \ | |
396 | "spm\n\t" \ | |
397 | : \ | |
398 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
399 | "r" ((uint8_t)__BOOT_PAGE_WRITE), \ | |
400 | "z" ((uint16_t)address) \ | |
401 | ); \ | |
402 | })) | |
403 | ||
404 | #define __boot_page_write_alternate(address) \ | |
405 | (__extension__({ \ | |
406 | __asm__ __volatile__ \ | |
407 | ( \ | |
408 | "sts %0, %1\n\t" \ | |
409 | "spm\n\t" \ | |
410 | ".word 0xffff\n\t" \ | |
411 | "nop\n\t" \ | |
412 | : \ | |
413 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
414 | "r" ((uint8_t)__BOOT_PAGE_WRITE), \ | |
415 | "z" ((uint16_t)address) \ | |
416 | ); \ | |
417 | })) | |
418 | ||
419 | #define __boot_page_write_extended(address) \ | |
420 | (__extension__({ \ | |
421 | __asm__ __volatile__ \ | |
422 | ( \ | |
423 | "movw r30, %A3\n\t" \ | |
424 | "sts %1, %C3\n\t" \ | |
425 | "sts %0, %2\n\t" \ | |
426 | "spm\n\t" \ | |
427 | : \ | |
428 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
429 | "i" (_SFR_MEM_ADDR(RAMPZ)), \ | |
430 | "r" ((uint8_t)__BOOT_PAGE_WRITE), \ | |
431 | "r" ((uint32_t)address) \ | |
432 | : "r30", "r31" \ | |
433 | ); \ | |
434 | })) | |
435 | #define __boot_page_write_extended_short(address) \ | |
436 | (__extension__({ \ | |
437 | __asm__ __volatile__ \ | |
438 | ( \ | |
439 | "movw r30, %A3\n\t" \ | |
440 | "out %1, %C3\n\t" \ | |
441 | "out %0, %2\n\t" \ | |
442 | "spm\n\t" \ | |
443 | : \ | |
444 | : "i" (_SFR_IO_ADDR(__SPM_REG)), \ | |
445 | "i" (_SFR_IO_ADDR(RAMPZ)), \ | |
446 | "r" ((uint8_t)__BOOT_PAGE_WRITE), \ | |
447 | "r" ((uint32_t)address) \ | |
448 | : "r30", "r31" \ | |
449 | ); \ | |
450 | })) | |
451 | ||
452 | #define __boot_rww_enable_short() \ | |
453 | (__extension__({ \ | |
454 | __asm__ __volatile__ \ | |
455 | ( \ | |
456 | "out %0, %1\n\t" \ | |
457 | "spm\n\t" \ | |
458 | : \ | |
459 | : "i" (_SFR_IO_ADDR(__SPM_REG)), \ | |
460 | "r" ((uint8_t)__BOOT_RWW_ENABLE) \ | |
461 | ); \ | |
462 | })) | |
463 | ||
464 | #define __boot_rww_enable() \ | |
465 | (__extension__({ \ | |
466 | __asm__ __volatile__ \ | |
467 | ( \ | |
468 | "sts %0, %1\n\t" \ | |
469 | "spm\n\t" \ | |
470 | : \ | |
471 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
472 | "r" ((uint8_t)__BOOT_RWW_ENABLE) \ | |
473 | ); \ | |
474 | })) | |
475 | ||
476 | #define __boot_rww_enable_alternate() \ | |
477 | (__extension__({ \ | |
478 | __asm__ __volatile__ \ | |
479 | ( \ | |
480 | "sts %0, %1\n\t" \ | |
481 | "spm\n\t" \ | |
482 | ".word 0xffff\n\t" \ | |
483 | "nop\n\t" \ | |
484 | : \ | |
485 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
486 | "r" ((uint8_t)__BOOT_RWW_ENABLE) \ | |
487 | ); \ | |
488 | })) | |
489 | ||
490 | /* From the mega16/mega128 data sheets (maybe others): | |
491 | ||
492 | Bits by SPM To set the Boot Loader Lock bits, write the desired data to | |
493 | R0, write "X0001001" to SPMCR and execute SPM within four clock cycles | |
494 | after writing SPMCR. The only accessible Lock bits are the Boot Lock bits | |
495 | that may prevent the Application and Boot Loader section from any | |
496 | software update by the MCU. | |
497 | ||
498 | If bits 5..2 in R0 are cleared (zero), the corresponding Boot Lock bit | |
499 | will be programmed if an SPM instruction is executed within four cycles | |
500 | after BLBSET and SPMEN (or SELFPRGEN) are set in SPMCR. The Z-pointer is | |
501 | don't care during this operation, but for future compatibility it is | |
502 | recommended to load the Z-pointer with $0001 (same as used for reading the | |
503 | Lock bits). For future compatibility It is also recommended to set bits 7, | |
504 | 6, 1, and 0 in R0 to 1 when writing the Lock bits. When programming the | |
505 | Lock bits the entire Flash can be read during the operation. */ | |
506 | ||
507 | #define __boot_lock_bits_set_short(lock_bits) \ | |
508 | (__extension__({ \ | |
509 | uint8_t value = (uint8_t)(~(lock_bits)); \ | |
510 | __asm__ __volatile__ \ | |
511 | ( \ | |
512 | "ldi r30, 1\n\t" \ | |
513 | "ldi r31, 0\n\t" \ | |
514 | "mov r0, %2\n\t" \ | |
515 | "out %0, %1\n\t" \ | |
516 | "spm\n\t" \ | |
517 | : \ | |
518 | : "i" (_SFR_IO_ADDR(__SPM_REG)), \ | |
519 | "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ | |
520 | "r" (value) \ | |
521 | : "r0", "r30", "r31" \ | |
522 | ); \ | |
523 | })) | |
524 | ||
525 | #define __boot_lock_bits_set(lock_bits) \ | |
526 | (__extension__({ \ | |
527 | uint8_t value = (uint8_t)(~(lock_bits)); \ | |
528 | __asm__ __volatile__ \ | |
529 | ( \ | |
530 | "ldi r30, 1\n\t" \ | |
531 | "ldi r31, 0\n\t" \ | |
532 | "mov r0, %2\n\t" \ | |
533 | "sts %0, %1\n\t" \ | |
534 | "spm\n\t" \ | |
535 | : \ | |
536 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
537 | "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ | |
538 | "r" (value) \ | |
539 | : "r0", "r30", "r31" \ | |
540 | ); \ | |
541 | })) | |
542 | ||
543 | #define __boot_lock_bits_set_alternate(lock_bits) \ | |
544 | (__extension__({ \ | |
545 | uint8_t value = (uint8_t)(~(lock_bits)); \ | |
546 | __asm__ __volatile__ \ | |
547 | ( \ | |
548 | "ldi r30, 1\n\t" \ | |
549 | "ldi r31, 0\n\t" \ | |
550 | "mov r0, %2\n\t" \ | |
551 | "sts %0, %1\n\t" \ | |
552 | "spm\n\t" \ | |
553 | ".word 0xffff\n\t" \ | |
554 | "nop\n\t" \ | |
555 | : \ | |
556 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
557 | "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ | |
558 | "r" (value) \ | |
559 | : "r0", "r30", "r31" \ | |
560 | ); \ | |
561 | })) | |
562 | ||
563 | /* | |
564 | Reading lock and fuse bits: | |
565 | ||
566 | Similarly to writing the lock bits above, set BLBSET and SPMEN (or | |
567 | SELFPRGEN) bits in __SPMREG, and then (within four clock cycles) issue an | |
568 | LPM instruction. | |
569 | ||
570 | Z address: contents: | |
571 | 0x0000 low fuse bits | |
572 | 0x0001 lock bits | |
573 | 0x0002 extended fuse bits | |
574 | 0x0003 high fuse bits | |
575 | ||
576 | Sounds confusing, doesn't it? | |
577 | ||
578 | Unlike the macros in pgmspace.h, no need to care for non-enhanced | |
579 | cores here as these old cores do not provide SPM support anyway. | |
580 | */ | |
581 | ||
582 | /** \ingroup avr_boot | |
583 | \def GET_LOW_FUSE_BITS | |
584 | address to read the low fuse bits, using boot_lock_fuse_bits_get | |
585 | */ | |
586 | #define GET_LOW_FUSE_BITS (0x0000) | |
587 | /** \ingroup avr_boot | |
588 | \def GET_LOCK_BITS | |
589 | address to read the lock bits, using boot_lock_fuse_bits_get | |
590 | */ | |
591 | #define GET_LOCK_BITS (0x0001) | |
592 | /** \ingroup avr_boot | |
593 | \def GET_EXTENDED_FUSE_BITS | |
594 | address to read the extended fuse bits, using boot_lock_fuse_bits_get | |
595 | */ | |
596 | #define GET_EXTENDED_FUSE_BITS (0x0002) | |
597 | /** \ingroup avr_boot | |
598 | \def GET_HIGH_FUSE_BITS | |
599 | address to read the high fuse bits, using boot_lock_fuse_bits_get | |
600 | */ | |
601 | #define GET_HIGH_FUSE_BITS (0x0003) | |
602 | ||
603 | /** \ingroup avr_boot | |
604 | \def boot_lock_fuse_bits_get(address) | |
605 | ||
606 | Read the lock or fuse bits at \c address. | |
607 | ||
608 | Parameter \c address can be any of GET_LOW_FUSE_BITS, | |
609 | GET_LOCK_BITS, GET_EXTENDED_FUSE_BITS, or GET_HIGH_FUSE_BITS. | |
610 | ||
611 | \note The lock and fuse bits returned are the physical values, | |
612 | i.e. a bit returned as 0 means the corresponding fuse or lock bit | |
613 | is programmed. | |
614 | */ | |
615 | #define boot_lock_fuse_bits_get_short(address) \ | |
616 | (__extension__({ \ | |
617 | uint8_t __result; \ | |
618 | __asm__ __volatile__ \ | |
619 | ( \ | |
620 | "ldi r30, %3\n\t" \ | |
621 | "ldi r31, 0\n\t" \ | |
622 | "out %1, %2\n\t" \ | |
623 | "lpm %0, Z\n\t" \ | |
624 | : "=r" (__result) \ | |
625 | : "i" (_SFR_IO_ADDR(__SPM_REG)), \ | |
626 | "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ | |
627 | "M" (address) \ | |
628 | : "r0", "r30", "r31" \ | |
629 | ); \ | |
630 | __result; \ | |
631 | })) | |
632 | ||
633 | #define boot_lock_fuse_bits_get(address) \ | |
634 | (__extension__({ \ | |
635 | uint8_t __result; \ | |
636 | __asm__ __volatile__ \ | |
637 | ( \ | |
638 | "ldi r30, %3\n\t" \ | |
639 | "ldi r31, 0\n\t" \ | |
640 | "sts %1, %2\n\t" \ | |
641 | "lpm %0, Z\n\t" \ | |
642 | : "=r" (__result) \ | |
643 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
644 | "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ | |
645 | "M" (address) \ | |
646 | : "r0", "r30", "r31" \ | |
647 | ); \ | |
648 | __result; \ | |
649 | })) | |
650 | ||
651 | /** \ingroup avr_boot | |
652 | \def boot_signature_byte_get(address) | |
653 | ||
654 | Read the Signature Row byte at \c address. For some MCU types, | |
655 | this function can also retrieve the factory-stored oscillator | |
656 | calibration bytes. | |
657 | ||
658 | Parameter \c address can be 0-0x1f as documented by the datasheet. | |
659 | \note The values are MCU type dependent. | |
660 | */ | |
661 | ||
662 | #define __BOOT_SIGROW_READ (_BV(__SPM_ENABLE) | _BV(SIGRD)) | |
663 | ||
664 | #define boot_signature_byte_get_short(addr) \ | |
665 | (__extension__({ \ | |
666 | uint16_t __addr16 = (uint16_t)(addr); \ | |
667 | uint8_t __result; \ | |
668 | __asm__ __volatile__ \ | |
669 | ( \ | |
670 | "out %1, %2\n\t" \ | |
671 | "lpm %0, Z" "\n\t" \ | |
672 | : "=r" (__result) \ | |
673 | : "i" (_SFR_IO_ADDR(__SPM_REG)), \ | |
674 | "r" ((uint8_t) __BOOT_SIGROW_READ), \ | |
675 | "z" (__addr16) \ | |
676 | ); \ | |
677 | __result; \ | |
678 | })) | |
679 | ||
680 | #define boot_signature_byte_get(addr) \ | |
681 | (__extension__({ \ | |
682 | uint16_t __addr16 = (uint16_t)(addr); \ | |
683 | uint8_t __result; \ | |
684 | __asm__ __volatile__ \ | |
685 | ( \ | |
686 | "sts %1, %2\n\t" \ | |
687 | "lpm %0, Z" "\n\t" \ | |
688 | : "=r" (__result) \ | |
689 | : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ | |
690 | "r" ((uint8_t) __BOOT_SIGROW_READ), \ | |
691 | "z" (__addr16) \ | |
692 | ); \ | |
693 | __result; \ | |
694 | })) | |
695 | ||
696 | /** \ingroup avr_boot | |
697 | \def boot_page_fill(address, data) | |
698 | ||
699 | Fill the bootloader temporary page buffer for flash | |
700 | address with data word. | |
701 | ||
702 | \note The address is a byte address. The data is a word. The AVR | |
703 | writes data to the buffer a word at a time, but addresses the buffer | |
704 | per byte! So, increment your address by 2 between calls, and send 2 | |
705 | data bytes in a word format! The LSB of the data is written to the lower | |
706 | address; the MSB of the data is written to the higher address.*/ | |
707 | ||
708 | /** \ingroup avr_boot | |
709 | \def boot_page_erase(address) | |
710 | ||
711 | Erase the flash page that contains address. | |
712 | ||
713 | \note address is a byte address in flash, not a word address. */ | |
714 | ||
715 | /** \ingroup avr_boot | |
716 | \def boot_page_write(address) | |
717 | ||
718 | Write the bootloader temporary page buffer | |
719 | to flash page that contains address. | |
720 | ||
721 | \note address is a byte address in flash, not a word address. */ | |
722 | ||
723 | /** \ingroup avr_boot | |
724 | \def boot_rww_enable() | |
725 | ||
726 | Enable the Read-While-Write memory section. */ | |
727 | ||
728 | /** \ingroup avr_boot | |
729 | \def boot_lock_bits_set(lock_bits) | |
730 | ||
731 | Set the bootloader lock bits. | |
732 | ||
733 | \param lock_bits A mask of which Boot Loader Lock Bits to set. | |
734 | ||
735 | \note In this context, a 'set bit' will be written to a zero value. | |
736 | Note also that only BLBxx bits can be programmed by this command. | |
737 | ||
738 | For example, to disallow the SPM instruction from writing to the Boot | |
739 | Loader memory section of flash, you would use this macro as such: | |
740 | ||
741 | \code | |
742 | boot_lock_bits_set (_BV (BLB11)); | |
743 | \endcode | |
744 | ||
745 | \note Like any lock bits, the Boot Loader Lock Bits, once set, | |
746 | cannot be cleared again except by a chip erase which will in turn | |
747 | also erase the boot loader itself. */ | |
748 | ||
749 | /* Normal versions of the macros use 16-bit addresses. | |
750 | Extended versions of the macros use 32-bit addresses. | |
751 | Alternate versions of the macros use 16-bit addresses and require special | |
752 | instruction sequences after LPM. | |
753 | ||
754 | FLASHEND is defined in the ioXXXX.h file. | |
755 | USHRT_MAX is defined in <limits.h>. */ | |
756 | ||
757 | #if defined(__AVR_ATmega161__) || defined(__AVR_ATmega163__) \ | |
758 | || defined(__AVR_ATmega323__) | |
759 | ||
760 | /* Alternate: ATmega161/163/323 and 16 bit address */ | |
761 | #define boot_page_fill(address, data) __boot_page_fill_alternate(address, data) | |
762 | #define boot_page_erase(address) __boot_page_erase_alternate(address) | |
763 | #define boot_page_write(address) __boot_page_write_alternate(address) | |
764 | #define boot_rww_enable() __boot_rww_enable_alternate() | |
765 | #define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_alternate(lock_bits) | |
766 | ||
767 | #elif (FLASHEND > USHRT_MAX) | |
768 | ||
769 | /* Extended: >16 bit address */ | |
770 | #define boot_page_fill(address, data) __boot_page_fill_extended_short(address, data) | |
771 | #define boot_page_erase(address) __boot_page_erase_extended_short(address) | |
772 | #define boot_page_write(address) __boot_page_write_extended_short(address) | |
773 | #define boot_rww_enable() __boot_rww_enable_short() | |
774 | #define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits) | |
775 | ||
776 | #else | |
777 | ||
778 | /* Normal: 16 bit address */ | |
779 | #define boot_page_fill(address, data) __boot_page_fill_short(address, data) | |
780 | #define boot_page_erase(address) __boot_page_erase_short(address) | |
781 | #define boot_page_write(address) __boot_page_write_short(address) | |
782 | #define boot_rww_enable() __boot_rww_enable_short() | |
783 | #define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits) | |
784 | ||
785 | #endif | |
786 | ||
787 | /** \ingroup avr_boot | |
788 | ||
789 | Same as boot_page_fill() except it waits for eeprom and spm operations to | |
790 | complete before filling the page. */ | |
791 | ||
792 | #define boot_page_fill_safe(address, data) \ | |
793 | do { \ | |
794 | boot_spm_busy_wait(); \ | |
795 | eeprom_busy_wait(); \ | |
796 | boot_page_fill(address, data); \ | |
797 | } while (0) | |
798 | ||
799 | /** \ingroup avr_boot | |
800 | ||
801 | Same as boot_page_erase() except it waits for eeprom and spm operations to | |
802 | complete before erasing the page. */ | |
803 | ||
804 | #define boot_page_erase_safe(address) \ | |
805 | do { \ | |
806 | boot_spm_busy_wait(); \ | |
807 | eeprom_busy_wait(); \ | |
808 | boot_page_erase (address); \ | |
809 | } while (0) | |
810 | ||
811 | /** \ingroup avr_boot | |
812 | ||
813 | Same as boot_page_write() except it waits for eeprom and spm operations to | |
814 | complete before writing the page. */ | |
815 | ||
816 | #define boot_page_write_safe(address) \ | |
817 | do { \ | |
818 | boot_spm_busy_wait(); \ | |
819 | eeprom_busy_wait(); \ | |
820 | boot_page_write (address); \ | |
821 | } while (0) | |
822 | ||
823 | /** \ingroup avr_boot | |
824 | ||
825 | Same as boot_rww_enable() except waits for eeprom and spm operations to | |
826 | complete before enabling the RWW mameory. */ | |
827 | ||
828 | #define boot_rww_enable_safe() \ | |
829 | do { \ | |
830 | boot_spm_busy_wait(); \ | |
831 | eeprom_busy_wait(); \ | |
832 | boot_rww_enable(); \ | |
833 | } while (0) | |
834 | ||
835 | /** \ingroup avr_boot | |
836 | ||
837 | Same as boot_lock_bits_set() except waits for eeprom and spm operations to | |
838 | complete before setting the lock bits. */ | |
839 | ||
840 | #define boot_lock_bits_set_safe(lock_bits) \ | |
841 | do { \ | |
842 | boot_spm_busy_wait(); \ | |
843 | eeprom_busy_wait(); \ | |
844 | boot_lock_bits_set (lock_bits); \ | |
845 | } while (0) | |
846 | ||
847 | #endif /* _AVR_BOOT_H_ */ |
0 | /**********************************************************/ | |
1 | /* Optiboot bootloader for Arduino */ | |
2 | /* */ | |
3 | /* http://optiboot.googlecode.com */ | |
4 | /* */ | |
5 | /* Arduino-maintained version : See README.TXT */ | |
6 | /* http://code.google.com/p/arduino/ */ | |
7 | /* */ | |
8 | /* Heavily optimised bootloader that is faster and */ | |
9 | /* smaller than the Arduino standard bootloader */ | |
10 | /* */ | |
11 | /* Enhancements: */ | |
12 | /* Fits in 512 bytes, saving 1.5K of code space */ | |
13 | /* Background page erasing speeds up programming */ | |
14 | /* Higher baud rate speeds up programming */ | |
15 | /* Written almost entirely in C */ | |
16 | /* Customisable timeout with accurate timeconstant */ | |
17 | /* Optional virtual UART. No hardware UART required. */ | |
18 | /* Optional virtual boot partition for devices without. */ | |
19 | /* */ | |
20 | /* What you lose: */ | |
21 | /* Implements a skeleton STK500 protocol which is */ | |
22 | /* missing several features including EEPROM */ | |
23 | /* programming and non-page-aligned writes */ | |
24 | /* High baud rate breaks compatibility with standard */ | |
25 | /* Arduino flash settings */ | |
26 | /* */ | |
27 | /* Fully supported: */ | |
28 | /* ATmega168 based devices (Diecimila etc) */ | |
29 | /* ATmega328P based devices (Duemilanove etc) */ | |
30 | /* */ | |
31 | /* Alpha test */ | |
32 | /* ATmega1280 based devices (Arduino Mega) */ | |
33 | /* */ | |
34 | /* Work in progress: */ | |
35 | /* ATmega644P based devices (Sanguino) */ | |
36 | /* ATtiny84 based devices (Luminet) */ | |
37 | /* */ | |
38 | /* Does not support: */ | |
39 | /* USB based devices (eg. Teensy) */ | |
40 | /* */ | |
41 | /* Assumptions: */ | |
42 | /* The code makes several assumptions that reduce the */ | |
43 | /* code size. They are all true after a hardware reset, */ | |
44 | /* but may not be true if the bootloader is called by */ | |
45 | /* other means or on other hardware. */ | |
46 | /* No interrupts can occur */ | |
47 | /* UART and Timer 1 are set to their reset state */ | |
48 | /* SP points to RAMEND */ | |
49 | /* */ | |
50 | /* Code builds on code, libraries and optimisations from: */ | |
51 | /* stk500boot.c by Jason P. Kyle */ | |
52 | /* Arduino bootloader http://arduino.cc */ | |
53 | /* Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */ | |
54 | /* avr-libc project http://nongnu.org/avr-libc */ | |
55 | /* Adaboot http://www.ladyada.net/library/arduino/bootloader.html */ | |
56 | /* AVR305 Atmel Application Note */ | |
57 | /* */ | |
58 | /* This program is free software; you can redistribute it */ | |
59 | /* and/or modify it under the terms of the GNU General */ | |
60 | /* Public License as published by the Free Software */ | |
61 | /* Foundation; either version 2 of the License, or */ | |
62 | /* (at your option) any later version. */ | |
63 | /* */ | |
64 | /* This program is distributed in the hope that it will */ | |
65 | /* be useful, but WITHOUT ANY WARRANTY; without even the */ | |
66 | /* implied warranty of MERCHANTABILITY or FITNESS FOR A */ | |
67 | /* PARTICULAR PURPOSE. See the GNU General Public */ | |
68 | /* License for more details. */ | |
69 | /* */ | |
70 | /* You should have received a copy of the GNU General */ | |
71 | /* Public License along with this program; if not, write */ | |
72 | /* to the Free Software Foundation, Inc., */ | |
73 | /* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ | |
74 | /* */ | |
75 | /* Licence can be viewed at */ | |
76 | /* http://www.fsf.org/licenses/gpl.txt */ | |
77 | /* */ | |
78 | /**********************************************************/ | |
79 | ||
80 | ||
81 | /**********************************************************/ | |
82 | /* */ | |
83 | /* Optional defines: */ | |
84 | /* */ | |
85 | /**********************************************************/ | |
86 | /* */ | |
87 | /* BIG_BOOT: */ | |
88 | /* Build a 1k bootloader, not 512 bytes. This turns on */ | |
89 | /* extra functionality. */ | |
90 | /* */ | |
91 | /* BAUD_RATE: */ | |
92 | /* Set bootloader baud rate. */ | |
93 | /* */ | |
94 | /* LUDICROUS_SPEED: */ | |
95 | /* 230400 baud :-) */ | |
96 | /* */ | |
97 | /* SOFT_UART: */ | |
98 | /* Use AVR305 soft-UART instead of hardware UART. */ | |
99 | /* */ | |
100 | /* LED_START_FLASHES: */ | |
101 | /* Number of LED flashes on bootup. */ | |
102 | /* */ | |
103 | /* LED_DATA_FLASH: */ | |
104 | /* Flash LED when transferring data. For boards without */ | |
105 | /* TX or RX LEDs, or for people who like blinky lights. */ | |
106 | /* */ | |
107 | /* SUPPORT_EEPROM: */ | |
108 | /* Support reading and writing from EEPROM. This is not */ | |
109 | /* used by Arduino, so off by default. */ | |
110 | /* */ | |
111 | /* TIMEOUT_MS: */ | |
112 | /* Bootloader timeout period, in milliseconds. */ | |
113 | /* 500,1000,2000,4000,8000 supported. */ | |
114 | /* */ | |
115 | /**********************************************************/ | |
116 | ||
117 | /**********************************************************/ | |
118 | /* Version Numbers! */ | |
119 | /* */ | |
120 | /* Arduino Optiboot now includes this Version number in */ | |
121 | /* the source and object code. */ | |
122 | /* */ | |
123 | /* Version 3 was released as zip from the optiboot */ | |
124 | /* repository and was distributed with Arduino 0022. */ | |
125 | /* Version 4 starts with the arduino repository commit */ | |
126 | /* that brought the arduino repository up-to-date with */ | |
127 | /* the optiboot source tree changes since v3. */ | |
128 | /* */ | |
129 | /**********************************************************/ | |
130 | ||
131 | /**********************************************************/ | |
132 | /* Edit History: */ | |
133 | /* */ | |
134 | /* Jan 2012: */ | |
135 | /* 4.5 WestfW: fix NRWW value for m1284. */ | |
136 | /* 4.4 WestfW: use attribute OS_main instead of naked for */ | |
137 | /* main(). This allows optimizations that we */ | |
138 | /* count on, which are prohibited in naked */ | |
139 | /* functions due to PR42240. (keeps us less */ | |
140 | /* than 512 bytes when compiler is gcc4.5 */ | |
141 | /* (code from 4.3.2 remains the same.) */ | |
142 | /* 4.4 WestfW and Maniacbug: Add m1284 support. This */ | |
143 | /* does not change the 328 binary, so the */ | |
144 | /* version number didn't change either. (?) */ | |
145 | /* June 2011: */ | |
146 | /* 4.4 WestfW: remove automatic soft_uart detect (didn't */ | |
147 | /* know what it was doing or why.) Added a */ | |
148 | /* check of the calculated BRG value instead. */ | |
149 | /* Version stays 4.4; existing binaries are */ | |
150 | /* not changed. */ | |
151 | /* 4.4 WestfW: add initialization of address to keep */ | |
152 | /* the compiler happy. Change SC'ed targets. */ | |
153 | /* Return the SW version via READ PARAM */ | |
154 | /* 4.3 WestfW: catch framing errors in getch(), so that */ | |
155 | /* AVRISP works without HW kludges. */ | |
156 | /* http://code.google.com/p/arduino/issues/detail?id=368n*/ | |
157 | /* 4.2 WestfW: reduce code size, fix timeouts, change */ | |
158 | /* verifySpace to use WDT instead of appstart */ | |
159 | /* 4.1 WestfW: put version number in binary. */ | |
160 | /**********************************************************/ | |
161 | ||
162 | #define OPTIBOOT_MAJVER 4 | |
163 | #define OPTIBOOT_MINVER 5 | |
164 | ||
165 | #define MAKESTR(a) #a | |
166 | #define MAKEVER(a, b) MAKESTR(a*256+b) | |
167 | ||
168 | asm(" .section .version\n" | |
169 | "optiboot_version: .word " MAKEVER(OPTIBOOT_MAJVER, OPTIBOOT_MINVER) "\n" | |
170 | " .section .text\n"); | |
171 | ||
172 | #include <inttypes.h> | |
173 | #include <avr/io.h> | |
174 | #include <avr/pgmspace.h> | |
175 | ||
176 | // <avr/boot.h> uses sts instructions, but this version uses out instructions | |
177 | // This saves cycles and program memory. | |
178 | #include "boot.h" | |
179 | ||
180 | ||
181 | // We don't use <avr/wdt.h> as those routines have interrupt overhead we don't need. | |
182 | ||
183 | #include "pin_defs.h" | |
184 | #include "stk500.h" | |
185 | ||
186 | #ifndef LED_START_FLASHES | |
187 | #define LED_START_FLASHES 0 | |
188 | #endif | |
189 | ||
190 | #ifdef LUDICROUS_SPEED | |
191 | #define BAUD_RATE 230400L | |
192 | #endif | |
193 | ||
194 | /* set the UART baud rate defaults */ | |
195 | #ifndef BAUD_RATE | |
196 | #if F_CPU >= 8000000L | |
197 | #define BAUD_RATE 115200L // Highest rate Avrdude win32 will support | |
198 | #elsif F_CPU >= 1000000L | |
199 | #define BAUD_RATE 9600L // 19200 also supported, but with significant error | |
200 | #elsif F_CPU >= 128000L | |
201 | #define BAUD_RATE 4800L // Good for 128kHz internal RC | |
202 | #else | |
203 | #define BAUD_RATE 1200L // Good even at 32768Hz | |
204 | #endif | |
205 | #endif | |
206 | ||
207 | #if 0 | |
208 | /* Switch in soft UART for hard baud rates */ | |
209 | /* | |
210 | * I don't understand what this was supposed to accomplish, where the | |
211 | * constant "280" came from, or why automatically (and perhaps unexpectedly) | |
212 | * switching to a soft uart is a good thing, so I'm undoing this in favor | |
213 | * of a range check using the same calc used to config the BRG... | |
214 | */ | |
215 | #if (F_CPU/BAUD_RATE) > 280 // > 57600 for 16MHz | |
216 | #ifndef SOFT_UART | |
217 | #define SOFT_UART | |
218 | #endif | |
219 | #endif | |
220 | #else // 0 | |
221 | #if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 > 250 | |
222 | #error Unachievable baud rate (too slow) BAUD_RATE | |
223 | #endif // baud rate slow check | |
224 | #if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 < 3 | |
225 | #error Unachievable baud rate (too fast) BAUD_RATE | |
226 | #endif // baud rate fastn check | |
227 | #endif | |
228 | ||
229 | /* Watchdog settings */ | |
230 | #define WATCHDOG_OFF (0) | |
231 | #define WATCHDOG_16MS (_BV(WDE)) | |
232 | #define WATCHDOG_32MS (_BV(WDP0) | _BV(WDE)) | |
233 | #define WATCHDOG_64MS (_BV(WDP1) | _BV(WDE)) | |
234 | #define WATCHDOG_125MS (_BV(WDP1) | _BV(WDP0) | _BV(WDE)) | |
235 | #define WATCHDOG_250MS (_BV(WDP2) | _BV(WDE)) | |
236 | #define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE)) | |
237 | #define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE)) | |
238 | #define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE)) | |
239 | #ifndef __AVR_ATmega8__ | |
240 | #define WATCHDOG_4S (_BV(WDP3) | _BV(WDE)) | |
241 | #define WATCHDOG_8S (_BV(WDP3) | _BV(WDP0) | _BV(WDE)) | |
242 | #endif | |
243 | ||
244 | /* Function Prototypes */ | |
245 | /* The main function is in init9, which removes the interrupt vector table */ | |
246 | /* we don't need. It is also 'naked', which means the compiler does not */ | |
247 | /* generate any entry or exit code itself. */ | |
248 | int main(void) __attribute__ ((OS_main)) __attribute__ ((section (".init9"))); | |
249 | void putch(char); | |
250 | uint8_t getch(void); | |
251 | static inline void getNch(uint8_t); /* "static inline" is a compiler hint to reduce code size */ | |
252 | void verifySpace(); | |
253 | static inline void flash_led(uint8_t); | |
254 | uint8_t getLen(); | |
255 | static inline void watchdogReset(); | |
256 | void watchdogConfig(uint8_t x); | |
257 | #ifdef SOFT_UART | |
258 | void uartDelay() __attribute__ ((naked)); | |
259 | #endif | |
260 | void appStart() __attribute__ ((naked)); | |
261 | ||
262 | /* | |
263 | * NRWW memory | |
264 | * Addresses below NRWW (Non-Read-While-Write) can be programmed while | |
265 | * continuing to run code from flash, slightly speeding up programming | |
266 | * time. Beware that Atmel data sheets specify this as a WORD address, | |
267 | * while optiboot will be comparing against a 16-bit byte address. This | |
268 | * means that on a part with 128kB of memory, the upper part of the lower | |
269 | * 64k will get NRWW processing as well, even though it doesn't need it. | |
270 | * That's OK. In fact, you can disable the overlapping processing for | |
271 | * a part entirely by setting NRWWSTART to zero. This reduces code | |
272 | * space a bit, at the expense of being slightly slower, overall. | |
273 | * | |
274 | * RAMSTART should be self-explanatory. It's bigger on parts with a | |
275 | * lot of peripheral registers. | |
276 | */ | |
277 | #if defined(__AVR_ATmega168__) | |
278 | #define RAMSTART (0x100) | |
279 | #define NRWWSTART (0x3800) | |
280 | #elif defined(__AVR_ATmega328P__) | |
281 | #define RAMSTART (0x100) | |
282 | #define NRWWSTART (0x7000) | |
283 | #elif defined (__AVR_ATmega644P__) | |
284 | #define RAMSTART (0x100) | |
285 | #define NRWWSTART (0xE000) | |
286 | #elif defined (__AVR_ATmega1284P__) | |
287 | #define RAMSTART (0x100) | |
288 | #define NRWWSTART (0xE000) | |
289 | #elif defined(__AVR_ATtiny84__) | |
290 | #define RAMSTART (0x100) | |
291 | #define NRWWSTART (0x0000) | |
292 | #elif defined(__AVR_ATmega1280__) | |
293 | #define RAMSTART (0x200) | |
294 | #define NRWWSTART (0xE000) | |
295 | #elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) | |
296 | #define RAMSTART (0x100) | |
297 | #define NRWWSTART (0x1800) | |
298 | #endif | |
299 | ||
300 | /* C zero initialises all global variables. However, that requires */ | |
301 | /* These definitions are NOT zero initialised, but that doesn't matter */ | |
302 | /* This allows us to drop the zero init code, saving us memory */ | |
303 | #define buff ((uint8_t*)(RAMSTART)) | |
304 | #ifdef VIRTUAL_BOOT_PARTITION | |
305 | #define rstVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+4)) | |
306 | #define wdtVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+6)) | |
307 | #endif | |
308 | ||
309 | /* main program starts here */ | |
310 | int main(void) { | |
311 | uint8_t ch; | |
312 | ||
313 | /* | |
314 | * Making these local and in registers prevents the need for initializing | |
315 | * them, and also saves space because code no longer stores to memory. | |
316 | * (initializing address keeps the compiler happy, but isn't really | |
317 | * necessary, and uses 4 bytes of flash.) | |
318 | */ | |
319 | register uint16_t address = 0; | |
320 | register uint8_t length; | |
321 | ||
322 | // After the zero init loop, this is the first code to run. | |
323 | // | |
324 | // This code makes the following assumptions: | |
325 | // No interrupts will execute | |
326 | // SP points to RAMEND | |
327 | // r1 contains zero | |
328 | // | |
329 | // If not, uncomment the following instructions: | |
330 | // cli(); | |
331 | asm volatile ("clr __zero_reg__"); | |
332 | #ifdef __AVR_ATmega8__ | |
333 | SP=RAMEND; // This is done by hardware reset | |
334 | #endif | |
335 | ||
336 | // Adaboot no-wait mod | |
337 | ch = MCUSR; | |
338 | MCUSR = 0; | |
339 | if (!(ch & _BV(EXTRF))) appStart(); | |
340 | ||
341 | #if LED_START_FLASHES > 0 | |
342 | // Set up Timer 1 for timeout counter | |
343 | TCCR1B = _BV(CS12) | _BV(CS10); // div 1024 | |
344 | #endif | |
345 | #ifndef SOFT_UART | |
346 | #ifdef __AVR_ATmega8__ | |
347 | UCSRA = _BV(U2X); //Double speed mode USART | |
348 | UCSRB = _BV(RXEN) | _BV(TXEN); // enable Rx & Tx | |
349 | UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0); // config USART; 8N1 | |
350 | UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); | |
351 | #else | |
352 | UCSR0A = _BV(U2X0); //Double speed mode USART0 | |
353 | UCSR0B = _BV(RXEN0) | _BV(TXEN0); | |
354 | UCSR0C = _BV(UCSZ00) | _BV(UCSZ01); | |
355 | UBRR0L = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); | |
356 | #endif | |
357 | #endif | |
358 | ||
359 | // Set up watchdog to trigger after 500ms | |
360 | watchdogConfig(WATCHDOG_1S); | |
361 | ||
362 | /* Set LED pin as output */ | |
363 | LED_DDR |= _BV(LED); | |
364 | ||
365 | #ifdef SOFT_UART | |
366 | /* Set TX pin as output */ | |
367 | UART_DDR |= _BV(UART_TX_BIT); | |
368 | #endif | |
369 | ||
370 | #if LED_START_FLASHES > 0 | |
371 | /* Flash onboard LED to signal entering of bootloader */ | |
372 | flash_led(LED_START_FLASHES * 2); | |
373 | #endif | |
374 | ||
375 | /* Forever loop */ | |
376 | for (;;) { | |
377 | /* get character from UART */ | |
378 | ch = getch(); | |
379 | ||
380 | if(ch == STK_GET_PARAMETER) { | |
381 | unsigned char which = getch(); | |
382 | verifySpace(); | |
383 | if (which == 0x82) { | |
384 | /* | |
385 | * Send optiboot version as "minor SW version" | |
386 | */ | |
387 | putch(OPTIBOOT_MINVER); | |
388 | } else if (which == 0x81) { | |
389 | putch(OPTIBOOT_MAJVER); | |
390 | } else { | |
391 | /* | |
392 | * GET PARAMETER returns a generic 0x03 reply for | |
393 | * other parameters - enough to keep Avrdude happy | |
394 | */ | |
395 | putch(0x03); | |
396 | } | |
397 | } | |
398 | else if(ch == STK_SET_DEVICE) { | |
399 | // SET DEVICE is ignored | |
400 | getNch(20); | |
401 | } | |
402 | else if(ch == STK_SET_DEVICE_EXT) { | |
403 | // SET DEVICE EXT is ignored | |
404 | getNch(5); | |
405 | } | |
406 | else if(ch == STK_LOAD_ADDRESS) { | |
407 | // LOAD ADDRESS | |
408 | uint16_t newAddress; | |
409 | newAddress = getch(); | |
410 | newAddress = (newAddress & 0xff) | (getch() << 8); | |
411 | #ifdef RAMPZ | |
412 | // Transfer top bit to RAMPZ | |
413 | RAMPZ = (newAddress & 0x8000) ? 1 : 0; | |
414 | #endif | |
415 | newAddress += newAddress; // Convert from word address to byte address | |
416 | address = newAddress; | |
417 | verifySpace(); | |
418 | } | |
419 | else if(ch == STK_UNIVERSAL) { | |
420 | // UNIVERSAL command is ignored | |
421 | getNch(4); | |
422 | putch(0x00); | |
423 | } | |
424 | /* Write memory, length is big endian and is in bytes */ | |
425 | else if(ch == STK_PROG_PAGE) { | |
426 | // PROGRAM PAGE - we support flash programming only, not EEPROM | |
427 | uint8_t *bufPtr; | |
428 | uint16_t addrPtr; | |
429 | ||
430 | getch(); /* getlen() */ | |
431 | length = getch(); | |
432 | getch(); | |
433 | ||
434 | // If we are in RWW section, immediately start page erase | |
435 | if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address); | |
436 | ||
437 | // While that is going on, read in page contents | |
438 | bufPtr = buff; | |
439 | do *bufPtr++ = getch(); | |
440 | while (--length); | |
441 | ||
442 | // If we are in NRWW section, page erase has to be delayed until now. | |
443 | // Todo: Take RAMPZ into account | |
444 | if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address); | |
445 | ||
446 | // Read command terminator, start reply | |
447 | verifySpace(); | |
448 | ||
449 | // If only a partial page is to be programmed, the erase might not be complete. | |
450 | // So check that here | |
451 | boot_spm_busy_wait(); | |
452 | ||
453 | #ifdef VIRTUAL_BOOT_PARTITION | |
454 | if ((uint16_t)(void*)address == 0) { | |
455 | // This is the reset vector page. We need to live-patch the code so the | |
456 | // bootloader runs. | |
457 | // | |
458 | // Move RESET vector to WDT vector | |
459 | uint16_t vect = buff[0] | (buff[1]<<8); | |
460 | rstVect = vect; | |
461 | wdtVect = buff[8] | (buff[9]<<8); | |
462 | vect -= 4; // Instruction is a relative jump (rjmp), so recalculate. | |
463 | buff[8] = vect & 0xff; | |
464 | buff[9] = vect >> 8; | |
465 | ||
466 | // Add jump to bootloader at RESET vector | |
467 | buff[0] = 0x7f; | |
468 | buff[1] = 0xce; // rjmp 0x1d00 instruction | |
469 | } | |
470 | #endif | |
471 | ||
472 | // Copy buffer into programming buffer | |
473 | bufPtr = buff; | |
474 | addrPtr = (uint16_t)(void*)address; | |
475 | ch = SPM_PAGESIZE / 2; | |
476 | do { | |
477 | uint16_t a; | |
478 | a = *bufPtr++; | |
479 | a |= (*bufPtr++) << 8; | |
480 | __boot_page_fill_short((uint16_t)(void*)addrPtr,a); | |
481 | addrPtr += 2; | |
482 | } while (--ch); | |
483 | ||
484 | // Write from programming buffer | |
485 | __boot_page_write_short((uint16_t)(void*)address); | |
486 | boot_spm_busy_wait(); | |
487 | ||
488 | #if defined(RWWSRE) | |
489 | // Reenable read access to flash | |
490 | boot_rww_enable(); | |
491 | #endif | |
492 | ||
493 | } | |
494 | /* Read memory block mode, length is big endian. */ | |
495 | else if(ch == STK_READ_PAGE) { | |
496 | // READ PAGE - we only read flash | |
497 | getch(); /* getlen() */ | |
498 | length = getch(); | |
499 | getch(); | |
500 | ||
501 | verifySpace(); | |
502 | #ifdef VIRTUAL_BOOT_PARTITION | |
503 | do { | |
504 | // Undo vector patch in bottom page so verify passes | |
505 | if (address == 0) ch=rstVect & 0xff; | |
506 | else if (address == 1) ch=rstVect >> 8; | |
507 | else if (address == 8) ch=wdtVect & 0xff; | |
508 | else if (address == 9) ch=wdtVect >> 8; | |
509 | else ch = pgm_read_byte_near(address); | |
510 | address++; | |
511 | putch(ch); | |
512 | } while (--length); | |
513 | #else | |
514 | #ifdef RAMPZ | |
515 | // Since RAMPZ should already be set, we need to use EPLM directly. | |
516 | // do putch(pgm_read_byte_near(address++)); | |
517 | // while (--length); | |
518 | do { | |
519 | uint8_t result; | |
520 | __asm__ ("elpm %0,Z\n":"=r"(result):"z"(address)); | |
521 | putch(result); | |
522 | address++; | |
523 | } | |
524 | while (--length); | |
525 | #else | |
526 | do putch(pgm_read_byte_near(address++)); | |
527 | while (--length); | |
528 | #endif | |
529 | #endif | |
530 | } | |
531 | ||
532 | /* Get device signature bytes */ | |
533 | else if(ch == STK_READ_SIGN) { | |
534 | // READ SIGN - return what Avrdude wants to hear | |
535 | verifySpace(); | |
536 | putch(SIGNATURE_0); | |
537 | putch(SIGNATURE_1); | |
538 | putch(SIGNATURE_2); | |
539 | } | |
540 | else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */ | |
541 | // Adaboot no-wait mod | |
542 | watchdogConfig(WATCHDOG_16MS); | |
543 | verifySpace(); | |
544 | } | |
545 | else { | |
546 | // This covers the response to commands like STK_ENTER_PROGMODE | |
547 | verifySpace(); | |
548 | } | |
549 | putch(STK_OK); | |
550 | } | |
551 | } | |
552 | ||
553 | void putch(char ch) { | |
554 | #ifndef SOFT_UART | |
555 | while (!(UCSR0A & _BV(UDRE0))); | |
556 | UDR0 = ch; | |
557 | #else | |
558 | __asm__ __volatile__ ( | |
559 | " com %[ch]\n" // ones complement, carry set | |
560 | " sec\n" | |
561 | "1: brcc 2f\n" | |
562 | " cbi %[uartPort],%[uartBit]\n" | |
563 | " rjmp 3f\n" | |
564 | "2: sbi %[uartPort],%[uartBit]\n" | |
565 | " nop\n" | |
566 | "3: rcall uartDelay\n" | |
567 | " rcall uartDelay\n" | |
568 | " lsr %[ch]\n" | |
569 | " dec %[bitcnt]\n" | |
570 | " brne 1b\n" | |
571 | : | |
572 | : | |
573 | [bitcnt] "d" (10), | |
574 | [ch] "r" (ch), | |
575 | [uartPort] "I" (_SFR_IO_ADDR(UART_PORT)), | |
576 | [uartBit] "I" (UART_TX_BIT) | |
577 | : | |
578 | "r25" | |
579 | ); | |
580 | #endif | |
581 | } | |
582 | ||
583 | uint8_t getch(void) { | |
584 | uint8_t ch; | |
585 | ||
586 | #ifdef LED_DATA_FLASH | |
587 | #ifdef __AVR_ATmega8__ | |
588 | LED_PORT ^= _BV(LED); | |
589 | #else | |
590 | LED_PIN |= _BV(LED); | |
591 | #endif | |
592 | #endif | |
593 | ||
594 | #ifdef SOFT_UART | |
595 | __asm__ __volatile__ ( | |
596 | "1: sbic %[uartPin],%[uartBit]\n" // Wait for start edge | |
597 | " rjmp 1b\n" | |
598 | " rcall uartDelay\n" // Get to middle of start bit | |
599 | "2: rcall uartDelay\n" // Wait 1 bit period | |
600 | " rcall uartDelay\n" // Wait 1 bit period | |
601 | " clc\n" | |
602 | " sbic %[uartPin],%[uartBit]\n" | |
603 | " sec\n" | |
604 | " dec %[bitCnt]\n" | |
605 | " breq 3f\n" | |
606 | " ror %[ch]\n" | |
607 | " rjmp 2b\n" | |
608 | "3:\n" | |
609 | : | |
610 | [ch] "=r" (ch) | |
611 | : | |
612 | [bitCnt] "d" (9), | |
613 | [uartPin] "I" (_SFR_IO_ADDR(UART_PIN)), | |
614 | [uartBit] "I" (UART_RX_BIT) | |
615 | : | |
616 | "r25" | |
617 | ); | |
618 | #else | |
619 | while(!(UCSR0A & _BV(RXC0))) | |
620 | ; | |
621 | if (!(UCSR0A & _BV(FE0))) { | |
622 | /* | |
623 | * A Framing Error indicates (probably) that something is talking | |
624 | * to us at the wrong bit rate. Assume that this is because it | |
625 | * expects to be talking to the application, and DON'T reset the | |
626 | * watchdog. This should cause the bootloader to abort and run | |
627 | * the application "soon", if it keeps happening. (Note that we | |
628 | * don't care that an invalid char is returned...) | |
629 | */ | |
630 | watchdogReset(); | |
631 | } | |
632 | ||
633 | ch = UDR0; | |
634 | #endif | |
635 | ||
636 | #ifdef LED_DATA_FLASH | |
637 | #ifdef __AVR_ATmega8__ | |
638 | LED_PORT ^= _BV(LED); | |
639 | #else | |
640 | LED_PIN |= _BV(LED); | |
641 | #endif | |
642 | #endif | |
643 | ||
644 | return ch; | |
645 | } | |
646 | ||
647 | #ifdef SOFT_UART | |
648 | // AVR305 equation: #define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6) | |
649 | // Adding 3 to numerator simulates nearest rounding for more accurate baud rates | |
650 | #define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6) | |
651 | #if UART_B_VALUE > 255 | |
652 | #error Baud rate too slow for soft UART | |
653 | #endif | |
654 | ||
655 | void uartDelay() { | |
656 | __asm__ __volatile__ ( | |
657 | "ldi r25,%[count]\n" | |
658 | "1:dec r25\n" | |
659 | "brne 1b\n" | |
660 | "ret\n" | |
661 | ::[count] "M" (UART_B_VALUE) | |
662 | ); | |
663 | } | |
664 | #endif | |
665 | ||
666 | void getNch(uint8_t count) { | |
667 | do getch(); while (--count); | |
668 | verifySpace(); | |
669 | } | |
670 | ||
671 | void verifySpace() { | |
672 | if (getch() != CRC_EOP) { | |
673 | watchdogConfig(WATCHDOG_16MS); // shorten WD timeout | |
674 | while (1) // and busy-loop so that WD causes | |
675 | ; // a reset and app start. | |
676 | } | |
677 | putch(STK_INSYNC); | |
678 | } | |
679 | ||
680 | #if LED_START_FLASHES > 0 | |
681 | void flash_led(uint8_t count) { | |
682 | do { | |
683 | TCNT1 = -(F_CPU/(1024*16)); | |
684 | TIFR1 = _BV(TOV1); | |
685 | while(!(TIFR1 & _BV(TOV1))); | |
686 | #ifdef __AVR_ATmega8__ | |
687 | LED_PORT ^= _BV(LED); | |
688 | #else | |
689 | LED_PIN |= _BV(LED); | |
690 | #endif | |
691 | watchdogReset(); | |
692 | } while (--count); | |
693 | } | |
694 | #endif | |
695 | ||
696 | // Watchdog functions. These are only safe with interrupts turned off. | |
697 | void watchdogReset() { | |
698 | __asm__ __volatile__ ( | |
699 | "wdr\n" | |
700 | ); | |
701 | } | |
702 | ||
703 | void watchdogConfig(uint8_t x) { | |
704 | WDTCSR = _BV(WDCE) | _BV(WDE); | |
705 | WDTCSR = x; | |
706 | } | |
707 | ||
708 | void appStart() { | |
709 | watchdogConfig(WATCHDOG_OFF); | |
710 | __asm__ __volatile__ ( | |
711 | #ifdef VIRTUAL_BOOT_PARTITION | |
712 | // Jump to WDT vector | |
713 | "ldi r30,4\n" | |
714 | "clr r31\n" | |
715 | #else | |
716 | // Jump to RST vector | |
717 | "clr r30\n" | |
718 | "clr r31\n" | |
719 | #endif | |
720 | "ijmp\n" | |
721 | ); | |
722 | } |
0 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) | |
1 | /* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duemilanove */ | |
2 | #define LED_DDR DDRB | |
3 | #define LED_PORT PORTB | |
4 | #define LED_PIN PINB | |
5 | #define LED PINB5 | |
6 | ||
7 | /* Ports for soft UART */ | |
8 | #ifdef SOFT_UART | |
9 | #define UART_PORT PORTD | |
10 | #define UART_PIN PIND | |
11 | #define UART_DDR DDRD | |
12 | #define UART_TX_BIT 1 | |
13 | #define UART_RX_BIT 0 | |
14 | #endif | |
15 | #endif | |
16 | ||
17 | #if defined(__AVR_ATmega8__) | |
18 | //Name conversion R.Wiersma | |
19 | #define UCSR0A UCSRA | |
20 | #define UDR0 UDR | |
21 | #define UDRE0 UDRE | |
22 | #define RXC0 RXC | |
23 | #define FE0 FE | |
24 | #define TIFR1 TIFR | |
25 | #define WDTCSR WDTCR | |
26 | #endif | |
27 | ||
28 | /* Luminet support */ | |
29 | #if defined(__AVR_ATtiny84__) | |
30 | /* Red LED is connected to pin PA4 */ | |
31 | #define LED_DDR DDRA | |
32 | #define LED_PORT PORTA | |
33 | #define LED_PIN PINA | |
34 | #define LED PINA4 | |
35 | /* Ports for soft UART - left port only for now. TX/RX on PA2/PA3 */ | |
36 | #ifdef SOFT_UART | |
37 | #define UART_PORT PORTA | |
38 | #define UART_PIN PINA | |
39 | #define UART_DDR DDRA | |
40 | #define UART_TX_BIT 2 | |
41 | #define UART_RX_BIT 3 | |
42 | #endif | |
43 | #endif | |
44 | ||
45 | /* Sanguino support */ | |
46 | #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) | |
47 | /* Onboard LED is connected to pin PB0 on Sanguino */ | |
48 | #define LED_DDR DDRB | |
49 | #define LED_PORT PORTB | |
50 | #define LED_PIN PINB | |
51 | #define LED PINB1 | |
52 | ||
53 | /* Ports for soft UART */ | |
54 | #ifdef SOFT_UART | |
55 | #define UART_PORT PORTD | |
56 | #define UART_PIN PIND | |
57 | #define UART_DDR DDRD | |
58 | #define UART_TX_BIT 1 | |
59 | #define UART_RX_BIT 0 | |
60 | #endif | |
61 | #endif | |
62 | ||
63 | /* Mega support */ | |
64 | #if defined(__AVR_ATmega1280__) | |
65 | /* Onboard LED is connected to pin PB7 on Arduino Mega */ | |
66 | #define LED_DDR DDRB | |
67 | #define LED_PORT PORTB | |
68 | #define LED_PIN PINB | |
69 | #define LED PINB7 | |
70 | ||
71 | /* Ports for soft UART */ | |
72 | #ifdef SOFT_UART | |
73 | #define UART_PORT PORTE | |
74 | #define UART_PIN PINE | |
75 | #define UART_DDR DDRE | |
76 | #define UART_TX_BIT 1 | |
77 | #define UART_RX_BIT 0 | |
78 | #endif | |
79 | #endif |
0 | /* STK500 constants list, from AVRDUDE */ | |
1 | #define STK_OK 0x10 | |
2 | #define STK_FAILED 0x11 // Not used | |
3 | #define STK_UNKNOWN 0x12 // Not used | |
4 | #define STK_NODEVICE 0x13 // Not used | |
5 | #define STK_INSYNC 0x14 // ' ' | |
6 | #define STK_NOSYNC 0x15 // Not used | |
7 | #define ADC_CHANNEL_ERROR 0x16 // Not used | |
8 | #define ADC_MEASURE_OK 0x17 // Not used | |
9 | #define PWM_CHANNEL_ERROR 0x18 // Not used | |
10 | #define PWM_ADJUST_OK 0x19 // Not used | |
11 | #define CRC_EOP 0x20 // 'SPACE' | |
12 | #define STK_GET_SYNC 0x30 // '0' | |
13 | #define STK_GET_SIGN_ON 0x31 // '1' | |
14 | #define STK_SET_PARAMETER 0x40 // '@' | |
15 | #define STK_GET_PARAMETER 0x41 // 'A' | |
16 | #define STK_SET_DEVICE 0x42 // 'B' | |
17 | #define STK_SET_DEVICE_EXT 0x45 // 'E' | |
18 | #define STK_ENTER_PROGMODE 0x50 // 'P' | |
19 | #define STK_LEAVE_PROGMODE 0x51 // 'Q' | |
20 | #define STK_CHIP_ERASE 0x52 // 'R' | |
21 | #define STK_CHECK_AUTOINC 0x53 // 'S' | |
22 | #define STK_LOAD_ADDRESS 0x55 // 'U' | |
23 | #define STK_UNIVERSAL 0x56 // 'V' | |
24 | #define STK_PROG_FLASH 0x60 // '`' | |
25 | #define STK_PROG_DATA 0x61 // 'a' | |
26 | #define STK_PROG_FUSE 0x62 // 'b' | |
27 | #define STK_PROG_LOCK 0x63 // 'c' | |
28 | #define STK_PROG_PAGE 0x64 // 'd' | |
29 | #define STK_PROG_FUSE_EXT 0x65 // 'e' | |
30 | #define STK_READ_FLASH 0x70 // 'p' | |
31 | #define STK_READ_DATA 0x71 // 'q' | |
32 | #define STK_READ_FUSE 0x72 // 'r' | |
33 | #define STK_READ_LOCK 0x73 // 's' | |
34 | #define STK_READ_PAGE 0x74 // 't' | |
35 | #define STK_READ_SIGN 0x75 // 'u' | |
36 | #define STK_READ_OSCCAL 0x76 // 'v' | |
37 | #define STK_READ_FUSE_EXT 0x77 // 'w' | |
38 | #define STK_READ_OSCCAL_EXT 0x78 // 'x' |
0 | /**********************************************************/ | |
1 | /* Serial Bootloader for Atmel megaAVR Controllers */ | |
2 | /* */ | |
3 | /* tested with ATmega8, ATmega128 and ATmega168 */ | |
4 | /* should work with other mega's, see code for details */ | |
5 | /* */ | |
6 | /* ATmegaBOOT.c */ | |
7 | /* */ | |
8 | /* */ | |
9 | /* 20090308: integrated Mega changes into main bootloader */ | |
10 | /* source by D. Mellis */ | |
11 | /* 20080930: hacked for Arduino Mega (with the 1280 */ | |
12 | /* processor, backwards compatible) */ | |
13 | /* by D. Cuartielles */ | |
14 | /* 20070626: hacked for Arduino Diecimila (which auto- */ | |
15 | /* resets when a USB connection is made to it) */ | |
16 | /* by D. Mellis */ | |
17 | /* 20060802: hacked for Arduino by D. Cuartielles */ | |
18 | /* based on a previous hack by D. Mellis */ | |
19 | /* and D. Cuartielles */ | |
20 | /* */ | |
21 | /* Monitor and debug functions were added to the original */ | |
22 | /* code by Dr. Erik Lins, chip45.com. (See below) */ | |
23 | /* */ | |
24 | /* Thanks to Karl Pitrich for fixing a bootloader pin */ | |
25 | /* problem and more informative LED blinking! */ | |
26 | /* */ | |
27 | /* For the latest version see: */ | |
28 | /* http://www.chip45.com/ */ | |
29 | /* */ | |
30 | /* ------------------------------------------------------ */ | |
31 | /* */ | |
32 | /* based on stk500boot.c */ | |
33 | /* Copyright (c) 2003, Jason P. Kyle */ | |
34 | /* All rights reserved. */ | |
35 | /* see avr1.org for original file and information */ | |
36 | /* */ | |
37 | /* This program is free software; you can redistribute it */ | |
38 | /* and/or modify it under the terms of the GNU General */ | |
39 | /* Public License as published by the Free Software */ | |
40 | /* Foundation; either version 2 of the License, or */ | |
41 | /* (at your option) any later version. */ | |
42 | /* */ | |
43 | /* This program is distributed in the hope that it will */ | |
44 | /* be useful, but WITHOUT ANY WARRANTY; without even the */ | |
45 | /* implied warranty of MERCHANTABILITY or FITNESS FOR A */ | |
46 | /* PARTICULAR PURPOSE. See the GNU General Public */ | |
47 | /* License for more details. */ | |
48 | /* */ | |
49 | /* You should have received a copy of the GNU General */ | |
50 | /* Public License along with this program; if not, write */ | |
51 | /* to the Free Software Foundation, Inc., */ | |
52 | /* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ | |
53 | /* */ | |
54 | /* Licence can be viewed at */ | |
55 | /* http://www.fsf.org/licenses/gpl.txt */ | |
56 | /* */ | |
57 | /* Target = Atmel AVR m128,m64,m32,m16,m8,m162,m163,m169, */ | |
58 | /* m8515,m8535. ATmega161 has a very small boot block so */ | |
59 | /* isn't supported. */ | |
60 | /* */ | |
61 | /* Tested with m168 */ | |
62 | /**********************************************************/ | |
63 | ||
64 | /* $Id$ */ | |
65 | ||
66 | ||
67 | /* some includes */ | |
68 | #include <inttypes.h> | |
69 | #include <avr/io.h> | |
70 | #include <avr/pgmspace.h> | |
71 | #include <avr/interrupt.h> | |
72 | #include <avr/wdt.h> | |
73 | #include <util/delay.h> | |
74 | ||
75 | /* the current avr-libc eeprom functions do not support the ATmega168 */ | |
76 | /* own eeprom write/read functions are used instead */ | |
77 | #if !defined(__AVR_ATmega168__) || !defined(__AVR_ATmega328P__) | |
78 | #include <avr/eeprom.h> | |
79 | #endif | |
80 | ||
81 | /* Use the F_CPU defined in Makefile */ | |
82 | ||
83 | /* 20060803: hacked by DojoCorp */ | |
84 | /* 20070626: hacked by David A. Mellis to decrease waiting time for auto-reset */ | |
85 | /* set the waiting time for the bootloader */ | |
86 | /* get this from the Makefile instead */ | |
87 | /* #define MAX_TIME_COUNT (F_CPU>>4) */ | |
88 | ||
89 | /* 20070707: hacked by David A. Mellis - after this many errors give up and launch application */ | |
90 | #define MAX_ERROR_COUNT 5 | |
91 | #define NUM_LED_FLASHES 3 | |
92 | /* set the UART baud rate */ | |
93 | /* 20060803: hacked by DojoCorp */ | |
94 | //#define BAUD_RATE 115200 | |
95 | #ifndef BAUD_RATE | |
96 | #define BAUD_RATE 19200 | |
97 | #endif | |
98 | ||
99 | ||
100 | /* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */ | |
101 | /* never allow AVR Studio to do an update !!!! */ | |
102 | #define HW_VER 0x02 | |
103 | #define SW_MAJOR 0x01 | |
104 | #define SW_MINOR 0x10 | |
105 | ||
106 | ||
107 | /* Adjust to suit whatever pin your hardware uses to enter the bootloader */ | |
108 | /* ATmega128 has two UARTS so two pins are used to enter bootloader and select UART */ | |
109 | /* ATmega1280 has four UARTS, but for Arduino Mega, we will only use RXD0 to get code */ | |
110 | /* BL0... means UART0, BL1... means UART1 */ | |
111 | #ifdef __AVR_ATmega128__ | |
112 | #define BL_DDR DDRF | |
113 | #define BL_PORT PORTF | |
114 | #define BL_PIN PINF | |
115 | #define BL0 PINF7 | |
116 | #define BL1 PINF6 | |
117 | #elif defined __AVR_ATmega1280__ | |
118 | /* we just don't do anything for the MEGA and enter bootloader on reset anyway*/ | |
119 | #elif defined __AVR_ATmega1284P__ | |
120 | ||
121 | #else | |
122 | /* other ATmegas have only one UART, so only one pin is defined to enter bootloader */ | |
123 | #define BL_DDR DDRD | |
124 | #define BL_PORT PORTD | |
125 | #define BL_PIN PIND | |
126 | #define BL PIND6 | |
127 | #endif | |
128 | ||
129 | ||
130 | /* onboard LED is used to indicate, that the bootloader was entered (3x flashing) */ | |
131 | /* if monitor functions are included, LED goes on after monitor was entered */ | |
132 | #if defined __AVR_ATmega128__ || defined __AVR_ATmega1280__ | |
133 | /* Onboard LED is connected to pin PB7 (e.g. Crumb128, PROBOmega128, Savvy128, Arduino Mega) */ | |
134 | #define LED_DDR DDRB | |
135 | #define LED_PORT PORTB | |
136 | #define LED_PIN PINB | |
137 | #define LED PINB7 | |
138 | #elif defined __AVR_ATmega1284P__ | |
139 | #define LED_DDR DDRB | |
140 | #define LED_PORT PORTB | |
141 | #define LED_PIN PINB | |
142 | #define LED PINB0 | |
143 | #else | |
144 | /* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duomilanuove */ | |
145 | /* other boards like e.g. Crumb8, Crumb168 are using PB2 */ | |
146 | #define LED_DDR DDRB | |
147 | #define LED_PORT PORTB | |
148 | #define LED_PIN PINB | |
149 | #define LED PINB5 | |
150 | #endif | |
151 | ||
152 | ||
153 | /* monitor functions will only be compiled when using ATmega128, due to bootblock size constraints */ | |
154 | #if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__) | |
155 | #define MONITOR 1 | |
156 | #endif | |
157 | ||
158 | ||
159 | /* define various device id's */ | |
160 | /* manufacturer byte is always the same */ | |
161 | #define SIG1 0x1E // Yep, Atmel is the only manufacturer of AVR micros. Single source :( | |
162 | ||
163 | #if defined __AVR_ATmega1280__ | |
164 | #define SIG2 0x97 | |
165 | #define SIG3 0x03 | |
166 | #define PAGE_SIZE 0x80U //128 words | |
167 | ||
168 | #elif defined __AVR_ATmega1284P__ | |
169 | #define SIG2 0x97 | |
170 | #define SIG3 0x05 | |
171 | #define PAGE_SIZE 0x080U //128 words | |
172 | ||
173 | #elif defined __AVR_ATmega1281__ | |
174 | #define SIG2 0x97 | |
175 | #define SIG3 0x04 | |
176 | #define PAGE_SIZE 0x80U //128 words | |
177 | ||
178 | #elif defined __AVR_ATmega128__ | |
179 | #define SIG2 0x97 | |
180 | #define SIG3 0x02 | |
181 | #define PAGE_SIZE 0x80U //128 words | |
182 | ||
183 | #elif defined __AVR_ATmega64__ | |
184 | #define SIG2 0x96 | |
185 | #define SIG3 0x02 | |
186 | #define PAGE_SIZE 0x80U //128 words | |
187 | ||
188 | #elif defined __AVR_ATmega32__ | |
189 | #define SIG2 0x95 | |
190 | #define SIG3 0x02 | |
191 | #define PAGE_SIZE 0x40U //64 words | |
192 | ||
193 | #elif defined __AVR_ATmega16__ | |
194 | #define SIG2 0x94 | |
195 | #define SIG3 0x03 | |
196 | #define PAGE_SIZE 0x40U //64 words | |
197 | ||
198 | #elif defined __AVR_ATmega8__ | |
199 | #define SIG2 0x93 | |
200 | #define SIG3 0x07 | |
201 | #define PAGE_SIZE 0x20U //32 words | |
202 | ||
203 | #elif defined __AVR_ATmega88__ | |
204 | #define SIG2 0x93 | |
205 | #define SIG3 0x0a | |
206 | #define PAGE_SIZE 0x20U //32 words | |
207 | ||
208 | #elif defined __AVR_ATmega168__ | |
209 | #define SIG2 0x94 | |
210 | #define SIG3 0x06 | |
211 | #define PAGE_SIZE 0x40U //64 words | |
212 | ||
213 | #elif defined __AVR_ATmega328P__ | |
214 | #define SIG2 0x95 | |
215 | #define SIG3 0x0F | |
216 | #define PAGE_SIZE 0x40U //64 words | |
217 | ||
218 | #elif defined __AVR_ATmega162__ | |
219 | #define SIG2 0x94 | |
220 | #define SIG3 0x04 | |
221 | #define PAGE_SIZE 0x40U //64 words | |
222 | ||
223 | #elif defined __AVR_ATmega163__ | |
224 | #define SIG2 0x94 | |
225 | #define SIG3 0x02 | |
226 | #define PAGE_SIZE 0x40U //64 words | |
227 | ||
228 | #elif defined __AVR_ATmega169__ | |
229 | #define SIG2 0x94 | |
230 | #define SIG3 0x05 | |
231 | #define PAGE_SIZE 0x40U //64 words | |
232 | ||
233 | #elif defined __AVR_ATmega8515__ | |
234 | #define SIG2 0x93 | |
235 | #define SIG3 0x06 | |
236 | #define PAGE_SIZE 0x20U //32 words | |
237 | ||
238 | #elif defined __AVR_ATmega8535__ | |
239 | #define SIG2 0x93 | |
240 | #define SIG3 0x08 | |
241 | #define PAGE_SIZE 0x20U //32 words | |
242 | #endif | |
243 | ||
244 | ||
245 | /* function prototypes */ | |
246 | void putch(char); | |
247 | char getch(void); | |
248 | void getNch(uint8_t); | |
249 | void byte_response(uint8_t); | |
250 | void nothing_response(void); | |
251 | char gethex(void); | |
252 | void puthex(char); | |
253 | void flash_led(uint8_t); | |
254 | ||
255 | /* some variables */ | |
256 | union address_union | |
257 | { | |
258 | uint16_t word; | |
259 | uint8_t byte[2]; | |
260 | } address; | |
261 | ||
262 | union length_union | |
263 | { | |
264 | uint16_t word; | |
265 | uint8_t byte[2]; | |
266 | } length; | |
267 | ||
268 | struct flags_struct | |
269 | { | |
270 | unsigned eeprom : 1; | |
271 | unsigned rampz : 1; | |
272 | } flags; | |
273 | ||
274 | uint8_t buff[256]; | |
275 | uint8_t address_high; | |
276 | ||
277 | uint8_t pagesz=0x80; | |
278 | ||
279 | uint8_t i; | |
280 | uint8_t bootuart = 0; | |
281 | ||
282 | uint8_t error_count = 0; | |
283 | ||
284 | void (*app_start)(void) = 0x0000; | |
285 | ||
286 | ||
287 | /* main program starts here */ | |
288 | int main(void) | |
289 | { | |
290 | uint8_t ch,ch2; | |
291 | uint16_t w; | |
292 | #ifdef WATCHDOG_MODS | |
293 | ch = MCUSR; | |
294 | MCUSR = 0; | |
295 | WDTCSR |= _BV(WDCE) | _BV(WDE); | |
296 | WDTCSR = 0; | |
297 | // Check if the WDT was used to reset, in which case we dont bootload and skip straight to the code. woot. | |
298 | if (! (ch & _BV(EXTRF))) // if its a not an external reset... | |
299 | app_start(); // skip bootloader | |
300 | #else | |
301 | asm volatile("nop\n\t"); | |
302 | #endif | |
303 | /* set pin direction for bootloader pin and enable pullup */ | |
304 | /* for ATmega128, two pins need to be initialized */ | |
305 | #ifdef __AVR_ATmega128__ | |
306 | BL_DDR &= ~_BV(BL0); | |
307 | BL_DDR &= ~_BV(BL1); | |
308 | BL_PORT |= _BV(BL0); | |
309 | BL_PORT |= _BV(BL1); | |
310 | #else | |
311 | /* We run the bootloader regardless of the state of this pin. Thus, don't | |
312 | put it in a different state than the other pins. --DAM, 070709 | |
313 | This also applies to Arduino Mega -- DC, 080930 | |
314 | BL_DDR &= ~_BV(BL); | |
315 | BL_PORT |= _BV(BL); | |
316 | */ | |
317 | #endif | |
318 | #ifdef __AVR_ATmega128__ | |
319 | /* check which UART should be used for booting */ | |
320 | if(bit_is_clear(BL_PIN, BL0)) | |
321 | { | |
322 | bootuart = 1; | |
323 | } | |
324 | else if(bit_is_clear(BL_PIN, BL1)) | |
325 | { | |
326 | bootuart = 2; | |
327 | } | |
328 | #endif | |
329 | #if defined __AVR_ATmega1280__ || defined __AVR_ATmega1284P__ | |
330 | /* the mega1280 chip has four serial ports ... we could eventually use any of them, or not? */ | |
331 | /* however, we don't wanna confuse people, to avoid making a mess, we will stick to RXD0, TXD0 */ | |
332 | bootuart = 1; | |
333 | #endif | |
334 | /* check if flash is programmed already, if not start bootloader anyway */ | |
335 | if(pgm_read_byte_near(0x0000) != 0xFF) | |
336 | { | |
337 | #ifdef __AVR_ATmega128__ | |
338 | /* no UART was selected, start application */ | |
339 | if(!bootuart) | |
340 | { | |
341 | app_start(); | |
342 | } | |
343 | #else | |
344 | /* check if bootloader pin is set low */ | |
345 | /* we don't start this part neither for the m8, nor m168 */ | |
346 | //if(bit_is_set(BL_PIN, BL)) { | |
347 | // app_start(); | |
348 | // } | |
349 | #endif | |
350 | } | |
351 | #ifdef __AVR_ATmega128__ | |
352 | /* no bootuart was selected, default to uart 0 */ | |
353 | if(!bootuart) | |
354 | { | |
355 | bootuart = 1; | |
356 | } | |
357 | #endif | |
358 | /* initialize UART(s) depending on CPU defined */ | |
359 | #if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1284P__) | |
360 | if(bootuart == 1) | |
361 | { | |
362 | UBRR0L = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1); | |
363 | UBRR0H = (F_CPU/(BAUD_RATE*16L)-1) >> 8; | |
364 | UCSR0A = 0x00; | |
365 | UCSR0C = 0x06; | |
366 | UCSR0B = _BV(TXEN0)|_BV(RXEN0); | |
367 | } | |
368 | if(bootuart == 2) | |
369 | { | |
370 | UBRR1L = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1); | |
371 | UBRR1H = (F_CPU/(BAUD_RATE*16L)-1) >> 8; | |
372 | UCSR1A = 0x00; | |
373 | UCSR1C = 0x06; | |
374 | UCSR1B = _BV(TXEN1)|_BV(RXEN1); | |
375 | } | |
376 | #elif defined __AVR_ATmega163__ | |
377 | UBRR = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1); | |
378 | UBRRHI = (F_CPU/(BAUD_RATE*16L)-1) >> 8; | |
379 | UCSRA = 0x00; | |
380 | UCSRB = _BV(TXEN)|_BV(RXEN); | |
381 | #elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) | |
382 | #ifdef DOUBLE_SPEED | |
383 | UCSR0A = (1<<U2X0); //Double speed mode USART0 | |
384 | UBRR0L = (uint8_t)(F_CPU/(BAUD_RATE*8L)-1); | |
385 | UBRR0H = (F_CPU/(BAUD_RATE*8L)-1) >> 8; | |
386 | #else | |
387 | UBRR0L = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1); | |
388 | UBRR0H = (F_CPU/(BAUD_RATE*16L)-1) >> 8; | |
389 | #endif | |
390 | UCSR0B = (1<<RXEN0) | (1<<TXEN0); | |
391 | UCSR0C = (1<<UCSZ00) | (1<<UCSZ01); | |
392 | /* Enable internal pull-up resistor on pin D0 (RX), in order | |
393 | to supress line noise that prevents the bootloader from | |
394 | timing out (DAM: 20070509) */ | |
395 | DDRD &= ~_BV(PIND0); | |
396 | PORTD |= _BV(PIND0); | |
397 | #elif defined __AVR_ATmega8__ | |
398 | /* m8 */ | |
399 | UBRRH = (((F_CPU/BAUD_RATE)/16)-1)>>8; // set baud rate | |
400 | UBRRL = (((F_CPU/BAUD_RATE)/16)-1); | |
401 | UCSRB = (1<<RXEN)|(1<<TXEN); // enable Rx & Tx | |
402 | UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // config USART; 8N1 | |
403 | #else | |
404 | /* m16,m32,m169,m8515,m8535 */ | |
405 | UBRRL = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1); | |
406 | UBRRH = (F_CPU/(BAUD_RATE*16L)-1) >> 8; | |
407 | UCSRA = 0x00; | |
408 | UCSRC = 0x06; | |
409 | UCSRB = _BV(TXEN)|_BV(RXEN); | |
410 | #endif | |
411 | #if defined __AVR_ATmega1280__ | |
412 | /* Enable internal pull-up resistor on pin D0 (RX), in order | |
413 | to supress line noise that prevents the bootloader from | |
414 | timing out (DAM: 20070509) */ | |
415 | /* feature added to the Arduino Mega --DC: 080930 */ | |
416 | DDRE &= ~_BV(PINE0); | |
417 | PORTE |= _BV(PINE0); | |
418 | #endif | |
419 | /* set LED pin as output */ | |
420 | LED_DDR |= _BV(LED); | |
421 | /* flash onboard LED to signal entering of bootloader */ | |
422 | #if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1284P__) | |
423 | // 4x for UART0, 5x for UART1 | |
424 | flash_led(NUM_LED_FLASHES + bootuart); | |
425 | #else | |
426 | flash_led(NUM_LED_FLASHES); | |
427 | #endif | |
428 | /* 20050803: by DojoCorp, this is one of the parts provoking the | |
429 | system to stop listening, cancelled from the original */ | |
430 | //putch('\0'); | |
431 | /* forever loop */ | |
432 | for (;;) | |
433 | { | |
434 | /* get character from UART */ | |
435 | ch = getch(); | |
436 | /* A bunch of if...else if... gives smaller code than switch...case ! */ | |
437 | /* Hello is anyone home ? */ | |
438 | if(ch=='0') | |
439 | { | |
440 | nothing_response(); | |
441 | } | |
442 | /* Request programmer ID */ | |
443 | /* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundry */ | |
444 | /* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares. */ | |
445 | else if(ch=='1') | |
446 | { | |
447 | if (getch() == ' ') | |
448 | { | |
449 | putch(0x14); | |
450 | putch('A'); | |
451 | putch('V'); | |
452 | putch('R'); | |
453 | putch(' '); | |
454 | putch('I'); | |
455 | putch('S'); | |
456 | putch('P'); | |
457 | putch(0x10); | |
458 | } | |
459 | else | |
460 | { | |
461 | if (++error_count == MAX_ERROR_COUNT) | |
462 | app_start(); | |
463 | } | |
464 | } | |
465 | /* AVR ISP/STK500 board commands DON'T CARE so default nothing_response */ | |
466 | else if(ch=='@') | |
467 | { | |
468 | ch2 = getch(); | |
469 | if (ch2>0x85) getch(); | |
470 | nothing_response(); | |
471 | } | |
472 | /* AVR ISP/STK500 board requests */ | |
473 | else if(ch=='A') | |
474 | { | |
475 | ch2 = getch(); | |
476 | if(ch2==0x80) byte_response(HW_VER); // Hardware version | |
477 | else if(ch2==0x81) byte_response(SW_MAJOR); // Software major version | |
478 | else if(ch2==0x82) byte_response(SW_MINOR); // Software minor version | |
479 | else if(ch2==0x98) byte_response(0x03); // Unknown but seems to be required by avr studio 3.56 | |
480 | else byte_response(0x00); // Covers various unnecessary responses we don't care about | |
481 | } | |
482 | /* Device Parameters DON'T CARE, DEVICE IS FIXED */ | |
483 | else if(ch=='B') | |
484 | { | |
485 | getNch(20); | |
486 | nothing_response(); | |
487 | } | |
488 | /* Parallel programming stuff DON'T CARE */ | |
489 | else if(ch=='E') | |
490 | { | |
491 | getNch(5); | |
492 | nothing_response(); | |
493 | } | |
494 | /* P: Enter programming mode */ | |
495 | /* R: Erase device, don't care as we will erase one page at a time anyway. */ | |
496 | else if(ch=='P' || ch=='R') | |
497 | { | |
498 | nothing_response(); | |
499 | } | |
500 | /* Leave programming mode */ | |
501 | else if(ch=='Q') | |
502 | { | |
503 | nothing_response(); | |
504 | #ifdef WATCHDOG_MODS | |
505 | // autoreset via watchdog (sneaky!) | |
506 | WDTCSR = _BV(WDE); | |
507 | while (1); // 16 ms | |
508 | #endif | |
509 | } | |
510 | /* Set address, little endian. EEPROM in bytes, FLASH in words */ | |
511 | /* Perhaps extra address bytes may be added in future to support > 128kB FLASH. */ | |
512 | /* This might explain why little endian was used here, big endian used everywhere else. */ | |
513 | else if(ch=='U') | |
514 | { | |
515 | address.byte[0] = getch(); | |
516 | address.byte[1] = getch(); | |
517 | nothing_response(); | |
518 | } | |
519 | /* Universal SPI programming command, disabled. Would be used for fuses and lock bits. */ | |
520 | else if(ch=='V') | |
521 | { | |
522 | if (getch() == 0x30) | |
523 | { | |
524 | getch(); | |
525 | ch = getch(); | |
526 | getch(); | |
527 | if (ch == 0) | |
528 | { | |
529 | byte_response(SIG1); | |
530 | } | |
531 | else if (ch == 1) | |
532 | { | |
533 | byte_response(SIG2); | |
534 | } | |
535 | else | |
536 | { | |
537 | byte_response(SIG3); | |
538 | } | |
539 | } | |
540 | else | |
541 | { | |
542 | getNch(3); | |
543 | byte_response(0x00); | |
544 | } | |
545 | } | |
546 | /* Write memory, length is big endian and is in bytes */ | |
547 | else if(ch=='d') | |
548 | { | |
549 | length.byte[1] = getch(); | |
550 | length.byte[0] = getch(); | |
551 | flags.eeprom = 0; | |
552 | if (getch() == 'E') flags.eeprom = 1; | |
553 | for (w=0; w<length.word; w++) | |
554 | { | |
555 | buff[w] = getch(); // Store data in buffer, can't keep up with serial data stream whilst programming pages | |
556 | } | |
557 | if (getch() == ' ') | |
558 | { | |
559 | if (flags.eeprom) //Write to EEPROM one byte at a time | |
560 | { | |
561 | address.word <<= 1; | |
562 | for(w=0; w<length.word; w++) | |
563 | { | |
564 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) | |
565 | while(EECR & (1<<EEPE)); | |
566 | EEAR = (uint16_t)(void *)address.word; | |
567 | EEDR = buff[w]; | |
568 | EECR |= (1<<EEMPE); | |
569 | EECR |= (1<<EEPE); | |
570 | #else | |
571 | eeprom_write_byte((void *)address.word,buff[w]); | |
572 | #endif | |
573 | address.word++; | |
574 | } | |
575 | } | |
576 | else //Write to FLASH one page at a time | |
577 | { | |
578 | if (address.byte[1]>127) address_high = 0x01; //Only possible with m128, m256 will need 3rd address byte. FIXME | |
579 | else address_high = 0x00; | |
580 | #if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1284P__) | |
581 | RAMPZ = address_high; | |
582 | #endif | |
583 | address.word = address.word << 1; //address * 2 -> byte location | |
584 | /* if ((length.byte[0] & 0x01) == 0x01) length.word++; //Even up an odd number of bytes */ | |
585 | if ((length.byte[0] & 0x01)) length.word++; //Even up an odd number of bytes | |
586 | cli(); //Disable interrupts, just to be sure | |
587 | #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1284P__) | |
588 | while(bit_is_set(EECR,EEPE)); //Wait for previous EEPROM writes to complete | |
589 | #else | |
590 | while(bit_is_set(EECR,EEWE)); //Wait for previous EEPROM writes to complete | |
591 | #endif | |
592 | asm volatile( | |
593 | "clr r17 \n\t" //page_word_count | |
594 | "lds r30,address \n\t" //Address of FLASH location (in bytes) | |
595 | "lds r31,address+1 \n\t" | |
596 | "ldi r28,lo8(buff) \n\t" //Start of buffer array in RAM | |
597 | "ldi r29,hi8(buff) \n\t" | |
598 | "lds r24,length \n\t" //Length of data to be written (in bytes) | |
599 | "lds r25,length+1 \n\t" | |
600 | "length_loop: \n\t" //Main loop, repeat for number of words in block | |
601 | "cpi r17,0x00 \n\t" //If page_word_count=0 then erase page | |
602 | "brne no_page_erase \n\t" | |
603 | "wait_spm1: \n\t" | |
604 | "lds r16,%0 \n\t" //Wait for previous spm to complete | |
605 | "andi r16,1 \n\t" | |
606 | "cpi r16,1 \n\t" | |
607 | "breq wait_spm1 \n\t" | |
608 | "ldi r16,0x03 \n\t" //Erase page pointed to by Z | |
609 | "sts %0,r16 \n\t" | |
610 | "spm \n\t" | |
611 | #ifdef __AVR_ATmega163__ | |
612 | ".word 0xFFFF \n\t" | |
613 | "nop \n\t" | |
614 | #endif | |
615 | "wait_spm2: \n\t" | |
616 | "lds r16,%0 \n\t" //Wait for previous spm to complete | |
617 | "andi r16,1 \n\t" | |
618 | "cpi r16,1 \n\t" | |
619 | "breq wait_spm2 \n\t" | |
620 | "ldi r16,0x11 \n\t" //Re-enable RWW section | |
621 | "sts %0,r16 \n\t" | |
622 | "spm \n\t" | |
623 | #ifdef __AVR_ATmega163__ | |
624 | ".word 0xFFFF \n\t" | |
625 | "nop \n\t" | |
626 | #endif | |
627 | "no_page_erase: \n\t" | |
628 | "ld r0,Y+ \n\t" //Write 2 bytes into page buffer | |
629 | "ld r1,Y+ \n\t" | |
630 | "wait_spm3: \n\t" | |
631 | "lds r16,%0 \n\t" //Wait for previous spm to complete | |
632 | "andi r16,1 \n\t" | |
633 | "cpi r16,1 \n\t" | |
634 | "breq wait_spm3 \n\t" | |
635 | "ldi r16,0x01 \n\t" //Load r0,r1 into FLASH page buffer | |
636 | "sts %0,r16 \n\t" | |
637 | "spm \n\t" | |
638 | "inc r17 \n\t" //page_word_count++ | |
639 | "cpi r17,%1 \n\t" | |
640 | "brlo same_page \n\t" //Still same page in FLASH | |
641 | "write_page: \n\t" | |
642 | "clr r17 \n\t" //New page, write current one first | |
643 | "wait_spm4: \n\t" | |
644 | "lds r16,%0 \n\t" //Wait for previous spm to complete | |
645 | "andi r16,1 \n\t" | |
646 | "cpi r16,1 \n\t" | |
647 | "breq wait_spm4 \n\t" | |
648 | #ifdef __AVR_ATmega163__ | |
649 | "andi r30,0x80 \n\t" // m163 requires Z6:Z1 to be zero during page write | |
650 | #endif | |
651 | "ldi r16,0x05 \n\t" //Write page pointed to by Z | |
652 | "sts %0,r16 \n\t" | |
653 | "spm \n\t" | |
654 | #ifdef __AVR_ATmega163__ | |
655 | ".word 0xFFFF \n\t" | |
656 | "nop \n\t" | |
657 | "ori r30,0x7E \n\t" // recover Z6:Z1 state after page write (had to be zero during write) | |
658 | #endif | |
659 | "wait_spm5: \n\t" | |
660 | "lds r16,%0 \n\t" //Wait for previous spm to complete | |
661 | "andi r16,1 \n\t" | |
662 | "cpi r16,1 \n\t" | |
663 | "breq wait_spm5 \n\t" | |
664 | "ldi r16,0x11 \n\t" //Re-enable RWW section | |
665 | "sts %0,r16 \n\t" | |
666 | "spm \n\t" | |
667 | #ifdef __AVR_ATmega163__ | |
668 | ".word 0xFFFF \n\t" | |
669 | "nop \n\t" | |
670 | #endif | |
671 | "same_page: \n\t" | |
672 | "adiw r30,2 \n\t" //Next word in FLASH | |
673 | "sbiw r24,2 \n\t" //length-2 | |
674 | "breq final_write \n\t" //Finished | |
675 | "rjmp length_loop \n\t" | |
676 | "final_write: \n\t" | |
677 | "cpi r17,0 \n\t" | |
678 | "breq block_done \n\t" | |
679 | "adiw r24,2 \n\t" //length+2, fool above check on length after short page write | |
680 | "rjmp write_page \n\t" | |
681 | "block_done: \n\t" | |
682 | "clr __zero_reg__ \n\t" //restore zero register | |
683 | #if defined __AVR_ATmega168__ || __AVR_ATmega328P__ || __AVR_ATmega128__ || __AVR_ATmega1280__ || __AVR_ATmega1281__ || __AVR_ATmega1284P__ | |
684 | : "=m" (SPMCSR) : "M" (PAGE_SIZE) : "r0","r16","r17","r24","r25","r28","r29","r30","r31" | |
685 | #else | |
686 | : "=m" (SPMCR) : "M" (PAGE_SIZE) : "r0","r16","r17","r24","r25","r28","r29","r30","r31" | |
687 | #endif | |
688 | ); | |
689 | /* Should really add a wait for RWW section to be enabled, don't actually need it since we never */ | |
690 | /* exit the bootloader without a power cycle anyhow */ | |
691 | } | |
692 | putch(0x14); | |
693 | putch(0x10); | |
694 | } | |
695 | else | |
696 | { | |
697 | if (++error_count == MAX_ERROR_COUNT) | |
698 | app_start(); | |
699 | } | |
700 | } | |
701 | /* Read memory block mode, length is big endian. */ | |
702 | else if(ch=='t') | |
703 | { | |
704 | length.byte[1] = getch(); | |
705 | length.byte[0] = getch(); | |
706 | #if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1284P__) | |
707 | if (address.word>0x7FFF) flags.rampz = 1; // No go with m256, FIXME | |
708 | else flags.rampz = 0; | |
709 | #endif | |
710 | address.word = address.word << 1; // address * 2 -> byte location | |
711 | if (getch() == 'E') flags.eeprom = 1; | |
712 | else flags.eeprom = 0; | |
713 | if (getch() == ' ') // Command terminator | |
714 | { | |
715 | putch(0x14); | |
716 | for (w=0; w < length.word; w++) // Can handle odd and even lengths okay | |
717 | { | |
718 | if (flags.eeprom) // Byte access EEPROM read | |
719 | { | |
720 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) | |
721 | while(EECR & (1<<EEPE)); | |
722 | EEAR = (uint16_t)(void *)address.word; | |
723 | EECR |= (1<<EERE); | |
724 | putch(EEDR); | |
725 | #else | |
726 | putch(eeprom_read_byte((void *)address.word)); | |
727 | #endif | |
728 | address.word++; | |
729 | } | |
730 | else | |
731 | { | |
732 | if (!flags.rampz) putch(pgm_read_byte_near(address.word)); | |
733 | #if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1284P__) | |
734 | else putch(pgm_read_byte_far(address.word + 0x10000)); | |
735 | // Hmmmm, yuck FIXME when m256 arrvies | |
736 | #endif | |
737 | address.word++; | |
738 | } | |
739 | } | |
740 | putch(0x10); | |
741 | } | |
742 | } | |
743 | /* Get device signature bytes */ | |
744 | else if(ch=='u') | |
745 | { | |
746 | if (getch() == ' ') | |
747 | { | |
748 | putch(0x14); | |
749 | putch(SIG1); | |
750 | putch(SIG2); | |
751 | putch(SIG3); | |
752 | putch(0x10); | |
753 | } | |
754 | else | |
755 | { | |
756 | if (++error_count == MAX_ERROR_COUNT) | |
757 | app_start(); | |
758 | } | |
759 | } | |
760 | /* Read oscillator calibration byte */ | |
761 | else if(ch=='v') | |
762 | { | |
763 | byte_response(0x00); | |
764 | } | |
765 | #if defined MONITOR | |
766 | /* here come the extended monitor commands by Erik Lins */ | |
767 | /* check for three times exclamation mark pressed */ | |
768 | else if(ch=='!') | |
769 | { | |
770 | ch = getch(); | |
771 | if(ch=='!') | |
772 | { | |
773 | ch = getch(); | |
774 | if(ch=='!') | |
775 | { | |
776 | PGM_P welcome = ""; | |
777 | #if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__) | |
778 | uint16_t extaddr; | |
779 | #endif | |
780 | uint8_t addrl, addrh; | |
781 | #ifdef CRUMB128 | |
782 | welcome = "ATmegaBOOT / Crumb128 - (C) J.P.Kyle, E.Lins - 050815\n\r"; | |
783 | #elif defined PROBOMEGA128 | |
784 | welcome = "ATmegaBOOT / PROBOmega128 - (C) J.P.Kyle, E.Lins - 050815\n\r"; | |
785 | #elif defined SAVVY128 | |
786 | welcome = "ATmegaBOOT / Savvy128 - (C) J.P.Kyle, E.Lins - 050815\n\r"; | |
787 | #elif defined __AVR_ATmega1280__ | |
788 | welcome = "ATmegaBOOT / Arduino Mega - (C) Arduino LLC - 090930\n\r"; | |
789 | #endif | |
790 | /* turn on LED */ | |
791 | LED_DDR |= _BV(LED); | |
792 | LED_PORT &= ~_BV(LED); | |
793 | /* print a welcome message and command overview */ | |
794 | for(i=0; welcome[i] != '\0'; ++i) | |
795 | { | |
796 | putch(welcome[i]); | |
797 | } | |
798 | /* test for valid commands */ | |
799 | for(;;) | |
800 | { | |
801 | putch('\n'); | |
802 | putch('\r'); | |
803 | putch(':'); | |
804 | putch(' '); | |
805 | ch = getch(); | |
806 | putch(ch); | |
807 | /* toggle LED */ | |
808 | if(ch == 't') | |
809 | { | |
810 | if(bit_is_set(LED_PIN,LED)) | |
811 | { | |
812 | LED_PORT &= ~_BV(LED); | |
813 | putch('1'); | |
814 | } | |
815 | else | |
816 | { | |
817 | LED_PORT |= _BV(LED); | |
818 | putch('0'); | |
819 | } | |
820 | } | |
821 | /* read byte from address */ | |
822 | else if(ch == 'r') | |
823 | { | |
824 | ch = getch(); | |
825 | putch(ch); | |
826 | addrh = gethex(); | |
827 | addrl = gethex(); | |
828 | putch('='); | |
829 | ch = *(uint8_t *)((addrh << 8) + addrl); | |
830 | puthex(ch); | |
831 | } | |
832 | /* write a byte to address */ | |
833 | else if(ch == 'w') | |
834 | { | |
835 | ch = getch(); | |
836 | putch(ch); | |
837 | addrh = gethex(); | |
838 | addrl = gethex(); | |
839 | ch = getch(); | |
840 | putch(ch); | |
841 | ch = gethex(); | |
842 | *(uint8_t *)((addrh << 8) + addrl) = ch; | |
843 | } | |
844 | /* read from uart and echo back */ | |
845 | else if(ch == 'u') | |
846 | { | |
847 | for(;;) | |
848 | { | |
849 | putch(getch()); | |
850 | } | |
851 | } | |
852 | #if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__) | |
853 | /* external bus loop */ | |
854 | else if(ch == 'b') | |
855 | { | |
856 | putch('b'); | |
857 | putch('u'); | |
858 | putch('s'); | |
859 | MCUCR = 0x80; | |
860 | XMCRA = 0; | |
861 | XMCRB = 0; | |
862 | extaddr = 0x1100; | |
863 | for(;;) | |
864 | { | |
865 | ch = *(volatile uint8_t *)extaddr; | |
866 | if(++extaddr == 0) | |
867 | { | |
868 | extaddr = 0x1100; | |
869 | } | |
870 | } | |
871 | } | |
872 | #endif | |
873 | else if(ch == 'j') | |
874 | { | |
875 | app_start(); | |
876 | } | |
877 | } /* end of monitor functions */ | |
878 | } | |
879 | } | |
880 | } | |
881 | /* end of monitor */ | |
882 | #endif | |
883 | else if (++error_count == MAX_ERROR_COUNT) | |
884 | { | |
885 | app_start(); | |
886 | } | |
887 | } /* end of forever loop */ | |
888 | } | |
889 | ||
890 | ||
891 | char gethexnib(void) | |
892 | { | |
893 | char a; | |
894 | a = getch(); | |
895 | putch(a); | |
896 | if(a >= 'a') | |
897 | { | |
898 | return (a - 'a' + 0x0a); | |
899 | } | |
900 | else if(a >= '0') | |
901 | { | |
902 | return(a - '0'); | |
903 | } | |
904 | return a; | |
905 | } | |
906 | ||
907 | ||
908 | char gethex(void) | |
909 | { | |
910 | return (gethexnib() << 4) + gethexnib(); | |
911 | } | |
912 | ||
913 | ||
914 | void puthex(char ch) | |
915 | { | |
916 | char ah; | |
917 | ah = ch >> 4; | |
918 | if(ah >= 0x0a) | |
919 | { | |
920 | ah = ah - 0x0a + 'a'; | |
921 | } | |
922 | else | |
923 | { | |
924 | ah += '0'; | |
925 | } | |
926 | ch &= 0x0f; | |
927 | if(ch >= 0x0a) | |
928 | { | |
929 | ch = ch - 0x0a + 'a'; | |
930 | } | |
931 | else | |
932 | { | |
933 | ch += '0'; | |
934 | } | |
935 | putch(ah); | |
936 | putch(ch); | |
937 | } | |
938 | ||
939 | ||
940 | void putch(char ch) | |
941 | { | |
942 | #if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1284P__) | |
943 | if(bootuart == 1) | |
944 | { | |
945 | while (!(UCSR0A & _BV(UDRE0))); | |
946 | UDR0 = ch; | |
947 | } | |
948 | else if (bootuart == 2) | |
949 | { | |
950 | while (!(UCSR1A & _BV(UDRE1))); | |
951 | UDR1 = ch; | |
952 | } | |
953 | #elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) | |
954 | while (!(UCSR0A & _BV(UDRE0))); | |
955 | UDR0 = ch; | |
956 | #else | |
957 | /* m8,16,32,169,8515,8535,163 */ | |
958 | while (!(UCSRA & _BV(UDRE))); | |
959 | UDR = ch; | |
960 | #endif | |
961 | } | |
962 | ||
963 | ||
964 | char getch(void) | |
965 | { | |
966 | #if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1284P__) | |
967 | uint32_t count = 0; | |
968 | if(bootuart == 1) | |
969 | { | |
970 | while(!(UCSR0A & _BV(RXC0))) | |
971 | { | |
972 | /* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/ | |
973 | /* HACKME:: here is a good place to count times*/ | |
974 | count++; | |
975 | if (count > MAX_TIME_COUNT) | |
976 | app_start(); | |
977 | } | |
978 | return UDR0; | |
979 | } | |
980 | else if(bootuart == 2) | |
981 | { | |
982 | while(!(UCSR1A & _BV(RXC1))) | |
983 | { | |
984 | /* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/ | |
985 | /* HACKME:: here is a good place to count times*/ | |
986 | count++; | |
987 | if (count > MAX_TIME_COUNT) | |
988 | app_start(); | |
989 | } | |
990 | return UDR1; | |
991 | } | |
992 | return 0; | |
993 | #elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) | |
994 | uint32_t count = 0; | |
995 | while(!(UCSR0A & _BV(RXC0))) | |
996 | { | |
997 | /* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/ | |
998 | /* HACKME:: here is a good place to count times*/ | |
999 | count++; | |
1000 | if (count > MAX_TIME_COUNT) | |
1001 | app_start(); | |
1002 | } | |
1003 | return UDR0; | |
1004 | #else | |
1005 | /* m8,16,32,169,8515,8535,163 */ | |
1006 | uint32_t count = 0; | |
1007 | while(!(UCSRA & _BV(RXC))) | |
1008 | { | |
1009 | /* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/ | |
1010 | /* HACKME:: here is a good place to count times*/ | |
1011 | count++; | |
1012 | if (count > MAX_TIME_COUNT) | |
1013 | app_start(); | |
1014 | } | |
1015 | return UDR; | |
1016 | #endif | |
1017 | } | |
1018 | ||
1019 | ||
1020 | void getNch(uint8_t count) | |
1021 | { | |
1022 | while(count--) | |
1023 | { | |
1024 | #if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1284P__) | |
1025 | if(bootuart == 1) | |
1026 | { | |
1027 | while(!(UCSR0A & _BV(RXC0))); | |
1028 | UDR0; | |
1029 | } | |
1030 | else if(bootuart == 2) | |
1031 | { | |
1032 | while(!(UCSR1A & _BV(RXC1))); | |
1033 | UDR1; | |
1034 | } | |
1035 | #elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) | |
1036 | getch(); | |
1037 | #else | |
1038 | /* m8,16,32,169,8515,8535,163 */ | |
1039 | /* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/ | |
1040 | //while(!(UCSRA & _BV(RXC))); | |
1041 | //UDR; | |
1042 | getch(); // need to handle time out | |
1043 | #endif | |
1044 | } | |
1045 | } | |
1046 | ||
1047 | ||
1048 | void byte_response(uint8_t val) | |
1049 | { | |
1050 | if (getch() == ' ') | |
1051 | { | |
1052 | putch(0x14); | |
1053 | putch(val); | |
1054 | putch(0x10); | |
1055 | } | |
1056 | else | |
1057 | { | |
1058 | if (++error_count == MAX_ERROR_COUNT) | |
1059 | app_start(); | |
1060 | } | |
1061 | } | |
1062 | ||
1063 | ||
1064 | void nothing_response(void) | |
1065 | { | |
1066 | if (getch() == ' ') | |
1067 | { | |
1068 | putch(0x14); | |
1069 | putch(0x10); | |
1070 | } | |
1071 | else | |
1072 | { | |
1073 | if (++error_count == MAX_ERROR_COUNT) | |
1074 | app_start(); | |
1075 | } | |
1076 | } | |
1077 | ||
1078 | void flash_led(uint8_t count) | |
1079 | { | |
1080 | while (count--) | |
1081 | { | |
1082 | LED_PORT |= _BV(LED); | |
1083 | _delay_ms(100); | |
1084 | LED_PORT &= ~_BV(LED); | |
1085 | _delay_ms(100); | |
1086 | } | |
1087 | } | |
1088 | ||
1089 | ||
1090 | /* end of file ATmegaBOOT.c */ |
0 | # Makefile for ATmegaBOOT | |
1 | # E.Lins, 18.7.2005 | |
2 | # $Id$ | |
3 | ||
4 | ||
5 | # program name should not be changed... | |
6 | PROGRAM = ATmegaBOOT_1284P | |
7 | ||
8 | # enter the target CPU frequency | |
9 | AVR_FREQ = 16000000L | |
10 | ||
11 | MCU_TARGET = atmega1284p | |
12 | LDSECTION = --section-start=.text=0x1F800 | |
13 | ||
14 | OBJ = $(PROGRAM).o | |
15 | OPTIMIZE = -Os | |
16 | ||
17 | DEFS = -DWATCHDOG_MODS -DBAUD_RATE=57600 | |
18 | LIBS = | |
19 | ||
20 | CC = avr-gcc | |
21 | ||
22 | ||
23 | # Override is only needed by avr-lib build system. | |
24 | ||
25 | override CFLAGS = -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS) | |
26 | override LDFLAGS = -Wl,$(LDSECTION) | |
27 | #override LDFLAGS = -Wl,-Map,$(PROGRAM).map,$(LDSECTION) | |
28 | ||
29 | OBJCOPY = avr-objcopy | |
30 | OBJDUMP = avr-objdump | |
31 | ||
32 | all: CFLAGS += '-DMAX_TIME_COUNT=16000000L>>1' -DADABOOT | |
33 | all: $(PROGRAM).hex | |
34 | ||
35 | $(PROGRAM).hex: $(PROGRAM).elf | |
36 | $(OBJCOPY) -j .text -j .data -O ihex $< $@ | |
37 | ||
38 | $(PROGRAM).elf: $(OBJ) | |
39 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) | |
40 | ||
41 | $(OBJ): ATmegaBOOT.c | |
42 | avr-gcc $(CFLAGS) $(LDFLAGS) -c -Wall -mmcu=$(MCU_TARGET) ATmegaBOOT.c -o $(PROGRAM).o | |
43 | ||
44 | %.lst: %.elf | |
45 | $(OBJDUMP) -h -S $< > $@ | |
46 | ||
47 | %.srec: %.elf | |
48 | $(OBJCOPY) -j .text -j .data -O srec $< $@ | |
49 | ||
50 | %.bin: %.elf | |
51 | $(OBJCOPY) -j .text -j .data -O binary $< $@ | |
52 | ||
53 | clean: | |
54 | rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex | |
55 |
0 | #ifndef Pins_Arduino_h | |
1 | #define Pins_Arduino_h | |
2 | ||
3 | #include <avr/pgmspace.h> | |
4 | ||
5 | // ATMEL ATMEGA1284P | |
6 | // | |
7 | // +---\/---+ | |
8 | // (D 0) PB0 1| |40 PA0 (AI 0 / D24) | |
9 | // (D 1) PB1 2| |39 PA1 (AI 1 / D25) | |
10 | // INT2 (D 2) PB2 3| |38 PA2 (AI 2 / D26) | |
11 | // PWM (D 3) PB3 4| |37 PA3 (AI 3 / D27) | |
12 | // PWM/SS (D 4) PB4 5| |36 PA4 (AI 4 / D28) | |
13 | // MOSI (D 5) PB5 6| |35 PA5 (AI 5 / D29) | |
14 | // PWM/MISO (D 6) PB6 7| |34 PA6 (AI 6 / D30) | |
15 | // PWM/SCK (D 7) PB7 8| |33 PA7 (AI 7 / D31) | |
16 | // RST 9| |32 AREF | |
17 | // VCC 10| |31 GND | |
18 | // GND 11| |30 AVCC | |
19 | // XTAL2 12| |29 PC7 (D 23) | |
20 | // XTAL1 13| |28 PC6 (D 22) | |
21 | // RX0 (D 8) PD0 14| |27 PC5 (D 21) TDI | |
22 | // TX0 (D 9) PD1 15| |26 PC4 (D 20) TDO | |
23 | // RX1/INT0 (D 10) PD2 16| |25 PC3 (D 19) TMS | |
24 | // TX1/INT1 (D 11) PD3 17| |24 PC2 (D 18) TCK | |
25 | // PWM (D 12) PD4 18| |23 PC1 (D 17) SDA | |
26 | // PWM (D 13) PD5 19| |22 PC0 (D 16) SCL | |
27 | // PWM (D 14) PD6 20| |21 PD7 (D 15) PWM | |
28 | // +--------+ | |
29 | // | |
30 | ||
31 | /* | |
32 | PCINT15-8: D7-0 : bit 1 | |
33 | PCINT31-24: D15-8 : bit 3 | |
34 | PCINT23-16: D23-16 : bit 2 | |
35 | PCINT7-0: D31-24 : bit 0 | |
36 | */ | |
37 | ||
38 | #define NUM_DIGITAL_PINS 32 | |
39 | #define NUM_ANALOG_INPUTS 8 | |
40 | #define analogInputToDigitalPin(p) ((p < NUM_ANALOG_INPUTS) ? (p) + 24 : -1) | |
41 | ||
42 | #define digitalPinHasPWM(p) ((p) == 3 || (p) == 4 || (p) == 6 || (p) == 7 || (p) == 12 || (p) == 13 || (p) == 14 || (p) == 15) | |
43 | ||
44 | static const uint8_t SS = 4; | |
45 | static const uint8_t MOSI = 5; | |
46 | static const uint8_t MISO = 6; | |
47 | static const uint8_t SCK = 7; | |
48 | ||
49 | static const uint8_t SDA = 17; | |
50 | static const uint8_t SCL = 16; | |
51 | static const uint8_t LED = 7; | |
52 | ||
53 | static const uint8_t A0 = 24; | |
54 | static const uint8_t A1 = 25; | |
55 | static const uint8_t A2 = 26; | |
56 | static const uint8_t A3 = 27; | |
57 | static const uint8_t A4 = 28; | |
58 | static const uint8_t A5 = 29; | |
59 | static const uint8_t A6 = 30; | |
60 | static const uint8_t A7 = 31; | |
61 | ||
62 | #define digitalPinToPCICR(p) (((p) >= 0 && (p) < NUM_DIGITAL_PINS) ? (&PCICR) : ((uint8_t *)0)) | |
63 | #define digitalPinToPCICRbit(p) (((p) <= 7) ? 1 : (((p) <= 15) ? 3 : (((p) <= 23) ? 2 : 0))) | |
64 | #define digitalPinToPCMSK(p) (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0)))) | |
65 | #define digitalPinToPCMSKbit(p) ((p) % 8) | |
66 | ||
67 | #ifdef ARDUINO_MAIN | |
68 | ||
69 | #define PA 1 | |
70 | #define PB 2 | |
71 | #define PC 3 | |
72 | #define PD 4 | |
73 | ||
74 | // these arrays map port names (e.g. port B) to the | |
75 | // appropriate addresses for various functions (e.g. reading | |
76 | // and writing) | |
77 | const uint16_t PROGMEM port_to_mode_PGM[] = | |
78 | { | |
79 | NOT_A_PORT, | |
80 | (uint16_t) &DDRA, | |
81 | (uint16_t) &DDRB, | |
82 | (uint16_t) &DDRC, | |
83 | (uint16_t) &DDRD, | |
84 | }; | |
85 | ||
86 | const uint16_t PROGMEM port_to_output_PGM[] = | |
87 | { | |
88 | NOT_A_PORT, | |
89 | (uint16_t) &PORTA, | |
90 | (uint16_t) &PORTB, | |
91 | (uint16_t) &PORTC, | |
92 | (uint16_t) &PORTD, | |
93 | }; | |
94 | ||
95 | const uint16_t PROGMEM port_to_input_PGM[] = | |
96 | { | |
97 | NOT_A_PORT, | |
98 | (uint16_t) &PINA, | |
99 | (uint16_t) &PINB, | |
100 | (uint16_t) &PINC, | |
101 | (uint16_t) &PIND, | |
102 | }; | |
103 | ||
104 | const uint8_t PROGMEM digital_pin_to_port_PGM[] = | |
105 | { | |
106 | PB, /* 0 */ | |
107 | PB, | |
108 | PB, | |
109 | PB, | |
110 | PB, | |
111 | PB, | |
112 | PB, | |
113 | PB, | |
114 | PD, /* 8 */ | |
115 | PD, | |
116 | PD, | |
117 | PD, | |
118 | PD, | |
119 | PD, | |
120 | PD, | |
121 | PD, | |
122 | PC, /* 16 */ | |
123 | PC, | |
124 | PC, | |
125 | PC, | |
126 | PC, | |
127 | PC, | |
128 | PC, | |
129 | PC, | |
130 | PA, /* 24 */ | |
131 | PA, | |
132 | PA, | |
133 | PA, | |
134 | PA, | |
135 | PA, | |
136 | PA, | |
137 | PA /* 31 */ | |
138 | }; | |
139 | ||
140 | const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = | |
141 | { | |
142 | _BV(0), /* 0, port B */ | |
143 | _BV(1), | |
144 | _BV(2), | |
145 | _BV(3), | |
146 | _BV(4), | |
147 | _BV(5), | |
148 | _BV(6), | |
149 | _BV(7), | |
150 | _BV(0), /* 8, port D */ | |
151 | _BV(1), | |
152 | _BV(2), | |
153 | _BV(3), | |
154 | _BV(4), | |
155 | _BV(5), | |
156 | _BV(6), | |
157 | _BV(7), | |
158 | _BV(0), /* 16, port C */ | |
159 | _BV(1), | |
160 | _BV(2), | |
161 | _BV(3), | |
162 | _BV(4), | |
163 | _BV(5), | |
164 | _BV(6), | |
165 | _BV(7), | |
166 | _BV(0), /* 24, port A */ | |
167 | _BV(1), | |
168 | _BV(2), | |
169 | _BV(3), | |
170 | _BV(4), | |
171 | _BV(5), | |
172 | _BV(6), | |
173 | _BV(7) | |
174 | }; | |
175 | ||
176 | const uint8_t PROGMEM digital_pin_to_timer_PGM[] = | |
177 | { | |
178 | NOT_ON_TIMER, /* 0 - PB0 */ | |
179 | NOT_ON_TIMER, /* 1 - PB1 */ | |
180 | NOT_ON_TIMER, /* 2 - PB2 */ | |
181 | TIMER0A, /* 3 - PB3 */ | |
182 | TIMER0B, /* 4 - PB4 */ | |
183 | NOT_ON_TIMER, /* 5 - PB5 */ | |
184 | TIMER3A, /* 6 - PB6 */ | |
185 | TIMER3B, /* 7 - PB7 */ | |
186 | NOT_ON_TIMER, /* 8 - PD0 */ | |
187 | NOT_ON_TIMER, /* 9 - PD1 */ | |
188 | NOT_ON_TIMER, /* 10 - PD2 */ | |
189 | NOT_ON_TIMER, /* 11 - PD3 */ | |
190 | TIMER1B, /* 12 - PD4 */ | |
191 | TIMER1A, /* 13 - PD5 */ | |
192 | TIMER2B, /* 14 - PD6 */ | |
193 | TIMER2A, /* 15 - PD7 */ | |
194 | NOT_ON_TIMER, /* 16 - PC0 */ | |
195 | NOT_ON_TIMER, /* 17 - PC1 */ | |
196 | NOT_ON_TIMER, /* 18 - PC2 */ | |
197 | NOT_ON_TIMER, /* 19 - PC3 */ | |
198 | NOT_ON_TIMER, /* 20 - PC4 */ | |
199 | NOT_ON_TIMER, /* 21 - PC5 */ | |
200 | NOT_ON_TIMER, /* 22 - PC6 */ | |
201 | NOT_ON_TIMER, /* 23 - PC7 */ | |
202 | NOT_ON_TIMER, /* 24 - PA0 */ | |
203 | NOT_ON_TIMER, /* 25 - PA1 */ | |
204 | NOT_ON_TIMER, /* 26 - PA2 */ | |
205 | NOT_ON_TIMER, /* 27 - PA3 */ | |
206 | NOT_ON_TIMER, /* 28 - PA4 */ | |
207 | NOT_ON_TIMER, /* 29 - PA5 */ | |
208 | NOT_ON_TIMER, /* 30 - PA6 */ | |
209 | NOT_ON_TIMER /* 31 - PA7 */ | |
210 | }; | |
211 | ||
212 | #endif // ARDUINO_MAIN | |
213 | ||
214 | #endif // Pins_Arduino_h | |
215 | // vim:ai:cin:sts=2 sw=2 ft=cpp |