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.

CC2430 / CC2431 Flash Write using DMA and sdcc compiler

Other Parts Discussed in Thread: CC2431

Dear Forum,

I am trying to write to the CC2431 flash memory using DMA. Even though I followed the required steps as described in the datasheet closely, I didn't have success with flash writing.

My hope is that my problem is not the DMA itself but releasing the DMA-FLash-Trigger by setting FCTL Register bits.

The datasheet states:

When performing DMA flash write while
executing code from within flash memory, the
instruction that triggers the first DMA trigger
event FLASH (TRIG[4:0]=10010 DMA in
configuration) must be aligned on a 4-byte
boundary.

Some example code is also given:

#include “ioCC2430.h”
       MODULE flashDmaTrigger.s51
       RSEG RCODE (2)
       PUBLIC halFlashDmaTrigger
       FUNCTION halFlashDmaTrigger, 0203H
       halFlashDmaTrigger:
       ORL FCTL, #0x02;
       RET;
       END;

I didn't implement this because I have no experience in assembly and simply don't know how to get this piece of code to work with my sdcc compiler. I tried to find out how an inline __asm funcion could look like that first aligns the code on a word boundary and then sets the FCTL register. But here I'm completely lost...

My code so far:

// init dma
   
    EA=0;
    DMAIRQ &= ~1;
    IEN1 &= ~1;
    IRCON &= ~1;
    DMAARM &= ~1;

    dma_config.o0 = ((uint16_t)&datax) >> 8;        //src high
    dma_config.o1 = (uint16_t)&datax;    //src low
    dma_config.o2 = ((uint16_t)&FWDATA) >> 8;        //dst high
    dma_config.o3 = (uint16_t)&FWDATA;    //dst low
    dma_config.o4 = 0;                        //VLEN
    dma_config.o5 = 4;                        //Transfer Count
    dma_config.o6 = 18;                        //Flash Trigger, Byte Size Transfer, Single Mode
    dma_config.o7 = 0x4A;                        //srcinc, dstnoinc, irq on, m8=0, prio high

    DMA0CFGH = ((uint16_t)&dma_config) >> 8;
    DMA0CFGL = (uint16_t)&dma_config;
   
    IEN1 |= 0x01;
    EA=1;

    FADDRH = 0x7E; //0b01111110 -> 64. Flash page (last one)
    FADDRL = 0x00; //0b00000000 -> 0. word (first one)

    LED1_ON();
   
    pause_us(100000);

    DMAARM |= 0x01; // arm dma

    pause_us(100000); //wait some time for dma_config to load..

    FCTL |= 0x03; //start flash page erase and write

    LED2_ON();


while(!(DMAIRQ & 0x01)){ pause_us(100000); LED2_TOGGLE();}

 

With this code the DMA transfer never completes, most likely it will never start due to an insufficient bit-setting of FCTL. I also wrote a DMA ISR routine that, on occurrence of a DMA interrupt, toggles LED1 (which doesn't happen).

 

So my question is: How could I manage to set FCTL correct? Does anybody know some examples of how to implement the code piece from the datasheet into an inline asm function that works with my sdcc compiler?

 

Thank you in advance,

Philipp

 

  • Solved! Thanks a lot for your help [;)]

    It works when the DMA channel is configured with FWDATA at address location 0xDFAF in XDATA space. With sdcc FWDATA seems to be mapped to SFR at 0xAF, which is not accessible by DMA.

    Secondly, setting of FCTL should be on a 4-byte boundary, so my code looks like this:

    void _flash_seg_Begin(void) _naked
    {
            _asm                                            
                    .area FLASHCODE (REL,CON,CODE)
                    .even
            _endasm;                                        
    }
    void flash_start_write ()
    {
        _asm
            MOV _FCTL,#0x02
        _endasm;
    }
    void flash_start_erase ()
    {
        EA = 0; //disable interrupts
        _asm                                                               
            C1:    MOV   A,_FCTL              
                   JB    ACC.7,C1
                   MOV   _FCTL,#0x01           
                   NOP                      
                   RET                       
        _endasm;
         EA = 1; //enable interrupts
    }
    void _flash_seg_End(void) _naked                   
    {                                                       
            _asm                                            
                    .area CSEG (REL,CODE)                   
            _endasm;                                        
    }

     

    usage for flash page erase:

    1: set FADDRH[7..1] for page number

    2: call flash_erase_start()

     

    usage for dma flash write:

    1: setup dma like outlined in datasheet BUT with FCTL in XDATA space (i.e. __xdata __at (0xDFAF) X_FWDATA;). Note that the source also has to be in XDATA space

    2: arm dma

    3: set FADDRH, FADDRL,FWT

    4: call flash_write_start()

    5: wait for dma interrupt

     

    last but not least: reading from flash (i copied this from sensinodes nanostack v1.1.0)

    void flash_read(uint8_t *buffer, uint32_t address, uint8_t size)
    {
        buffer;         /*dptr0*/
        address;     /*stack-6*/
        size;            /*stack-7*/
       
        buffer;
       
        portDISABLE_INTERRUPTS();
        _asm
                mov dpl, r2
                mov dph, r3
                mov a, r0
                push acc
                mov a, r2
                push acc
                mov a, _MEMCTR
                push acc
               
                mov a, _bp
                add a, #0xf9         ;stack - 7 = size
                mov r0,a
                mov a, @r0          ;r2 = size
                mov r2, a           ;r2 = size
               
                inc r0
                mov a, @r0
                mov _DPL1, a        ;DPTR1 = address & 0x7FFF | 0x8000
                inc r0
                mov a, @r0
                orl a, #0x80
                mov _DPH1, a
                inc r0                    ;MEMCTR = ((address >> 15 & 3) << 4) | 0x01 (bank select)
                mov a, @r0
                dec r0
                rrc a
                mov a, @r0
                rrc a
                rr a
                rr a
                anl a, #0x30
                orl a, #1
                mov _MEMCTR,a
    lp1:
                mov _DPS, #1        ;active DPTR = 1
                clr a
                movc a, @a+dptr            ;read flash (DPTR1)
                inc dptr
                mov _DPS, #0                 ;active DPTR = 0
                movx @dptr,a                ;write to DPTR0
                inc dptr
                djnz r2,lp1                    ;while (--size)
               
                pop acc
                mov _MEMCTR, a    ;restore bank
               
                pop acc
                mov r2,a
                pop acc
                mov r0,a
        _endasm;
        portENABLE_INTERRUPTS();
        DPL1 = *buffer++;
    }