Difference between revisions of "LPC1768: UART Programming"
Line 319: | Line 319: | ||
char uart_RxChar(void) | char uart_RxChar(void) | ||
{ | { | ||
+ | char ch; | ||
while(util_IsBitCleared(LPC_UART0->LSR,SBIT_RDR)); | while(util_IsBitCleared(LPC_UART0->LSR,SBIT_RDR)); | ||
ch = LPC_UART0->RBR; | ch = LPC_UART0->RBR; | ||
Line 324: | Line 325: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | |||
− | |||
=Code= | =Code= |
Revision as of 15:06, 31 May 2015
Contents
Objective
In this tutorial we are going to discuss the serial communication using UART. For more info on UART/RS232 check 8051 tutorial.
LPC1768 has four inbuilt USARTs. We are going to discuss only UART0. After this tutorial you should be able to extend it to remaining three UARTS.
After understating the basics of LPC1768 UART module, We will discuss how to use the ExploreEmbedded libraries to communicate with any of the UART devices.
UART module
UART module and registers.
LPC1768 has 4-UARTs numbering 0-3, similarly the pins are also named as RXD0-RXD3 and TXD0-TXD3.
As the LPC1768 pins are multiplexed for multiple functionalities, first they have to be configured as UART pins.
Below table shows the multiplexed UARTs pins.
Port Pin | Pin Number | PINSEL_FUNC_0 | PINSEL_FUNC_1 | PINSEL_FUNC_2 | PINSEL_FUNC_3 |
---|---|---|---|---|---|
P0.02 | 98 | GPIO | TXD0 | ADC0[7] | |
P0.03 | 99 | GPIO | RXD0 | ADC0[6] | |
p2.00 | 75 | GPIO | PWM1[1] | TXD1 | |
P2.01 | 74 | GPIO | PWM1[2] | RXD1 | |
P0.10 | 48 | GPIO | TXD2 | SDA2 | MAT3[0] |
P0.11 | 49 | GPIO | RXD2 | SCL2 | MAT3[1] |
P4.28 | 82 | GPIO | RX_MCLK | MAT2[0] | TXD3 |
P4.29 | 85 | GPIO | TX_MCLK | MAT2[1] | RXD3 |
UART Registers
The below table shows the registers associated with LPC1768 ADC.
We are going to focus only on ADCR and ADGDR as these are sufficient for simple A/D conversion.
However once you are familer with LPC1768 ADC, you can explore the other features and the associated registers.
Register | Description |
---|---|
RBR | Contains the recently received Data |
THR | Contains the data to be transmitted |
FCR | FIFO Control Register |
LCR | Controls the UART frame formatting(Number of Data Bits, Stop bits) |
DLL | Least Significant Byte of the UART baud rate generator value. |
DLM | Most Significant Byte of the UART baud rate generator value. |
UART Register Configuration
Now lets see how to configure the individual registers for UART communication.
FCR ( FIFO Control Register )
LPC1768 has inbuilt 16byte FIFO for Receiver/Transmitter. Thus it can store 16-bytes of data received on UART without overwriting. If the data is not read before the Queue(FIFO) is filled then the new data will be lost and the OVERRUN error bit will set.
ADCR | ||||||||
---|---|---|---|---|---|---|---|---|
31:8 | 7:6 | 5:4 | 3 | 2 | 1 | 0 | ||
RESERVED | RX TRIGGER | RESERVED | DMA MODE | TX RIFO RESET | RX RIFO RESET | FIFO ENABLE |
Bit 0 – FIFO:
This bit is used to enable/disable the FIFO for the data received/transmitted.
0--FIFO is Disabled.
1--FIFO is Enabled for both Rx and Tx.
Bit 1 – RX_FIFO:
This is used to clear the 16-byte Rx FIFO.
0--No impact.
1--CLears the 16-byte Rx FIFO and the resets the FIFO pointer.
Bit 2 – Tx_FIFO:
This is used to clear the 16-byte Tx FIFO.
0--No impact.
1--Clears the 16-byte Tx FIFO and the resets the FIFO pointer.
Bit 3 – DMA_MODE:
This is used for Enabling/Disabling DMA mode.
0--Disables the DMA.
1--Enables DMA only when the FIFO(bit-0) bit is SET.
Bit 7:6 – Rx_TRIGGER:
This bit is used to select the number of bytes of the receiver data to be written so as to enable the interrupt/DMA.
00-- Trigger level 0 (1 character or 0x01)
01-- Trigger level 1 (4 characters or 0x04)
10-- Trigger level 2 (8 characters or 0x08)
11-- Trigger level 3 (14 characters or 0x0E)
LCR ( Line Control Register )
This register is used for defining the UART frame format ie. Number of Data bits, STOP bits etc.
LCR | ||||||||
---|---|---|---|---|---|---|---|---|
31:8 | 7 | 6 | 5:4 | 3 | 2 | 1:0 | ||
Reserved | DLAB | Break COntrol | Parity Select | Parity Enable | Stop Bit Select | Word Length Select |
Bit 1:0 – WLS : WordLenghtSelect
These two bits are used to select the character length
00-- 5-bit character length
01-- 6-bit character length
10-- 7-bit character length
11-- 8-bit character length
Bit 2 – Stop Bit Selection:
This bit is used to select the number(1/2) of stop bits
0-- 1 Stop bit
1-- 2 Stop Bits
Bit 3 – Parity Enable:
This bit is used to Enable or Disable the Parity generation and checking.
0-- Disable parity generation and checking.
1-- Enable parity generation and checking.
Bit 5:4 – Parity Selection:
These two bits will be used to select the type of parity.
00-- Odd parity. Number of 1s in the transmitted character and the attached parity bit will be odd.
01-- Even Parity. Number of 1s in the transmitted character and the attached parity bit will be even.
10-- Forced "1" stick parity.
11-- Forced "0" stick parity
Bit 6 – Break Control
0-- Disable break transmission.
1-- Enable break transmission. Output pin UARTn TXD is forced to logic 0
Bit 8 – DLAB: Divisor Latch Access Bit
This bit is used to enable the access to divisor latch.
0-- Disable access to divisor latch
0-- Enable access to divisor latch
LSR (Line Status Register)
The is a read-only register that provides status information of the UART TX and RX blocks.
LSR | ||||||||
---|---|---|---|---|---|---|---|---|
31:8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Reserved | RXFE | TEMT | THRE | BI | FE | PE | OE | RDR |
Bit 0 – RDR: Receive Data Ready
This bit will be set when there is a received data in RBR register. This bit will be automatically cleared when RBR is empty.
0-- The UARTn receiver FIFO is empty.
1-- The UARTn receiver FIFO is not empty.
Bit 1 – OE: Overrun Error
The overrun error condition is set when the UART Rx FIFO is full and a new character is received.
In this case, the UARTn RBR FIFO will not be overwritten and the character in the UARTn RSR will be lost.
0-- No overrun
1-- Buffer over run
Bit 2 – PE: Parity Error
This bit is set when the receiver detects a error in the Parity.
0-- No Parity Error
1-- Parity Error
Bit 3 – FE: Framing Error
This bit is set when there is error in the STOP bit(LOGIC 0)
0-- No Framing Error
1-- Framing Error
Bit 4 – BI: Break Interrupt
This bit is set when the RXDn is held in the spacing state (all zeroes) for one full character transmission
0-- No Break interrupt
1-- Break Interrupt detected.
Bit 5 – THRE: Transmitter Holding Register Empty
THRE is set immediately upon detection of an empty THR. It is automatically cleared when the THR is written.
0-- THR register is Empty
1-- THR has valid data to be transmitted
Bit 6 – TEMT: Transmitter Empty
TEMT is set when both UnTHR and UnTSR are empty; TEMT is cleared when any of them contain valid data.
0-- THR and/or the TSR contains valid data.
1-- THR and the TSR are empty.
Bit 7 – RXFE: Error in Rx FIFO
This bit is set when the received data is affected by Framing Error/Parity Error/Break Error.
0-- RBR contains no UARTn RX errors.
1-- RBR contains at least one RX error.
TER (Transmitter Enable register)
This register is used to Enable/Disable the transmission
TER | ||||||||
---|---|---|---|---|---|---|---|---|
31:8 | 7 | 6-0 | ||||||
Reserved | TXEN | Reserved |
Bit 7 – TXEN: Trsnamitter Enable
When this bit is 1, the data written to the THR is output on the TXD pin.
If this bit is cleared to 0 while a character is being sent, the transmission of that character is completed, but no further characters are sent until this bit is set again.
In other words, a 0 in this bit blocks the transfer of characters.
- Note: By default this bit will be set after Reset.
Some other registers
Though there are some more registers, we are restricting ourselves to use these registers only as this will be more convenient.
Apart from ADC Global Data register there are more 8 ADC Data registers (one Data register per ADC channel). DONE and OVERRUN bits for each channel can be monitored separately from the bits present in ADC Status register.
One can use the A/D Global Data Register to read all data from the ADC else use the A/D Channel Data Registers. It is important to use one method consistently because the DONE and OVERRUN flags can otherwise get out of synch between the AD0GDR and the A/D Channel Data Registers, potentially causing erroneous interrupts or DMA activity.
Schematic
Steps for Configuring UART0
Below are the steps for configuring the UART0.
- Step1: Configure the GPIO pin for UART0 function using PINSEL register.
- Step2: Configure the FCR for enabling the FIXO and Reste both the Rx/Tx FIFO.
- Step3: Configure LCR for 8-data bits, 1 Stop bit, Disable Parity and Enable DLAB.
- Step4: Get the PCLK from PCLKSELx register 7-6 bits.
- Step5: Calculate the DLM,DLL vaues for required baudrate from PCLK.
- Step6: Updtae the DLM,DLL with the calculated values.
- Step6: Finally clear DLAB to disable the access to DLM,DLL.
After this the UART will be ready to Transmit/Receive Data at the specified baudrate.
Code sniffet:
void uart_init(uint32_t baudrate) { uint32_t var_UartPclk_u32,var_Pclk_u32,var_RegValue_u32; LPC_PINCON->PINSEL0 &= ~0x000000F0; LPC_PINCON->PINSEL0 |= 0x00000050; // Enable TxD0 P0.2 and p0.3 LPC_UART0->FCR = (1<<SBIT_FIFO) | (1<<SBIT_RxFIFO) | (1<<Tx_FIFO); // Enable FIFO and reset Rx/Tx FIFO buffers LPC_UART0->LCR = (0x03<<SBIT_WordLenght) | (1<<SBIT_DLAB); // 8bit data, 1Stop bit, No parity /** Baud Rate Calculation : PCLKSELx registers contains the PCLK info for all the clock dependent peripherals. Bit6,Bit7 contains the Uart Clock(ie.UART_PCLK) information. The UART_PCLK and the actual Peripheral Clock(PCLK) is calculated as below. (Refer data sheet for more info) UART_PCLK PCLK 0x00 SystemFreq/4 0x01 SystemFreq 0x02 SystemFreq/2 0x03 SystemFreq/8 **/ var_UartPclk_u32 = (LPC_SC->PCLKSEL0 >> 6) & 0x03; switch( var_UartPclk_u32 ) { case 0x00: var_Pclk_u32 = SystemFrequency/4; break; case 0x01: var_Pclk_u32 = SystemFrequency; break; case 0x02: var_Pclk_u32 = SystemFrequency/2; break; case 0x03: var_Pclk_u32 = SystemFrequency/8; break; } var_RegValue_u32 = ( var_Pclk_u32 / (16 * baudrate )); LPC_UART0->DLL = var_RegValue_u32 & 0xFF; LPC_UART0->DLM = (var_RegValue_u32 >> 0x08) & 0xFF; util_BitClear(LPC_UART0->LCR,(M_DlabBitPosition_U8)); // Clear DLAB after setting DLL,DLM }
Steps for transmitting a char
- Step1: Wait till the previous char is transmitted ie. till THRE becomes high.
- Step2: Load the new char to be transmitted into THR.
Code snippet
void uart_TxChar(char ch) { while(util_IsBitCleared(LPC_UART0->LSR,SBIT_THRE)); LPC_UART0->THR=ch; }
Steps for Receiving a char
- Step1: Wait till the a char is received ie. till RDR becomes high.
- Step2: Copy the received data from receive buffer(RBR).
Code snippet
char uart_RxChar(void) { char ch; while(util_IsBitCleared(LPC_UART0->LSR,SBIT_RDR)); ch = LPC_UART0->RBR; return ch; }
Code
Below is the code for transmitting and receiving chars at 9600 baud
#include <lpc17xx.h> #include "stdutils.h" #define SBIT_WordLenght 0x00u #define SBIT_DLAB 0x07u #define SBIT_FIFO 0x00u #define SBIT_RxFIFO 0x01u #define SBIT_TxFIFO 0x02u #define SBIT_RDR 0x00u #define SBIT_THRE 0x05u /* Function to initialize the UART0 at specifief baud rate */ void uart_init(uint32_t baudrate) { uint32_t var_UartPclk_u32,var_Pclk_u32,var_RegValue_u32; LPC_PINCON->PINSEL0 &= ~0x000000F0; LPC_PINCON->PINSEL0 |= 0x00000050; // Enable TxD0 P0.2 and p0.3 LPC_UART0->FCR = (1<<SBIT_FIFO) | (1<<SBIT_RxFIFO) | (1<<SBIT_TxFIFO); // Enable FIFO and reset Rx/Tx FIFO buffers LPC_UART0->LCR = (0x03<<SBIT_WordLenght) | (1<<SBIT_DLAB); // 8bit data, 1Stop bit, No parity /** Baud Rate Calculation : PCLKSELx registers contains the PCLK info for all the clock dependent peripherals. Bit6,Bit7 contains the Uart Clock(ie.UART_PCLK) information. The UART_PCLK and the actual Peripheral Clock(PCLK) is calculated as below. (Refer data sheet for more info) UART_PCLK PCLK 0x00 SystemFreq/4 0x01 SystemFreq 0x02 SystemFreq/2 0x03 SystemFreq/8 **/ var_UartPclk_u32 = (LPC_SC->PCLKSEL0 >> 6) & 0x03; switch( var_UartPclk_u32 ) { case 0x00: var_Pclk_u32 = SystemFrequency/4; break; case 0x01: var_Pclk_u32 = SystemFrequency; break; case 0x02: var_Pclk_u32 = SystemFrequency/2; break; case 0x03: var_Pclk_u32 = SystemFrequency/8; break; } var_RegValue_u32 = ( var_Pclk_u32 / (16 * baudrate )); LPC_UART0->DLL = var_RegValue_u32 & 0xFF; LPC_UART0->DLM = (var_RegValue_u32 >> 0x08) & 0xFF; util_BitClear(LPC_UART0->LCR,(SBIT_DLAB)); // Clear DLAB after setting DLL,DLM } /* Function to transmit a char */ void uart_TxChar(char ch) { while(util_IsBitCleared(LPC_UART0->LSR,SBIT_THRE)); // Wait for Previous transmission LPC_UART0->THR=ch; // Load the data to be transmitted } /* Function to Receive a char */ char uart_RxChar() { char ch; while(util_IsBitCleared(LPC_UART0->LSR,SBIT_RDR)); // Wait till the data is received ch = LPC_UART0->RBR; // Read received data return ch; } void main() { char ch,a[]="\n\rExploreEmbedded"; int i; SystemInit(); uart_init(9600); // Initialize the UART0 for 9600 baud rate uart_TxChar('h'); //Transmit "hello" char by char uart_TxChar('e'); uart_TxChar('l'); uart_TxChar('l'); uart_TxChar('o'); for(i=0;a[i];i++) //transmit a predefined string uart_TxChar(a[i]); while(1) { //Finally receive a char and transmit it infinitely ch = uart_RxChar(); uart_TxChar(ch); } }
Using Explore Embedded Libraries
In the above tutorial we discussed how to configure and use the inbuilt LPC1768 ADC.
Now we will see how to use the exploreEmbededd ADC libraries and interface POT,LDR and Temperature Sensor(LM35).
For this you have to include the adc.c/adc.h files. As the result will be displayed on the LCD, lcd.c/lcd.h also needs to be included.
Refer the LCD tutorial for interfacing the 2x16 lcd.
#include<lpc17xx.h> #include "lcd.h" //User defined LCD library which contains the lcd routines #include "delay.h" //User defined library which contains the delay routines #include "adc.h" void main() { uint16_t pot_value,ldr_value, temp_raw, temp_final; float voltage; SystemInit(); //Clock and PLL configuration /* Setup/Map the controller pins for LCD operation RS RW EN D0 D1 D2 D3 D4 D5 D6 D7*/ LCD_SetUp(P2_0,P2_1,P2_2,P1_20,P1_21,P1_22,P1_23,P1_24,P1_25,P1_26,P1_27); LCD_Init(2,16); /* Specify the LCD type(2x16) for initialization*/ ADC_Init(); /* Initialize the ADC */ while(1) { pot_value = ADC_GetAdcValue(0); /* Read pot value connect to AD0(P0_23) */ ldr_value = ADC_GetAdcValue(1); /* Read LDR value connect to AD1(P0_24) */ temp_raw = ADC_GetAdcValue(2); /* Read Temp value connect to AD2(P0_25) */ /*Converting the raw adc value to equivalent temperature with 3.3v as ADC reference using 12bit resolution. Step size of ADC= (3.3v/2^12)= 3.3/4096 = 0.0008056640625 = 0.0806mv For every degree celcius the Lm35 provides 10mv voltage change. 1 degree celcius = 10mv = 10mv/0.0806mv = 12.41 uinits Hence the Raw ADC value can be divided by 12.41 to get equivalent temp*/ temp_final = temp_raw/12.41; /* Vin = (Adc_value * REF)/ 2^12 */ voltage = (pot_value * 3.3)/ 4096.0; LCD_GoToLine(0); LCD_Printf("P:%4d %f",pot_value,voltage); LCD_Printf("\nL:%4d T:%4d",ldr_value,temp_final); } }