Reset required after doing SPM -- or can the SPMEN bit in SPMCR be trusted?

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

I have a modified version of the  AVR231 bootloader--actually modified version of  the port to gcc that's posted on this website.

 

After all the application code has been saved to flash (and data to eeprom), an spmEnableRWW() function is executed.  This is supposed to enable RWW of the loaded code and loop until it's enabled.  A CRC check of the newly, self programmd flash is then done.

 

However, while doing the CRC,the function pgm_read_byte returns 0xff at every address.

 

#define pgm_read_byte (   address_short )    pgm_read_byte_near(address_short)

 

In debug mode using the dragon, flash memory also shows all 0xff.

 

If I set a break point anywhere (in AS 6.2) suddenly Dragon's display of flash memory is valid--not all 0xff.  Furthermore, subsequent pgm_read_byte calls result in valid CRC (after processing all of the newly loaded memory).

 

Doing the CRC immediately after a RST also works.

 

After self programming flash, the spmEnableRWW function is called.  I think this should enable the applicaiton code to be read?

 

The assembly code C function spmEnableRWW() maps to is pretty much right out of avr231:

 

 

 

spmEnableRWW:

    ldi     r19, (1<<RWWSRE) | (1<<SPMEN)
    rjmp    spmSPM

 

....

 

spmSPM:

spmWait:
    LOAD    r23, SPMCR
    sbrc    r23, SPMEN
    rjmp    spmWait

 

 

 

 

So, I think the code will be in the spmWait loop until the application code section can be read.  However, I see no looping at all, SPMEN bit says it's ready the first time through the loop (this is suspicious).

 

The original AVR gcc code actually used the WDT to generate a RST after the application code was programmed.  I changed to code to only do the CRC after programming, rather than every time the processor is booted.

 

I can change the code to only do the memory CRC after a RST, but I'd like to understand why the spmEnableRWW isn't working. 

 

I thought maybe this was a quirk of being in debugWire mode and specifically cards that were difficult to get out of debugWire mode.  I got some great help from this forum to get out of debugWire mode, but the problem is still there.

 

After self programming application memory I have a simple loop that doesn't exit while pgm_read_byte is returning 0xff.  It flashes LEDs while 0xff is returned.  That loop never exits, so nowI know that application memory can't be read when not in debug mode.

 

I see this on two different cards. 

 

 

 

 

 

 

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

Should have said that the processor is atmega328P.   No memory lock bits have been set.

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

FWIW, I think AMFORTH uses SPM to save words to flash, without doing a subsequent reset.

 

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

I know that this works. I once wrote some app updating code (not a true bootloader) using:

 

http://www.nongnu.org/avr-libc/u...

 

At the time I made the mistake of forgetting to call boot_rww_enable (); at the end and saw the exact effect you are seeing. When I connected up the JTAG I could see that the entire app space was just 0xFF. I scratched my head for a while then reread the bit in the datasheet about access to the app section and finally it twigged. Once I made the boot_rww_enable() call all was well.

 

Just out of interest why are you reimplementing spmEnableRWW() when it just sounds like it does the same as the standard boot_rww_enable() in <avr/boot.h> ?

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

The spmEnableRWW is definitely getting executed.  I step through it in the debugger.  (But I think I should be in the SPM delay spin loop for many cycles instead of falling through the first time).

 

Also, it's very wierd that setting a breakpoint in the debugger makes the RWW flash readable!

 

Just out of interest why are you reimplementing spmEnableRWW() when it just sounds like it does the same as the standard boot_rww_enable() in <avr/boot.h> ?

 

That's what the AVR231 code (ported to gcc) had, so I never changed it.  Maybe I should try NOT running the .S version?

 

Thanks!

 

Dave Thomas

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

 I step through it in the debugger.

I forget but I thought some of this SPM stuff had time constraints? If so then stepping in the debugger probably won't cut it and you would need to let it free run to a breakpoint (but something still in the BLS in case the app section doesn't become visible!)

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

I only stepped through the spmEnableRWW() code to debug why I was failing in the subsequent CRC check of memory.  So, that might be why it didn't work when I was debugging.

 

But, even when I don't step through that code and run to a breakpoint after that code has been executed, the debugger shows flash memory as all 0xff.   Code will run in a loop checking for anything but 0xff forever.  But, if I break using the debugger AND then set a breakpoint, the memory is accessible by both the debugger and my code.

 

Still, I thought it my be an issue only when in debug mode, but I've confirmed that only 0xff is read after the spmEnableRWW() even when not in debug mode.   (I use LEDS to indicate that I reached certain points of the code instead of depending on the debugger.)

 

I got side tracked on another AS 6.2  issue, I'll try out using the spmEnableRWW()  avr/boot.h when I can get back to avr stuff late this afternoon.  I can make everything work fine by writting to eeprom to communicate what should be done after RST, so if I can't figure out why the spmEnableRWW() doesn't seem to be reliable, I'll just do that.  Unless someone else is interested--then I'll do whatever experiments make sense.

 

Thanks!

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

spmEnableRWW:

    ldi     r19, (1<<RWWSRE) | (1<<SPMEN)
    rjmp    spmSPM

 

....

 

spmSPM:

spmWait:
    LOAD    r23, SPMCR
    sbrc    r23, SPMEN
    rjmp    spmWait

Where does it actually do the SPM ?  Or, did I miss something ?

Mike Adams
ADI Development, Inc.
http://www.adidev.com

... When it has to actually work.

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

I'm guessing the next opcode after the rjmp that wasn't shown ;-)

 

(clearly the loop is waiting for SPMEN to clear in SPMCR before it does it).

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

The SPM is done before the spmEnableRWW().   

 

You can' read program he application memory segment while doing SPM.  Once SPM programming is finish, then you can use the spmEnableRWW() to read flash from the application section.

 

There are many op codes between where the spmEnableRWW() and the attempted read of the application flash is done.  It doesn't matter how many--it never becomes readable unless I set a break point (or do a reset).

 

I don't mean running to a break point, I mean just setting a breakpoint.   For some reason, that lets Studio read the flash and  subsequenty program_read_bytes  from the CRC checking code return valid data instead of 0xff.

 

 

Last Edited: Thu. May 14, 2015 - 03:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can' read program he application memory segment while its readable. 

 

Meant to say:

 

You can't write application memory segment while it's readable.

 

 

 

 

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

Below is  the code fragment where the self programming takes place.

 

The last record sent is the fytpe RESET record.   Original implementation loops  forever after doing the SPMEnableRWW which results in the WDT timing out (and a reset).  The CRC check is then done right after reset.

This works fine, and I guess I'll just go back to that approach.  

 

Just seemed like it should work without having to do the reset, but maybe this is why it was coded for an expiring wdt reset in the first place.  Otherwise, it just seems harder to read the code and understand than "just doing it" (the CRC after programming, I mean).

 

       

switch (ftype)       

{
                            // Erase page
                            case TYPE_ERASE:
                            {
                                #if defined(RAMPZ)
                                spmErasePage(address, bits);
                                #else
                                spmErasePage(address);
                                #endif
                                pagesTouched++;
                            }
                            // Fall-through!

                            // Prepare for incoming data chunks by copying the page
                            // contents into the page buffer
                            case TYPE_PREPARE:
                            {
                                #if defined(RAMPZ)
                                memcpy_PF(pageBuffer, bits, address, size);
                                #else
                                memcpy_PN(pageBuffer, address, size);
                                #endif
                                break;
                            }

                            // Chunk of data is written into the page buffer
                            case TYPE_DATA:
                            {
                                uint8_t *pPageBuff = &pageBuffer[(uint16_t)(address) & 0xffff];

                                do
                                {
                                    *pPageBuff++ = *pRcvBuf++;
                                }
                                while (--size);

                                break;
                            }

                            // Program page buffer into flash page
                            case TYPE_PROGRAM:
                            {
                                #if defined(RAMPZ)
                                spmWritePage(address, pageBuffer, size, bits);
                                spmErasePage(address, bits);
                                spmProgramPage(address, bits);
                                #else
                                spmWritePage(address, pageBuffer, size);
                                spmErasePage(address);
                                spmProgramPage(address);
                                #endif
                                break;
                            }

                            // Write a chunk of data into EEPROM
                            case TYPE_EEPROM:
                            {
                                //_delay_ms(1000);
                                do
                                {
                                    wdt_reset();
                                    loop_until_bit_is_clear(EECR, EEPE);
                                    loop_until_bit_is_clear(SPMCSR, SPMEN);
                                    EEAR = (uint16_t)address++;
                                    EEDR = *(pRcvBuf++);
                                    set_bit(EECR, EEMPE);
                                    set_bit(EECR, EEPE);

                                    loop_until_bit_is_set(EECR, EEPE);
                                }
                                while (--size);

                                break;
                            }

                            // Write Lock Bits
                            case TYPE_LOCKBITS:
                            {
                                spmWriteLockBits(bits);
                                break;
                            }

                
                            case TYPE_RESET:
                            {
                                transceive(csn,Error_OK);
                                spmEnableRWW();
                                // Turn red LED off to indicate done with loading bootstrap records
                                SYNC2_HIGH;
                                WDT_off();
                            
                                return;

                            }

 

 

 

Last Edited: Thu. May 14, 2015 - 03:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think your problem is being locked in debugWire mode. cheeky

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

I'm not locked in debugWfre mode.

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

Not funny, eh?  (I thought given the other thread...)

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Well, I actually was thinking it WAS because I was stuck in debugWire mode.  

 

The only two cards I had on hand were ones I didn't ship as part of system because they were stuck in debugWire mode.  So, I needed to get them out of debug mode to make sure it wasn't a quirk.

 

That's why I wasn't sure you were joking---not such a ridiculous thought.