As part of my application, I need to be able to update the code on my mega 2560 in the field with a download from the internet.

I have found this code in the AT Mega 2560 data sheet

 ;-the routine writes one page of data from RAM to Flash
 ; the first data location in RAM is pointed to by the Y pointer
 ; the first data location in Flash is pointed to by the Z-pointer
 ;-error handling is not included
 ;-the routine must be placed inside the Boot space
 ; (at least the Do_spm sub routine). Only code inside NRWW section can
 ; be read during Self-Programming (Page Erase and Page Write).
 ;-registers used: r0, r1, temp1 (r16), temp2 (r17), looplo (r24),
 ; loophi (r25), spmcrval (r20)
 ; storing and restoring of registers is not included in the routine
 ; register usage can be optimized at the expense of code size
 ;-It is assumed that either the interrupt table is moved to the Boot
 ; loader section or that the interrupts are disabled
..equ PAGESIZEB = PAGESIZE*2 ;PAGESIZEB is page size in BYTES, not words
    ; Page Erase
    ldi  spmcrval, (1<<PGERS) | (1<<SPMEN)
    call Do_spm

    ; re-enable the RWW section
    ldi  spmcrval, (1<<RWWSRE) | (1<<SPMEN)
    call Do_spm

    ; transfer data from RAM to Flash page buffer
    ldi  looplo, low(PAGESIZEB) ;init loop variable
    ldi  loophi, high(PAGESIZEB) ;not required for PAGESIZEB<=256

    ld   r0, Y+
    ld   r1, Y+
    ldi  spmcrval, (1<<SPMEN)
    call Do_spm
    adiw ZH:ZL, 2
    sbiw loophi:looplo, 2 ;use subi for PAGESIZEB<=256
    brne Wrloop

    ; execute Page Write
    subi ZL, low(PAGESIZEB)       ;restore pointer
    sbci ZH, high(PAGESIZEB)      ;not required for PAGESIZEB<=256
    ldi  spmcrval, (1<<PGWRT) | (1<<SPMEN)
    call Do_spm

    ; re-enable the RWW section
    ldi  spmcrval, (1<<RWWSRE) | (1<<SPMEN)
    call Do_spm

    ; read back and check, optional
    ldi  looplo, low(PAGESIZEB)   ;init loop variable
    ldi  loophi, high(PAGESIZEB)  ;not required for PAGESIZEB<=256
    subi YL, low(PAGESIZEB)       ;restore pointer
    sbci YH, high(PAGESIZEB)
    elpm r0, Z+
    ld   r1, Y+
    cpse r0, r1
    jmp  Error
    sbiw loophi:looplo, 1         ;use subi for PAGESIZEB<=256
    brne Rdloop

    ; return to RWW section
    ; verify that RWW section is safe to read
    in   temp1, SPMCSR
    sbrs temp1, RWWSB     ; If RWWSB is set, the RWW section is not ready yet
    ; re-enable the RWW section
    ldi  spmcrval, (1<<RWWSRE) | (1<<SPMEN)
    call Do_spmr
    jmp Return

    ; check for previous SPM complete
    in   temp1, SPMCSR
    sbrc temp1, SPMEN
    rjmp Wait_spm
    ; input: spmcrval determines SPM action
    ; disable interrupts if enabled, store status
    in   temp2, SREG
    ; check that no EEPROM write access is present
    sbic EECR, EEPE
    rjmp Wait_ee
    ; SPM timed sequence
    out  SPMCSR, spmcrval
    ; restore SREG (to enable interrupts if originally enabled)
    out  SREG, temp2

I am trying to convert this to code I can use in my arduino project under wiring. My first question is the register. It looks like spmcrval is register 20, but how can I access that register from within my arduino project?

I have found constants like SPMEN in the arduino header, but not these register names.

Also, feel free, if you wish, to avoid the drama and say, "Here's the C source code," which will be worth a certain amount of hero worship.

Everything appears to use avrdude and so I'm trying to parse that as well.


1 Answer 1


Only from bootloader section is it possible to write to flash on ATmega2560. Optiboot 8 has a do_spm function to write to flash. It is accesible over a header file available in examples in the Optiboot GithHub repository.

After the updated application binary is written to free part of the flash by the running application it is necessary to copy the updated application to run location from address 0. This must be done again by the bootloader.

Optiboot builds in MCUdude Mega Core and Mighty Core have Optiboot enhanced with my copy_flash_pages function which copies the pages and then resets the MCU.

My ArduinoOTA library uses do_spm and copy_flash_pages function to store and apply uploaded sketch binary. The InternalStorage object can be used to apply a downloaded binary too.

  • 1
    What I'm seeing handles the downloads. Is there something here that installs those downloads into the Mega 2560? I am pushing from a tablet.
    – Thom
    Commented Jun 25, 2021 at 18:56
  • 1
    it is a self update. calling InternalStorage.apply replaces the sketch with the downloaded binary
    – Juraj
    Commented Jun 25, 2021 at 19:43
  • posted another question here: arduino.stackexchange.com/questions/85142/… about how to change a serial port to the one used by HC-05. can't find an example, but it seems basic.
    – Thom
    Commented Jul 12, 2021 at 16:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.