mx rt 1020 send 9bit over DMA

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

mx rt 1020 send 9bit over DMA

ソリューションへジャンプ
3,319件の閲覧回数
bp1979
Senior Contributor I

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 

bp1979_0-1634911199353.png

but is should send one "9bit byte" 0x108.

I am obviously doing this wrong, how can I send 9bits over DMA?

 

 

0 件の賞賛
返信
1 解決策
3,238件の閲覧回数
Omar_Anguiano
NXP TechSupport
NXP TechSupport

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.

Omar_Anguiano_0-1636076857352.png

2. In LPUART_SendEDMA() modified the parameters from EDMA_PrepareTransfer() function, the parameters I modified are bytesEachRequest and transferBytes:

Omar_Anguiano_1-1636076877119.png
Here are my results:

Omar_Anguiano_2-1636076909711.png
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

元の投稿で解決策を見る

9 返答(返信)
2,406件の閲覧回数
masterboy
Contributor III

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:

Snímek obrazovky 2023-03-07 v 8.26.20.png

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:

Snímek obrazovky 2023-03-07 v 8.34.00.png

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.

 

 

 

0 件の賞賛
返信
2,396件の閲覧回数
bp1979
Senior Contributor I

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

0 件の賞賛
返信
1,314件の閲覧回数
davenadler
Senior Contributor I

@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:

  1. transmit an address byte with 9-bit set to trigger message reception, followed by all payload bytes in message with 9-bit cleared,
  2. use DMA for transmission to minimize ISR overhead
  3. DMA 8-bit quantities as that's how the messages are normally constructed and processed.

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:

  1. Enable the TX FIFO.
  2. Write the address (first byte) as a 32-bit value to the DATA register with the 9-bit set. This pushes the address through the FIFO and starts sending.
  3. Write the second byte of the message as a 32-bit quantity with the 9-bit cleared to the DATA register. This queues the second byte and clears the 9-bit control bit.
  4. DMA the 8-bit message from the 3rd byte. Because the above step cleared the 9-bit control bit the values are all sent with the 9-bit cleared.

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:

  1. change the FSL LPUART driver, especially as we're normally using this driver for other (non-RS485) ports. In my application 3 RS-232 ports...
  2. reformat RS485 messages from 8-bit to 16-bit just to accommodate the 9-bit issue

Hope that helps folks!
Best Regards, Dave

0 件の賞賛
返信
1,312件の閲覧回数
davenadler
Senior Contributor I
0 件の賞賛
返信
466件の閲覧回数
bp1979
Senior Contributor I
Oef, no not that I am aware of. Have glanced at your question, but I am not a hardware engineer so doubt I can keep up in your domain
0 件の賞賛
返信
3,239件の閲覧回数
Omar_Anguiano
NXP TechSupport
NXP TechSupport

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.

Omar_Anguiano_0-1636076857352.png

2. In LPUART_SendEDMA() modified the parameters from EDMA_PrepareTransfer() function, the parameters I modified are bytesEachRequest and transferBytes:

Omar_Anguiano_1-1636076877119.png
Here are my results:

Omar_Anguiano_2-1636076909711.png
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

3,170件の閲覧回数
bp1979
Senior Contributor I

@Omar_Anguiano  Thank you very much! Took me a while before I could dip into this, but  finally got  this to work!  

0 件の賞賛
返信
3,279件の閲覧回数
bp1979
Senior Contributor I

Dear nxp

Would anybody care to give some guidance? How do i send 9bit over lpuart using dma? 

0 件の賞賛
返信
3,275件の閲覧回数
bp1979
Senior Contributor I

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);
        }
    }
0 件の賞賛
返信