0
\$\begingroup\$

I want to write bootloader for avr atmega328p in C language. I want to perfom a page erase:

So I have to write the address of the z pointer. // Don't know how to implement in c code; Then make SPMEN AND PGERS bits high. // SPMCSR = (1 << SPMEN) | (1 << PGERS); Then execute SPM instruction within the next 4 clock cycles // Don't know code;

My 1st question is how do I access the Z-register in order to write the address of the page to be erased, Like I have been able to access the SPMCSR register and set the SPMEN and PGERS bits. something like ZPOINTER = 0x00FFEE;

My second question is that, in the datasheet it states that in order to erase the page at a certain address you have to SET the SPMEN and the PGERS bits, then you execute an SPM instruction within the next 4 clock cycles. How do I execute the SPM instruction after setting those aforementioned bits in C code?

Help will be highly appreciated. Thanks. And I throughly searched for similar info on the internet and came with nothing.

\$\endgroup\$
  • \$\begingroup\$ You may need to use in line assembly for this \$\endgroup\$ – alex.forencich Jan 22 at 17:34
  • \$\begingroup\$ @alex.forencich are you saying its impossible to implement in C? \$\endgroup\$ – tmoeti Jan 22 at 18:12
  • \$\begingroup\$ Look at AVR109 source code. It has everything you need. I used it with an ATmega8, but implementation for a 328p should not be much different. \$\endgroup\$ – filo Jan 22 at 18:26
  • \$\begingroup\$ @filo Thanks for the referral to AVR109 source code. \$\endgroup\$ – tmoeti Jan 22 at 18:56
  • 1
    \$\begingroup\$ @ChrisStratton Thanks, my date with AVR109 source code is coming on well now. \$\endgroup\$ – tmoeti Jan 22 at 22:39
0
\$\begingroup\$

Here's a way to do it in GCC using asm(). The rest of the bootloader was in C except for enabling and disabling interrupts.

while (NVM_STATUS & NVM_NVMBUSY_bm) ;
NVM_CMD = NVM_CMD_LOAD_FLASH_BUFFER_gc;

// load bytes into page buffer
p = flash_RAM_buffer;

for(ix = 0; ix < 512; ix+=2) {
    asm("ld r0, %a0+":: "z" (p) : "r0");
    asm("ld r1, Z"::: "r1");    // load R0:R1 from flash_RAM_buffer
    asm("movw r30, %0":: "w" (ix) : "r30","r31");   // load Z with ix;
    asm("spm"::);               // not change protected
    asm("clr r1"::);
    p += 2;
    }

asm("ldi r30, 0" ::: "r30");        // low byte of flash address (ignored)
asm("mov r31, %0" :: "r" (curr_flash_address.uval8.ML) : "r31");
asm("out __RAMPZ__, %0" :: "r" (curr_flash_address.uval8.MH));

NVM_CMD = NVM_CMD_ERASE_WRITE_APP_PAGE_gc;
asm("cli"::);
CPU_CCP = CCP_SPM_gc;    // set change control register to enable
asm("spm"::);
asm("clr r1"::: "r1");
asm("sei"::);

curr_flash_address is a union that allows accessing it as 32, 16 or 8 bit variable.

\$\endgroup\$
  • \$\begingroup\$ I can't really can't understand assembler, but I am studying AVR109 source code, I think it will sort me out. Thanks for the effort though, highly appreciated. \$\endgroup\$ – tmoeti Jan 22 at 22:41
  • \$\begingroup\$ You're going to have to use assembler since the register setup is quite specific to write xMega flash memory. R0 and R1 need to be loaded with a word and the Z register needs to have the destination flash address before executing the SPM instruction. That can't be done in C alone. The GCC asm() extension is needed. \$\endgroup\$ – Warren Feb 3 at 1:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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