This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Odd problem with FlashLib.

Hello,

I'm having a rather odd problem with FlashLib 1.06. My device is an TMS470M X4MF03107 . I am (for various reasons) obliged to have the watchdog turned on and I am trying to erase a sector in flash bank 0 (the sector at 0x20000, in fact).  I'm using EABI, no VFP.

The main body of my code is in sector 0 at 0x00000, and I have copied both my relevant routines and the pf035 flash library (v 1.06) into RAM starting at 0x8000100.

I'm following the instructions in SPNU493C S6.3 and S6.4.

With the watchdog off, everything works just fine - Flash_Erase_B() is a little slow, but it gets there in the end, I can program my flash and checksum it to prove that it's right and all is happy.

With the watchdog on, I get a watchdog reset whilst trying to run Flash_Erase_B(). Compacting the sector works just fine and I am doing that before I try erasing.

A little disassembly gets me to the code:

start = 0x20000

flashCore = FLASH_CORE0

delay = 90 (overkill, since HCLK=80MHz, but setting delay=40 makes no difference)

flashControl = 0xFFF87000

setup_state_machine(start, flashCore, delay, flashControl)

Flash_Start_Command_B(start, flashCore, delay, flashControl, CMND_ERS_SECT, 0xFFFF)

The Flash_Start_Command_B() causes a watchdog reset. If I turn the watchdog off, Flash_Start_Command_B() will return very happily so it isn't that I am going off into the weeds.

A little more investigation (read: overwriting bits of the RAM-resident copy of the library with NOPs) suggests that  Flash_Start_Command_B() calls IssueCommand, which calls IssueCommand_U16() twice. The second such call takes a very long while to return, the watchdog gets bored and reboots me.

My question is: what is it that I am doing that has angered the hardware so? And how do I stop doing it? Turning off the watchdog is not an option and neither is leaving this product without an upgrade facility.

I am pretty certain that I am not accidentally accessing Flash whilst trying to program - I've done that before and it leads to an outright hang if the watchdog is off. In this situation, control does eventually return (and the command has succeeded), but too late.

  • In case anyone recognises a culprit, the time for which the CPU hangs is 1.38s, and this seems to be independent of what was in the flash bank at the time.

    I have temporarily hacked around the problem by reducing my RTICLK to 2.5MHz and having a 6s watchdog, but I hope no-one will seriously suggest that this qualifies as a solution.

  • Hello Richard,

    Flash_Start_Command_B() calls the following functions:

    setup_state_machine()

    IssueCommand()  // Command issued is clear status register

    |_> IssueCommand_U16()  // On TMS470M06607

    or

    |_> IssueCommand_U32()  // On TMS470M04207/03107

    IssueCommand()  // Program command for address and data

    |_> IssueCommand_U16()  // On TMS470M06607 - write 16bits of data

    or

    |_> IssueCommand_U32()  // On TMS470M04207/03107 - write 32bits of data

    return;

    setup_state_machine() is the only function that should take a significant amount of time to execute, therefore it makes calls to the user re-definable Feed_Watchdog_V().  The function Feed_Watchdog_V() is meant for the user to overwrite with their own version of the function with the steps necessary to service their watchdog timer.

    The IssueCommand_Uxx is 3 lines of C assignments and no looping or decision constructs and therefore should not take any significant amount of time to execute.

  • Hello,

     You're quite right in what you say and this is what is confusing me!

     I do have a Feed_Watchdog_V() and setup_state_machine() conscientiously calls it, and it pats the watchdog just fine.

     What I can't account for is why IssueCommand_U32() is hanging. The relevant bit of assembler is:

    8000968: Flash_Start_Command_B:
    8000968: .thumb
    8000968: B5F8 PUSH {R3, R4, R5, R6, R7, LR}
    800096a: AF06 ADD R7, SP, #0x18
    800096c: 1C1C ADDS R4, R3, #0x0
    800096e: 1C0E ADDS R6, R1, #0x0
    8000970: 1C05 ADDS R5, R0, #0x0
    8000972: F7FFFBC5 BL 0x08000100
    8000976: 2800 CMP R0, #0x0
    8000978: D001 BEQ 0x0800097E
    800097a: 2000 MOVS R0, #0x0
    800097c: E016 B 0x080009AC
    800097e: $C$L1:
    800097e: 1C30 ADDS R0, R6, #0x0
    8000980: 1C21 ADDS R1, R4, #0x0
    8000982: F000F859 BL 0x08000A38
    8000986: 2310 MOVS R3, #0x10
    8000988: 1428 ASRS R0, R5, #0x10
    800098a: 0400 LSLS R0, R0, #0x10
    800098c: 4909 LDR R1, $C$CON1 [0x80009b4]
    800098e: 180E ADDS R6, R1, R0
    8000990: 9400 STR R4, [SP]
    8000992: 1C1A ADDS R2, R3, #0x0
    8000994: 1C30 ADDS R0, R6, #0x0
    8000996: 1C29 ADDS R1, R5, #0x0
    8000998: F7FFFFC4 BL 0x08000924
    800099c: 9400 STR R4, [SP]
    800099e: 887A LDRH R2, [R7, #0x2]
    80009a0: 1C30 ADDS R0, R6, #0x0
    80009a2: 1C29 ADDS R1, R5, #0x0
    80009a4: 687B LDR R3, [R7, #0x4]
    80009a6: F7FFFFBD BL 0x08000924
    80009aa: 2001 MOVS R0, #0x1
    80009ac: $C$L2:
    80009ac: BCF8 POP {R3, R4, R5, R6, R7}
    80009ae: BC04 POP {R2}
    80009b0: 4710 BX R2
    80009b2: 46C0 MOV R8, R8
    80009b4: $d:
    80009b4: $C$CON1:
    80009b4: 0000 .half 0x0000
    80009b6: 5550 .half 0x5550

    0x08000924 is IssueCommand

    (as obtained from dis470). If I do a:

    *((uint32_t *)0x80009a6) = 0xBF00BF00;

    Before running Flash_Start_Command_B(), return is almost instant (but of course the erase operation never happens). If I don't, Flash_Start_Command_B() takes 1.38s to return - as timed by raising a GPIO just before Flash_Start_Command_B() and lowering it again just after, and timing the pulse on a scope.

    I can only think that I am doing something appalling like accidentally referencing constants in Flash, or failing to set up a clock somewhere, thereby confusing the Flash hardware itself into waiting some internal bus for a long time, but I can't see how - I can mail you (or attach I guess?) an assembler listing for the whole flashlib that I'm relocating into RAM? I've tried checksumming my RAM and it's the same before and after the operation.

  • (I should perhaps mention that what I reckon is happening is that I have given the (silicon) flash engine some patently bogus setup data that it is conscientiously acting on - I'm just not sure what data I should have given it so working out what precisely is wrong is perplexing me .. )

  • Do you have interrupts enabled during the Flash operation?  If an interrupt occurs while a Flash operation is occurring, the core will hang until the flash operation is finished.   Basically any reads of Flash memory while a program or erase operation is occurring in the same bank will cause a core stall until the flash operation is finished which sounds like the behavior you are seeing.

  • Great minds .. - I was just thinking that! I shall check that our DI() operation actually Ds the Is and get back to you - and many thanks for confirming that bit of flash behaviour!

     

  • Hello Richard,

    What is the actual code you are calling setup_state_machine() with?  I am especially interested in the type given to flashControl.  The long time for the function to come back may be induced if the setup_state_machine() does not setup the Flash Controller properly.  Also, delay should be 40 as 90 will cause longer execution times. Flash_Start_Command_B() already calls setup_state_machine() and Flash_Sector_Select_V(), I will show 2 different options.

    When I am using the API, I would have done this (using your variable names previously presented):

    Option A:

    UINT32 *flashControl = 0xFFF87000;

    delay = 40;

    if (setup_state_machine((UINT32 *)start,flashCore,delay,(FLASH_ARRAY_ST)flashControl) != FAPI_ERROR_CODE_SUCCESS)

    {

    // Handle error code

    }

    Flash_Sector_Select_V(flashCore,(FLASH_ARRAY_ST)flashControl);

    Flash_Start_Async_Command_B((UINT32 *)start,flashCore,delay,(FLASH_ARRAY_ST)flashControl, CMND_ERS_SECT, 0xFFFF);

    . . .

    Option B:

    UINT32 *flashControl = 0xFFF87000;

    delay = 40;

    Flash_Start_Command_B((UINT32 *)start,flashCore,delay,(FLASH_ARRAY_ST)flashControl, CMND_ERS_SECT, 0xFFFF);

    Also what is the value you have in FRDCNTL register?

  • Hello John,

    Right. Sorry for the radio silence - it turns out that our interrupts were a lot more interesting than I had anticipated. I have now sorted them all out, our DI() and EI() nest properly and actually do now disable interrupts (the previous culprit was SysTick() which isn't run by the VIM and was therefore escaping - the RTI was in any case a better way of doing this and is now how we do it).

    DI(); asm("  wfi"); EI(); print("Oops!"); now never prints oops, but DI(); EI(); print("Oops!") does.

    That's the good news. The bad news is that it doesn't change the behaviour of the flash.

    The second bit of bad news is that it appears to be possible to get the flash engine so confused that NowFlash will refuse to touch it (can connect but hangs before printing its erase messages) until you power-cycle the TMS470M - a reset won't work.

    I'll now go through your comments above (for which many thanks) and see if I can make my life better. Sorry again for the long delay.

  • So, using Flash_Erase_B() and delay=40 gets me to 880ms of delay.

    Using flashControl = 0xFFF8700  (note lack of the last zero) in either of your examples above causes my watchdog to fire. One in three or four times or so, this seems to launchus into a hang so severe that toggling the RESET line won't get us out of it.

    Any of the #if'd options in:

    #if 1
    /* John Hall's option A */
    flashControl = (UINT32 *)0xFFF87000;
    delay = 40;
    if (setup_state_machine(start, flashCore, delay, flashControl) != FAPI_ERROR_CODE_SUCCESS)
    {
    return FALSE;
    }
    Flash_Sector_Select_V(flashCore, (FLASH_ARRAY_ST) flashControl);
    #if 0
    Flash_Start_Async_Command_B(start,
    flashCore,
    delay,
    (FLASH_ARRAY_ST)flashControl,
    CMND_ERS_SECT, 0xFFFF);
    #else
    Flash_Start_Async_Command_B(start, CMND_ERS_SECT, 0xFFFF, (FLASH_ARRAY_ST)flashControl);
    #endif
    #endif
    #if 0
    flashControl = (UINT32 *)0xFFF87000;
    delay = 40;
    Flash_Start_Command_B(start, flashCore, delay,
    (FLASH_ARRAY_ST)flashControl,
    CMND_ERS_SECT, 0xFFFF);
    #endif

    Has exactly the same effect (this function returns after 880ms).

    FRDCNTL = 0x201  before I do any flash operations.

    After your Option A, it is 0x101

    I wonder if the NVIC or VIM is accessing flash behind my back to get at its vectors, despite BASEPRI being set high (this being the way of disabling interrupts I inherited from the suppliers of some of the code)?

  • When you are saying the times are the same, are you talking about the complete code sequence execution time or just the calls to Flash_Start_Async_Command_B(), Flash_Start_Command_B(), and Flash_Erase_B()?

    If you use 0xFFF8700 for flashControl, that has the setup_state_machine() trying to write data to undefined memory.

    Also, which RESET line are you toggling?

  • Just the calls to Flash_Start_Async_Command_B() , Flash_Start_Command_B(), for Flash_Erase_B() take 880ms for delay = 40, or 1.32s for delay = 90.

    Re 0xFFF8700 : Oh, absolutely. But I would expect the watchdog-induced reset to allow the processor to restart execution. I am toggling PORRST (pin 89).

    I have now stripped my program down to just:

    - Set up the flash control registers.

    - Shadow the ARM vector table in RAM and set the VTOR pointer to it, just in case.

    - Lock HCLK=80MHz

    - Start peripherals

    - Try to call one of the above flash functions

    With no change in behaviour. Is there a particular bit of example code that I can feed CCS or something that you think should work? I'm afraid the only I/O I have is a couple of lines on SPI2 which I can wiggle .. 

  • I am, of course, an utter moron. Whilst the flash routines were running from RAM, the "toggle this GPIO" routines weren''t, and this has been the cause of my problems ever since I managed to correctly disable systick - you were quite right the first time and my problem all along was that I had to wait for the flash operation to finish before I could run from flash again. Sorry to take up so much of your time with what turned out to be me being a bit stupid!

    I've now sorted this and I have my flash programming working just fine - your method A above now takes a much more reasonable 44ms, and my watchdog is nice and stable at 300ms or so.

    Many, many thanks for all your help - if there's any more investigation you'd like me to do, please let me know and if we're ever in the same pub (or the same continent) I owe you several pints.

  • Richard,

    Not a problem at all.  I have had plenty of those types of moments myself.

    Cheers.