Quantcast
Channel: Wireless Connectivity
Viewing all articles
Browse latest Browse all 116964

Forum Post: RE: Writing CC2530 flash during run-time

$
0
0

Here is our code for flash fetch/write/copy. NOTE, I have exported it from the actual C file - we don't use the TI HAL (we have our own OS) and use a 'bios' on the CC25XX series radios that includes flash i/o so, in our system, these functions are exported to a function table.

I don't think there any particular header dependencies that should cause problems.

Other than excluding the headers and cutting out some unused code, this is as we use it (the tests in initFlash() won't work without our library).

We dedicate DMA 0 to flash i/o - this saves a lot of flash i/o setup but may not be valid if you use DMA 0 for something else. We also use a 256 byte low RAM block as 'system' memory (apps 'can't' access) and we have a reserved location for the two code fragments (erase and write). You will need to place these somewhere convenient. I didn't bother changing the reserved sizes, but I seem to recall 32 bytes is very generous.

[Yes, we separate the OS from the apps which are compiled, linked and loaded separately to the OS - often times, we use SDCC for the apps, oh and did I mention, we have over the air loading too ;-)]


#define FLASHDRV_DMA_CH 0
#define ERASE           0x01

// DMA descriptor
typedef struct
    {
    unsigned char srcAddrH;
    unsigned char srcAddrL;
    unsigned char dstAddrH;
    unsigned char dstAddrL;
    unsigned char xferLenV;
    unsigned char xferLenL;
    unsigned char ctrlA;
    unsigned char ctrlB;
    } flashdrvDmaDesc_t;

static flashdrvDmaDesc_t flashdrvDmaDesc; // DMA descriptor table

/////////////////////////////////////////////////////////////////
static void __flashDmaTrigger(void) //@ "flashRamCode"
    {
    FCTL |= 0x02;         // Trigger the DMA writes.
    while (FCTL & 0x80);  // Wait until writing is done.
    }

static void __flashErasePage(unsigned char page) //@ "flashRamCode"
    {
    // erase the page
    FADDRH = page << 1;
    FCTL |= ERASE;
    // CPU stalls until done

    // done
    }
////////////////////////////////////////////////////////////////

static void erase(unsigned char page)
    {
    // disable interrupts
    __asm("PUSH 0xA8");/* IE */
    __asm("CLR  0xAF");/* IE.7 */
   
    // switch RAM into CODE
    unsigned char memctr = MEMCTR;
    MEMCTR |= 0x08;    // map RAM into CODE

    // call the erase snippet
    ((void (*)()) 0x8120)(page);

    // switch RAM to XDATA
    MEMCTR = memctr;    // map RAM into XDATA

    // done
    __asm("POP 0xA8");/* IE */
    }

void fetch(word addr, byte *buf, word count)
    {
    // note this is a 4 byte aligned read from 18bit loc >> 2
    // count is # of UInt32

    // figure the page and the offset
    unsigned char pg = (((UInt32)addr) << 2) / kFlashPageSize;
    unsigned short offset = (((UInt32)addr) << 2) - pg * kFlashPageSize;

    // Calculate the offset into the containing flash bank as it gets mapped into XDATA.
    unsigned char *ptr = (unsigned char *)(offset + 0x8000) + ((pg % 16) * kFlashPageSize);
    unsigned char memctr = MEMCTR;  // Save to restore.
   
    pg /= 16;  // Calculate the flash bank from the flash page.
   
    // disable interrupts
    __asm("PUSH 0xA8");/* IE */
    __asm("CLR  0xAF");/* IE.7 */

    // map the containing flash bank into XDATA.
    MEMCTR = (MEMCTR & 0xF8) | pg;
   
    while (count--)
        {
        *buf++ = *ptr++;
        *buf++ = *ptr++;
        *buf++ = *ptr++;
        *buf++ = *ptr++;
        }
   
    // restore map
    MEMCTR = memctr;

    // done
    __asm("POP 0xA8");/* IE */
    }

void write(unsigned short addr, unsigned char *buf, unsigned short cnt)
    {
    flashdrvDmaDesc.srcAddrH = (unsigned char) ((unsigned short)buf >> 8);
    flashdrvDmaDesc.srcAddrL = (unsigned char) (unsigned short) buf;
    flashdrvDmaDesc.xferLenV =
            (0x00 << 5) |               // use length
            (unsigned char)(unsigned short)(cnt >> 6);  // length (12:8). Note that cnt is flash word
    flashdrvDmaDesc.xferLenL = (unsigned char)(unsigned short)(cnt * 4);
   
    DMAIRQ &= ~( 1 << FLASHDRV_DMA_CH ); // clear IRQ
    DMAARM = (0x01 << FLASHDRV_DMA_CH ); // arm DMA
   
    FADDRL = (unsigned char) addr;
    FADDRH = (unsigned char)(addr >> 8);

    // disable interrupts
    __asm("PUSH 0xA8");/* IE */
    __asm("CLR  0xAF");/* IE.7 */
   
    // switch RAM into CODE
    unsigned char memctr = MEMCTR;
    MEMCTR |= 0x08;    // map RAM into CODE

    // call the trigger snippet
    ((void (*)()) 0x8100)();

    // switch RAM to XDATA
    MEMCTR = memctr;    // map RAM into XDATA

    // done
    __asm("POP 0xA8");/* IE */
    }


void copy(unsigned short dst, unsigned short src, unsigned short count)
    {
    UInt32 buf[8];        // []*4 bytes on stack!

    for (; !(count < 8); count -= 8)
        {
        fetch(src, (byte *) buf, 8);
        write(dst, (byte *) buf, 8);
        src += 8;
        dst += 8;
        }

    if (count)
        {
        fetch(src, (byte *) buf, count);
        write(dst, (byte *) buf, count);
        }
    }


void initFlash()
    {
    // put flash code into RAM
    unsigned char memctr = MEMCTR;
    MEMCTR = 0;    // map page 1 to XDATA
    memcpy((void *) 0x100, (void *) (0x8000 + (word) &__flashDmaTrigger), 32);
    memcpy((void *) 0x120, (void *) (0x8000 + (word) &__flashErasePage), 32);

    MEMCTR = memctr;

#if FLASHDRV_DMA_CH == 0
    DMA0CFGH = (unsigned char) ((unsigned short) &flashdrvDmaDesc >> 8);
    DMA0CFGL = (unsigned char)  (unsigned short) &flashdrvDmaDesc;
    flashdrvDmaDesc.dstAddrH = (unsigned char) ((unsigned short)&FWDATA >> 8);
    flashdrvDmaDesc.dstAddrL = (unsigned char) (unsigned short) &FWDATA;
    flashdrvDmaDesc.ctrlA =
            (0x00 << 7) | // word size is byte
            (0x00 << 5) | // single byte/word trigger mode
            18;           // trigger source is flash
    flashdrvDmaDesc.ctrlB =
            (0x01 << 6) | // 1 byte/word increment on source address
            (0x00 << 4) | // zero byte/word increment on destination address
            (0x00 << 3) | // The DMA is to be polled and shall not issue an IRQ upon completion.
            (0x00 << 2) | // use all 8 bits for transfer count
            0x02; // DMA priority high
#else
    # error "flashdrv DMA channel other than 0 is not supported"
#endif

#if 0
// test FLASH
#define TEST_ADDR 0x14014
    debug("Testing erase/write/fetch to 0x%06lx\n", (UInt32) TEST_ADDR);
    debug("bank %u\n", FlashBank(TEST_ADDR));
    debug("page %u\n", FlashPage(TEST_ADDR));
    debug("offset %u\n", FlashPageOffset(TEST_ADDR));
    erase(FlashPage(TEST_ADDR));
    dump(0xc010, 16, 1);

    byte buf[32];
    memcpy(buf, "Hello World\n", 13);
    write(FlashAddr(TEST_ADDR), buf, 4);

    memset(buf, 0, sizeof(buf));
    fetch(FlashAddr(TEST_ADDR), buf, 4);
   
    copy(FlashAddr(TEST_ADDR + 32), FlashAddr(TEST_ADDR), 4);

    debug("%s\n", buf);
#endif
    }



Viewing all articles
Browse latest Browse all 116964

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>