Skip to content

Commit a0f3303

Browse files
Keyur HariyaKeyur Hariya
authored andcommitted
Rework UART implementation
* Allow all support baud rates * Fix RX FIFO overflow issue * Fix mask name for interrupt enable of RX overflow
1 parent 9e5ebfc commit a0f3303

File tree

1 file changed

+97
-30
lines changed
  • source/hic_hal/maxim/max32625

1 file changed

+97
-30
lines changed

source/hic_hal/maxim/max32625/uart.c

Lines changed: 97 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,7 @@
2525
#include "uart.h"
2626

2727
// Size must be 2^n
28-
#define BUFFER_SIZE (4096)
29-
30-
#define UART_ERRORS (MXC_F_UART_INTFL_RX_FRAMING_ERR | \
31-
MXC_F_UART_INTFL_RX_PARITY_ERR | \
32-
MXC_F_UART_INTFL_RX_FIFO_OVERFLOW)
33-
28+
#define BUFFER_SIZE (4096)
3429

3530
// Track bit rate to avoid calculation from bus clock, clock scaler and baud divisor values
3631
static uint32_t baudrate;
@@ -39,6 +34,7 @@ static mxc_uart_regs_t *CdcAcmUart = NULL;
3934
static mxc_uart_fifo_regs_t *CdcAcmUartFifo = NULL;
4035
static IRQn_Type CdcAcmUartIrqNumber = MXC_IRQ_EXT_COUNT;
4136

37+
// Ring buffer
4238
static struct {
4339
uint8_t data[BUFFER_SIZE];
4440
volatile uint16_t idx_in;
@@ -48,15 +44,85 @@ static struct {
4844
} write_buffer, read_buffer;
4945

5046
/******************************************************************************/
51-
static void set_bitrate(uint32_t bps)
47+
static void set_bitrate(uint32_t target_baud)
5248
{
53-
uint32_t baud_divisor;
49+
uint32_t clk_scale;
50+
uint32_t min_baud;
51+
uint32_t uart_clk;
52+
uint16_t baud_shift;
53+
uint16_t baud_div;
54+
uint32_t baud, diff_baud;
55+
uint32_t baud_1, diff_baud_1;
56+
57+
// Setup system clock divider for given bit rate
58+
clk_scale = 0;
59+
do {
60+
min_baud = (SystemCoreClock >> clk_scale++) / (16 * (MXC_F_UART_BAUD_BAUD_DIVISOR >> MXC_F_UART_BAUD_BAUD_DIVISOR_POS));
61+
} while ((target_baud < min_baud) && (clk_scale < MXC_V_CLKMAN_CLK_SCALE_DIV_256));
62+
63+
// Check if the bit rate can be reached
64+
if (target_baud < min_baud) {
65+
// Fail silently
66+
return;
67+
}
68+
69+
if (MXC_CLKMAN->sys_clk_ctrl_8_uart != clk_scale) {
70+
MXC_CLKMAN->sys_clk_ctrl_8_uart = clk_scale;
71+
}
72+
73+
uart_clk = SystemCoreClock >> (clk_scale - 1);
5474

55-
baud_divisor = SystemCoreClock / (1 << (MXC_CLKMAN->sys_clk_ctrl_8_uart - 1));
56-
baud_divisor /= (bps * 16);
57-
CdcAcmUart->baud = baud_divisor;
75+
baud_shift = 2;
76+
baud_div = uart_clk / (target_baud * 4);
77+
78+
// Bitrate too high
79+
if (baud_div == 0) {
80+
// Fail silently
81+
return;
82+
}
83+
84+
// Decrease the divisor if baud_div is overflowing
85+
while (baud_div > 0x00FF) {
86+
if (baud_shift == 0) {
87+
// Fail silently
88+
return;
89+
}
90+
baud_shift--;
91+
baud_div = uart_clk / (target_baud * (16 >> baud_shift));
92+
}
93+
94+
// Adjust baud_div to avoid overflow in the calculations below
95+
if (baud_div == 0x00FF) {
96+
baud_div = 0x00FE;
97+
}
98+
99+
if (baud_div == 0x0000) {
100+
baud_div = 0x0001;
101+
}
58102

59-
baudrate = bps;
103+
// Determine if truncation increases the error
104+
baud = uart_clk / (baud_div * (16 >> baud_shift));
105+
baud_1 = uart_clk / ((baud_div + 1) * (16 >> baud_shift));
106+
107+
if (target_baud > baud) {
108+
diff_baud = target_baud - baud;
109+
} else {
110+
diff_baud = baud - target_baud;
111+
}
112+
113+
if (target_baud > baud_1) {
114+
diff_baud_1 = target_baud - baud_1;
115+
} else {
116+
diff_baud_1 = baud_1 - target_baud;
117+
}
118+
119+
if (diff_baud < diff_baud_1) {
120+
CdcAcmUart->baud = (baud_div & MXC_F_UART_BAUD_BAUD_DIVISOR) | (baud_shift << MXC_F_UART_BAUD_BAUD_MODE_POS);
121+
} else {
122+
CdcAcmUart->baud = ((baud_div + 1) & MXC_F_UART_BAUD_BAUD_DIVISOR) | (baud_shift << MXC_F_UART_BAUD_BAUD_MODE_POS);
123+
}
124+
125+
baudrate = target_baud;
60126
}
61127

62128
/******************************************************************************/
@@ -81,21 +147,18 @@ int32_t uart_initialize(void)
81147
{
82148
int idx;
83149

150+
/* Do not enable UART Common Clock here, must happen inside uart_set_configuration()
151+
to ensure correct clock scale for a given baud rate */
152+
84153
if (CdcAcmUart == MXC_UART0) {
85154
MXC_CLKMAN->clk_gate_ctrl1 |= MXC_F_CLKMAN_CLK_GATE_CTRL1_UART0_CLK_GATER;
86-
if (MXC_CLKMAN->sys_clk_ctrl_8_uart != MXC_S_CLKMAN_CLK_SCALE_DIV_4) {
87-
MXC_CLKMAN->sys_clk_ctrl_8_uart = MXC_S_CLKMAN_CLK_SCALE_DIV_4;
88-
}
89155

90156
// Configure GPIO for UART
91157
MXC_IOMAN->uart0_req = ((MXC_V_IOMAN_MAP_A << MXC_F_IOMAN_UART0_REQ_IO_MAP_POS) | MXC_F_IOMAN_UART0_REQ_IO_REQ);
92158
while (MXC_IOMAN->uart0_ack != ((MXC_V_IOMAN_MAP_A << MXC_F_IOMAN_UART0_REQ_IO_MAP_POS) | MXC_F_IOMAN_UART0_REQ_IO_REQ));
93159

94160
} else if (CdcAcmUart == MXC_UART2) {
95161
MXC_CLKMAN->clk_gate_ctrl1 |= MXC_F_CLKMAN_CLK_GATE_CTRL1_UART2_CLK_GATER;
96-
if (MXC_CLKMAN->sys_clk_ctrl_8_uart != MXC_S_CLKMAN_CLK_SCALE_DIV_4) {
97-
MXC_CLKMAN->sys_clk_ctrl_8_uart = MXC_S_CLKMAN_CLK_SCALE_DIV_4;
98-
}
99162

100163
// Configure GPIO for UART
101164
MXC_IOMAN->uart2_req = ((MXC_V_IOMAN_MAP_A << MXC_F_IOMAN_UART2_REQ_IO_MAP_POS) | MXC_F_IOMAN_UART2_REQ_IO_REQ);
@@ -132,7 +195,7 @@ int32_t uart_initialize(void)
132195
CdcAcmUart->tx_fifo_ctrl |= (MXC_UART_FIFO_DEPTH - (MXC_UART_FIFO_DEPTH >> 2)) << MXC_F_UART_TX_FIFO_CTRL_FIFO_AE_LVL_POS;
133196

134197
// Enable RX and TX interrupts
135-
CdcAcmUart->inten = (MXC_F_UART_INTEN_RX_FIFO_NOT_EMPTY | MXC_F_UART_INTFL_RX_FIFO_OVERFLOW | MXC_F_UART_INTEN_TX_FIFO_AE);
198+
CdcAcmUart->inten = (MXC_F_UART_INTEN_RX_FIFO_NOT_EMPTY | MXC_F_UART_INTEN_RX_FIFO_OVERFLOW | MXC_F_UART_INTEN_TX_FIFO_AE);
136199

137200
// Enable UART
138201
CdcAcmUart->ctrl |= MXC_F_UART_CTRL_UART_EN;
@@ -177,14 +240,11 @@ int32_t uart_set_configuration(UART_Configuration *config)
177240
{
178241
uint32_t ctrl;
179242

180-
// Get current configuration; clearing parameters that may be configured here
181-
ctrl = CdcAcmUart->ctrl & ~(MXC_F_UART_CTRL_PARITY |
182-
MXC_F_UART_CTRL_DATA_SIZE |
183-
MXC_F_UART_CTRL_EXTRA_STOP |
184-
MXC_F_UART_CTRL_CTS_EN |
185-
MXC_F_UART_CTRL_RTS_EN);
243+
// Disable UART, clear FIFOs and configuration
244+
CdcAcmUart->ctrl = 0;
186245

187246
switch (config->Parity) {
247+
default:
188248
case UART_PARITY_NONE: break;
189249
case UART_PARITY_ODD: ctrl |= MXC_S_UART_CTRL_PARITY_ODD;
190250
case UART_PARITY_EVEN: ctrl |= MXC_S_UART_CTRL_PARITY_EVEN;
@@ -196,26 +256,30 @@ int32_t uart_set_configuration(UART_Configuration *config)
196256
case UART_DATA_BITS_5: ctrl |= MXC_S_UART_CTRL_DATA_SIZE_5_BITS; break;
197257
case UART_DATA_BITS_6: ctrl |= MXC_S_UART_CTRL_DATA_SIZE_6_BITS; break;
198258
case UART_DATA_BITS_7: ctrl |= MXC_S_UART_CTRL_DATA_SIZE_7_BITS; break;
259+
default:
199260
case UART_DATA_BITS_8: ctrl |= MXC_S_UART_CTRL_DATA_SIZE_8_BITS; break;
200261
case UART_DATA_BITS_16: return 0;
201262
}
202263

203264
switch (config->StopBits) {
265+
default:
204266
case UART_STOP_BITS_1: break;
205267
case UART_STOP_BITS_1_5:
206268
case UART_STOP_BITS_2: ctrl |= MXC_F_UART_CTRL_EXTRA_STOP; break;
207269
}
208270

209271
switch (config->FlowControl) {
272+
default:
210273
case UART_FLOW_CONTROL_NONE: break;
211274
case UART_FLOW_CONTROL_RTS_CTS: return 0;
212275
case UART_FLOW_CONTROL_XON_XOFF: return 0;
213276
}
214277

215278
set_bitrate(config->Baudrate);
216279

217-
// Set the new configuration
280+
// Set the new configuration, enable FIFOs and UART
218281
CdcAcmUart->ctrl = ctrl;
282+
CdcAcmUart->ctrl |= MXC_F_UART_CTRL_RX_FIFO_EN | MXC_F_UART_CTRL_TX_FIFO_EN | MXC_F_UART_CTRL_UART_EN;
219283

220284
return 1;
221285
}
@@ -273,6 +337,7 @@ int32_t uart_write_data(uint8_t *data, uint16_t size)
273337
{
274338
uint16_t xfer_count = size;
275339

340+
// Prioritize writes to TX FIFO, then to write_buffer
276341
if (write_buffer.cnt_in == write_buffer.cnt_out) {
277342
while ((((CdcAcmUart->tx_fifo_ctrl & MXC_F_UART_TX_FIFO_CTRL_FIFO_ENTRY) >> MXC_F_UART_TX_FIFO_CTRL_FIFO_ENTRY_POS) < MXC_UART_FIFO_DEPTH) &&
278343
(xfer_count > 0)) {
@@ -326,19 +391,21 @@ void UART_IRQHandler(void)
326391
CdcAcmUart->intfl = intfl;
327392

328393
if (intfl & MXC_F_UART_INTFL_RX_FIFO_OVERFLOW) {
329-
read_buffer.data[read_buffer.idx_in++] = '*';
330-
read_buffer.idx_in &= (BUFFER_SIZE - 1);
331-
read_buffer.cnt_in++;
394+
// Flush RX FIFO, prepare for new characters
395+
CdcAcmUart->ctrl &= ~MXC_F_UART_CTRL_RX_FIFO_EN;
396+
CdcAcmUart->ctrl |= MXC_F_UART_CTRL_RX_FIFO_EN;
332397
}
333398

334-
if (intfl & (MXC_F_UART_INTFL_RX_FIFO_NOT_EMPTY | UART_ERRORS)) {
399+
if (intfl & MXC_F_UART_INTFL_RX_FIFO_NOT_EMPTY) {
335400
while ((CdcAcmUart->rx_fifo_ctrl & MXC_F_UART_RX_FIFO_CTRL_FIFO_ENTRY) &&
336401
((read_buffer.cnt_in - read_buffer.cnt_out) < BUFFER_SIZE)) {
337402
read_buffer.data[read_buffer.idx_in++] = CdcAcmUartFifo->rx;
338403
CdcAcmUart->intfl = MXC_F_UART_INTFL_RX_FIFO_NOT_EMPTY;
339404
read_buffer.idx_in &= (BUFFER_SIZE - 1);
340405
read_buffer.cnt_in++;
341406
}
407+
408+
// Ring buffer overflow
342409
if (((read_buffer.cnt_in - read_buffer.cnt_out) >= BUFFER_SIZE)) {
343410
read_buffer.data[read_buffer.idx_in++] = '%';
344411
read_buffer.idx_in &= (BUFFER_SIZE - 1);

0 commit comments

Comments
 (0)