imx rt 1020 9bit uart DMA

cancel
Showing results for 
Search instead for 
Did you mean: 

imx rt 1020 9bit uart DMA

Jump to solution
204 Views
bp1979
Contributor IV

I am working with an imx rt 1020 board, and experiencing weird readouts with LPUART3 set to 9bit using DMA:

- dma interrupts half full and full

- uart idle line detection

- buffer for DMA is array of uint16_t (size is 128 elements)

When I use this uart interrupt based (storing every read 9bit byte in a ringbuffer) I can read the received bytes without problems. It's connected to some MBD bus which is constantly polling a device on address 0x12, so the master is sending 0x112 0x12 over and over again. Storing the bytes on each interrupt and reading from the ring buffer in a freertos task gives me the expected output, I print 0x112 0x12 repeatedly.

Also, when I set `LPUART_Enable9bitMode(_instance, 0);` and I change the buffer from uint16_t to uint8_t (so basically ignoring the 9th bit which I am receiving) I receive 0x12 0x12 over and over again. So also this, seems to work just fine.

bp1979_0-1632946639101.png

But then, when I then use DMA with 9bit enabled, and the buffer is created as array of uint16_t again, I receive garbage. DMA is filling my array with correct expected 0x112 0x12 bytes, but there is a garbage too.

bp1979_2-1632946924436.png

The creation of the 9bit uart object

Uart2<uint16_t> uartMdb(
	LPUART3,
	LPUART3_IRQn,
	DMA4_DMA20_IRQn,
	DMA5_DMA21_IRQn,
	5,
	128,
	true,
	kDmaRequestMuxLPUART3Rx,
	4,
	kDmaRequestMuxLPUART3Tx,
	5);

 

The method that starts the uart (called from main task with arguments 9600, true)

    void Start(uint32_t baudRate = 115200, bool is9bit = false)
    {
        _baudRate = baudRate;

        InitializeUart();
        InitializeDma();

        LPUART_Enable9bitMode(_instance, is9bit);

        // Enable idle line detection
        if (_canRead)
        {
            InitializeRingBuffer();
            LPUART_EnableInterrupts(_instance, (uint32_t)kLPUART_IdleLineInterruptEnable);
            //LPUART_EnableInterrupts(_instance, (uint32_t)kLPUART_RxDataRegFullInterruptEnable | (uint32_t)kLPUART_RxOverrunInterruptEnable);

            // Uart irq and dma rx are only required when uart should receive data
            EnableIRQ(_uartIrq);
            NVIC_SetPriority(_uartIrq, _priority);
            NVIC_SetPriority(_dmaRxIrq, _priority);
        }

        // Dma tx is always required (tx is not optional in this design)
        NVIC_SetPriority(_dmaTxIrq, _priority);
    }

 

The private method InitializeRingBuffer, which I believe is the only relevant method

NOTE: T = uint16_t

    void InitializeRingBuffer()
    {
        EDMA_InstallTCDMemory(&_rxDmaHandle, &_tcdMemoryPool, 1U);

        edma_transfer_config_t xferConfig;
        EDMA_PrepareTransfer(
            &xferConfig, 
            (void *)LPUART_GetDataRegisterAddress(_instance),
            sizeof(T),
            _rxBuffer, 
            sizeof(T),
            sizeof(T),
            _rxRbSize,
            kEDMA_PeripheralToMemory);
        
        _rxDmaHandle.tcdUsed = 1U;
        _rxDmaHandle.tail = 0U;

        EDMA_TcdReset(&_rxDmaHandle.tcdPool[0U]);
        EDMA_TcdSetTransferConfig(&_rxDmaHandle.tcdPool[0U], &xferConfig, &_tcdMemoryPool);

        // Enable both half complete and complete interrupts
        _rxDmaHandle.tcdPool[0U].CSR |= DMA_CSR_INTMAJOR_MASK | DMA_CSR_INTHALF_MASK ;

        EDMA_InstallTCD(_rxDmaHandle.base, _rxDmaHandle.channel, _rxDmaHandle.tcdPool);

        // Install rx dma callback
        EDMA_SetCallback(&_rxDmaHandle, RxDmaCallback, this);

        // Start the dma transfer
        EDMA_StartTransfer(&_rxDmaHandle);

        // Enable rx dma for this uart instance
        LPUART_EnableRxDMA(_instance, true);
    }

 

I can share more code if desired, I can share my entire project if that helps.

With this limited information, can somebody already give a hint what I am doing wrong?

 

 

 

 

0 Kudos
1 Solution
133 Views
bp1979
Contributor IV

oh..........my................god..................

Steps to solve my problem:

- make buffer which is being written by DMA smaller for easier debugging (array of 10 elements of type uint16_6)

- each time the interrupt idle line of dma (half) full fired and wakes up my read from uart task: log the buffer

then, I could easily see: my buffer only gets filled for 50%....

The fix:

        EDMA_PrepareTransfer(
            &xferConfig, 
            (void *)LPUART_GetDataRegisterAddress(_instance),
            sizeof(T),
            _rxBuffer, 
            sizeof(T),
            sizeof(T),
            _rxRbSize * sizeof(T), <===== the size of the buffer (10 elements) TIMES the sizeof the element (which is a uint16_t....)
            kEDMA_PeripheralToMemory);

 

And voila... problem solved.

The reason for the "sometimes correct and sometimes garbage" is then very easy to explain. The buffer is created and I am reading elements in the buffer which were never written by DMA, so random memory, random values....

Ah well, at least it works now

 

Thx for the help anyway!!

View solution in original post

0 Kudos
4 Replies
191 Views
bp1979
Contributor IV

When I change a few things and ignore the 9th bit, thus 

LPUART_Enable9bitMode(_instance, false)

and settings DMA as follows

EDMA_PrepareTransfer(
            &xferConfig, 
            (void *)LPUART_GetDataRegisterAddress(_instance), // _instance = LPUART3
            sizeof(uint8_t),
            _rxBuffer, 
            sizeof(uint8_t),
            sizeof(uint8_t),
            _rxRbSize, // 128
            kEDMA_PeripheralToMemory);

then the received bytes only contain 0x12 bytes. Which makes sense, the 9th bit is cut off, so 0x112 is read as 0x12.

Is there anybody who can give a hint what can go wrong when I want to use DMA with LPUART set to 9bit?

 

0 Kudos
168 Views
Omar_Anguiano
NXP TechSupport
NXP TechSupport

Hello
Hope you are well. I apologize for my delayed reply.
I suggest you change the parameter transfer size from the variable "xferConfig" so it is configured for 2 bytes.

Let me know if this is helpful, if you have more questions do not hesitate to ask me.
Best regards,
Omar

0 Kudos
151 Views
bp1979
Contributor IV

Hi @Omar_Anguiano 

Thanks for your reply, I am afraid I don't understand what you mean.

        EDMA_PrepareTransfer(
            &xferConfig, 
            (void *)LPUART_GetDataRegisterAddress(_instance),
            sizeof(T),
            _rxBuffer, 
            sizeof(T),
            sizeof(T),
            _rxRbSize,
            kEDMA_PeripheralToMemory);

T is uint16_t, so sizeof(T) returns 2.

With this signature that would already do as you suggested, right?

void EDMA_PrepareTransfer(edma_transfer_config_t *config,
                          void *srcAddr,
                          uint32_t srcWidth, = 2
                          void *destAddr,
                          uint32_t destWidth, = 2
                          uint32_t bytesEachRequest, = 2
                          uint32_t transferBytes,
                          edma_transfer_type_t type)

 

 

0 Kudos
134 Views
bp1979
Contributor IV

oh..........my................god..................

Steps to solve my problem:

- make buffer which is being written by DMA smaller for easier debugging (array of 10 elements of type uint16_6)

- each time the interrupt idle line of dma (half) full fired and wakes up my read from uart task: log the buffer

then, I could easily see: my buffer only gets filled for 50%....

The fix:

        EDMA_PrepareTransfer(
            &xferConfig, 
            (void *)LPUART_GetDataRegisterAddress(_instance),
            sizeof(T),
            _rxBuffer, 
            sizeof(T),
            sizeof(T),
            _rxRbSize * sizeof(T), <===== the size of the buffer (10 elements) TIMES the sizeof the element (which is a uint16_t....)
            kEDMA_PeripheralToMemory);

 

And voila... problem solved.

The reason for the "sometimes correct and sometimes garbage" is then very easy to explain. The buffer is created and I am reading elements in the buffer which were never written by DMA, so random memory, random values....

Ah well, at least it works now

 

Thx for the help anyway!!

View solution in original post

0 Kudos