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.

CC2530 UART - RX with DMA not working

Other Parts Discussed in Thread: CC2530

Hello,

I'm developing test codes for custom CC2530 PCB and I faced problems with configuring UART to work in DMA configuration. I used directly DN112 document example (with small modifications). Pooling and ISR works fine but I cannot get DMA working.

Below I attached a complete source code:

typedef struct {
  unsigned char START   : 1;
  unsigned char STOP    : 1;
  unsigned char SPB     : 1;
  unsigned char PARITY  : 1;
  unsigned char BIT9    : 1;
  unsigned char D9      : 1;
  unsigned char FLOW    : 1;
  unsigned char ORDER   : 1;
} UART_PROT_CONFIG;

typedef struct {
  unsigned char SRCADDRH;
  unsigned char SRCADDRL;
  unsigned char DESTADDRH;
  unsigned char DESTADDRL;
  unsigned char VLEN            : 3;
  unsigned char LENH            : 5;
  unsigned char LENL            : 8;
  unsigned char WORDSIZE        : 1;
  unsigned char TMODE           : 2;
  unsigned char TRIG            : 5;
  unsigned char SRCINC          : 2;
  unsigned char DESTINC         : 2;
  unsigned char IRQMASK         : 1;
  unsigned char M8              : 1;
  unsigned char PRIORITY        : 2;
} DMA_DESC;

void uartMapPort(unsigned char uartPortAlt, unsigned char uartNum)
{
  if (uartPortAlt == 1)
  {
    if (uartNum == 0)
    {
      PERCFG &= ~0x01;
      P0SEL |= 0x3C;
      P1SEL &= ~0x3C;
    }
    else
    {
      PERCFG &= ~0x02;
      P0SEL |= 0x3C;
      P1SEL &= ~0xF0;
    }
  }
  else
  {
    if (uartNum == 0)
    {
      PERCFG |= 0x01;
      P1SEL |= 0x3C;
      P0SEL &= ~0x3C;
    }
    else
    {
      PERCFG |= 0x02;
      P1SEL |= 0xF0;
      P0SEL &= ~0x3C;
    }
  }
}

void uartInitBitrate(unsigned char uartBaudM, unsigned char uartBaudE)
{
  unsigned int i;
  
  SLEEPCMD &= ~OSC_PD;                       /* turn on 16MHz RC and 32MHz XOSC */                \
  while (!(SLEEPSTA & XOSC_STB));            /* wait for 32MHz XOSC stable */                     \
  asm("NOP");                                /* chip bug workaround */                            \
  for (i=0; i<504; i++) asm("NOP");          /* Require 63us delay for all revs */                \
  CLKCONCMD = (CLKCONCMD_32MHZ | OSC_32KHZ); /* Select 32MHz XOSC and the source for 32K clock */ \
  while (CLKCONSTA != (CLKCONCMD_32MHZ | OSC_32KHZ)); /* Wait for the change to be effective */   \
  SLEEPCMD |= OSC_PD;                        /* turn off 16MHz RC */ 
  
  U0BAUD = uartBaudM;
  U0GCR = (U0GCR & ~0x1F) | uartBaudE;
  
  U1BAUD = uartBaudM;
  U1GCR = (U1GCR & ~0x1F) | uartBaudE;
}

void uartConfig(unsigned char uartNum, UART_PROT_CONFIG config)
{
  if (uartNum == 0)
  {
    U0CSR |= 0x80;
    U0UCR = (U0UCR & ~0x01) | config.START;
    U0UCR = (U0UCR & ~0x02) | (config.STOP << 1);
    U0UCR = (U0UCR & ~0x04) | (config.SPB << 2);
    U0UCR = (U0UCR & ~0x08) | (config.PARITY << 3);
    U0UCR = (U0UCR & ~0x10) | (config.BIT9 << 4);
    U0UCR = (U0UCR & ~0x20) | (config.D9 << 5);
    U0UCR = (U0UCR & ~0x40) | (config.FLOW << 6);
    U0GCR = (U0GCR & ~0x20) | (config.ORDER << 5);
  }
  else
  {
    U1CSR |= 0x80;
    U1UCR = (U1UCR & ~0x01) | config.START;
    U1UCR = (U1UCR & ~0x02) | (config.STOP << 1);
    U1UCR = (U1UCR & ~0x04) | (config.SPB << 2);
    U1UCR = (U1UCR & ~0x08) | (config.PARITY << 3);
    U1UCR = (U1UCR & ~0x10) | (config.BIT9 << 4);
    U1UCR = (U1UCR & ~0x20) | (config.D9 << 5);
    U1UCR = (U1UCR & ~0x40) | (config.FLOW << 6);
    U1GCR = (U1GCR & ~0x20) | (config.ORDER << 5);
  }
}

void uartStartRxForDma(unsigned char uartNum, 
                       DMA_DESC * uartDmaRxDescr, 
                       unsigned char uartDmaRxChan,
                       unsigned short __xdata * uartRxBuf,
                       unsigned char uartRxBufSize)
{
  uartDmaRxDescr->SRCADDRH = 0xDF;
  uartDmaRxDescr->SRCADDRL = (uartNum == 0) ? 0xC1 : 0xF9;
  uartDmaRxDescr->DESTADDRH = (unsigned short) uartRxBuf >> 8;
  uartDmaRxDescr->DESTADDRL = (unsigned short) uartRxBuf;
  uartDmaRxDescr->LENH = (uartRxBufSize >> 8) & 0xFF;
  uartDmaRxDescr->LENL = uartRxBufSize & 0xFF;
  
  uartDmaRxDescr->VLEN = 0x00;
  uartDmaRxDescr->WORDSIZE = 0x00;
  uartDmaRxDescr->TMODE = 0x00;
  uartDmaRxDescr->TRIG = 14 + (2 * uartNum);
  uartDmaRxDescr->SRCINC = 0x00;
  uartDmaRxDescr->DESTINC = 0x00;
  uartDmaRxDescr->IRQMASK = 0x01;
  uartDmaRxDescr->M8 = 0x00;
  uartDmaRxDescr->PRIORITY = 0x02;
  
  if (uartDmaRxChan == 0)
  {
    DMA0CFGH = (unsigned char) ((unsigned short) uartDmaRxDescr >> 8);
    DMA0CFGL = (unsigned char) ((unsigned short) uartDmaRxDescr & 0x00FF);
  }
  else
  {
    DMA1CFGH = (unsigned char) ((unsigned short) uartDmaRxDescr >> 8);
    DMA1CFGL = (unsigned char) ((unsigned short) uartDmaRxDescr & 0x00FF);
  }
  
  DMAARM = ((1 << uartDmaRxChan) & 0x1F);
  asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
  asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
  asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
  asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
  asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
  asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
  asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
  asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
  asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
  
  IEN0 |= 0x80;
  IEN1 |= 0x01;
  IRCON &= ~0x01;
  
  if (uartNum == 0)
  {
    U0CSR |= 0x40;
  }
  else
  {
    U1CSR |= 0x40;
  }
}

DMA_DESC uartDmaRxTxCh0[1];
DMA_DESC uartDmaRxTxCh1[4];

unsigned char byte1 = 'a';
unsigned char byte2 = 'b';

unsigned short __xdata data[2];

#pragma vector=DMA_VECTOR
__interrupt void DMA_ISR(void)
{
  IRCON &= ~0x01;
  
  if (DMAIRQ & 0x01)
  {
    DMAIRQ &= ~0x01;
    DMAARM |= 0x01;
  }
}

int main(void)
{
  unsigned int delay;
  unsigned int delay2;
  
  // Set P1.0 of CC2530 as output
  // Set P1.1 of CC2530 as output
  P1DIR |= 0x03;
  // Green diode ON
  P1_0 ^= 1;
  
  //-------------------------------------------------
  // Baud rate:         9600
  // Data:              8-bit
  // Parity:            none
  // Stop:              1-bit
  // Flow control:      NONE
  //-------------------------------------------------
  UART_PROT_CONFIG config;
  config.START = 0;
  config.STOP = 1;
  config.SPB = 0;
  config.PARITY = 0;
  config.BIT9 = 0;
  config.D9 = 0;
  config.FLOW = 0;
  config.ORDER = 0;
  
  uartInitBitrate(59, 8);
  
  // Configure UART 1
  // UART 1 Alt.1 location
  // RX: P0.2
  // TX: P0.3
  uartMapPort(1, 0);
  uartConfig(0, config);
  P2SEL &= ~(1 << 6);        // UART 1 priority over UART 2
  P2SEL &= ~(1 << 3);        // UART 1 priority over Timer 1
  
  // Configure UART 2
  // RX: P0.5
  // TX: P0.4
  // UART 2 Alt.1 location
  uartMapPort(1, 1);
  uartConfig(1, config);
  P2SEL &= ~(1 << 5);        // UART 2 priority over Timer 3
  
  // Priority: UART0 > UART 1 > TImer 1
  P2DIR &= ~(0x01 << 7);
  P2DIR &= ~(0x01 << 6);
  
  EA = 1;
  
  uartStartRxForDma(0, uartDmaRxTxCh0, 0, data, 1);
  uartStartRxForDma(1, uartDmaRxTxCh1, 1, data + 1, 1);
  
  
  while (1)
  {
    // Negate diodes state
    P1_0 ^= 1;
    P1_1 ^= 1;
    
    // Send one byte1 over UART 1
    U0DBUF = data[0];
    while (!UTX0IF);
    UTX0IF = 0;
    // Send one byte2 over UART 2
    U1DBUF = data[1];
    while (!UTX1IF);
    UTX1IF = 0;
    
    for ( delay = 0; delay < 2; delay++)
      for ( delay2 = 0; delay2 < 50000; delay2++);
    
  }
}



Could anyone tell me what I'm doing wrong? I want to make this code running in both ways... TX (without DMA) and RX (with DMA) but I tried almost everything. DOcumentation or DN112 document don't help me anymore. 

Any help will be appreciated!

Thank you in advance.

Best regards,

Lukasz Spas

  • Could anyone help me please? I'm loosing my mind to get this peace of code running... I went through the whole documentation couple of times and don't know why it doesn't work.

    DMA doesn't require HW flow control to be enabled, does it?

  • I finally solved the problem myself.

    The answer is: bit fields in DMA config struct.

    IAR compiler is so dumb that even if it's possible to group bit fields into group of 8 bits (1 byte) it won't do that unless there is either high optimization turned on or before struct declaration you place below line of code:

    #pragma bitfields=reversed

    Later on to enable default IAR compiler behavior you may want to put:

    #pragma bitfields=default

    IAR IDE sucks like a hell but I never thought that compiler is on the same level of quality / smartness. :P