Skip to content

lpc4322_hic: clock enhancements #925

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from
6 changes: 3 additions & 3 deletions source/hic_hal/nxp/lpc4322/RTE_Device.h
Original file line number Diff line number Diff line change
@@ -1010,12 +1010,12 @@
// </e> I2C1 (Inter-integrated Circuit Interface 1) [Driver_I2C1]

// <e> USART0 (Universal synchronous asynchronous receiver transmitter) [Driver_USART0]
#define RTE_USART0 0
#define RTE_USART0 1

// <h> Pin Configuration
// <o> TX <0=>Not used <1=>P2_0 <2=>P6_4 <3=>P9_5 <4=>PF_10
// <i> USART0 Serial Output pin
#define RTE_USART0_TX_ID 0
#define RTE_USART0_TX_ID 1
#if (RTE_USART0_TX_ID == 0)
#define RTE_USART0_TX_PIN_EN 0
#elif (RTE_USART0_TX_ID == 1)
@@ -1042,7 +1042,7 @@
#endif
// <o> RX <0=>Not used <1=>P2_1 <2=>P6_5 <3=>P9_6 <4=>PF_11
// <i> USART0 Serial Input pin
#define RTE_USART0_RX_ID 0
#define RTE_USART0_RX_ID 1
#if (RTE_USART0_RX_ID == 0)
#define RTE_USART0_RX_PIN_EN 0
#elif (RTE_USART0_RX_ID == 1)
17 changes: 0 additions & 17 deletions source/hic_hal/nxp/lpc4322/board_LPC43xx.c
Original file line number Diff line number Diff line change
@@ -20,24 +20,7 @@
*/

#include "sdk.h"
#include "lpc43xx_cgu.h"

void sdk_init(void)
{
/* Set core clock to 120MHz */
CGU_Init(120000000);
/* Set up USB0 clock */
/* Disable PLL first */
CGU_EnableEntity(CGU_CLKSRC_PLL0, DISABLE);

/* the usb core require output clock = 480MHz */
if (CGU_SetPLL0() != CGU_ERROR_SUCCESS) {
while (1);
}

CGU_EntityConnect(CGU_CLKSRC_XTAL_OSC, CGU_CLKSRC_PLL0);
/* Enable PLL after all setting is done */
CGU_EnableEntity(CGU_CLKSRC_PLL0, ENABLE);
/* Turn on the USB0PHY */
LPC_CREG->CREG0 &= ~(1 << 5);
}
1,132 changes: 0 additions & 1,132 deletions source/hic_hal/nxp/lpc4322/lpc43xx_cgu.c

This file was deleted.

265 changes: 0 additions & 265 deletions source/hic_hal/nxp/lpc4322/lpc43xx_cgu.h

This file was deleted.

160 changes: 96 additions & 64 deletions source/hic_hal/nxp/lpc4322/system_LPC43xx.c
Original file line number Diff line number Diff line change
@@ -319,6 +319,91 @@ uint32_t GetClockFreq (uint32_t clk_src);
uint32_t SystemCoreClock = 120000000U; /* System Clock Frequency (Core Clock) */


/*----------------------------------------------------------------------------
Approximate delay function (must be used after SystemCoreClockUpdate() call)
*----------------------------------------------------------------------------*/
static void WaitUs(uint32_t us, uint32_t clock_hz)
{
us *= (clock_hz / 1000000) / 3;

while (us--);
}


#define PLL0_NSEL_MAX (1<<8)
/* pre-divider: compute ndec from nsel */
static unsigned ndec_new(unsigned nsel)
{
unsigned x=0x80, in;
switch (nsel)
{
case 0: return 0xFFFFFFFF;
case 1: return 0x302;
case 2: return 0x202;
default:
for (in = nsel; in <= PLL0_NSEL_MAX; in++)
x = ((x ^ x>>2 ^ x>>3 ^ x>>4) & 1) << 7 | x>>1 & 0xFF;
return x;
}
}

#define PLL0_PSEL_MAX (1<<5)
/* post-divider: compute pdec from psel */
static unsigned pdec_new(unsigned psel)
{
unsigned x=0x10, ip;
switch (psel)
{
case 0: return 0xFFFFFFFF;
case 1: return 0x62;
case 2: return 0x42;
default:
for (ip = psel; ip <= PLL0_PSEL_MAX; ip++)
x = ((x ^ x>>2) & 1) << 4 | x>>1 & 0x3F;
return x;
}
}

#define PLL0_MSEL_MAX (1<<15)
/* multiplier: compute mdec from msel */
static unsigned mdec_new (unsigned msel)
{
unsigned x=0x4000, im;
switch (msel)
{
case 0: return 0xFFFFFFFF;
case 1: return 0x18003;
case 2: return 0x10003;
default:
for (im = msel; im <= PLL0_MSEL_MAX; im++)
x = (((x ^ (x >> 1)) & 1) << 14) | ((x >> 1) & 0xFFFF);
return x;
}
}

/* bandwidth: compute seli from msel */
unsigned anadeci_new(unsigned msel)
{
unsigned tmp;
if (msel > 16384) return 1;
if (msel > 8192) return 2;
if (msel > 2048) return 4;
if (msel >= 501) return 8;
if (msel >= 60)
{
tmp=1024/(msel+9);
return ( 1024 == ( tmp*(msel+9)) ) == 0 ? tmp*4 : (tmp+1)*4 ;
}
return (msel & 0x3c) + 4;
}

/* bandwidth: compute selp from msel */
unsigned anadecp_new(unsigned msel)
{
if (msel < 60) return (msel>>1) + 1;
return 31;
}

/******************************************************************************
* SetClock
******************************************************************************/
@@ -343,7 +428,7 @@ static void SetClock (void) {
(0 << 2) ; /* Low-frequency mode */

/* Wait ~250us @ 12MHz */
for (i = 1500; i; i--);
WaitUs(250, CLK_XTAL);

#ifdef USE_SPIFI
/* configure SPIFI clk to IRC via IDIVA (later IDIVA is configured to PLL1/3) */
@@ -380,10 +465,10 @@ static void SetClock (void) {

/* CPU base clock is in the mid frequency range before final clock set */
LPC_CGU->BASE_M4_CLK = (0x01 << 11) | /* Autoblock En */
(0x09 << 24) ; /* Clock source: PLL1 */
(CLK_SRC_PLL1 << 24) ; /* Clock source: PLL1 */

/* Max. BASE_M4_CLK frequency here is 102MHz, wait at least 20us */
for (i = 1050; i; i--); /* Wait minimum 2100 cycles */
/* Wait 20us */
WaitUs(20, (CLK_XTAL * (PLL1_MSEL + 1)) / ((PLL1_NSEL + 1) * 2));
#endif
/* Configure PLL1 */
LPC_CGU->PLL1_CTRL = (0 << 0) | /* PLL1 Enabled */
@@ -415,63 +500,20 @@ static void SetClock (void) {
LPC_CGU->PLL0USB_CTRL |= 1;

/* M divider */
x = 0x00004000;
switch (PLL0USB_M) {
case 0: x = 0xFFFFFFFF;
break;
case 1: x = 0x00018003;
break;
case 2: x = 0x00010003;
break;
default:
for (i = PLL0USB_M; i <= 0x8000; i++) {
x = (((x ^ (x >> 1)) & 1) << 14) | ((x >> 1) & 0x3FFF);
}
}
x = mdec_new(PLL0USB_M);

if (PLL0USB_M < 60) selp = (PLL0USB_M >> 1) + 1;
else selp = 31;

if (PLL0USB_M > 16384) seli = 1;
else if (PLL0USB_M > 8192) seli = 2;
else if (PLL0USB_M > 2048) seli = 4;
else if (PLL0USB_M >= 501) seli = 8;
else if (PLL0USB_M >= 60) seli = 4 * (1024 / (PLL0USB_M + 9));
else seli = (PLL0USB_M & 0x3C) + 4;
selp = anadecp_new(PLL0USB_M);
seli = anadeci_new(PLL0USB_M);
LPC_CGU->PLL0USB_MDIV = (selp << 17) |
(seli << 22) |
(x << 0);

/* N divider */
x = 0x80;
switch (PLL0USB_N) {
case 0: x = 0xFFFFFFFF;
break;
case 1: x = 0x00000302;
break;
case 2: x = 0x00000202;
break;
default:
for (i = PLL0USB_N; i <= 0x0100; i++) {
x =(((x ^ (x >> 2) ^ (x >> 3) ^ (x >> 4)) & 1) << 7) | ((x >> 1) & 0x7F);
}
}
x = ndec_new(PLL0USB_N);
LPC_CGU->PLL0USB_NP_DIV = (x << 12);

/* P divider */
x = 0x10;
switch (PLL0USB_P) {
case 0: x = 0xFFFFFFFF;
break;
case 1: x = 0x00000062;
break;
case 2: x = 0x00000042;
break;
default:
for (i = PLL0USB_P; i <= 0x200; i++) {
x = (((x ^ (x >> 2)) & 1) << 4) | ((x >> 1) &0x0F);
}
}
x = pdec_new(PLL0USB_P);
LPC_CGU->PLL0USB_NP_DIV |= x;

LPC_CGU->PLL0USB_CTRL = (PLL0USB_CLK_SEL << 24) | /* Clock source sel */
@@ -481,6 +523,7 @@ static void SetClock (void) {
(PLL0USB_DIRECTI << 2 ) | /* Direct input */
(PLL0USB_BYPASS << 1 ) | /* PLL bypass */
(0 << 0 ) ; /* PLL0USB Enabled */
LPC_CREG->CREG0 &= ~(1 << 5); // Enable USB0 PHY power.
while (!(LPC_CGU->PLL0USB_STAT & 1));


@@ -516,17 +559,6 @@ static void SetClock (void) {
}


/*----------------------------------------------------------------------------
Approximate delay function (must be used after SystemCoreClockUpdate() call)
*----------------------------------------------------------------------------*/
#define CPU_NANOSEC(x) (((uint64_t)(x) * SystemCoreClock)/1000000000)

static void WaitUs (uint32_t us) {
uint32_t cyc = us * CPU_NANOSEC(1000)/4;
while(cyc--);
}


/*----------------------------------------------------------------------------
Measure frequency using frequency monitor
*----------------------------------------------------------------------------*/
@@ -545,7 +577,7 @@ uint32_t MeasureFreq (uint32_t clk_sel) {
}
}
fcnt = (LPC_CGU->FREQ_MON >> 9) & 0x3FFF;
fout = fcnt * (12000000U/511U); /* FCNT * (IRC_CLK / RCNT) */
fout = fcnt * (CLK_IRC/511U); /* FCNT * (IRC_CLK / RCNT) */

return (fout);
}
385 changes: 136 additions & 249 deletions source/hic_hal/nxp/lpc4322/uart.c
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
* @brief
*
* DAPLink Interface Firmware
* Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
* Copyright (c) 2020 Arm Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -19,241 +19,167 @@
* limitations under the License.
*/

#include "string.h"
#include "LPC43xx.h"
#include "RTE_Driver/USART_LPC43xx.h"
#include "uart.h"
#include "lpc43xx_cgu.h"
#include "lpc43xx_scu.h"
#include "util.h"
#include "cortex_m.h"
#include "circ_buf.h"
#include "settings.h" // for config_get_overflow_detect

static uint32_t baudrate;
static uint32_t dll;
static uint32_t tx_in_progress;
#define USART_INSTANCE (Driver_USART0)
#define USART_IRQ (USART0_IRQn)

extern uint32_t SystemCoreClock;

static void clear_buffers(void);

#define RX_OVRF_MSG "<DAPLink:Overflow>\n"
#define RX_OVRF_MSG_SIZE (sizeof(RX_OVRF_MSG) - 1)
#define BUFFER_SIZE (512)
#define BUFFER_SIZE (512)

circ_buf_t write_buffer;
uint8_t write_buffer_data[BUFFER_SIZE];
circ_buf_t read_buffer;
uint8_t read_buffer_data[BUFFER_SIZE];

static int32_t reset(void);
struct {
// Number of bytes pending to be transferred. This is 0 if there is no
// ongoing transfer and the uart_handler processed the last transfer.
volatile uint32_t tx_size;

#define UART_IRQn USART0_IRQn
#define LPC_USART LPC_USART0
#define UART_IRQHandler USART0_IRQHandler
uint8_t rx;
} cb_buf;

// UART Control Pin P2_2: GPIO5[2]
#define PORT_UARTCTRL 5
#define PIN_UARTCTRL_IN_BIT 2
#define PIN_UARTCTRL (1<<PIN_UARTCTRL_IN_BIT)
void uart_handler(uint32_t event);

void clear_buffers(void)
{
circ_buf_init(&write_buffer, write_buffer_data, sizeof(write_buffer_data));
circ_buf_init(&read_buffer, read_buffer_data, sizeof(read_buffer_data));
}

int32_t uart_initialize(void)
{
NVIC_DisableIRQ(UART_IRQn);

// The baudrate calculations require the UART to be clocked as SystemCoreClock
CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_UART0);
CGU_EnableEntity(CGU_BASE_UART0, ENABLE);
scu_pinmux(2, 0, UART_RX_TX, FUNC1); /* P2_0: U0_TXD */
scu_pinmux(2, 1, UART_RX_TX, FUNC1); /* P2_1: U0_RXD */

scu_pinmux(2, 2, GPIO_NOPULL, FUNC4); /* UARTCTRL: GPIO5[2] */
// Control target's UART RX:
// UARTCTRL high: The LPC1549 gets uart input from the LPC4322
// UARTCTRL low: The LPC1549 gets uart input from the ISP_RX on the pinlist
LPC_GPIO_PORT->CLR[PORT_UARTCTRL] = PIN_UARTCTRL;
LPC_GPIO_PORT->DIR[PORT_UARTCTRL] |= (PIN_UARTCTRL);
// enable FIFOs (trigger level 1) and clear them
LPC_USART->FCR = 0x87;
// Transmit Enable
LPC_USART->TER = 0x01;
// reset uart
reset();
// enable rx and tx interrupt
LPC_USART->IER |= (1 << 0) | (1 << 1);
NVIC_EnableIRQ(UART_IRQn);
clear_buffers();
cb_buf.tx_size = 0;
USART_INSTANCE.Initialize(uart_handler);
USART_INSTANCE.PowerControl(ARM_POWER_FULL);

return 1;
}

int32_t uart_uninitialize(void)
{
// disable interrupt
LPC_USART->IER &= ~(0x7);
NVIC_DisableIRQ(UART_IRQn);
// reset uart
reset();
USART_INSTANCE.Control(ARM_USART_CONTROL_RX, 0);
USART_INSTANCE.Control(ARM_USART_ABORT_RECEIVE, 0U);
USART_INSTANCE.PowerControl(ARM_POWER_OFF);
USART_INSTANCE.Uninitialize();
clear_buffers();
cb_buf.tx_size = 0;

return 1;
}

int32_t uart_reset(void)
{
// disable interrupt
NVIC_DisableIRQ(UART_IRQn);
// reset uart
reset();
NVIC_DisableIRQ(USART_IRQ);
clear_buffers();
// enable interrupt
NVIC_EnableIRQ(UART_IRQn);
NVIC_EnableIRQ(USART_IRQ);

return 1;
}

int32_t uart_set_configuration(UART_Configuration *config)
{
uint8_t DivAddVal = 0;
uint8_t MulVal = 1;
uint8_t mv, data_bits = 8, parity, stop_bits = 0;
// disable interrupt
NVIC_DisableIRQ(UART_IRQn);
// reset uart
reset();
baudrate = config->Baudrate;
// Compute baud rate dividers
mv = 15;
dll = util_div_round_down(SystemCoreClock, 16 * config->Baudrate);
DivAddVal = util_div_round(SystemCoreClock * mv, dll * config->Baudrate * 16) - mv;
// set LCR[DLAB] to enable writing to divider registers
LPC_USART->LCR |= (1 << 7);
// set divider values
LPC_USART->DLM = (dll >> 8) & 0xFF;
LPC_USART->DLL = (dll >> 0) & 0xFF;
LPC_USART->FDR = (uint32_t) DivAddVal << 0
| (uint32_t) MulVal << 4;
// clear LCR[DLAB]
LPC_USART->LCR &= ~(1 << 7);

// set data bits, stop bits, parity
if ((config->DataBits < 5) || (config->DataBits > 8)) {
data_bits = 8;
}

data_bits -= 5;

if (config->StopBits != 1 && config->StopBits != 2) {
stop_bits = 1;
}

stop_bits -= 1;

switch (config->Parity) {
case UART_PARITY_ODD:
parity = 0x01;
break; // Parity Odd

case UART_PARITY_EVEN:
parity = 0x03;
break; // Parity Even
uint32_t control = ARM_USART_MODE_ASYNCHRONOUS;

case UART_PARITY_MARK:
parity = 0x05;
break; // Parity Mark

case UART_PARITY_SPACE:
parity = 0x07;
break; // Parity Space

case UART_PARITY_NONE: // Parity None
default:
parity = 0x00;
switch (config->DataBits) {
case UART_DATA_BITS_5:
control |= ARM_USART_DATA_BITS_5;
break;
}

LPC_USART->LCR = (data_bits << 0)
| (stop_bits << 2)
| (parity << 3);
// Enable UART interrupt
NVIC_EnableIRQ(UART_IRQn);
return 1;
}

int32_t uart_get_configuration(UART_Configuration *config)
{
float br;
uint32_t lcr;
// line control parameter
lcr = LPC_USART->LCR;
// baudrate
br = SystemCoreClock / (dll * 16);

// If inside +/- 2% tolerance
if (((br * 100) <= (baudrate * 102)) && ((br * 100) >= (baudrate * 98))) {
config->Baudrate = baudrate;
} else {
config->Baudrate = br;
}
case UART_DATA_BITS_6:
control |= ARM_USART_DATA_BITS_6;
break;

// get data bits
switch ((lcr >> 0) & 3) {
case 0:
config->DataBits = UART_DATA_BITS_5;
case UART_DATA_BITS_7:
control |= ARM_USART_DATA_BITS_7;
break;

case 1:
config->DataBits = UART_DATA_BITS_6;
case UART_DATA_BITS_8: /* fallthrough */
default:
control |= ARM_USART_DATA_BITS_8;
break;
}

case 2:
config->DataBits = UART_DATA_BITS_7;
switch (config->Parity) {
case UART_PARITY_EVEN:
control |= ARM_USART_PARITY_EVEN;
break;

case 3:
config->DataBits = UART_DATA_BITS_8;
case UART_PARITY_ODD:
control |= ARM_USART_PARITY_ODD;
break;

case UART_PARITY_NONE: /* fallthrough */
default:
return 0;
control |= ARM_USART_PARITY_NONE;
break;
}

// get parity
switch ((lcr >> 3) & 7) {
case 0:
case 2:
case 4:
case 6:
config->Parity = UART_PARITY_NONE;
switch (config->StopBits) {
case UART_STOP_BITS_1: /* fallthrough */
default:
control |= ARM_USART_STOP_BITS_1;
break;

case 1:
config->Parity = UART_PARITY_ODD;
case UART_STOP_BITS_1_5:
control |= ARM_USART_STOP_BITS_1_5;
break;

case 3:
config->Parity = UART_PARITY_MARK;
case UART_STOP_BITS_2:
control |= ARM_USART_STOP_BITS_2;
break;
}

case 5:
config->Parity = UART_PARITY_EVEN;
switch (config->FlowControl) {
case UART_FLOW_CONTROL_NONE: /* fallthrough */
default:
control |= ARM_USART_FLOW_CONTROL_NONE;
break;

case 7:
config->Parity = UART_PARITY_SPACE;
case UART_FLOW_CONTROL_RTS_CTS:
control |= ARM_USART_FLOW_CONTROL_RTS_CTS;
break;

default:
return 0;
}

// get stop bits
switch ((lcr >> 2) & 1) {
case 0:
config->StopBits = UART_STOP_BITS_1;
break;
NVIC_DisableIRQ(USART_IRQ);
clear_buffers();

case 1:
config->StopBits = UART_STOP_BITS_2;
break;
// If there was no Receive() call in progress aborting it is harmless.
USART_INSTANCE.Control(ARM_USART_CONTROL_RX, 0U);
USART_INSTANCE.Control(ARM_USART_ABORT_RECEIVE, 0U);

default:
return 0;
uint32_t r = USART_INSTANCE.Control(control, config->Baudrate);
if (r != ARM_DRIVER_OK) {
return 0;
}
USART_INSTANCE.Control(ARM_USART_CONTROL_TX, 1);
USART_INSTANCE.Control(ARM_USART_CONTROL_RX, 1);
USART_INSTANCE.Receive(&(cb_buf.rx), 1);

NVIC_ClearPendingIRQ(USART_IRQ);
NVIC_EnableIRQ(USART_IRQ);

return 1;
}

// get flow control
config->FlowControl = UART_FLOW_CONTROL_NONE;
int32_t uart_get_configuration(UART_Configuration *config)
{
return 1;
}

@@ -266,104 +192,65 @@ int32_t uart_write_free(void)
return circ_buf_count_free(&write_buffer);
}

// Start a new TX transfer if there are bytes pending to be transferred on the
// write_buffer buffer. The transferred bytes are not removed from the circular
// by this function, only the event handler will remove them once the transfer
// is done.
static void uart_start_tx_transfer() {
uint32_t tx_size = 0;
const uint8_t* buf = circ_buf_peek(&write_buffer, &tx_size);
if (tx_size > BUFFER_SIZE / 4) {
// The bytes being transferred remain on the circular buffer memory
// until the transfer is done. Limiting the UART transfer size
// allows the uart_handler to clear those bytes earlier.
tx_size = BUFFER_SIZE / 4;
}
cb_buf.tx_size = tx_size;
if (tx_size) {
USART_INSTANCE.Send(buf, tx_size);
}
}

int32_t uart_write_data(uint8_t *data, uint16_t size)
{
uint32_t cnt;

cnt = circ_buf_write(&write_buffer, data, size);

// Make sure that the target LPC1549 can receive the output
LPC_GPIO_PORT->SET[PORT_UARTCTRL] = PIN_UARTCTRL;

// enable THRE interrupt
LPC_USART->IER |= (1 << 1);
if (size == 0) {
return 0;
}

if (!tx_in_progress) {
// force THRE interrupt to start
NVIC_SetPendingIRQ(UART_IRQn);
uint32_t cnt = circ_buf_write(&write_buffer, data, size);
if (cb_buf.tx_size == 0) {
// There's no pending transfer and the value of cb_buf.tx_size will not
// change to non-zero by the event handler once it is zero. Note that it
// is entirely possible that we transferred all the bytes we added to
// the circular buffer in this function by the time we are in this
// branch, in that case uart_start_tx_transfer() would not schedule any
// transfer.
uart_start_tx_transfer();
}

return cnt;
}


int32_t uart_read_data(uint8_t *data, uint16_t size)
{
return circ_buf_read(&read_buffer, data, size);
}

void uart_enable_flow_control(bool enabled)
{
// Flow control not implemented for this platform
}

void UART_IRQHandler(void)
{
uint32_t iir;
// read interrupt status
iir = LPC_USART->IIR;

// handle character to transmit
if (circ_buf_count_used(&write_buffer) > 0) {
// if THR is empty
if (LPC_USART->LSR & (1 << 5)) {
LPC_USART->THR = circ_buf_pop(&write_buffer);
tx_in_progress = 1;
void uart_handler(uint32_t event) {
if (event & ARM_USART_EVENT_RECEIVE_COMPLETE) {
uint32_t free = circ_buf_count_free(&read_buffer);
if (free > RX_OVRF_MSG_SIZE) {
circ_buf_push(&read_buffer, cb_buf.rx);
} else if ((RX_OVRF_MSG_SIZE == free) && config_get_overflow_detect()) {
circ_buf_write(&read_buffer, (uint8_t*)RX_OVRF_MSG, RX_OVRF_MSG_SIZE);
} else {
// Drop character
}

} else if (tx_in_progress) {
tx_in_progress = 0;
// Turn back input for the target LPC1549 to it's pinlist
LPC_GPIO_PORT->CLR[PORT_UARTCTRL] = PIN_UARTCTRL;
// disable THRE interrupt
LPC_USART->IER &= ~(1 << 1);
USART_INSTANCE.Receive(&(cb_buf.rx), 1);
}

// handle received character
if (((iir & 0x0E) == 0x04) || // Rx interrupt (RDA)
((iir & 0x0E) == 0x0C)) { // Rx interrupt (CTI)
while (LPC_USART->LSR & 0x01) {
uint32_t free;
uint8_t data;

data = LPC_USART->RBR;
free = circ_buf_count_free(&read_buffer);
if (free > RX_OVRF_MSG_SIZE) {
circ_buf_push(&read_buffer, data);
} else if (config_get_overflow_detect()) {
if (RX_OVRF_MSG_SIZE == free) {
circ_buf_write(&read_buffer, (uint8_t*)RX_OVRF_MSG, RX_OVRF_MSG_SIZE);
} else {
// Drop newest
}
} else {
// Drop oldest
circ_buf_pop(&read_buffer);
circ_buf_push(&read_buffer, data);
}
}
if (event & ARM_USART_EVENT_SEND_COMPLETE) {
circ_buf_pop_n(&write_buffer, cb_buf.tx_size);
uart_start_tx_transfer();
}

LPC_USART->LSR;
}

static int32_t reset(void)
{
// Reset FIFOs
LPC_USART->FCR = 0x06;
baudrate = 0;
dll = 0;
tx_in_progress = 0;

circ_buf_init(&write_buffer, write_buffer_data, sizeof(write_buffer_data));
circ_buf_init(&read_buffer, read_buffer_data, sizeof(read_buffer_data));

// Ensure a clean start, no data in either TX or RX FIFO
while ((LPC_USART->LSR & ((1 << 5) | (1 << 6))) != ((1 << 5) | (1 << 6)));

while (LPC_USART->LSR & 0x01) {
LPC_USART->RBR; // Dump data from RX FIFO
}

return 1;
}