Skip to content

Commit 8d68385

Browse files
Allow loading an OSCCAL value from PROGMEM
When the OSCCAL_PROGMEM variable is given at compiletime, a byte is allocated in PROGMEM (flash) at a fixed location at the top of the flash space (just below the version bytes, so the third byte from the top). If this byte is overwritten with a calibration value (e.g. when programming the bootloader), it will be automatically loaded on startup. This allows improving the accuracy of the UART baudrate when running off the internal oscillator, and prevents the actual program from having to worry about calibration. The default value of this byte is 0xff, which causes it to be ignored. To fix the address of this variable, a dedicated .osccal section is used for it, and the linker is passed some options to put it in the right place (identical to what happens for the version variable). Enabling this option adds 15 bytes on the atmega328p build.
1 parent 9f7159e commit 8d68385

2 files changed

Lines changed: 32 additions & 9 deletions

File tree

optiboot/bootloaders/optiboot/Makefile

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export
5959

6060
# defaults
6161
MCU_TARGET = atmega168
62-
LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffe
62+
LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.osccal=0x3ffd -Wl,--section-start=.version=0x3ffe
6363

6464
# Build environments
6565
# Start of some ugly makefile-isms to allow optiboot to be built
@@ -195,6 +195,11 @@ OSCCAL_CMD = -DOSCCAL_EEPROM_ADDR=$(OSCCAL_EEPROM_ADDR)
195195
dummy = FORCE
196196
endif
197197

198+
ifdef OSCCAL_PROGMEM
199+
OSCCAL_CMD = -DOSCCAL_PROGMEM
200+
dummy = FORCE
201+
endif
202+
198203
COMMON_OPTIONS = $(BAUD_RATE_CMD) $(LED_START_FLASHES_CMD) $(BIGBOOT_CMD)
199204
COMMON_OPTIONS += $(SOFT_UART_CMD) $(LED_DATA_FLASH_CMD) $(LED_CMD) $(SS_CMD)
200205
COMMON_OPTIONS += $(OSCCAL_CMD)
@@ -246,7 +251,7 @@ virboot8: TARGET = atmega8
246251
virboot8: MCU_TARGET = atmega8
247252
virboot8: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' '-Dsave_vect_num=EE_RDY_vect_num'
248253
virboot8: AVR_FREQ ?= 16000000L
249-
virboot8: LDSECTIONS = -Wl,--section-start=.text=0x1c00 -Wl,--section-start=.version=0x1ffe
254+
virboot8: LDSECTIONS = -Wl,--section-start=.text=0x1c00 -Wl,--section-start=.osccal=0x1ffd -Wl,--section-start=.version=0x1ffe
250255
virboot8: $(PROGRAM)_virboot8.hex
251256
virboot8: $(PROGRAM)_virboot8.lst
252257

@@ -255,7 +260,7 @@ virboot328: TARGET = atmega328
255260
virboot328: MCU_TARGET = atmega328p
256261
virboot328: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION'
257262
virboot328: AVR_FREQ ?= 16000000L
258-
virboot328: LDSECTIONS = -Wl,--section-start=.text=0x7d80 -Wl,--section-start=.version=0x7ffe
263+
virboot328: LDSECTIONS = -Wl,--section-start=.text=0x7d80 -Wl,--section-start=.osccal=0x7ffd -Wl,--section-start=.version=0x7ffe
259264
virboot328: $(PROGRAM)_virboot328.hex
260265
virboot328: $(PROGRAM)_virboot328.lst
261266

@@ -303,7 +308,7 @@ atmega328: TARGET = atmega328
303308
atmega328: MCU_TARGET = atmega328p
304309
atmega328: CFLAGS += $(COMMON_OPTIONS)
305310
atmega328: AVR_FREQ ?= 16000000L
306-
atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
311+
atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.osccal=0x7ffd -Wl,--section-start=.version=0x7ffe
307312
atmega328: $(PROGRAM)_atmega328.hex
308313
atmega328: $(PROGRAM)_atmega328.lst
309314

@@ -322,7 +327,7 @@ atmega328_isp: isp
322327
atmega1280: MCU_TARGET = atmega1280
323328
atmega1280: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD)
324329
atmega1280: AVR_FREQ ?= 16000000L
325-
atmega1280: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
330+
atmega1280: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.osccal=0x1fffd -Wl,--section-start=.version=0x1fffe
326331
atmega1280: $(PROGRAM)_atmega1280.hex
327332
atmega1280: $(PROGRAM)_atmega1280.lst
328333

@@ -333,7 +338,7 @@ atmega8: TARGET = atmega8
333338
atmega8: MCU_TARGET = atmega8
334339
atmega8: CFLAGS += $(COMMON_OPTIONS)
335340
atmega8: AVR_FREQ ?= 16000000L
336-
atmega8: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe -Wl,--gc-sections -Wl,--undefined=optiboot_version
341+
atmega8: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.osccal=0x1ffd -Wl,--section-start=.version=0x1ffe -Wl,--gc-sections -Wl,--undefined=optiboot_version
337342
atmega8: $(PROGRAM)_atmega8.hex
338343
atmega8: $(PROGRAM)_atmega8.lst
339344

@@ -544,10 +549,10 @@ clean:
544549
$(OBJDUMP) -h -S $< > $@
545550

546551
%.hex: %.elf
547-
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex $< $@
552+
$(OBJCOPY) -j .text -j .data -j .version -j .osccal --set-section-flags .version=alloc,load --set-section-flags .osccal=alloc,load -O ihex $< $@
548553

549554
%.srec: %.elf
550-
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O srec $< $@
555+
$(OBJCOPY) -j .text -j .data -j .version -j .osccal -set-section-flags .version=alloc,load --set-section-flags .osccal=alloc,load -O srec $< $@
551556

552557
%.bin: %.elf
553-
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O binary $< $@
558+
$(OBJCOPY) -j .text -j .data -j .version -j .osccal --set-section-flags .version=alloc,load --set-section-flags .osccal=alloc,load -O binary $< $@

optiboot/bootloaders/optiboot/optiboot.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@
133133
/* this address in EEPROM and write it to OSCCAL (unless */
134134
/* it is 0xff). */
135135
/* */
136+
/* OSCCAL_PROGMEM */
137+
/* On startup, load an oscillator calibration value from */
138+
/* the top of the flash memory (unless it is 0xff, which */
139+
/* is the default). This byte is put into its own .osccal */
140+
/* section, so its address should be set through the */
141+
/* linker. */
142+
/* */
136143
/**********************************************************/
137144

138145
/**********************************************************/
@@ -244,6 +251,11 @@
244251
unsigned const int __attribute__((section(".version")))
245252
optiboot_version = 256*(OPTIBOOT_MAJVER + OPTIBOOT_CUSTOMVER) + OPTIBOOT_MINVER;
246253

254+
#if defined(OSCCAL_PROGMEM)
255+
unsigned const char __attribute__((section(".osccal")))
256+
optiboot_osccal = 0xff;
257+
#endif
258+
247259

248260
#include <inttypes.h>
249261
#include <avr/io.h>
@@ -480,6 +492,12 @@ int main(void) {
480492
OSCCAL = ch;
481493
#endif
482494

495+
#if defined(OSCCAL_PROGMEM)
496+
// Load OSCCAL before app start, so the app does not have to
497+
ch = pgm_read_byte(&optiboot_osccal);
498+
if (ch != 0xff)
499+
OSCCAL = ch;
500+
#endif
483501
/*
484502
* modified Adaboot no-wait mod.
485503
* Pass the reset reason to app. Also, it appears that an Uno poweron

0 commit comments

Comments
 (0)