Problems with writing to internal flash memory

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Problems with writing to internal flash memory

Jump to solution
1,485 Views
MJWeston
Contributor III

Hello,

 

I added a bootloader to my project and it does work but I am having some trouble with it.  I will explain and maybe there is something commonly known that I am just missing.  The microcontroller core used is the MC9S08GB60A in the MC13213 chip.

 

First, my bootloader is entirely custom except for using the file doonstack.asm provided by Freescale in one of their application packages.  It is 4KB in size, protected, and uses hardware vector relocation (I use no ISR in my bootloader for simplicity).  I have an onboard EEPROM that stores the new firmware to be flashed into the chip and a configuration area that the bootloader uses to decide if it should update or not.  This all works fine.  My bootloader and main app are two separate projects so no code sharing occurs.

 

The problem is that when I create one .S19 file with my main app and bootloader together, the flash routine in the bootloader will fail to successfully alter the flash at the same point every time.  If I build the bootloader and just send it alone over JTAG, it succeeds.  On some boards, it ALL just works fine and on others it won't flash unless freshly loaded over JTAG.

 

My CPU clock is the internal 8MHz one and FCDIV is set to (4000000L/200000L)-1 which equals 19.  I also tried 20 to slow it down a bit more.

 

My firmware starts at 0x1080 and packets of 64 bytes (generally two lines in the S-record file) are passed to the FlashProgBurst function.  I have tried erasing all areas of the chip below the bootloader first before flashing anything and I also tried a dynamic eraser that clears each block as it is needed.  For example, data starting at 0x1080 would erase the area designated as 0x1000 to 0x11FF and then flash those values. Data starting at 0x10C0 would erase nothing and then get flashed in.  0x1100 would erase nothing, etc. etc.  Data starting at 0x1200 would erase the area from 0x1200 to 0x13FF and then load the data in.  Most of the time, flashing fails when I write to 0x1200.  Trying to step through the bootloader using the JTAG debugger generally makes the flashing fail right at 0x1080 so I now use messages out through the UART to determine where things are failing.  Maybe the flash controller doesn't like the background interface running.

 

Am I understanding the memory map correctly?  According to the RM: "a high block of 59348 bytes (115 pages of 512 bytes each plus 1 page of 468 bytes) and a low block of 1920 bytes."  The low block is 1920 bytes but do I still erase it in 512 byte chunks or just send the erase command anywhere in this 1920 byte area?  I seem to get the best results sticking to 512 byte chunks with the boundaries assumed to begin at 0, then 512, 1024, etc.

 

Thanks for any help you can give,

 

 

Michael

Labels (1)
0 Kudos
1 Solution
910 Views
MJWeston
Contributor III

I think I just fixed it.  I removed these lines from the erase function in doonstack.asm:

; see Errata: SE133-FLASH : Unexpected Flash Block Protection Errors
;   STA ,X              ;latch the unprotected address from H:X
;   NOP                     ;brief delay to allow the command state machine to start
;   STA ,X              ;intentionally cause an access error to abort this command


Without that abort stuff, it actually does the erase and reads back as 0xFF before I write new data to it.  It looks like I can wrap this up today but if you think I removed something important, please let me know.  This code was probably written for some other slightly different variant of the CPU that I don't have.



Michael

View solution in original post

0 Kudos
7 Replies
910 Views
bigmac
Specialist III

Hello Michael,

Michael Weston wrote:

The problem is that when I create one .S19 file with my main app and bootloader together, the flash routine in the bootloader will fail to successfully alter the flash at the same point every time.  If I build the bootloader and just send it alone over JTAG, it succeeds.  On some boards, it ALL just works fine and on others it won't flash unless freshly loaded over JTAG.

Are you attempting to program both bootloader and application code using existing bootloader code?  If so, this would seem a recipe for disaster.  If simultaneously programming both, you should be using the Multilink.  To re-program a currently write-protected area, you would need a mass erase.

When using the Multilink for programming the application code, there would need to be a special configuration for the compile and link process, so that the application vectors within the S19 file are at the redirected address, rather than the standard vector table location.  This need not apply when the application is programmed by the bootloader, provided the bootloader itself relocates each vector address for the application.

You did not say which flash block fails to program, and its relationship to the bootloader or application code?  You also did not mention whether you are setting the non-volatile trim value for the internal reference, during programming of the bootloader.  When untrimmed, there is a wide tolerance for the reference frequency, that may be problematic for the flash clock.  The flash clock frequency requirement is 175kHz +/-14%, whereas the untrimmed reference could be 243kHz +/-25% for a worst case tolerance.  Obvioulsy, the trim value is specifiic to each MCU device.

Regards,

Mac

0 Kudos
910 Views
MJWeston
Contributor III

Hi Mac,

Thanks for getting back to me on this so promptly.  I'll try to offer some extra clarity.

> Are you attempting to program both bootloader and application code using existing bootloader code?

No.  Since the bootloader and application are two separate Codewarrior projects, I build each one on its own.  Then I open both .s19 files in a text editor.  I copy all of the S1 entries plus the S9 entry from the bootloader file into the application file at the end of it, deleting the S9 from the application file (not that it really matters).  I load this one new .s19 file onto the board by creating an image for the Cyclone Pro programmers we have.  In the bootloader .s19 records are the addresses used to secure the boot area and enable vector redirection.  My bootloader uses no interrupts and the redirection works flawlessly.  My application code has no idea it got moved around. :smileyhappy:

> You did not say which flash block fails to program, and its relationship to the bootloader or application code?

I mentioned that it fails at 0x1200 which is the main one.  One time it was a bit higher in the range (but still in that lower block I think) and when I try to debug the bootloader, it fails a lot on the very first write (0x1080).  Then there are other boards that just work start to finish but the way I load the EEPROM with the new firmware is time consuming and so grabbing 50 boards to see how many will work is tough.  In the end, it should work on all of them.

> When untrimmed, there is a wide tolerance for the reference frequency, that may be problematic for the flash clock.  The flash clock frequency requirement is 175kHz +/-14%, whereas the untrimmed reference could be 243kHz +/-25% for a worst case tolerance.

I enable the trim feature during the image creation for the Cyclone Pro but it has a default value of 243KHz.  Are you saying I need to trim it to center around 175KHz?  The text above the field says I can't go less than 182.25KHz so that can't be it.  I feel like this clock drift is going to be the key to figuring this out so I will investigate further.  If you can help me clarify this clock trim requirement for flash access, I'm sure I can sort it out.

Thanks again for the advice!

Michael

0 Kudos
910 Views
bigmac
Specialist III

Hello Michael,

You should trim the infernal reference for the default frequency of 243kHz.  The non-volatile trim value will be programmed into flash memory, at address 0xFFBE.  The bootloader code will need to write this value to the ICGTRM register.

The ICG output frequency will be determined by the ICGC2 register, in particular the MFD bit field (N value) and the RFD bit field (R value), using the expression:  (f irg / 7) * 64 * N / R

The POR default setting will provide N = 4, R = 1, for a trimmed module output frequency (ICGOUT) of 8.88 MHz.  However, in accordance with Fig. 1.2 in the datasheet, the bus frequency will be one half this value, at 4.44 MHz.  To provide a flash clock between the limits 150-200 kHz, FCDIV should be set to a value between 22 and 28 inclusive.  Your previous setting would give a flash clock frequency that is too high, and might be the cause of your intermittent programming problem.

Since FCDIV is a write once register, this should be written only as you are about to program flash using the bootloader.  Then assuming that a further reset is required for the bootloader to cause a jump to the start of the application code, this would allow flexibility for the application to use a different bus frequency than the bootloader, and maintain the capability for the programming of non-volatile variables by the application.

As I previously alluded to, the application section of the composite S19 file will require that its vector entries incorporate the translation from the normal vector addresses, to the relocated address range below the bootloader.  Only the bootloader reset vector should be programmed within the normal vector range.

Regards,

Mac

0 Kudos
910 Views
MJWeston
Contributor III

Hi Mac,

I've spent some time with this and the clock might not be the problem.  I trimmed the clock and even used the external 16MHz crystal from the radio section.  The results were the same.

From what I can see, the FlashErase function isn't working properly.  The reason the bootloader worked after a JTAG programming is because it set all unused areas back to 0xFF for me, basically covering up the erase failure.

In my code, erasing block by block as needed results in a read back after write failure at 0x1200 so erasing the blocks between 0x1080 and 0x11FF seems to work.  Erasing the entire application area before writing anything results in read back failure at 0x186C.  The second one seems simpler to diagnose so I will show my erase code:

FlashErase((uint8_t *)(0x1080));

FlashErase((uint8_t *)(0x1200));

FlashErase((uint8_t *)(0x1400));

FlashErase((uint8_t *)(0x1600));

FlashErase((uint8_t *)(0x182C));

for(i=13;i<(107+13);i++)        //Start at 0x1A00, last one is 0xEE00

    FlashErase((uint8_t *)(uint16_t)((uint16_t)i*512));


Maybe the CodeWarrior software is compiling these addresses wrong because it seems like only the hard coded addresses are working (well, except whatever is going on at 0x186C).  I'll keep at it but any advice would be greatly appreciated.


*** I also want to mention that the FlashErase code is straight out of doonstack.asm and not something I wrote.  It is well tested and documented code that just doesn't seem to want to work for me.  I wrote a new piece of code to call the functions in doonstack.asm that erases a block, writes data to it, erases it again and then writes different data to it that has a different bit pattern.  It fails to erase every time and the resulting data is the combination of all bits that can be forced to '0'.


Thanks!


Michael

0 Kudos
911 Views
MJWeston
Contributor III

I think I just fixed it.  I removed these lines from the erase function in doonstack.asm:

; see Errata: SE133-FLASH : Unexpected Flash Block Protection Errors
;   STA ,X              ;latch the unprotected address from H:X
;   NOP                     ;brief delay to allow the command state machine to start
;   STA ,X              ;intentionally cause an access error to abort this command


Without that abort stuff, it actually does the erase and reads back as 0xFF before I write new data to it.  It looks like I can wrap this up today but if you think I removed something important, please let me know.  This code was probably written for some other slightly different variant of the CPU that I don't have.



Michael

0 Kudos
910 Views
bigmac
Specialist III

Hello Michael,

I do not use the "doonstack" method, but use a fixed block of RAM (at the bottom of the stack) for during erasing and programming flash, which I consider to be simpler.  Additionally, I also tend not to use burst programming.  The additional time required for byte-by-byte programming will still be shorter than the page erase period, so IMHO not worth the extra complication for most projects.

However, I did check out a version of the doonstack approach that I have on hand, and may not be the most recent offering.  I assume that you are referring to the code for the 'SpSub' sub-routine that gets transferred to the stack?  This code for the version that I have, is as follows:

; Sub-routine code transferred to the stack for execution

SpSub:    ldhx   LOW(SpSubSize+4),sp ; get flash address from stack
          sta    ,x             ; write to flash; latch addr and data
          lda    SpSubSize+3,sp ; get flash command
          sta    FCMD           ; write the flash command
          lda    #mFCBEF        ; mask to initiate command
          sta    FSTAT          ; [pwpp] register command
          nop                   ; [p] want min 4~ from w cycle to r
ChkDone:  lda    FSTAT          ; [prpp] so FCCF is valid
          lsla                  ; FCCF now in MSB
          bpl    ChkDone        ; loop if FCCF = 0
SpSubEnd: rts                   ; back into DoOnStack in flash

SpSubSize: equ (*-SpSub)

As you can see, there is only a single write within the flash page being erased, so I do not know the reason for the second write operation.  The flash erase sub-routine is as follows:

FlashErase1:

          PSHA                  ; Adjust SP for DoOnStack entry

          LDA    #(mFPVIOL|mFACCERR) ; Mask

          STA    FSTAT          ; Abort any command & clear errors

          LDA    #mPageErase    ; Mask pattern for page erase command

          BSR    DoOnStack      ; Execute stack-based sub-routine

          ais    #1             ; Deallocate data location from stack

          rts


Regards,

Mac

910 Views
MJWeston
Contributor III

Thanks for the feedback Mac.  Your code example doesn't have that abort stuff either so I have removed it permanently and set up a system of five units running production firmware to test the bootloader.  All units updated with no errors now that this code is gone.  It will have to undergo a lot more testing before shipping to customers but I think I can work with it now.

Take care,

Michael

0 Kudos