lpc1788: UART with 3 Mbaud - receiver not working

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

lpc1788: UART with 3 Mbaud - receiver not working

1,039 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TKoe on Tue Sep 18 00:41:24 MST 2012
Hello!

As the title says I have a problem with receiving data at higher speeds. I have tested the UART with the speed of 3 Mbaud and sending data is not a problem. The reason for trying out the 3 Mbaud is that the FTDI chip which the UART is connected to supports those speeds.
So when I try to receive data with the normal RBR interrupt I  can receive data, but only the first byte is correct, the rest is completely wrong, not just single bits. I found that plausible because the whole interrupt would need less than 40 cycles to finish to not lose any data, possibly less.
So I figured I'd use DMA instead. The following test program expects five bytes which it will echo together with some debug data. This program works just fine with i.e. 750 kbaud. Sending "hello" will return "00 01 FF 00 ff 'hello' 00".
However, when I set it to the desired 3 Mbaud it will return some weird stuff:
"00 01 FF 00 FF 90 29 12 BB B8 00"
"00 02 FF 00 FF F9 F3 D0 29 13 00"
etc.

What am I doing wrong?


Regards,
Tim




Here's my code:

<code>
#ifdef __USE_CMSIS
#include "LPC177x_8x.h"
#endif

#include <cr_section_macros.h>
#include <NXP/crp.h>

// Variable to store CRP value in. Will be placed automatically
// by the linker when "Enable Code Read Protect" selected.
// See crp.h header for more information
__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;

#include <stdbool.h>
#include "lpc177x_8x_uart.h"
#include "lpc177x_8x_pinsel.h"
#include "lpc177x_8x_nvic.h"
#include "lpc177x_8x_gpdma.h"


// UART definitions
#define UART_ID   UART_0
#define UART        LPC_UART0
#define UART_IRQ UART0_IRQn

// DMA definition
#define DMA_CH_NUM 0
#define DMA_CH         LPC_GPDMACH0
#define DMA_SIZE       5


UART_CFG_Type uart_cfg =
{
      .Baud_rate = 3000000, // Yes, that's 3 Mbaud
      .Parity = UART_PARITY_NONE,
      .Databits = UART_DATABIT_8,
      .Stopbits = UART_STOPBIT_1,
};

UART_FIFO_CFG_Type uart_fifo_cfg =
{
      .FIFO_ResetRxBuf = ENABLE,
      .FIFO_ResetTxBuf = ENABLE,
      .FIFO_DMAMode = ENABLE,
      .FIFO_Level = UART_FIFO_TRGLEV0,
};

GPDMA_Channel_CFG_Type dma_cfg =
{
      .ChannelNum = DMA_CH_NUM,
      .TransferSize = 0,
      .TransferWidth = GPDMA_WIDTH_BYTE,
      .SrcMemAddr = 0,
      .DstMemAddr = 0,
      .TransferType = GPDMA_TRANSFERTYPE_P2M,
      .SrcConn = GPDMA_CONN_UART0_Rx,
      .DstConn = 0,
      .DMALLI = 0,
};


uint8_t buffer[100];
bool dmaflag = false;
int dma_counter = 0;
int dma_error = 0;



void DMA_IRQHandler()
{
   if (GPDMA_IntGetStatus(GPDMA_STAT_INTTC, DMA_CH_NUM))
   {
      dmaflag = true;
      dma_counter++;
      GPDMA_ClearIntPending(GPDMA_STATCLR_INTTC, DMA_CH_NUM);
   }
   else
   {
      dma_error++;
      GPDMA_ClearIntPending(GPDMA_STATCLR_INTERR, DMA_CH_NUM);
   }
}



void DisableDMAch(void)
{
   GPDMA_ChannelCmd(DMA_CH_NUM, DISABLE);
   NVIC_DisableIRQ(DMA_IRQn);
}

void EnableDMAch(uint32_t count, uint8_t * memp)
{
   if (DMA_CH->CConfig & 0x00000001)
   {
      // if the channel is enabled we need to disable
      // it, set the parameters and re-enable it!
      DisableDMAch();
   }

   // dma_cfg-modifications
   dma_cfg.DstMemAddr = (uint32_t)memp;
   dma_cfg.TransferSize = count;

   GPDMA_Setup(&dma_cfg);
   NVIC_SetPriority(DMA_IRQn, 1);
   dmaflag = false;
   NVIC_EnableIRQ(DMA_IRQn);
   GPDMA_ChannelCmd(DMA_CH_NUM, ENABLE);
}

int main(void)
{
   GPDMA_Init();
   PINSEL_ConfigPin(0, 2, 0b001);
   PINSEL_ConfigPin(0, 3, 0b001);
   UART_Init(UART, &uart_cfg);
   UART_FIFOConfig(UART_ID, &uart_fifo_cfg);
   UART_TxCmd(UART, ENABLE);
   EnableDMAch(DMA_SIZE, buffer);

   while(1)
   {
      while (!dmaflag);

      {
         uint8_t txbuf[200];
         int i;
         txbuf[0] = 0x00;
         txbuf[1] = dma_counter & 0xFF;
         txbuf[2] = 0xFF;
         txbuf[3] = dma_error & 0xFF;
         txbuf[4] = 0xFF;
         for (i = 0; i < DMA_SIZE; i++)
            txbuf[5 + i] = buffer;
         txbuf[5 + DMA_SIZE] = 0x00;

         UART_Send(UART, txbuf, 6 + DMA_SIZE, BLOCKING);
         EnableDMAch(DMA_SIZE, buffer);
      }
   }
   return 0 ;
}
</code>
Labels (1)
0 Kudos
6 Replies

739 Views
stefannikolov
Contributor I

Hello, 

We have same issue. LPC1788 is not receiving correctly at 3MBit speed. Even we use loopback and is still not correct.

Frequency that is working correctly:

2Mbit, 2.5Mbit,3.75Mbit, 7Mbit.

We need 3Mbit or 3.25MBit. both have problem. We use UART0 for 3Mbit: DivaddVal=1, MulVal=4, UnDll =2, Pclck=120Mhz

It is not CTI related. 

I don not see anything in errata document. 

Currently we use 921600 but is too slow.  

This is quite urgent.

Best Regards,

Stefan

0 Kudos

739 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Daniel Widyanto on Thu Oct 04 06:24:04 MST 2012
Hi,

Please handle the CTI interrupt !!

The CTI will trigger if there's UART data in FIFO, but no of data hasn't reached the watermark. If you don't handle CTI, that is what will happen: the data is left over at the FIFO, and no RDA is triggered

<code>
void UART0_IRQHandler()
{
    uint8_t inttype = (UART_GetIntId(UART_ID) >> 1) & 0b00000111;
    uint8_t tmp;
    switch (inttype)
    {
        case 0b011: // Receive Line Status (RLS)
            break;
        case 0b010: // Receive Data Available (RDA)
            if (UART_Receive(UART, &tmp, 1, NONE_BLOCKING))
            {
                buffer[(buffer_len)++] = tmp;
            }
        break;

        case 0b110: // Character Time-out Indicator (CTI)
            break; /**< HANDLE THIS !!! */

        case 0b001: // THRE Interrupt
            break;

        default:
            break;
    }
}
</code>
0 Kudos

739 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by jdurand on Thu Sep 20 10:29:13 MST 2012
This probably isn't related, but on a different part I ran into problems where the SPI could send just fine but always read 0x00 off the SPI input.  It turned out that I had to set reserved bit 7 high in the pin configuration.  You might check you pin configurations (which will be different for this part).
0 Kudos

739 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TKoe on Thu Sep 20 00:30:51 MST 2012
Well, I tried some stuff out.
<code>
PCLKSEL   |             1              |             2
--------------------------------------------------------------
Mode      |    RBR-IRQ     DMA-IRQ     |    RBR-IRQ     DMA-IRQ
--------------------------------------------------------------
Baudrate  |                            |
750k      |      OK!         OK!       |      OK!         OK!
1.5M      |      OK!         OK!       |      Error2      Error5
  3M      |      Error1      Error4    |      Error3      Error6


Error1: Tx works, RBR interrupt doesn't trigger
Error2: Tx works, RBR interrupt doesn't trigger
Error3: Tx works, RBR interrupt does trigger, but picks up wrong data and wrong number of bytes

Error4: Tx works, DMA interrupt doesn't trigger
Error5: Tx works, DMA interrupt doesn't trigger
Error6: Tx works, DMA interrupt does trigger, but picks up wrong data and wrong number of bytes (sending 3 bytes will trigger the 5-byte DMA interrupt)
</code>


I do see a connection here, but I seem to be unable to solve the problem...


Here are the register contents again...
PCLKSEL: 1
DLM = 0
DLL = 1
FDR = 0x41 (DIVADDVAL = 1; MULVAL = 4)
0 Kudos

739 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TKoe on Wed Sep 19 08:30:56 MST 2012
Hi!

Thank you for your suggestion. I am actually not sure if it was too low.
The PCLK divisor was set to 2 so the AHB clock was 60 MHz. The CMSIS library calculated the following values:
DIVADDVAL: 1
MULVAL: 4
DLM: 0
DLL: 1
Which *would* be okay, if the datasheet didn't have the "Important" note there which says that DLL needs to be greater than 2 if DLM = 0 and DIVADDVAL > 0. So I set the PCLK divisor to 1 and the values are okay and easily within spec.

Sending works fine.
Receiving doesn't.

After some testing I think I made a mistake: I can't even receive single bytes correctly at that speed.
I uncommented the DMA part for now and switched back to using the RBR interrupt of UART0. I don't seem to get any interrupts at all even though I'm sending data with a terminal program. I am not sure why the data was okay when I tested it first.




UART0 interrupt code:
<code>
void UART0_IRQHandler()
{
    uint8_t inttype = (UART_GetIntId(UART_ID) >> 1) & 0b00000111;
    uint8_t tmp;
    switch (inttype)
    {
        case 0b011: // Receive Line Status (RLS)
            break;

        case 0b010: // Receive Data Available (RDA)
            if (UART_Receive(UART, &tmp, 1, NONE_BLOCKING))
            {
                buffer[(buffer_len)++] = tmp;
            }
        break;

        case 0b110: // Character Time-out Indicator (CTI)
            break;

        case 0b001: // THRE Interrupt
            break;

        default:
            break;
    }
}

....

// in main:
while (1)
{
    if (buffer_len > 0)
    {
        UART_Send(UART, buffer, buffer_len, BLOCKING);
        buffer_len = 0;
    }
}
</code>
0 Kudos

739 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by FrankAndersen on Wed Sep 19 04:34:46 MST 2012
I would suggest that you look in the User manual in section 18.6.11.

Mabye your PCLK is too low to gennerate, the clock for the UART.

// Frank
0 Kudos