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.

CC2543: flash memory write only works when attached to debugger

Part Number: CC2543

I have a board with a CC2543, running 32MHz.  Compiler is IAR.  I am using the TI CC2543 development kit with a debug cable between it at the board.  Everything works perfectly: download code, single stepping, setting breakpoints, examining registers, memory, etc.

I am attempting to write four bytes to flash memory at 0xFC00.  The code was taken from some demo code I found on the TI development site.  It works perfectly when I run the program from the debugger, i.e., download the code and start the program.  Now here is where is gets really strange.  All I do is next is remove the debug cable and cycle power to the board.  The program runs perfectly but fails to write the flash.  It remains unchanged.

The "write_flash()" function is listed below.  It uses DMA to write a four-byte array 'finalCardCount' to flash at 0xFC00.

To examine what was going on, I used an unused port, P1_1, to toggle a signal that I could examine on a o'scope.  That proved the program is definitely running the function.  Then I added other port toggles around various sections of the code, running it with the debugger attached and stand-alone.  That allowed me to see that it was actually exercising all the code, and also record how long it was taking to run various statement.

There were two huge differences when running with the debugger vs. stand-alone.

1.  The statement "FCTL  |= FCTL_ERASE;" takes 904nS to execute when running stand-alone, but 21.6mS when attached to the debugger.

2.  The statement "FCTL |= FCTL_WRITE;" takes 1.16uS to execute when running stand-alone vs. 44.8uS.

All the other parts of the code run the same in both debug and stand-alone mode.

The datasheet says that a page erase (the first statement) should take ~20mS and a four-byte write (the second statement) should take ~20uS, which are in the right neighborhood for the values I measured when running with the debugger.  The values when running stand-alone are much too short.

I'm at a loss to explain this.  What is going on when the debugger is running vs. stand-alone?  As proven by observing the port-toggles, the program is definitely executing the two "FCTL |= " statements.  Does debug mode somehow permit erasures and writes but when the program just run normally, that access is denied?  The fact that the statements return so quickly without performing the write tells me something is cancelling the erase or write.

=======================

void write_flash(void)
{

P1_1 = 1;   //set port so we can tell function is running on 'scope

DMA_DESC dmaConfig0;
dmaConfig0.SRCADDRH = ((uint16)finalCardCount >> 8) & 0x00FF;

dmaConfig0.SRCADDRL = (uint16)finalCardCount & 0x00FF;
dmaConfig0.DESTADDRH = ((uint16)&FWDATA >> 8) & 0x00FF;
dmaConfig0.DESTADDRL = (uint16)&FWDATA & 0x00FF;
dmaConfig0.VLEN = DMA_VLEN_USE_LEN;
dmaConfig0.LENH = (FINAL_CARD_COUNT_ARRAY_SIZE >> 8) & 0x00FF;
dmaConfig0.LENL = FINAL_CARD_COUNT_ARRAY_SIZE & 0x00FF;
dmaConfig0.WORDSIZE = DMA_WORDSIZE_BYTE;
dmaConfig0.TMODE = DMA_TMODE_SINGLE;
dmaConfig0.TRIG = DMA_TRIG_FLASH;
dmaConfig0.SRCINC = DMA_SRCINC_1;
dmaConfig0.DESTINC = DMA_DESTINC_0;
dmaConfig0.IRQMASK = DMA_IRQMASK_ENABLE;
dmaConfig0.M8 = DMA_M8_USE_8_BITS;
dmaConfig0.PRIORITY = DMA_PRI_HIGH;

/* The DMA configuration data structure may reside at any location in
* unified memory space, and the address location is passed to the DMA
* through DMA0CFGH:DMA0CFGL.
*/
DMA0CFGH = ((uint16)&dmaConfig0 >> 8) & 0x00FF;
DMA0CFGL = (uint16)&dmaConfig0 & 0x00FF;

// Waiting for the flash controller to be ready.
while (FCTL & FCTL_BUSY);
/* Configuring the flash controller.

* FADDRH:FADDRL: point to the area in flash to write to.
*/
uint16 addr;
addr = (uint16)flashDataAddr >> 2; // You address 32-bit words through the flash controller.

FADDRH = (addr >> 8) & 0x00FF;
FADDRL = addr & 0x00FF;

// Erase the page that will be written to.
FCTL |= FCTL_ERASE;

// Wait for the erase operation to complete.
while (FCTL & FCTL_BUSY);

// Arm the DMA channel, takes 9 system clock cycles.
DMAARM |= DMAARM_DMAARM0;
NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP(); // 9 NOPs
// Enable flash write. Generates a DMA trigger.

FCTL |= FCTL_WRITE;

// Wait for DMA transfer to complete.
while (!(DMAIRQ & DMAIRQ_DMAIF0));
// Wait until flash controller not busy.

while (FCTL & (FCTL_BUSY | FCTL_FULL));
/* By now, the transfer is completed, so the transfer count is reached.

* The DMA channel 0 interrupt flag is then set, so we clear it here.
*/
DMAIRQ = ~DMAIRQ_DMAIF0; // Clear interrupt flag by R/W0, see datasheet.


P1_1 = 0;  //clear port indicating function exit
}

  • So I found a solution, but I'm not completely clear what is going on.

    The solution is to change where I want to write in flash memory from 0xFC00 (the 31st 1K flash page) to 0xF800 (the 30th flash page.)

    OK, now a bit of hand-waving regarding the solution.   Quoting from the manual, "The flash memory is organized as a set of 1 KB pages. The 16 bytes of the upper available page contain page-lock bits and the debug-lock bit. There is one lock bit for each page, except the lock-bit page which is implicitly locked when not in debug mode."  [emphasis added.]  In another part of the manual, it reads " The rest of the lock-bit page can be used to store code/constants, but cannot be changed without entering debug mode."

    (In typically awful T.I. style, this information is not in, nor referenced in, the Flash Memory section of the documentation.  Also "lock-bit page" isn't defined until after it is used here.  As it turns out, the "lock-bit page" is the 31st flash page.)

    The key here is "...the lock-bit page which is implicitly locked when not in debug mode."  So my problem was that I was trying to write to the 31st page, which worked perfectly when running the debugger because it debugger unlocks that page, but failed when running stand-alone because the page was locked.

    The TI debugger interface to the IAR compiler allows you to specify which pages to not erase when loading the code.  It also allows you to set the lock bits = 0 (lock the page) for all pages.  What I haven't figured out is how to set the lock bit = 1 for the 31st page, so that the program can write there.

  • Hi Carl,

    Thanks for the updates and apologies that you are experiencing difficulties with the TI documentation.  You should be able to see the LOCK_BITS_ADDRESS_SPACE defined from your linker command file (f8w2534.xcl) and then modify the _lockBits from your application.

    #pragma location="LOCK_BITS_ADDRESS_SPACE"
    __no_init uint8 _lockBits[16];
    #pragma required=_lockBits

    Regards,
    Ryan

  • Ryan-

    I don't understand what you mean by "...and then modify the _lockBits from your application."  That array is in flash memory, and can only be modified by doing a flash write/erase.  As I have detailed earlier, the problem is leaving the DBGLOCK bit = 1, so the top-most page of flash can be written to.  (See page 55 of the CC2543 User's Manual.) 

    So far, I have not been able preset the flash memory at location 0xFFF0 - 0xFFFF.

  • I apologize for the confusion, I do not intend for the lock bits to be variables which are changed from the application.  Instead I showed how the constant could be defined so that it may be set if desired.  I believe you would want to alter the PAGELOCK bits (32 flash pages), not DBGLOCK (debug access).

    Regards,
    Ryan

  • The lock-bit page is the 32nd 1K page of flash memory.  The manual states:

    "The flash memory is organized as a set of 1 KB pages. The 16 bytes of the upper available page contain page-lock bits and the debug-lock bit. There is one lock bit for each page, except the lock-bit page which is implicitly locked when not in debug mode."

    At the top of the lock-bit page, as shown on page 55, is 31-bit (not 32-bit) structure where each bit corresponds to flash pages [0:30].  The DBGLOCK bit corresponds to the 32nd page.  Setting it is the only way to unlock the top, i.e., lock-bit, page.

    Let's cut to the chase.  I am looking for whatever combination of pragmas and other preprocessor commands that leave the DBGLOCK bit = 1 so that when the debugger is not attached, that top page is not locked.  Nothing I've tried so far has worked. 

    No more hand-waving.  Go write a hello_world() program, down load it with the Ti CC2543 debugger and see if you can preset those upper bits.

  • Thanks for pointing that out again, I was mistaken about the lock-bit functionality in this regard.  Note that on the same page, "The rest of the lock-bit page can be used to store code/constants, but cannot be changed without entering debug mode."  Hence the program will not be able to write the lock-bit page without the debugger attached.  I will attempt to confirm this through hardware.  Are you able to use a different flash page for your solution?

    Regards,
    Ryan

  • Ryan-

    Yes, as I reported somewhere above, moving the write-location to the 30th flash page did the trick, since that page is not locked by default.

    Also, just to help anyone reading this discussion in the future, be sure to check the debugger options to make sure the page you want to write to is not locked.  As shown by example here, it is possible to force pages to be locked.