mirror of
https://github.com/brmlab/edubrm.git
synced 2025-06-09 13:24:00 +02:00
243 lines
8.6 KiB
C
243 lines
8.6 KiB
C
/*----------------------------------------------------------------------------
|
|
* Name: serial.c
|
|
* Purpose: serial port handling for LPC134x
|
|
* Version: V1.10
|
|
*----------------------------------------------------------------------------
|
|
* This software is supplied "AS IS" without any warranties, express,
|
|
* implied or statutory, including but not limited to the implied
|
|
* warranties of fitness for purpose, satisfactory quality and
|
|
* noninfringement. Keil extends you a royalty-free right to reproduce
|
|
* and distribute executable files created using this software for use
|
|
* on NXP Semiconductors LPC microcontroller devices only. Nothing else
|
|
* gives you the right to use this software.
|
|
*
|
|
* Copyright (c) 2009 Keil - An ARM Company. All rights reserved.
|
|
*---------------------------------------------------------------------------*/
|
|
#include "LPC13xx.h" // LPC13xx definitions
|
|
#include "type.h"
|
|
#include "serial.h"
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
Defines for ring buffers
|
|
*---------------------------------------------------------------------------*/
|
|
#define SER_BUF_SIZE (128) // serial buffer in bytes (power 2)
|
|
#define SER_BUF_MASK (SER_BUF_SIZE-1ul) // buffer size mask
|
|
|
|
/* Buffer read / write macros */
|
|
#define SER_BUF_RESET(serBuf) (serBuf.rdIdx = serBuf.wrIdx = 0)
|
|
#define SER_BUF_WR(serBuf, dataIn) (serBuf.data[SER_BUF_MASK & serBuf.wrIdx++] = (dataIn))
|
|
#define SER_BUF_RD(serBuf) (serBuf.data[SER_BUF_MASK & serBuf.rdIdx++])
|
|
#define SER_BUF_EMPTY(serBuf) (serBuf.rdIdx == serBuf.wrIdx)
|
|
#define SER_BUF_FULL(serBuf) (serBuf.rdIdx == serBuf.wrIdx+1)
|
|
#define SER_BUF_COUNT(serBuf) (SER_BUF_MASK & (serBuf.wrIdx - serBuf.rdIdx))
|
|
|
|
// buffer type
|
|
typedef struct __SER_BUF_T {
|
|
unsigned char data[SER_BUF_SIZE];
|
|
unsigned int wrIdx;
|
|
unsigned int rdIdx;
|
|
} SER_BUF_T;
|
|
|
|
unsigned long ser_txRestart; // NZ if TX restart is required
|
|
unsigned short ser_lineState; // ((msr << 8) | (lsr))
|
|
SER_BUF_T ser_out; // Serial data buffers
|
|
SER_BUF_T ser_in;
|
|
|
|
/*----------------------------------------------------------------------------
|
|
open the serial port
|
|
*---------------------------------------------------------------------------*/
|
|
void ser_OpenPort (void) {
|
|
|
|
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 */
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
close the serial port
|
|
*---------------------------------------------------------------------------*/
|
|
void ser_ClosePort (void) {
|
|
LPC_IOCON->PIO1_6 &= ~0x07; /* UART I/O config */
|
|
LPC_IOCON->PIO1_7 &= ~0x07;
|
|
|
|
/* Disable the interrupt in the VIC and UART controllers */
|
|
LPC_UART->IER = 0;
|
|
NVIC_DisableIRQ(UART_IRQn);
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
initialize the serial port
|
|
*---------------------------------------------------------------------------*/
|
|
void ser_InitPort (unsigned long baudrate, unsigned int databits,
|
|
unsigned int parity, unsigned int stopbits) {
|
|
|
|
uint8_t lcr_p, lcr_s, lcr_d;
|
|
uint32_t dll;
|
|
uint32_t Fdiv;
|
|
|
|
switch (databits) {
|
|
case 5: // 5 Data bits
|
|
lcr_d = 0x00;
|
|
break;
|
|
case 6: // 6 Data bits
|
|
lcr_d = 0x01;
|
|
break;
|
|
case 7: // 7 Data bits
|
|
lcr_d = 0x02;
|
|
break;
|
|
case 8: // 8 Data bits
|
|
default:
|
|
lcr_d = 0x03;
|
|
break;
|
|
}
|
|
|
|
switch (stopbits) {
|
|
case 1: // 1,5 Stop bits
|
|
case 2: // 2 Stop bits
|
|
lcr_s = 0x04;
|
|
break;
|
|
case 0: // 1 Stop bit
|
|
default:
|
|
lcr_s = 0x00;
|
|
break;
|
|
}
|
|
|
|
switch (parity) {
|
|
case 1: // Parity Odd
|
|
lcr_p = 0x08;
|
|
break;
|
|
case 2: // Parity Even
|
|
lcr_p = 0x18;
|
|
break;
|
|
case 3: // Parity Mark
|
|
lcr_p = 0x28;
|
|
break;
|
|
case 4: // Parity Space
|
|
lcr_p = 0x38;
|
|
break;
|
|
case 0: // Parity None
|
|
default:
|
|
lcr_p = 0x00;
|
|
break;
|
|
}
|
|
|
|
SER_BUF_RESET(ser_out); // reset out buffer
|
|
SER_BUF_RESET(ser_in); // reset in buffer
|
|
|
|
/* Note that the pclk is 24,0 MHz. (48.0 MHz / 2) */
|
|
/* 24 MHz PCLK generates also rates for 115200, 57600 baud */
|
|
Fdiv = LPC_SYSCON->UARTCLKDIV;
|
|
dll = (((SystemCoreClock/LPC_SYSCON->SYSAHBCLKDIV)/Fdiv)/16)/baudrate ; /*baud rate */
|
|
LPC_UART->FDR = 0; // Fractional divider not used
|
|
LPC_UART->LCR = 0x80 | lcr_d | lcr_p | lcr_s; // Data bits, Parity, Stop bit
|
|
LPC_UART->DLL = dll; // Baud Rate depending on PCLK
|
|
LPC_UART->DLM = (dll >> 8); // High divisor latch
|
|
LPC_UART->LCR = 0x00 | lcr_d | lcr_p | lcr_s; // DLAB = 0
|
|
LPC_UART->IER = 0x03; // Enable TX/RX interrupts
|
|
|
|
LPC_UART->FCR = 0x07; /* Enable and reset TX and RX FIFO. */
|
|
ser_txRestart = 1; // TX fifo is empty
|
|
|
|
/* Enable the UART Interrupt */
|
|
NVIC_EnableIRQ(UART_IRQn);
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
read data from serial port
|
|
*---------------------------------------------------------------------------*/
|
|
int ser_Read (char *buffer, const int *length) {
|
|
int bytesToRead, bytesRead;
|
|
|
|
/* Read *length bytes, block if *bytes are not avaialable */
|
|
bytesToRead = *length;
|
|
bytesToRead = (bytesToRead < (*length)) ? bytesToRead : (*length);
|
|
bytesRead = bytesToRead;
|
|
|
|
while (bytesToRead--) {
|
|
while (SER_BUF_EMPTY(ser_in)); // Block until data is available if none
|
|
*buffer++ = SER_BUF_RD(ser_in);
|
|
}
|
|
return (bytesRead);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
write data to the serial port
|
|
*---------------------------------------------------------------------------*/
|
|
int ser_Write (const char *buffer, int *length) {
|
|
int bytesToWrite, bytesWritten;
|
|
|
|
// Write *length bytes
|
|
bytesToWrite = *length;
|
|
bytesWritten = bytesToWrite;
|
|
|
|
while (!SER_BUF_EMPTY(ser_out)); // Block until space is available if none
|
|
while (bytesToWrite) {
|
|
SER_BUF_WR(ser_out, *buffer++); // Read Rx FIFO to buffer
|
|
bytesToWrite--;
|
|
}
|
|
|
|
if (ser_txRestart) {
|
|
ser_txRestart = 0;
|
|
LPC_UART->THR = SER_BUF_RD(ser_out); // Write to the Tx Register
|
|
}
|
|
|
|
return (bytesWritten);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
check if character(s) are available at the serial interface
|
|
*---------------------------------------------------------------------------*/
|
|
void ser_AvailChar (int *availChar) {
|
|
|
|
*availChar = SER_BUF_COUNT(ser_in);
|
|
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
read the line state of the serial port
|
|
*---------------------------------------------------------------------------*/
|
|
void ser_LineState (unsigned short *lineState) {
|
|
|
|
*lineState = ser_lineState;
|
|
ser_lineState = 0;
|
|
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
serial port 1 interrupt
|
|
*---------------------------------------------------------------------------*/
|
|
void UART_IRQHandler(void)
|
|
{
|
|
volatile unsigned long iir;
|
|
|
|
iir = LPC_UART->IIR;
|
|
|
|
if ((iir & 0x4) || (iir & 0xC)) { // RDA or CTI pending
|
|
while (LPC_UART->LSR & 0x01) { // Rx FIFO is not empty
|
|
SER_BUF_WR(ser_in, LPC_UART->RBR); // Read Rx FIFO to buffer
|
|
}
|
|
}
|
|
if ((iir & 0x2)) { // TXMIS pending
|
|
if (SER_BUF_COUNT(ser_out) != 0) {
|
|
LPC_UART->THR = SER_BUF_RD(ser_out); // Write to the Tx FIFO
|
|
ser_txRestart = 0;
|
|
}
|
|
else {
|
|
ser_txRestart = 1;
|
|
}
|
|
}
|
|
ser_lineState = LPC_UART->LSR & 0x1E; // update linestate
|
|
return;
|
|
}
|
|
|
|
|