QN9020 UART RX by DMA

cancel
Showing results for 
Search instead for 
Did you mean: 

QN9020 UART RX by DMA

294 Views
Contributor I

QN9020 DMA Documentation

I am using DMA_RX to access to the UART RX (1Mb).

The problem I have is that I lost some buffer.

The FIFO of UART_RX is 8bits and I receive information by packet of 4/8/16/bytes.

So I read the DMA by 4 bytes in the IRQ.

But even If i ask for a new DMA request in the IRQ , I lost some bytes.

I put the DMA priority to 1 and others to 3

I cannot find any information on the DMA register that can help me.

Thx

Oliver

Labels (1)
  • QN

0 Kudos
9 Replies

100 Views
NXP TechSupport
NXP TechSupport

Hi Oliver,

I hope you are doing great.

The UART baud rate could be taking all the CPU, and the timer could not get the exact time that you set.

Is it possible that you could use a higher 32M OSC and set the AHB clock to 32M?

Regards,

Mario

0 Kudos

156 Views
NXP TechSupport
NXP TechSupport

Hi Oliver,

I hope you are doing great.

How are you implementing the reading of the DMA on the IRQ?

Just to confirm, did you look at the DMA example that we provide in our SDK?

C:\NXP\QN902x_SDK_1.4.0\Projects\Driver\dma\

Please look at the DMA configuration, Peripheral (UART0) to memory.

 dma_rx(DMA_TRANS_BYTE, DMA_UART0_RX, (uint32_t)rxbuffer, 20, dma_done);

You have 3 different transfer modes. 

enum DMA_TRANS_MODE
{
    DMA_TRANS_BYTE      = 0,        /*!< Set DMA transfer mode as byte transfer */
    DMA_TRANS_HALF_WORD = 1,        /*!< Set DMA transfer mode as half word transfer */
    DMA_TRANS_WORD      = 2         /*!< Set DMA transfer mode as word transfer */
};

Regards,

Mario

0 Kudos

156 Views
Contributor I

Hi Mario,

Thank you for your feedback

As I am using UART1 with 8bits FIFO, I use DMA_TRANS_BYTE. Note that UART1 is set at 1Mb and I receive a lot of traffic

void init_dma()

{

   dma_rx(DMA_TRANS_BYTE, DMA_UART1_RX, (uint32_t)midi_uart_env.buf_rx,200, midi_uart_rx_done);

}

void midi_uart_rx_done(void)
{

if(midi_uart_env.buf_rx[0] != 0x09)

   {

      QPRINTF("I LOST ONE BYTE OR MORE");

   }

dma_rx(DMA_TRANS_BYTE, DMA_UART1_RX, (uint32_t)midi_uart_env.buf_rx,200, midi_uart_rx_done);

}

The problem is that sometimes I lost one bytes between two DMA call and I cannot lost 1 bytes otherwise by buffers are Shifted.

And unfortunatley I do not see any option for using circular buffer.

If I use bigger buffer I not have any bytes lost during the transfer, but only during two request even If I ask for a new DMA request as soon as possible.

Regards

Oliver

0 Kudos

156 Views
NXP TechSupport
NXP TechSupport

Hi Oliver,

Is there a specific reason why are calling again the dma_rx()?

Are you calling the dma_init()?

However, could you please try with the DMA driver example?

"C:\NXP\QN902x_SDK_1.4.0\Projects\Driver\dma\src\dma_example.c"

    /* Peripheral(UART0) to Memory */
    done = FALSE;
    dma_rx(DMA_TRANS_BYTE, DMA_UART1_RX, (uint32_t)rxbuffer, 200, dma_done);
    while(done == FALSE);

The callback dma_done.

void dma_done(void)
{
    done = TRUE;
}

After, all this process you could look at the buffer and be sure that your data is there.

Regards,

Mario

0 Kudos

156 Views
Contributor I

Hi Mario,

I am calling again the dma_rx because I still receive data on the UART, and I cannot allocate a buffer more than 2047 bytes ( according nxp documentation ).

So I ask for a new DMA request.

The best will be to have a DMA that allows circular buffer.

I have tried the dma_example, and I well receive my data .

If I wait for dma_done in main loop and do not lost any buffer, but the problem is that it blocks all other event and especially BLE.

while(1)
{
   done = FALSE;
   dma_rx(DMA_TRANS_BYTE, DMA_UART1_RX, (uint32_t)rxbuffer,4, dma_done);
   while(done == FALSE);
   if(rxbuffer[0] != FIRST_MARKER_BYTE)
      {
      uart_printf(QN_UART0, (uint8_t *)"Lost BYTES!!!\n");
      }
 }

if I do the second request in the call_back,

void dma_done(void)
{
dma_rx(DMA_TRANS_BYTE, DMA_UART1_RX, (uint32_t)rxbuffer, 4, dma_done);

if(rxbuffer[0] != FIRST_MARKER_BYTE)
      {
      uart_printf(QN_UART0, (uint8_t *)"Lost BYTES!!!\n");
      }
 }
}

I lost some bytes between the requests. If I use huge DMA buffer, I do not have any data lost on the requested buffer, it's only between the requests

Regards,

Oliver

0 Kudos

156 Views
NXP TechSupport
NXP TechSupport

Hi Oliver,

You have to add the DMA routing to the scheduler and it will provide the resources without bocking the Bluetooth communication.

The example provides this implementation depending on the UART 0 or 1 and if you want to use DMA or not.

by default, the example doesn't have defined this feature. driver_config.h

#define UART_DMA_EN         FALSE       /*!< Enable/Disable UART DMA function */

You could define as true and look for the UART_RX_DMA_EN, you could call the uart_read included in the app_sys.c

Regards,

Mario

0 Kudos

156 Views
Contributor I

Hi Marco,

I think , I have found the reason of my issue but unfortunateley not the solution.

It seems it's related to My TIMER.

I have a TIMER2 at 1ms and if I disable this TIMER  all the DMA request are OK,

Even if I set the DMA Priority to 1 and TIMER2 Priority to 3 and still have the problem.

Is there another way to do a 1ms timer or a reason why this TIMER disturn so much the DMA .

Regards,

Oliver

0 Kudos

156 Views
NXP TechSupport
NXP TechSupport

Hi Oliver,

The timer should not disturb the DMA, the DMA is not using the MCU, but when you try to read out this information the timer or the Bluetooth could avoid entering this routine.

I recommend adding the peripheral configuration to the scheduler, it will provide all the resources to the task in the running process.

How are you adding this timer? are you calling the ke_timer_set to get this 1 ms?

Regards,

Mario

0 Kudos

156 Views
Contributor I

Hi Mario,

I use hardware TIMER0, I do not use ke_timer_set because I was thinking it was 10ms precision

void app_timer_init(void)
{
midi_uart_env.mytimer = 0;
timer_init(QN_TIMER0, timer_callback_1ms);
timer_config(QN_TIMER0, 10, TIMER_COUNT_MS(1, 10));
timer_enable(QN_TIMER0, MASK_ENABLE);

}

Regards,

Olivier

0 Kudos