Hi
I am using an imx rt 1020 and try to send 9bit data over dma, but having trouble sending the 9th bit.
status_t LPUART_SendEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, lpuart_transfer_t *xfer)
the lpuart_transfer_t is defined as follows
typedef struct _lpuart_transfer
{
uint8_t *data; /*!< The buffer of data to be transfer.*/
size_t dataSize; /*!< The byte count to be transfer. */
} lpuart_transfer_t;
I tried to split uint16_t bytes in two bytes and sent that over, but it doesn't work.
uint32_t txIndex = 0;
for (uint32_t i = 0; i < length; i++)
{
// T == uint16_t
T d = data[i];
if (sizeof(T) == 2)
{
_txBuffer[txIndex++] = d & 0xFF ;
_txBuffer[txIndex++] = (d & 0x100) >> 8 ;
}
else
{
_txBuffer[txIndex++] = d;
}
}
_sendXfer.data = _txBuffer;
_sendXfer.dataSize = length;
LPUART_SendEDMA(_instance, &_uartDmaHandle, &_sendXfer);
this sends
but is should send one "9bit byte" 0x108.
I am obviously doing this wrong, how can I send 9bits over DMA?
已解决! 转到解答。
Hello
Hope you are well and I apologize for my delayed reply.
Commonly the 9bit is used to send the parity bit and have 8 bits of data, this can be done in the example without the need of setting anything extra besides the 9th bit and parity enable.
I did some modifications to the example so it supports the 9bith data without parity:
1. Modified the data types from structure "lpuart_transfer_t" so the uint´s are of 16bits.
2. In LPUART_SendEDMA() modified the parameters from EDMA_PrepareTransfer() function, the parameters I modified are bytesEachRequest and transferBytes:
Here are my results:
Notes: xfer.dataSize needs to be in multiples of 2. If you write 4 to that variable then 2 9bit LPUART frames are sent.
Let me know if this is helpful, if you have more questions do not hesitate to ask me.
Best regards,
Omar
Hello,
I am also addressing the 9-bit mode of LPUART via eDMA. I modified the code as Omar_Anguiano wrote. I am unable to send more than one 9-bit byte. Each byte sent has 1 at the beginning e.g. if I send 0x48 it sends 0x148, if I send 0x02 it sends 0x102.
#include "pin_mux.h"
#include "clock_config.h"
#include "board.h"
#include "fsl_lpuart_edma.h"
#include "fsl_dmamux.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define DEMO_LPUART LPUART3
#define DEMO_LPUART_CLK_FREQ BOARD_DebugConsoleSrcFreq()
#define LPUART_TX_DMA_CHANNEL 0U
#define LPUART_RX_DMA_CHANNEL 1U
#define LPUART_TX_DMA_REQUEST kDmaRequestMuxLPUART3Tx
#define LPUART_RX_DMA_REQUEST kDmaRequestMuxLPUART3Rx
#define EXAMPLE_LPUART_DMAMUX_BASEADDR DMAMUX
#define EXAMPLE_LPUART_DMA_BASEADDR DMA0
#define ECHO_BUFFER_LENGTH 8
/*******************************************************************************
* Prototypes
******************************************************************************/
/* LPUART user callback */
void LPUART_UserCallback(LPUART_Type *base, lpuart_edma_handle_t *handle, status_t status, void *userData);
/*******************************************************************************
* Variables
******************************************************************************/
lpuart_edma_handle_t g_lpuartEdmaHandle;
edma_handle_t g_lpuartTxEdmaHandle;
edma_handle_t g_lpuartRxEdmaHandle;
AT_NONCACHEABLE_SECTION_INIT(uint8_t g_tipString[]) =
"LPUART EDMA example\r\nSend back received data\r\nEcho every 8 characters\r\n";
AT_NONCACHEABLE_SECTION_INIT(uint8_t g_txBuffer[ECHO_BUFFER_LENGTH]) = {0};
AT_NONCACHEABLE_SECTION_INIT(uint8_t g_rxBuffer[ECHO_BUFFER_LENGTH]) = {0};
AT_NONCACHEABLE_SECTION_INIT(uint16_t test[ECHO_BUFFER_LENGTH]) = {0};
volatile bool rxBufferEmpty = true;
volatile bool txBufferFull = false;
volatile bool txOnGoing = false;
volatile bool rxOnGoing = false;
edma_config_t config;
/*******************************************************************************
* Code
******************************************************************************/
/* LPUART user callback */
void LPUART_UserCallback(LPUART_Type *base, lpuart_edma_handle_t *handle, status_t status, void *userData)
{
userData = userData;
if (kStatus_LPUART_TxIdle == status)
{
txBufferFull = false;
txOnGoing = false;
}
if (kStatus_LPUART_RxIdle == status)
{
rxBufferEmpty = false;
rxOnGoing = false;
}
}
/*!
* @brief Main function
*/
int main(void)
{
lpuart_config_t lpuartConfig;
lpuart_transfer_t xfer;
lpuart_transfer_t sendXfer;
lpuart_transfer_t receiveXfer;
BOARD_ConfigMPU();
BOARD_InitBootPins();
BOARD_InitBootClocks();
/* Initialize the LPUART. */
/*
* lpuartConfig.baudRate_Bps = 115200U;
* lpuartConfig.parityMode = kLPUART_ParityDisabled;
* lpuartConfig.stopBitCount = kLPUART_OneStopBit;
* lpuartConfig.txFifoWatermark = 0;
* lpuartConfig.rxFifoWatermark = 0;
* lpuartConfig.enableTx = false;
* lpuartConfig.enableRx = false;
*/
LPUART_GetDefaultConfig(&lpuartConfig);
lpuartConfig.baudRate_Bps = BOARD_DEBUG_UART_BAUDRATE;
lpuartConfig.enableTx = true;
lpuartConfig.enableRx = true;
LPUART_Init(DEMO_LPUART, &lpuartConfig, DEMO_LPUART_CLK_FREQ);
/* Init DMAMUX */
DMAMUX_Init(EXAMPLE_LPUART_DMAMUX_BASEADDR);
/* Set channel for LPUART */
DMAMUX_SetSource(EXAMPLE_LPUART_DMAMUX_BASEADDR, LPUART_TX_DMA_CHANNEL, LPUART_TX_DMA_REQUEST);
DMAMUX_SetSource(EXAMPLE_LPUART_DMAMUX_BASEADDR, LPUART_RX_DMA_CHANNEL, LPUART_RX_DMA_REQUEST);
DMAMUX_EnableChannel(EXAMPLE_LPUART_DMAMUX_BASEADDR, LPUART_TX_DMA_CHANNEL);
DMAMUX_EnableChannel(EXAMPLE_LPUART_DMAMUX_BASEADDR, LPUART_RX_DMA_CHANNEL);
/* Init the EDMA module */
EDMA_GetDefaultConfig(&config);
EDMA_Init(EXAMPLE_LPUART_DMA_BASEADDR, &config);
EDMA_CreateHandle(&g_lpuartTxEdmaHandle, EXAMPLE_LPUART_DMA_BASEADDR, LPUART_TX_DMA_CHANNEL);
EDMA_CreateHandle(&g_lpuartRxEdmaHandle, EXAMPLE_LPUART_DMA_BASEADDR, LPUART_RX_DMA_CHANNEL);
/* Create LPUART DMA handle. */
LPUART_TransferCreateHandleEDMA(DEMO_LPUART, &g_lpuartEdmaHandle, LPUART_UserCallback, NULL, &g_lpuartTxEdmaHandle, &g_lpuartRxEdmaHandle);
/* Send out. */
test[0] = 0x48;
xfer.data = test;
xfer.dataSize = 2;
txOnGoing = true;
LPUART_SendEDMA(DEMO_LPUART, &g_lpuartEdmaHandle, &xfer);
/* Wait send finished */
while (txOnGoing)
{
}
test[0] = 0x02;
xfer.data = test;
xfer.dataSize = 2;
txOnGoing = true;
LPUART_SendEDMA(DEMO_LPUART, &g_lpuartEdmaHandle, &xfer);
while (1);
}
This is the result:
I need the first byte to be 0x148 and the second only 0x02. There is also the problem of having to send each byte separately.
If I edit the code to send the data:
/* Send out. */
test[0] = 0x48;
test[1] = 0x02;
xfer.data = test;
xfer.dataSize = 4;
txOnGoing = true;
LPUART_SendEDMA(DEMO_LPUART, &g_lpuartEdmaHandle, &xfer);
/* Wait send finished */
while (txOnGoing)
{
}
This is the result:
What could be the problem?
Besides, this is only half of what I'm dealing with. The other is receiving data in 9-bit mode. Again, the first byte must have a flag of 1 and the other flags for the data are 0.
Hi @masterboy ,
Just had a real quick look at your code which looks fine at a first glance. One thing that you seem to miss is to configure the uart as 9bit
```
LPUART_Enable9bitMode
```
Does that fix anything? If not, I'll have another look
@bp1979, @masterboy , @Omar_Anguiano - a few notes on 9-bit for those still working on these this...
First, what we're all trying to do for the usual RS485 protocols:
Many UART implementations automatically clear the UART 9-bit control after sending the first byte, so you can just set this control bit then DMA the entire message (DMA of 8-bit bytes). Sadly the LPUART implementation in iMX.RT does not do that. But fortunately the LPUART has a decent FIFO. What I did for transmission of the RS485 message to work with these limitations:
This works just great with the minor setup overhead shown above but no additional ISR overhead.
@Omar_Anguianoplease note: while your example is helpful, we do not want to:
Hope that helps folks!
Best Regards, Dave
PS: @bp1979 , @masterboy - Have you also encountered this LPUART hardware problem?
https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/LPUART-hardware-bugs-framing-error-not-detected-...
Hello
Hope you are well and I apologize for my delayed reply.
Commonly the 9bit is used to send the parity bit and have 8 bits of data, this can be done in the example without the need of setting anything extra besides the 9th bit and parity enable.
I did some modifications to the example so it supports the 9bith data without parity:
1. Modified the data types from structure "lpuart_transfer_t" so the uint´s are of 16bits.
2. In LPUART_SendEDMA() modified the parameters from EDMA_PrepareTransfer() function, the parameters I modified are bytesEachRequest and transferBytes:
Here are my results:
Notes: xfer.dataSize needs to be in multiples of 2. If you write 4 to that variable then 2 9bit LPUART frames are sent.
Let me know if this is helpful, if you have more questions do not hesitate to ask me.
Best regards,
Omar
Dear NXP
if there is any better way, please let me know. For now just went for a hacky blocking write
virtual void Write(T *data, uint32_t length)
{
projectAssert(sizeof(_txBuffer) > length, ErrorCodeUartTxMessageTooLarge);
if (sizeof(T) == 2)
{
// If T is uint16_t, write to uart blocking
// Waiting for answer how to send 9bit data over uart with DMA
// https://community.nxp.com/t5/i-MX-RT/mx-rt-1020-send-9bit-over-DMA/td-p/1360134
for (uint32_t i=0; i<length; i++)
{
while (!(_instance->STAT & LPUART_STAT_TDRE_MASK))
{
// Wait for transmit ready
}
uint32_t temp = _instance->DATA & 0xFFFFFC00UL;
temp |= (uint32_t)data[i];
_instance->DATA = temp;
}
}
else if (sizeof(T) == 1)
{
// Else... regular send data over DMA
xSemaphoreTake(_txSemaphore, portMAX_DELAY);
for (uint32_t i = 0; i < length; i++)
{
_txBuffer[i] = data[i];
}
_sendXfer.data = _txBuffer;
_sendXfer.dataSize = length;
LPUART_SendEDMA(_instance, &_uartDmaHandle, &_sendXfer);
}
else
{
// For now we only support 8 bit and 16 bit data types
projectAssert(0, ErrorCodeUartUnsupportedType);
}
}