I am using a K10DN512VLQ10 chip in the older Kinetis Design Studio V3.2.0. I am not using any libraries and the drivers are self developed.
I want to start using the DMA controller to transmit variable length messages over UART2. I have tried everything and cannot get it to work. It is either a case of only the first cycle of the minor loop is execute and stops there, or all data is dumped immediately to the UART thereby overrunning it.
Only the first character of the buffer is seen on the UART. The DMA done bit is set.
To test I have written this code. The transfer is software triggered and transmits 8 bytes from a 'str' buffer (type char str[]). Only 1 major loop and no linkage.
UART2_BASE_PTR->C2 = 0;
// Enable clock for DMAMUX and DMA
SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
SIM->SCGC7 |= SIM_SCGC7_DMA_MASK;
//disable request channels
DMA0->ERQ = 0u;
DMA0->EEI = 0u;
DMA0->SEEI = 0u;
// Clear pending errors and/or the done bit
DMA0->ES = 0u;
//set source addr
DMA0->TCD[0].SADDR = (__IO uint32_t)str;
DMA0->TCD[0].NBYTES_MLNO = 8;
DMA0->TCD[0].ATTR = DMA_ATTR_SSIZE(0) | DMA_ATTR_DSIZE(0); //8-bit transfer
DMA0->TCD[0].DADDR = (__IO uint32_t)&UART2_BASE_PTR->D;
DMA0->TCD[0].CSR = DMA_CSR_BWC(3) | DMA_CSR_DREQ_MASK
// Adjustment value used to restore the source and destiny address to the initial value
DMA0->TCD[0].SLAST = 0;//(-1 * size_of_tx); // Source address adjustment
DMA0->TCD[0].DLAST_SGA = 0;//(-1); // Destination address adjustment
// Set an offset for source and destination address
DMA0->TCD[0].SOFF = 0x00; // Source address offset
DMA0->TCD[0].DOFF = 0x00; // Destination address
// Current major iteration count (a single iteration of 'size_of_tx' bytes)
DMA0->TCD[0].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(1);
DMA0->TCD[0].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(1);
UART_C1_REG(m_uart) = UART_C1_UARTSWAI_MASK | UART_C1_ILT_MASK;
UART_PFIFO_REG(m_uart) = 0u;
UART_TWFIFO_REG(m_uart) = 0u;
SetSpeed(baud); //sets baud
UART2_BASE_PTR->C2 = UART_C2_TIE_MASK;
UART2_BASE_PTR->C5 = UART_C5_TDMAS_MASK;
SetIrqStatus(irq, priority);
m_configured = true;
uint8_t temp_val = UART2_BASE_PTR->S1;
UART2_BASE_PTR->C2 |= (UART_C2_TE_MASK | UART_C2_RE_MASK);
DMA0->CERR = DMA_CERR_CAEI_MASK;
DMA0->CERQ = DMA_CERQ_CAER_MASK;
// Enable request signal for channel 0
DMAMUX->CHCFG[0] = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(7); //UART2 TX
DMA0->ERQ = 1;
DMA0->TCD[0].CSR |= DMA_CSR_START_MASK;
//wait for DMA to complete
while(!(DMA0->TCD[0].CSR & DMA_CSR_DONE_MASK)); //DMA_CSR_DREQ_MASK
Hi
You can use the open source uTasker project as reference for UART (it supports Rx and Tx DMA on all parts - LPUARTs, UART with eDMA or the simpler DMA in KL parts, for example, on all UART instances). It allows the UART, its DMA and interrupt operation to be accurately simulated in Visual Studio to analyse the internal operation and then adjust your solution accordingly.
Some ideas/notes:
1. Enable Tx DMA by setting
UART_C5_TDMAS in UARTx_C5
2. DMA_TCD_SOFF will normally be 1 when transmitting from a buffer to the output
3. DMA_TCD_NBYTES_ML should be 1 (and not 8) to transfer a single byte on each trigger
4. DMA_TCD_CITER_ELINK and DMA_TCD_BITER_ELINK should be 8 to transfer 8 bytes, one on each trigger
5. Don't use the SW start bit to enable the DMA transfer since this is controlled by the Tx interrupt flag in the correct mode
6. Generally a DMA interrupt is used to signal when the buffer transmission has completed. In the meantime SW can queue further data to be sent that can then be started in the driver so that the user can add data whenever required and it will be sent continuously.
7. If using low power modes that can change dynamically such switching should be disabled until complete UART transmission has terminated (plus waiting for the final end of transmission interrupt after the final byte transfer) in order to avoid premature transmission freeze.
The uTasker project includes a complete solution (industrially proven in many Kinetis based products since 2011) so can be used to avoid needing to redevelop the wheel or its suported version is available for mission critical requirements. It can also be used inside FreeRTOS with undefined UART reception lengths for very high speed, loss-free DMA based reception. The code and project is compatible with KDS, MCUXpresso, CW, IAR, Keil, Rowley, CooCox, Atollic, GreenHills, Visual Studio, GCC makefile.
Regards
Mark
Open Source Version: https://github.com/uTasker/uTasker-Kinetis
Complete Kinetis solutions for professionals, training and support: http://www.utasker.com/kinetis.html
Kinetis K60/K10:
- http://www.utasker.com/kinetis/TWR-K60N512.html
- http://www.utasker.com/kinetis/TWR-K60D100M.html
- http://www.utasker.com/kinetis/TWR-K60F120M.html
- http://www.utasker.com/kinetis/ELZET80_NET-KBED.html
- http://www.utasker.com/kinetis/ELZET80_NET-K60.html
UART: http://www.utasker.com/docs/uTasker/uTaskerUART.PDF
UART videos:
- https://www.youtube.com/watch?v=89sZ4nW-mgw&list=PLWKlVb_MqDQFZAulrUywU30v869JBYi9Q&index=2
- https://www.youtube.com/watch?v=dNZvvouiqis&list=PLWKlVb_MqDQFZAulrUywU30v869JBYi9Q&index=10
- https://www.youtube.com/watch?v=GaoWE-tMRq4&list=PLWKlVb_MqDQFZAulrUywU30v869JBYi9Q&index=11
Hello,
in such configuration described above, the I got interrupt after 8 bytes are transfered to UART tx buffer, but DMA continues to feed UART TX buffer. How to ensure that DMA stops feeding UART tx without software intervention.
Thanks
Hi
DMAx_TCD_BITER_ELINK and DMAx_TCD_CITER_ELINK must be set to the number of bytes to be sent.
Then
DMAx_TCD_CSR |= DMA_TCD_CSR_DREQ;
is required so that the DMA activity stops after the number of characters has been sent, otherwise it will keep repeating.
Regards
Mark
[uTasker project developer for Kinetis and i.MX RT]
Hi Mark,
I am also trying to send 8 bytes of data with uart0. As soon as i write below line in configuration my 8 byte data is sent.
DMAMUX0_CHCFG(channel) = DMAMUX_CHCFG_ENBL_MASK;
I don't know what is triggering the dma transfer. But I wanna know how should I initiate another transfer.
Hi, my UART "flush" function is this
/***********************************************************************
*
Function Name : UDMASendData
Description : Sends (transmits) data out through the UART-DMA module
with resource control
*
resource control - waits till PREVIOUS operation is finished. So once
you call uart66SendBuf
and module is not actually sending data, function takes semaphore and
starts UART-DMA sending
and function returns immediatelly. Consequent calling will block the
task (wait for semaphore)
till previous message is sent out, or semaphore timeout.
*
***************************************************************************/
uint32_t uart66SendBuf(const uint8_t * txBuff, uint32_t txSize, uint32_t
timeout)
{
portBASE_TYPE semaphoreStat;
if (uart66.txIrqSync == NULL)
{
LOGM66P(6, logmDebug, "M66portuart66SendBuf() semaphore NULL\n");
return kStatus_UART_NullParameter;
}
semaphoreStat = xSemaphoreTake(uart66.txIrqSync, timeout);
if(semaphoreStat == pdFALSE) // timeout
{
LOGM66P(7, logmDebug, "M66portuart66SendBuf() semaphore take
FAIL\n");
return (kStatus_UART_Timeout);
}
/* Update txBuff and txSize. */
DMA0->TCD[TXDMACH].SADDR = (uint32_t)txBuff;
DMA0->TCD[TXDMACH].BITER_ELINKNO = txSize;
DMA0->TCD[TXDMACH].CITER_ELINKNO = txSize;
/* Enable DMA major loop interrupt */
DMA0->TCD[TXDMACH].CSR = DMA_CSR_INTMAJOR_MASK | DMA_CSR_DREQ_MASK;
/* Start DMA channel */
DMA0->SERQ = 1;
LOGM66P(8, logmDebug, "M66portuart 66SendBuf() UART Tx started\n");
return (kStatus_UART_Success);
}
Radomir
po 25. 5. 2020 v 8:36 odesílatel prashantdev <admin@community.nxp.com>
napsal:
NXP Community
<https://community.freescale.com/resources/statics/1000/35400-NXP-Community-Email-banner-600x75.jpg>
Re: DMA buffer to Tx UART on K10DN512
reply from prashantdev
<https://community.nxp.com/people/prashantdev?et=watches.email.thread> in *Kinetis
Microcontrollers* - View the full discussion
<https://community.nxp.com/message/1316554?commentID=1316554&et=watches.email.thread#comment-1316554>
thanx for the help.
That works, thank you