Using UART on LPC12xx

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

Using UART on LPC12xx

1,456 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by tbutuza on Sat May 14 02:24:32 MST 2011
I opened this thread to discuss about use UART on LPC12xx mcu.

Previously I used uart on LPC1769 without problems. Now I'd like to do this on LPC1227 but after several hours (days?) fighting, I did not have success.

I can send data on uart but receive is not working.
After initializing uart I receive only one character, but no further receive is possible.
I tried it with interrupts and polling. I also tried Uart0 and Uart1.
All 4 tests had the same result: Only one character can be received right after the initialization, and no more.

Similar code runs well on LPC1769 without problem. As I know the Uart  module is exactly the same in LPC1768 and LPC1227. Just the base  addresses are different.

I can send characters, it indicates that the power, clock are right.
Something wrong with the receiver side but what?

It is my code:

Initialization:
// =======================================
static void UART1Init (uint32_t baudrate) {
    uint32_t Fdiv;
    uint32_t pclk;

    // Assign txd, rxd lines to pins.
    LPC_IOCON->PIO0_8 = 0x02;
    LPC_IOCON->PIO0_9 = 0x02;

    // SYSAHBCLKCTRL  12. bit should be set to 1.

    pclk = UART_INPUT_FREQ;

    LPC_UART1->LCR = 0x83;        // 8 bits, no Parity, 1 Stop bit
    Fdiv = ( pclk / 16 ) / baudrate ;    // baud rate

    LPC_UART1->DLM = Fdiv / 256;                            
    LPC_UART1->DLL = Fdiv % 256;
    LPC_UART1->LCR = 0x03;        // DLAB = 0
    LPC_UART1->FCR = 0x07;        // Enable and reset TX and RX FIFO.


    //LPC_UART1->IER = IER_RBR | IER_THRE | IER_RLS;    // Enable UART0 interrupt
    //LPC_UART0->IER = IER_RBR;    // Enable UART0 interrupt (Only the receive data available interrupt is enabled.)

    //NVIC_EnableIRQ (UART1_IRQn);
}
The content of the main function:

    unsigned char lsrValue;

    UART0RcvSignal = 0;
    ledState = 0;
    counter = 0;

    // Disable watchdog
    LPC_WDT->MOD = 0x00;
    LPC_WDT->FEED = 0xAA;
    LPC_WDT->FEED = 0x55;

//    UART0Init (9600);
    UART1Init (9600);

    // enable all interrupts (Is this necessary ???)
    //__asm volatile ("cpsie i");

    LPC_GPIO0->DIR = LEDPIN;

    LPC_GPIO0->OUT = LEDPIN;    // Initially the led is on.

    // Enter an infinite loop
    while (1) {
        counter++;
        if (counter >= COUNTER_MAX) {
            counter = 0;
            LPC_UART1->THR = 'A';
        }

        lsrValue = LPC_UART1->LSR;
        if (lsrValue & 0x01) {
            UART0RcvSignal = 1;
            UART0RcvData = LPC_UART1->RBR;
        }

        if (UART0RcvSignal) {
            // Echo back the character
            LPC_UART1->THR = (UART0RcvData + 1);

            // Blink the led
            if (ledState) {
                ledState = 0;
                LPC_GPIO0->OUT = LEDPIN;
            } else {
                ledState = 1;
                LPC_GPIO0->OUT = 0;
            }
            UART0RcvSignal = 0;
        }
    }
As you see it is a polling-based program.
It sends characters periodiccaly. When a character received, it echoes (received + 1) and blinks the led.

Led blinks only once and character echoed only immediatelly after the initialization.
Subsequent receive is not possible, apparently the receiver part of the uart freezes.

What did I wrong?
Did I forget something?
0 Kudos
8 Replies

955 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Chevin on Mon Dec 07 06:46:29 MST 2015
Hello,

I had the same problem and it took me some hours to sort it out. Just replace

LPC_IOCON->PIO0_8 = 0x02;

with

LPC_IOCON->PIO0_8 |= 0x02;

Background: If you clear the reserved Bit 7, then the UART1 receiver will stop working. UART0 seems not to be affected by this problem.
I'm glad that it works now for me.

Bye, Eike
0 Kudos

954 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NXP_Europe on Fri Dec 30 17:23:17 MST 2011
Hello adwiens,

the first two lines (0x...02) are explained in User Manual UM10441.


Quote:


[LEFT]2:0 FUNC Selects pin function. 000
0x0 Selects function PIO0_8.
0x1 Reserved. Do not use.
0x2 Select function RXD1.
0x3 Select function CT32B1_CAP2.[/LEFT]
0x4 Select function CT32B1_MAT2.





But your last line (0x...000) would suggest that a standard IO-function is choosen...
0 Kudos

955 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by adwiens on Fri Dec 30 15:33:20 MST 2011
I am not sure why, but I tried adding

LPC_IOCON->PIO0_8 &= ~(0x07);


to clear the bottom three bits of the IOCON register before

LPC_IOCON->PIO0_8 |= (0x02);


and my code works now.  I am puzzled by it because when I remove

LPC_IOCON->PIO0_8 &= ~(0x07);


now it still works.  :confused:  Maybe the bottom three bits got "stuck" at some value and did not reset to zero?
0 Kudos

955 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NXP_Europe on Fri Dec 30 06:10:57 MST 2011
Hello adwiens,

How did you visualize the output of the UARTx?

Apparently it seems to work.

I used the software provided on de NXP LPCXpresso website.

http://ics.nxp.com/support/lpcxpresso/

Example projects LPC1200 Series
0 Kudos

955 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by adwiens on Fri Dec 30 02:18:32 MST 2011
UART0 appears to receive characters but UART1 does not.  Is there some kind of trick to setting up UART1 that's different from UART0?
0 Kudos

955 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by adwiens on Fri Dec 30 01:44:55 MST 2011
Anybody?
0 Kudos

955 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by adwiens on Sat Dec 24 14:15:45 MST 2011
I apologize for resurrecting a dead thread, but it looks like a solution to this problem was never posted  :confused:

I am having a similar problem with the LPC1227 where I can send but not receive with the UART.  Did you ever find a solution to the problem?

I've been trying to figure this out for a whole day and I feel like this right now http://xkcd.com/979/  

/**
 * @briefInitializes UART.
 * @param[in]setThe desired settings for UART.
 * @return0 on error, else 1.
 * @remarkImplements the fractional bit rate algorithm outlined in NXP manual.
 * @remarkFor NXP122x, Bit length must be in the range 5-8.
 */
int init_uart(uart_settings set){
double pclk = MainClock / PCLK_DIVIDER_VALUE;// Calculate peripheral clock
uint8_t divaddval, mulval, dlm = 0, dll = 0;// Register fields

UART_settings = set;

// PART A: Calculate register values

double frest = INITIAL_FREST;
double dlest = pclk / (16.0 * ((double)(set.bit_rate)));
uint16_t dlest_int = ((uint16_t)dlest);
uint8_t isodd = FALSE, offset = 0;

if(((double)dlest_int) != dlest){// If dlest is not an integer...
do {
// Try FRest values between (INITIAL_FREST - FREST_RANGE) and (INITIAL_FREST + FREST_RANGE); 1.1-1.9 by default.
if(isodd){
frest = (INITIAL_FREST) + (offset++) * (UART0_BITRATE_ALGO_STEP_SIZE);
isodd = FALSE;
}
else{
frest = (INITIAL_FREST) - (offset) * (UART0_BITRATE_ALGO_STEP_SIZE);
isodd = TRUE;
}

dlest_int = (uint16_t)(pclk / (16.0 * ((double)(set.bit_rate)) * frest));

if(dlest_int == 0)
goto cfg_error;

frest = pclk / (16.0 * ((double)(set.bit_rate)) * ((double)dlest_int));
} while ((frest <= (INITIAL_FREST - FREST_RANGE) || frest >= (INITIAL_FREST + FREST_RANGE)) && (offset <= FREST_RANGE / UART0_BITRATE_ALGO_STEP_SIZE));

// Get LUT index
int i = find_uart_lut_index(frest);

// Look up fractional values in LUT
divaddval = uart_divaddval_lut;
mulval = uart_mulval_lut;
dlm = (dlest_int>>8);
dll = (dlest_int);
}
else {// dlest was an integer; no need for fractional division.
divaddval = 0;
mulval = 1;
dll = 1;
}

// PART B: Set registers
// Different registers for each UART.
switch(set.uart_port){
case UART0:
ENABLE_UART0;// UART0 MUST BE ENABLED FOR REGISTERS TO ACCEPT VALUES!!!!!  It took me FOREVER to figure this out...
SET_UART0_DLAB;
(LPC_UART0 -> DLL) = dll;
(LPC_UART0 -> DLM) = dlm;
CLEAR_UART0_DLAB;
(LPC_UART0 -> FDR) = ((mulval << MULVAL_OFFSET) | divaddval);
(LPC_UART0 -> LCR) = (set.payload_length - 5) | (set.stop_bit << 2) | (set.parity != 0) | (set.parity != 0 ? set.parity - 1 : 0x0);// Sets UART parameters
(LPC_UART0 -> FCR) = (1 << UART0_FIFOEN_BIT);// Enable FIFO
//(LPC_UART0 -> IER) = (1<<UART0_RBRIE_BIT);// Enable receive interrupt
break;
case UART1:
ENABLE_UART1;
SET_UART1_DLAB;
(LPC_UART1 -> DLL) = dll;
(LPC_UART1 -> DLM) = dlm;
CLEAR_UART1_DLAB;
(LPC_UART1 -> FDR) = ((mulval << MULVAL_OFFSET) | divaddval);
(LPC_UART1 -> LCR) = (set.payload_length - 5) | (set.stop_bit << 2) | (set.parity != 0) | (set.parity != 0 ? set.parity - 1 : 0x0);// Sets UART parameters
(LPC_UART1 -> FCR) = (1<<UART1_FIFOEN_BIT)|(1<<UART1_RX_RESET_BIT)|(1<<UART1_TX_RESET_BIT);// Enable FIFO + clear RX & TX FIFOs
(LPC_UART1 -> IER) = (1<<UART1_RBRIE_BIT);// Enable receive interrupt
break;
}

return 1;// Exit normally.

cfg_error:// Error handler.
return 0;
}


To read the RX buffer I'm just doing:

char s = LPC_UART1 -> RBR;


Any help would be greatly appreciated!
0 Kudos

955 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Sat May 14 02:39:25 MST 2011
Since LPC12xx is also M0, I would suggest you start with a working LPC11xx UART code like UART.c (see LPC11 samples) and just change a few pins there.
Receiving is done there a little bit different....

/*****************************************************************************
 *   uart.c:  UART API file for [COLOR=Red]NXP LPC11xx[/COLOR] Family Microprocessors
 *
 *   Copyright(C) 2008, NXP Semiconductor
 *   All rights reserved.
 *
 *   History
 *   2009.12.07  ver 1.00    Preliminary version, first Release
 *
******************************************************************************/

#include "uart.h"

volatile uint32_t UARTStatus;
volatile uint8_t  UARTTxEmpty = 1;
volatile uint8_t  UARTBuffer[BUFSIZE];
volatile uint32_t UARTCount = 0;

/*****************************************************************************
** Function name:        UART_IRQHandler
**
** Descriptions:        UART interrupt handler
**
** parameters:            None
** Returned value:        None
** 
*****************************************************************************/
void UART_IRQHandler(void)
{
  uint8_t IIRValue, LSRValue;
  uint8_t Dummy = Dummy;

  IIRValue = LPC_UART->IIR;
    
  IIRValue >>= 1;            /* skip pending bit in IIR */
  IIRValue &= 0x07;            /* check bit 1~3, interrupt identification */
  if (IIRValue == IIR_RLS)        /* Receive Line Status */
  {
    LSRValue = LPC_UART->LSR;
    /* Receive Line Status */
    if (LSRValue & (LSR_OE | LSR_PE | LSR_FE | LSR_RXFE | LSR_BI))
    {
      /* There are errors or break interrupt */
      /* Read LSR will clear the interrupt */
      UARTStatus = LSRValue;
      Dummy = LPC_UART->RBR;    /* Dummy read on RX to clear 
                                interrupt, then bail out */
      return;
    }
    if (LSRValue & LSR_RDR)    /* Receive Data Ready */            
    {
      /* If no error on RLS, normal ready, save into the data buffer. */
      /* Note: read RBR will clear the interrupt */
      UARTBuffer[UARTCount++] = LPC_UART->RBR;
      if (UARTCount == BUFSIZE)
      {
        UARTCount = 0;        /* buffer overflow */
      }    
    }
  }
  else if (IIRValue == IIR_RDA)    /* Receive Data Available */
  {
    /* Receive Data Available */
    UARTBuffer[UARTCount++] = LPC_UART->RBR;
    if (UARTCount == BUFSIZE)
    {
      UARTCount = 0;        /* buffer overflow */
    }
  }
  else if (IIRValue == IIR_CTI)    /* Character timeout indicator */
  {
    /* Character Time-out indicator */
    UARTStatus |= 0x100;        /* Bit 9 as the CTI error */
  }
  else if (IIRValue == IIR_THRE)    /* THRE, transmit holding register empty */
  {
    /* THRE interrupt */
    LSRValue = LPC_UART->LSR;        /* Check status in the LSR to see if
                                valid data in U0THR or not */
    if (LSRValue & LSR_THRE)
    {
      UARTTxEmpty = 1;
    }
    else
    {
      UARTTxEmpty = 0;
    }
  }
  return;
}

/*****************************************************************************
** Function name:        UARTInit
**
** Descriptions:        Initialize UART0 port, setup pin select,
**                clock, parity, stop bits, FIFO, etc.
**
** parameters:            UART baudrate
** Returned value:        None
** 
*****************************************************************************/
void UARTInit(uint32_t baudrate)
{
  uint32_t Fdiv;
  uint32_t regVal;

  UARTTxEmpty = 1;
  UARTCount = 0;
  
  NVIC_DisableIRQ(UART_IRQn);

  LPC_IOCON->PIO1_6 &= ~0x07;    /*  UART I/O config */
  LPC_IOCON->PIO1_6 |= 0x01;     /* UART RXD */
  LPC_IOCON->PIO1_7 &= ~0x07;    
  LPC_IOCON->PIO1_7 |= 0x01;     /* UART TXD */
  /* Enable UART clock */
  LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12);
  LPC_SYSCON->UARTCLKDIV = 0x1;     /* divided by 1 */

  LPC_UART->LCR = 0x83;             /* 8 bits, no Parity, 1 Stop bit */
  regVal = LPC_SYSCON->UARTCLKDIV;

  Fdiv = (((SystemCoreClock*LPC_SYSCON->SYSAHBCLKDIV)/regVal)/16)/baudrate ;    /*baud rate */

  LPC_UART->DLM = Fdiv / 256;                            
  LPC_UART->DLL = Fdiv % 256;
  LPC_UART->LCR = 0x03;        /* DLAB = 0 */
  LPC_UART->FCR = 0x07;        /* Enable and reset TX and RX FIFO. */

  /* Read to clear the line status. */
  regVal = LPC_UART->LSR;

  /* Ensure a clean start, no data in either TX or RX FIFO. */
// CodeRed - added parentheses around comparison in operand of &
  while (( LPC_UART->LSR & (LSR_THRE|LSR_TEMT)) != (LSR_THRE|LSR_TEMT) );
  while ( LPC_UART->LSR & LSR_RDR )
  {
    regVal = LPC_UART->RBR;    /* Dump data from RX FIFO */
  }
 
  /* Enable the UART Interrupt */
  NVIC_EnableIRQ(UART_IRQn);


#if CONFIG_UART_ENABLE_TX_INTERRUPT==1
  LPC_UART->IER = IER_RBR | IER_THRE | IER_RLS;    /* Enable UART interrupt */
#else
  LPC_UART->IER = IER_RBR | IER_RLS;    /* Enable UART interrupt */
#endif
 return;
}

/*****************************************************************************
** Function name:        UARTSend
**
** Descriptions:        Send a block of data to the UART 0 port based
**                on the data length
**
** parameters:        buffer pointer, and data length
** Returned value:    None
** 
*****************************************************************************/
void UARTSend(uint8_t *BufferPtr, uint32_t Length)
{
  
  while ( Length != 0 )
  {
      /* THRE status, contain valid data */
#if CONFIG_UART_ENABLE_TX_INTERRUPT==1
      /* Below flag is set inside the interrupt handler when THRE occurs. */
      while ( !(UARTTxEmpty & 0x01) );
      LPC_UART->THR = *BufferPtr;
      UARTTxEmpty = 0;    /* not empty in the THR until it shifts out */
#else
      while ( !(LPC_UART->LSR & LSR_THRE) );
      LPC_UART->THR = *BufferPtr;
#endif
      BufferPtr++;
      Length--;
  }
  return;
}

/******************************************************************************
**                            End Of File
******************************************************************************/

0 Kudos