AnsweredAssumed Answered

DMA with UART: receiving every character twice

Question asked by Konrad Anton on Apr 30, 2012
Latest reply on Oct 8, 2013 by nurichard

Hello all,

 

I'm trying to use DMA to receive from my K70's UART (currently using UART1). When I send characters from my host computer over the serial line to the Kinetis, the debugger shows that the receive buffer contains every character twice. From the DMA TCD, I see that there have been as many major loops as characters received (i.e. twice as many as characters sent). Also, the RXUF (receive underflow) bit is set in UART1_SFIFO. 

 

I'm confident that the DMA source in the DMAMUX, as well as the baud rate, are correct because I'm seeing properly received characters after all. 

I've told the DMA controller to copy one byte from the UARTs D register to my buffer. When polling, that's too little because the protocol requires pollers to read S1 before D; however, I understand from section 57.7 in the K70 RM that S1 needn't be polled in DMA mode.

 

 This is my UART and DMA init code:

 

   /* Calculate baud settings */  /* baud_divisor = clock_speed/ baudrate + 0.5 */  uint32 baud_divisor =       (pInit->m_BaseClock + (8 * baudrate))          / (16 * baudrate);  if (baud_divisor > 0x1fff)     return ;//IO_ERROR;  sci_ptr->BDH = (uint8)((baud_divisor >> 8) & 0xFF);  sci_ptr->BDL = (uint8)(baud_divisor & 0xFF);  sci_ptr->C1 = 0; /* 8-bit mode. Normal operation */  sci_ptr->C2 = 0;   sci_ptr->C3 = 0;   /* Disable all errors interrupts */  sci_ptr->SFIFO = UART_SFIFO_TXOF_MASK | UART_SFIFO_RXUF_MASK ;   /* Reset RXUF and TXOF in SFIFO */  /* set watermark in the almost full TX buffer */  if (((sci_ptr->PFIFO & UART_PFIFO_TXFIFOSIZE_MASK) >> UART_PFIFO_TXFIFOSIZE_SHIFT) == 0) {     /* 1 dataword in D */     sci_ptr->TWFIFO = UART_TWFIFO_TXWATER(0);  }  else {     uint8 txsize = 1 << (((sci_ptr->PFIFO & UART_PFIFO_TXFIFOSIZE_MASK) >> UART_PFIFO_TXFIFOSIZE_SHIFT) + 1);     /* watermark for TX buffer generates interrupts below & equal to watermark */     sci_ptr->TWFIFO = UART_TWFIFO_TXWATER(txsize - 1);  }  /* watermark for RX buffer generates interrupts above & equal to watermark */  sci_ptr->RWFIFO = UART_RWFIFO_RXWATER(1);  /* Enable TX FIFO, DISable RX FIFO for DMA */  sci_ptr->PFIFO = (sci_ptr->PFIFO & ~UART_PFIFO_RXFE_MASK) | UART_PFIFO_TXFE_MASK;   /* Flush RX / TX buffers */     sci_ptr->CFIFO = UART_CFIFO_RXFLUSH_MASK | UART_CFIFO_TXFLUSH_MASK;  sci_ptr->C2 |= UART_C2_RIE_MASK;   /* Enable DMA source for receiver */  sci_ptr->C5 |= UART_C5_RDMAS_MASK;   /* trigger DMA instead of triggering interrupts*/  // Init DMA  // Cancel all requests, enable priority arbitration (0) enable EMLM (minor-loop mapping)  // set the group priorities such that channel 0 is lowest and channel 31 highest  DMA_CR = 0 | DMA_CR_CX_MASK | DMA_CR_EMLM_MASK | DMA_CR_GRP1PRI(1) | DMA_CR_GRP0PRI(0) ;    // Disable error interrupts and clear all pending interrupts.  DMA_EEI = 0;  DMA_INT = 0x0000FFFF;    // Clear all TCDs.  memset((void*)(&DMA_BASE_PTR->TCD[0]), 0, sizeof(DMA_BASE_PTR->TCD));  // Init TCD0 for DMA  uint8 dmaMuxSource = pInit->m_RxDmaMuxSource;  uint8 chan = 0;  DMAMUX0_CHCFG(chan) =  DMAMUX_CHCFG_SOURCE(dmaMuxSource)  | DMAMUX_CHCFG_ENBL_MASK;    uint16 srcWordSize = 1;  const uint32 DMA_TSIZE_8_BITS = 0;        uint32 srcWordSizeCode =  DMA_TSIZE_8_BITS;  uint32 destWordSizeCode = DMA_TSIZE_8_BITS;  UartBuffer volatile* pUartBuf = &m_UartBuffers[channel];    uchar8 volatile* srcAddr = &sci_ptr->D;    DMA_CERQ = DMA_CERQ_CERQ(chan);   // Disable DMA request.  DMA_NBYTES_MLNO(chan) = DMA_NBYTES_MLNO_NBYTES(srcWordSize);   // Number of bytes per minor loop:  DMA_SADDR(chan) = (uint32) srcAddr; // Source address, to be advanced by 0 bytes after one word.   DMA_SOFF(chan) = DMA_SOFF_SOFF(0);       DMA_SLAST(chan) = 0;  DMA_ATTR(chan) =  DMA_ATTR_SSIZE(srcWordSizeCode) | DMA_ATTR_DSIZE(destWordSizeCode) ;     DMA_DOFF(chan) = 1; // advance one byte per write     DMA_CSR(chan) = DMA_CSR_DREQ_MASK; // after the major iterations are through, disable DMA.  uint32 numberOfMinorLoops = BUFFER_SIZE;  uchar8 volatile* destAddr = &pUartBuf->m_Buffer[0];    DMA_CITER_ELINKNO(chan) = numberOfMinorLoops;  DMA_BITER_ELINKNO(chan) = numberOfMinorLoops;  DMA_DADDR(chan) = (uint32) (destAddr);   // Destination address  DMA_DLAST_SGA(chan) = 0;   // for a one-off transfer, we don't care about the DEST pointer afterwards.     DMA_SERQ = DMA_SERQ_SERQ(chan);  /* Transmitter and receiver enable */  sci_ptr->C2 |= UART_C2_RE_MASK + UART_C2_TE_MASK;

There's probably something I'm doing wrong, but what?

Greetings, KA

Outcomes