mirror of https://github.com/ARMmbed/mbed-os.git
[LPC812] Add serial_api implementation. Make sure to always pull in the stdio retargeting module. Remove redundant stdio serial initialization.
parent
1c981f929a
commit
ca6e1ed7ab
|
@ -75,8 +75,6 @@ static void init_serial() {
|
||||||
#if DEVICE_SERIAL
|
#if DEVICE_SERIAL
|
||||||
if (stdio_uart_inited) return;
|
if (stdio_uart_inited) return;
|
||||||
serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
|
serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
|
||||||
serial_format(&stdio_uart, 8, ParityNone, 1);
|
|
||||||
serial_baud(&stdio_uart, 9600);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,14 @@ typedef enum {
|
||||||
OpenDrain = 4
|
OpenDrain = 4
|
||||||
} PinMode;
|
} PinMode;
|
||||||
|
|
||||||
|
#define STDIO_UART_TX USBTX
|
||||||
|
#define STDIO_UART_RX USBRX
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char n;
|
||||||
|
unsigned char offset;
|
||||||
|
} SWM_Map;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#define DEVICE_ANALOGIN 0
|
#define DEVICE_ANALOGIN 0
|
||||||
#define DEVICE_ANALOGOUT 0
|
#define DEVICE_ANALOGOUT 0
|
||||||
|
|
||||||
#define DEVICE_SERIAL 0
|
#define DEVICE_SERIAL 1
|
||||||
|
|
||||||
#define DEVICE_I2C 0
|
#define DEVICE_I2C 0
|
||||||
#define DEVICE_I2CSLAVE 0
|
#define DEVICE_I2CSLAVE 0
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
|
|
||||||
#define DEVICE_DEBUG_AWARENESS 0
|
#define DEVICE_DEBUG_AWARENESS 0
|
||||||
|
|
||||||
#define DEVICE_STDIO_MESSAGES 0
|
#define DEVICE_STDIO_MESSAGES 1
|
||||||
|
|
||||||
#define DEVICE_ERROR_RED 1
|
#define DEVICE_ERROR_RED 1
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,11 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct serial_s {
|
||||||
|
LPC_USART_TypeDef *uart;
|
||||||
|
unsigned char uart_n;
|
||||||
|
};
|
||||||
|
|
||||||
#include "gpio_object.h"
|
#include "gpio_object.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -72,15 +72,106 @@ static const PinMap PinMap_UART_RX[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define UART_NUM 1
|
#define UART_NUM 1
|
||||||
|
|
||||||
|
#elif defined(TARGET_LPC812)
|
||||||
|
|
||||||
|
static const SWM_Map SWM_UART_TX[] = {
|
||||||
|
{0, 0},
|
||||||
|
{1, 8},
|
||||||
|
{2, 16},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const SWM_Map SWM_UART_RX[] = {
|
||||||
|
{0, 8},
|
||||||
|
{1, 16},
|
||||||
|
{2, 24},
|
||||||
|
};
|
||||||
|
|
||||||
|
// bit flags for used UARTs
|
||||||
|
static unsigned char uart_used = 0;
|
||||||
|
static int get_available_uart(void) {
|
||||||
|
for (int i=0; i<3; i++) {
|
||||||
|
if ((uart_used & (1 << i)) == 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UART_EN (0x01<<0)
|
||||||
|
|
||||||
|
#define CTS_DELTA (0x01<<5)
|
||||||
|
#define RXBRK (0x01<<10)
|
||||||
|
#define DELTA_RXBRK (0x01<<11)
|
||||||
|
|
||||||
|
#define RXRDY (0x01<<0)
|
||||||
|
#define TXRDY (0x01<<2)
|
||||||
|
|
||||||
|
static uint32_t UARTSysClk;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef TARGET_LPC812
|
||||||
static uint32_t serial_irq_ids[UART_NUM] = {0};
|
static uint32_t serial_irq_ids[UART_NUM] = {0};
|
||||||
static uart_irq_handler irq_handler;
|
static uart_irq_handler irq_handler;
|
||||||
|
#endif
|
||||||
|
|
||||||
int stdio_uart_inited = 0;
|
int stdio_uart_inited = 0;
|
||||||
serial_t stdio_uart;
|
serial_t stdio_uart;
|
||||||
|
|
||||||
void serial_init(serial_t *obj, PinName tx, PinName rx) {
|
void serial_init(serial_t *obj, PinName tx, PinName rx) {
|
||||||
|
int is_stdio_uart = 0;
|
||||||
|
|
||||||
|
#ifdef TARGET_LPC812
|
||||||
|
int uart_n = get_available_uart();
|
||||||
|
if (uart_n == -1) {
|
||||||
|
error("No available UART");
|
||||||
|
}
|
||||||
|
obj->uart_n = uart_n;
|
||||||
|
obj->uart = (LPC_USART_TypeDef *)(LPC_USART0_BASE + (0x4000 * uart_n));
|
||||||
|
|
||||||
|
const SWM_Map *swm;
|
||||||
|
uint32_t regVal;
|
||||||
|
|
||||||
|
swm = &SWM_UART_TX[uart_n];
|
||||||
|
regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
|
||||||
|
LPC_SWM->PINASSIGN[swm->n] = regVal | (tx << swm->offset);
|
||||||
|
|
||||||
|
swm = &SWM_UART_RX[uart_n];
|
||||||
|
regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
|
||||||
|
LPC_SWM->PINASSIGN[swm->n] = regVal | (rx << swm->offset);
|
||||||
|
|
||||||
|
/* uart clock divided by 1 */
|
||||||
|
LPC_SYSCON->UARTCLKDIV = 1;
|
||||||
|
|
||||||
|
/* disable uart interrupts */
|
||||||
|
NVIC_DisableIRQ((IRQn_Type)(UART0_IRQn + uart_n));
|
||||||
|
|
||||||
|
/* Enable UART clock */
|
||||||
|
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << (14 + uart_n));
|
||||||
|
|
||||||
|
/* Peripheral reset control to UART, a "1" bring it out of reset. */
|
||||||
|
LPC_SYSCON->PRESETCTRL &= ~(0x1 << (3 + uart_n));
|
||||||
|
LPC_SYSCON->PRESETCTRL |= (0x1 << (3 + uart_n));
|
||||||
|
|
||||||
|
UARTSysClk = SystemCoreClock / LPC_SYSCON->UARTCLKDIV;
|
||||||
|
|
||||||
|
// set default baud rate and format
|
||||||
|
serial_baud (obj, 9600);
|
||||||
|
serial_format(obj, 8, ParityNone, 1);
|
||||||
|
|
||||||
|
/* Clear all status bits. */
|
||||||
|
obj->uart->STAT = CTS_DELTA | DELTA_RXBRK;
|
||||||
|
|
||||||
|
/* enable uart interrupts */
|
||||||
|
NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn + uart_n));
|
||||||
|
|
||||||
|
/* Enable UART interrupt */
|
||||||
|
// obj->uart->INTENSET = RXRDY | TXRDY | DELTA_RXBRK;
|
||||||
|
|
||||||
|
/* Enable UART */
|
||||||
|
obj->uart->CFG |= UART_EN;
|
||||||
|
|
||||||
|
is_stdio_uart = ((tx == USBTX) && (rx == USBRX));
|
||||||
|
#else
|
||||||
// determine the UART to use
|
// determine the UART to use
|
||||||
UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
|
UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
|
||||||
UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
|
UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
|
||||||
|
@ -145,20 +236,54 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uart == STDIO_UART) {
|
is_stdio_uart = (uart == STDIO_UART) ? (1) : (0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (is_stdio_uart) {
|
||||||
stdio_uart_inited = 1;
|
stdio_uart_inited = 1;
|
||||||
memcpy(&stdio_uart, obj, sizeof(serial_t));
|
memcpy(&stdio_uart, obj, sizeof(serial_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_free(serial_t *obj) {
|
void serial_free(serial_t *obj) {
|
||||||
|
#ifdef TARGET_LPC812
|
||||||
|
uart_used &= ~(1 << obj->uart_n);
|
||||||
|
#else
|
||||||
serial_irq_ids[obj->index] = 0;
|
serial_irq_ids[obj->index] = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// serial_baud
|
// serial_baud
|
||||||
//
|
|
||||||
// set the baud rate, taking in to account the current SystemFrequency
|
// set the baud rate, taking in to account the current SystemFrequency
|
||||||
//
|
void serial_baud(serial_t *obj, int baudrate) {
|
||||||
|
#ifdef TARGET_LPC812
|
||||||
|
/* Integer divider:
|
||||||
|
BRG = UARTSysClk/(Baudrate * 16) - 1
|
||||||
|
|
||||||
|
Frational divider:
|
||||||
|
FRG = ((UARTSysClk / (Baudrate * 16 * (BRG + 1))) - 1)
|
||||||
|
|
||||||
|
where
|
||||||
|
FRG = (LPC_SYSCON->UARTFRDADD + 1) / (LPC_SYSCON->UARTFRDSUB + 1)
|
||||||
|
|
||||||
|
(1) The easiest way is set SUB value to 256, -1 encoded, thus SUB
|
||||||
|
register is 0xFF.
|
||||||
|
(2) In ADD register value, depending on the value of UartSysClk,
|
||||||
|
baudrate, BRG register value, and SUB register value, be careful
|
||||||
|
about the order of multiplier and divider and make sure any
|
||||||
|
multiplier doesn't exceed 32-bit boundary and any divider doesn't get
|
||||||
|
down below one(integer 0).
|
||||||
|
(3) ADD should be always less than SUB.
|
||||||
|
*/
|
||||||
|
obj->uart->BRG = UARTSysClk / 16 / baudrate - 1;
|
||||||
|
|
||||||
|
LPC_SYSCON->UARTFRGDIV = 0xFF;
|
||||||
|
LPC_SYSCON->UARTFRGMULT = ( ((UARTSysClk / 16) * (LPC_SYSCON->UARTFRGDIV + 1)) /
|
||||||
|
(baudrate * (obj->uart->BRG + 1))
|
||||||
|
) - (LPC_SYSCON->UARTFRGDIV + 1);
|
||||||
|
|
||||||
|
#else
|
||||||
|
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
|
||||||
// The LPC2300 and LPC1700 have a divider and a fractional divider to control the
|
// The LPC2300 and LPC1700 have a divider and a fractional divider to control the
|
||||||
// baud rate. The formula is:
|
// baud rate. The formula is:
|
||||||
//
|
//
|
||||||
|
@ -168,8 +293,6 @@ void serial_free(serial_t *obj) {
|
||||||
// 0 <= DivAddVal < 14
|
// 0 <= DivAddVal < 14
|
||||||
// DivAddVal < MulVal
|
// DivAddVal < MulVal
|
||||||
//
|
//
|
||||||
void serial_baud(serial_t *obj, int baudrate) {
|
|
||||||
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
|
|
||||||
// set pclk to /1
|
// set pclk to /1
|
||||||
switch ((int)obj->uart) {
|
switch ((int)obj->uart) {
|
||||||
case UART_0: LPC_SC->PCLKSEL0 &= ~(0x3 << 6); LPC_SC->PCLKSEL0 |= (0x1 << 6); break;
|
case UART_0: LPC_SC->PCLKSEL0 &= ~(0x3 << 6); LPC_SC->PCLKSEL0 |= (0x1 << 6); break;
|
||||||
|
@ -233,10 +356,38 @@ void serial_baud(serial_t *obj, int baudrate) {
|
||||||
|
|
||||||
// clear LCR[DLAB]
|
// clear LCR[DLAB]
|
||||||
obj->uart->LCR &= ~(1 << 7);
|
obj->uart->LCR &= ~(1 << 7);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
|
void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
|
||||||
// 5 data bits = 0 ... 8 data bits = 3
|
// 0: 1 stop bits, 1: 2 stop bits
|
||||||
|
if (stop_bits != 1 && stop_bits != 2) {
|
||||||
|
error("Invalid stop bits specified");
|
||||||
|
}
|
||||||
|
stop_bits -= 1;
|
||||||
|
|
||||||
|
#ifdef TARGET_LPC812
|
||||||
|
// 0: 7 data bits ... 2: 9 data bits
|
||||||
|
if (data_bits < 7 || data_bits > 9) {
|
||||||
|
error("Invalid number of bits (%d) in serial format, should be 7..9", data_bits);
|
||||||
|
}
|
||||||
|
data_bits -= 7;
|
||||||
|
|
||||||
|
int paritysel;
|
||||||
|
switch (parity) {
|
||||||
|
case ParityNone: paritysel = 0; break;
|
||||||
|
case ParityEven: paritysel = 2; break;
|
||||||
|
case ParityOdd : paritysel = 3; break;
|
||||||
|
default:
|
||||||
|
error("Invalid serial parity setting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj->uart->CFG = (data_bits << 2)
|
||||||
|
| (paritysel << 4)
|
||||||
|
| (stop_bits << 6);
|
||||||
|
#else
|
||||||
|
// 0: 5 data bits ... 3: 8 data bits
|
||||||
if (data_bits < 5 || data_bits > 8) {
|
if (data_bits < 5 || data_bits > 8) {
|
||||||
error("Invalid number of bits (%d) in serial format, should be 5..8", data_bits);
|
error("Invalid number of bits (%d) in serial format, should be 5..8", data_bits);
|
||||||
}
|
}
|
||||||
|
@ -255,25 +406,19 @@ void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_b
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1 stop bits = 0, 2 stop bits = 1
|
|
||||||
if (stop_bits != 1 && stop_bits != 2) {
|
|
||||||
error("Invalid stop bits specified");
|
|
||||||
}
|
|
||||||
stop_bits -= 1;
|
|
||||||
|
|
||||||
int break_transmission = 0; // 0 = Disable, 1 = Enable
|
|
||||||
int divisor_latch_access = 0; // 0 = Disable, 1 = Enable
|
|
||||||
obj->uart->LCR = data_bits << 0
|
obj->uart->LCR = data_bits << 0
|
||||||
| stop_bits << 2
|
| stop_bits << 2
|
||||||
| parity_enable << 3
|
| parity_enable << 3
|
||||||
| parity_select << 4
|
| parity_select << 4;
|
||||||
| break_transmission << 6
|
#endif
|
||||||
| divisor_latch_access << 7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* INTERRUPTS HANDLING
|
* INTERRUPTS HANDLING
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
#ifdef TARGET_LPC812
|
||||||
|
|
||||||
|
#else
|
||||||
static inline void uart_irq(uint32_t iir, uint32_t index) {
|
static inline void uart_irq(uint32_t iir, uint32_t index) {
|
||||||
// [Chapter 14] LPC17xx UART0/2/3: UARTn Interrupt Handling
|
// [Chapter 14] LPC17xx UART0/2/3: UARTn Interrupt Handling
|
||||||
SerialIrq irq_type;
|
SerialIrq irq_type;
|
||||||
|
@ -296,13 +441,21 @@ void uart3_irq() {uart_irq(LPC_UART3->IIR, 3);}
|
||||||
#elif defined(TARGET_LPC11U24)
|
#elif defined(TARGET_LPC11U24)
|
||||||
void uart0_irq() {uart_irq(LPC_USART->IIR, 0);}
|
void uart0_irq() {uart_irq(LPC_USART->IIR, 0);}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
|
void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
|
||||||
|
#ifdef TARGET_LPC812
|
||||||
|
|
||||||
|
#else
|
||||||
irq_handler = handler;
|
irq_handler = handler;
|
||||||
serial_irq_ids[obj->index] = id;
|
serial_irq_ids[obj->index] = id;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
|
void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
|
||||||
|
#ifdef TARGET_LPC812
|
||||||
|
|
||||||
|
#else
|
||||||
IRQn_Type irq_n = (IRQn_Type)0;
|
IRQn_Type irq_n = (IRQn_Type)0;
|
||||||
uint32_t vector = 0;
|
uint32_t vector = 0;
|
||||||
switch ((int)obj->uart) {
|
switch ((int)obj->uart) {
|
||||||
|
@ -329,6 +482,7 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
|
||||||
if (all_disabled)
|
if (all_disabled)
|
||||||
NVIC_DisableIRQ(irq_n);
|
NVIC_DisableIRQ(irq_n);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
@ -336,30 +490,54 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
int serial_getc(serial_t *obj) {
|
int serial_getc(serial_t *obj) {
|
||||||
while (!serial_readable(obj));
|
while (!serial_readable(obj));
|
||||||
|
#ifdef TARGET_LPC812
|
||||||
|
return obj->uart->RXDATA;
|
||||||
|
#else
|
||||||
return obj->uart->RBR;
|
return obj->uart->RBR;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_putc(serial_t *obj, int c) {
|
void serial_putc(serial_t *obj, int c) {
|
||||||
while (!serial_writable(obj));
|
while (!serial_writable(obj));
|
||||||
|
#ifdef TARGET_LPC812
|
||||||
|
obj->uart->TXDATA = c;
|
||||||
|
#else
|
||||||
obj->uart->THR = c;
|
obj->uart->THR = c;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int serial_readable(serial_t *obj) {
|
int serial_readable(serial_t *obj) {
|
||||||
|
#ifdef TARGET_LPC812
|
||||||
|
return obj->uart->STAT & RXRDY;
|
||||||
|
#else
|
||||||
return obj->uart->LSR & 0x01;
|
return obj->uart->LSR & 0x01;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int serial_writable(serial_t *obj) {
|
int serial_writable(serial_t *obj) {
|
||||||
|
#ifdef TARGET_LPC812
|
||||||
|
return obj->uart->STAT & TXRDY;
|
||||||
|
#else
|
||||||
return obj->uart->LSR & 0x20;
|
return obj->uart->LSR & 0x20;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_clear(serial_t *obj) {
|
void serial_clear(serial_t *obj) {
|
||||||
|
#ifdef TARGET_LPC812
|
||||||
|
// [TODO]
|
||||||
|
#else
|
||||||
obj->uart->FCR = 1 << 1 // rx FIFO reset
|
obj->uart->FCR = 1 << 1 // rx FIFO reset
|
||||||
| 1 << 2 // tx FIFO reset
|
| 1 << 2 // tx FIFO reset
|
||||||
| 0 << 6; // interrupt depth
|
| 0 << 6; // interrupt depth
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_pinout_tx(PinName tx) {
|
void serial_pinout_tx(PinName tx) {
|
||||||
|
#ifdef TARGET_LPC812
|
||||||
|
|
||||||
|
#else
|
||||||
pinmap_pinout(tx, PinMap_UART_TX);
|
pinmap_pinout(tx, PinMap_UART_TX);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -311,6 +311,9 @@ void SystemCoreClockUpdate (void) /* Get Core Clock Frequency */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure we are pulling in the retargeting module at link time
|
||||||
|
extern int stdio_retargeting_module;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the system
|
* Initialize the system
|
||||||
*
|
*
|
||||||
|
@ -364,4 +367,6 @@ void SystemInit (void) {
|
||||||
|
|
||||||
LPC_SYSCON->SYSAHBCLKDIV = SYSAHBCLKDIV_Val;
|
LPC_SYSCON->SYSAHBCLKDIV = SYSAHBCLKDIV_Val;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
stdio_retargeting_module = 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue