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.

cc2640 write to the flash from Hwi thread

Other Parts Discussed in Thread: CC2640, SYSBIOS

I want to write to flash (SNV region)  from a Hwi thread. The Hwi thread in this case is the exception handler invoked by hardware (perhaps in case of a divide by zero), which needs to write some debug info to the flash. What is the process for doing this? I know when a low priority task needs to write to SNV it needs to initialize the icall APIs and make a call to the SNV manager using osal_snv_write(), however when an exception occurs, software can be assumed to be dead so we want to do minimal amount of software processing.

 Thanks, 

Ali 

  • Hi Ali,

    That would be tricky. The way SNV works is the App side invokes the Stack side via an ICall message to do the writing. As you point out this won't be happening at this stage of the game.

    It wouldn't perhaps be 100% safe to write to the SNV area at all, because it is possible that an SNV operation was in progress at the time of the crash. Not likely at all, but possible.

    You could look at how the SNV implementation accesses the flash and do something similar from the Hwi, or, perhaps better/safer, you could reserve a sector of flash in the linker file for this purpose and in the Hwi use driverlib APIs to write to the flash there. If desired, on reboot, you could transfer this data to SNV from the running/working application. However, I can't see the point of the latter.

    See driverlib/flash.h :: FlashProgram.

    The reason you'd want an entire sector is so that you can erase it easily without concern for other data. If you want to store more than one thing, you could let the first 16/32 bits that you write be the length of that entry, and so parse the sector into chunks based on the length fields when reading out what you have written. This is more or less what SNV does.

    Best regards,
    Aslak

  • Hi Aslak,

    Thanks for your response. Is the driverlib part of TI-RTOS or the ble stack for cc2640?

    Ali
  • Hi Ali,

    Driverlib is delivered as a product inside TI-RTOS. products/cc26xxware_xx_xx/driverlib. Most/all of our projects already include driverlib by including the pre-compiled lib file, so those APIs are available in all TI-RTOS and BLE projects.

    If you can avoid writing to flash, it may be an idea to write to a __no_init area of RAM in the Hwi thing, and then check this area when you boot normally.

    On Power-on Reset the RAM is normally cleared, so this area should read 0x00. If however you have written there you know something has gone wrong, and can store this to SNV or do whatever you please.

    If you use CCS/TI-toolchain you define an arrays as no-init by

    #pragma NOINIT (panic_buffer)
    uint8_t panic_buffer[256];
    
    uint8_t normal_buffer[256] = {0};
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
    
        /* Call board init functions */
        Board_initGeneral();
    
        char a[] = "Hello there, World!";
    
        if (0 == strcmp(a, panic_buffer))
        {
        	System_printf("Value retained in panic_buffer\n");
        	System_flush();
        }
    
        if (0 != strcmp(a, normal_buffer))
        {
        	System_printf("Value not retained in normal_buffer\n");
        	System_flush();
        }
    
        memcpy(panic_buffer, a, sizeof a);
        memcpy(normal_buffer, a, sizeof a);
    
        /* Start BIOS */
        BIOS_start();
    
        return (0);
    }

    The above is a piece of the TI-RTOS empty project. After a reset, the value is retained in the panic_buffer.

  • Hi Aslak, 

    Thanks for your response. What advantage does writing to __no_init gives over flash? Where can I read more about the __no_init area of RAM? I am just sort of puzzled how it is non-volatile? :) 

    Thanks, 

    Ali 

  • Hi Ali,

    The advantage is that you don't write to Flash, really. You can probably write to Flash, but if you crash often etc, there is a limit to how often you can write to and erase sectors in Flash before performance of that flash segment degrades.

    You can read about it in SPNU151 ARM Optimizing C/C++ Compiler v15.12.0.LTS User's Guide chapter 5.10.18. The point is that global variables are initialized before main() starts by compiler-generated functions. But __no_init variables are not initialized and will retain their value.

    Best regards,
    Aslak

  • Hi Aslak, 

    Thanks for your answers, you have been super helpful! Sorry for the MIA, but I was busy with another task. I have another question: if I want the PC register value for all the RTOS threads, how do I get access to it? 

    Thanks,

    Ali 

  • Let me specify exactly what I want to do: In the exception handler I want to get the value of the crashing thread's PC value, as well as the PC value of any other thread in the system and save it to the no_init region.
  • Hi Ali,

    I don't think that is going to be fun. But I suppose it is possible. The best I can do for you right now is,

    * Add the precompiler symbol ti_sysbios_knl_Task__internalaccess

    Then do something like this:

    Task_Object *taskList[] = {(Task_Object *)&task0Struct, (Task_Object *)&task1Struct};
    
    Task_Stat taskStats;
    int i;
    Task_Object *pTask;
    for (i = 0; i < sizeof(taskList)/sizeof(taskList[0]); ++i)
    {
    	pTask = taskList[i];
    	Task_stat(pTask, &taskStats);
    	System_printf("Task fxn: %08x -- ", pTask->fxn);
    	System_printf("context: %08x\n", pTask->context);
    }
    System_flush();

    If you use CCS, then it should autocomplete for you when you write pTask->, and show you what exists. You can also look at Task.h to see the struct.

    This will give you the context pointer. That is to say, the stack pointer. From there you can probably work your way down the stack to see what function was the last one.

    The problem is that TI-RTOS will add some functions at the top of your real last function/PC. See the picture below. I don't know how to interpret the stack frames and figure out what was really going on.

    Best regards,
    Aslak

  • Go here: software-dl.ti.com/.../index.html and then to ti, sysbios, knl, task. This is the documentation about the Task module.
  • Hi Aslak, 

    Thank you, you have been super helpful so far. This is a good reference for future, as we may want to extend the debug capability and add PC values of other threads, but for now I am going to just return the crashing thread's PC value, that is given to us as a paramter of the exception handler. 

    I have one last question, well hopefully last! :)  I want a NULL memory (or Bus fault) exception to be caught by my exception handler. How do I enable this? 

    I have an exception handler hook which I can set in appBLE.cfg : 

    M3Hwi.enableException = true;  
    M3Hwi.excHandlerFunc = "&excHandler"; // this is my excHandler which I want to handle all exceptions 
    M3Hwi.nvicCCR.UNALIGN_TRP = 0;   // if I set this to 1, I can enable unaligned access exception
    M3Hwi.nvicCCR.DIV_0_TRP = 0; // if I set this to 1, I can enable divide by 0 exception 

    now I want to enable bus fault handling, what do I need to do? 

    Thanks, 

    Ali 

    Thanks, 

    Ali 

  • And to expand upon that previous question, is there a way for us to have a "catch all" exception handler that can handle anything and does not require explicit configuration for each different type of exception? A "catch-all exception handler", if you can call it that.

    Thanks,
    Ali
  • Hi Ali,

    Bus fault should already be caught by this. AFAIK, all exceptions possible in the CFSR (configurable fault status register) are sent to that generic handler, so bus fault, invalid operation, stacking error, what have you.

    Try writing to 0 via *(int *)0 = 31; and see if that works. Or HWREG(0) = 1; to use a define.

    To find the precise PC of bus-faults, it is necessary to disable write buffering. Unless you do this, the BFAR register will not contain the address that was attempted written/read, and PC will not be for the offending instruction, but a later one. Please see the chapter on 'deciphering cpu exceptions' under debugging in the Software Developers Guide document included in the BLE SDK installer.

    Best regards,
    Aslak