RWWSB bit always set after writing flash

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have written a bootloader that receives a new program from the UART and programs it into the flash as soon as it receives a full page. I have ISRs for the UART Tx, Rx, and SPM_READY.

I'm having an issue with the last page of flash not being written. I tried delaying for as long as 750 ms (an eternity in CPU time!) but the last page was never written. However, If I reset the MCU, the last page is immediately written.

I'm using an ATMega162.

The basic flow of the program is:

1. Rx ISR tells main that a frame was received.
2. Main pushes new data onto temp page buffer.
3. If temp page buffer is full, erase the page and enable SPM interrupt.
4a. Send a request down the UART for the next frame.
4b. When SPM interrupt fires, write the page.

The thing that really has me puzzled is that resetting the CPU causes the last page to be written, but delaying does not. What could cause this? Any help would be greatly appreciated.

Last Edited: Tue. Aug 28, 2007 - 10:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What you say doesn't make sense. How could a reset cause a page to be written? Clearly it HAS already been written by the time the thing is reset. Suggests your readback/checking mechanism may be the thing at fault.

Remember that at the end of page programming, if you try to read the app space flash and haven't cleared the ASRE/RWWSRE you'll just get 0xFFs read back.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think you're right. The problem is not that the page isn't being written, it's that the bootloader is being blocked from reading the flash. The entire application's flash shows up as FFs in the debugger, and the RWWSB bit is set.

I RTFMed on the RWWSRE bit and tried adding the following code just before reading the flash:

SPMCR |= (1 << RWWSRE)|(1 << SPMEN);
while(SPMCR & (1 << RWWSB));

The program gets stuck in the while() loop forever. If I break, I can see that the RWWSB bit is still set. What could be causing the RWW section to be busy even if I try forcing a read enable?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As you are posting in the GCC forum I take you are using GCC? In that case why try to re-invent the wheel? All the routines you need are in and there's even a piece of example code shown at the top of the file. Notice how, just before the return from the function, a call to:

        // Reenable RWW-section again. We need this if we want to jump back
        // to the application after bootloading.

        boot_rww_enable ();

is made? That's what you want. As you'll see the body of that boot_rww_enable() is:

#define __boot_rww_enable()                      \
({                                               \
    __asm__ __volatile__                         \
    (                                            \
        "sts %0, %1\n\t"                         \
        "spm\n\t"                                \
        :                                        \
        : "i" (_SFR_MEM_ADDR(__SPM_REG)),        \
          "r" ((uint8_t)__BOOT_RWW_ENABLE)       \
    );                                           \
})

and

#define __BOOT_RWW_ENABLE         (_BV(SPMEN) | _BV(__COMMON_ASRE))

So what your code above that is "getting stuck" appears to lack is an actual SPM opcode.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks cliff, that fixed it. I think it's a little strange that you have to use the SPM instruction to unlock the application section, though ;) .

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

All the SPM instruction itself really does is say "give one clock to the self programming state machine". So it seems to make sense that you first tell it what state you'd like it to go to next using SPMCR and then actually clock it into that state with an SPM

Cliff