Skip to content

Commit 15d9b14

Browse files
committed
fixup! [rp] Add UART module
1 parent 7c6b925 commit 15d9b14

File tree

3 files changed

+61
-54
lines changed

3 files changed

+61
-54
lines changed

src/modm/platform/uart/rp/module.lb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def prepare(module, options):
5757
return False
5858

5959
module.depends(
60+
":math:algorithm",
6061
":platform:gpio",
6162
":platform:clockgen",
6263
":architecture:uart",

src/modm/platform/uart/rp/uart.cpp.in

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ void modm::platform::Uart{{ id }}::unreset()
5757
Resets::unresetWait(RESETS_RESET_UART{{ id }}_BITS);
5858
}
5959

60-
6160
void
6261
modm::platform::Uart{{ id }}::writeBlocking(uint8_t data)
6362
{
@@ -67,10 +66,7 @@ modm::platform::Uart{{ id }}::writeBlocking(uint8_t data)
6766
void
6867
modm::platform::Uart{{ id }}::writeBlocking(const uint8_t *data, std::size_t length)
6968
{
70-
while (length--)
71-
{
72-
writeBlocking(*data++);
73-
}
69+
while (length--) writeBlocking(*data++);
7470
}
7571

7672
void
@@ -85,10 +81,7 @@ modm::platform::Uart{{ id }}::write(uint8_t data)
8581
{
8682
%% if options["buffer.tx"] <= fifo_size
8783
// No software buffer necessary, use hardware buffer only.
88-
if (tx_fifo_full())
89-
{
90-
return false;
91-
}
84+
if (tx_fifo_full()) return false;
9285
uart{{ id }}_hw->dr = data;
9386
return true;
9487
%% else
@@ -257,24 +250,26 @@ MODM_ISR(UART{{ id }}_IRQ)
257250
uint32_t IValue = uart{{ id }}_hw->mis;
258251
// clear
259252
uart{{ id }}_hw->icr = IValue;
260-
if (IValue & UART_UARTMIS_TXMIS_BITS) {
261253
%% if options["buffer.tx"] > fifo_size
254+
if (IValue & UART_UARTMIS_TXMIS_BITS)
255+
{
262256
while (!txBuffer.isEmpty() and !tx_fifo_full())
263257
{
264258
// Write to the hardware buffer
265259
uart{{ id }}_hw->dr = txBuffer.get();
266260
txBuffer.pop();
267261
}
268-
%% endif
269262
}
270-
if (IValue & UART_UARTMIS_RXMIS_BITS) {
263+
%% endif
271264
%% if options["buffer.rx"] > fifo_size
265+
if (IValue & UART_UARTMIS_RXMIS_BITS)
266+
{
272267
while(!rx_fifo_empty()) {
273268
rxBuffer.push(uart{{ id }}_hw->dr);
274269
}
275270
if (rxBuffer.isFull()) {
276271
uart{{ id }}_hw->imsc &= ~UART_UARTIMSC_RXIM_BITS;
277272
}
278-
%% endif
279273
}
274+
%% endif
280275
}

src/modm/platform/uart/rp/uart.hpp.in

Lines changed: 52 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <modm/architecture/interface/uart.hpp>
1515
#include <modm/platform/core/peripherals.hpp>
1616
#include <modm/platform/gpio/connector.hpp>
17+
#include <modm/math/algorithm/prescaler.hpp>
1718

1819
#include <hardware/structs/uart.h>
1920

@@ -51,14 +52,30 @@ public:
5152
static constexpr size_t TxBufferSize = {{ options["buffer.tx"] }};
5253

5354
public:
54-
55-
enum class Parity : uint32_t
55+
enum class
56+
Parity : uint32_t
5657
{
57-
Even = 2,
58-
Odd = 1,
58+
Even = UART_UARTLCR_H_PEN_BITS | UART_UARTLCR_H_EPS_BITS,
59+
Odd = UART_UARTLCR_H_PEN_BITS,
5960
Disabled = 0,
6061
};
6162

63+
enum class
64+
WordLength : uint32_t
65+
{
66+
Bit5 = 0 << UART_UARTLCR_H_WLEN_LSB,
67+
Bit6 = 1 << UART_UARTLCR_H_WLEN_LSB,
68+
Bit7 = 2 << UART_UARTLCR_H_WLEN_LSB,
69+
Bit8 = 3 << UART_UARTLCR_H_WLEN_LSB,
70+
};
71+
72+
enum class
73+
StopBits : uint32_t
74+
{
75+
Bit1 = 0,
76+
Bit2 = UART_UARTLCR_H_STP2_BITS,
77+
};
78+
6279
template< class... Signals >
6380
static void
6481
connect()
@@ -76,68 +93,62 @@ public:
7693
static void reset();
7794
static void unreset();
7895

79-
static void setFormat(uint8_t data_bits,uint8_t stop_bits,Parity parity) {
96+
static void
97+
setFormat(Parity parity, WordLength length, StopBits stop)
98+
{
8099
hw_write_masked(&uart{{ id }}_hw->lcr_h,
81-
((data_bits - 5u) << UART_UARTLCR_H_WLEN_LSB) |
82-
((stop_bits - 1u) << UART_UARTLCR_H_STP2_LSB) |
83-
((parity != Parity::Disabled ? 1 : 0) << UART_UARTLCR_H_PEN_LSB) |
84-
((parity == Parity::Even ? 1 : 0) << UART_UARTLCR_H_EPS_LSB),
85-
UART_UARTLCR_H_WLEN_BITS |
86-
UART_UARTLCR_H_STP2_BITS |
87-
UART_UARTLCR_H_PEN_BITS |
88-
UART_UARTLCR_H_EPS_BITS);
100+
uint32_t(parity) | uint32_t(length) | uint32_t(stop),
101+
UART_UARTLCR_H_WLEN_BITS | UART_UARTLCR_H_STP2_BITS |
102+
UART_UARTLCR_H_PEN_BITS | UART_UARTLCR_H_EPS_BITS);
89103
}
90104

91-
template< class SystemClock, baudrate_t baudrate >
92-
static uint32_t setBaudrate() {
93-
constexpr uint32_t baud_rate_div = (8 * SystemClock::PeriFrequency / baudrate);
94-
constexpr uint32_t baud_ibrd = baud_rate_div >> 7;
95-
uint32_t baud_fbrd;
96-
if constexpr (baud_ibrd == 0) {
97-
baud_ibrd = 1;
98-
baud_fbrd = 0;
99-
} else if constexpr (baud_ibrd >= 65535) {
100-
baud_ibrd = 65535;
101-
baud_fbrd = 0;
102-
} else {
103-
baud_fbrd = ((baud_rate_div & 0x7f) + 1) / 2;
104-
}
105+
template< class SystemClock, baudrate_t baudrate, percent_t tolerance=pct(1) >
106+
static baudrate_t
107+
setBaudrate()
108+
{
109+
static_assert(baudrate * 16 <= SystemClock::PeriFrequency and
110+
SystemClock::PeriFrequency <= baudrate * 16 * 65535ull,
111+
"SystemClock::PeriFrequency must be in the range [16 x baudrate, 16 x 65535 x baudrate].");
112+
// 16.6 fractional baudrate generator with 16x oversampling
113+
constexpr uint32_t min = (1ul << 7);
114+
constexpr uint32_t max = (1ul << 22) - 1ul;
115+
constexpr auto result = Prescaler::from_range(SystemClock::PeriFrequency*4, baudrate, min, max);
116+
modm::PeripheralDriver::assertBaudrateInTolerance< result.frequency, baudrate, tolerance >();
105117
// Load PL011's baud divisor registers
106-
uart{{ id }}_hw->ibrd = baud_ibrd;
107-
uart{{ id }}_hw->fbrd = baud_fbrd;
108-
118+
uart{{ id }}_hw->ibrd = result.prescaler >> 6;
119+
uart{{ id }}_hw->fbrd = result.prescaler & 0x3f;
109120
// PL011 needs a (dummy) line control register write to latch in the
110121
// divisors. We don't want to actually change LCR contents here.
111122
hw_set_bits(&uart{{ id }}_hw->lcr_h, 0);
112-
// See datasheet
113-
return (4 * SystemClock::PeriFrequency) / (64 * baud_ibrd + baud_fbrd);
123+
124+
return result.frequency;
114125
}
126+
115127
template< class SystemClock, baudrate_t baudrate, percent_t tolerance=pct(1) >
116-
static void inline
117-
initialize()
128+
static void
129+
initialize(Parity parity=Parity::Disabled, WordLength length=WordLength::Bit8, StopBits stop=StopBits::Bit1)
118130
{
119131
reset();
120132
unreset();
121-
setBaudrate<SystemClock,baudrate>();
122-
setFormat(8,1,Parity::Disabled);
133+
setBaudrate<SystemClock, baudrate, tolerance>();
134+
setFormat(parity, length, stop);
123135
// Enable the UART, both TX and RX
124136
uart{{ id }}_hw->cr = UART_UARTCR_UARTEN_BITS | UART_UARTCR_TXE_BITS | UART_UARTCR_RXE_BITS;
125137
// Enable FIFOs
126138
hw_set_bits(&uart{{ id }}_hw->lcr_h, UART_UARTLCR_H_FEN_BITS);
127139
// Always enable DREQ signals -- no harm in this if DMA is not listening
128140
uart{{ id }}_hw->dmacr = UART_UARTDMACR_TXDMAE_BITS | UART_UARTDMACR_RXDMAE_BITS;
129141

130-
%% if options["buffer.rx"] > fifo_size
142+
%% if options["buffer.rx"] > fifo_size
131143
/* If RX buffering with more than {{ fifo_size }} bytes is requested a software queue
132144
* must be used for receiving. This involves the Rx Interrupt only. */
133145
uart{{ id }}_hw->imsc = UART_UARTIMSC_RXIM_BITS;
134-
%% endif
146+
%% endif
135147

136-
%% if options["buffer.tx"] > fifo_size or options["buffer.rx"] > fifo_size
148+
%% if options["buffer.tx"] > fifo_size or options["buffer.rx"] > fifo_size
137149
/* Enable the UART Interrupt */
138150
NVIC_EnableIRQ(UART{{ id }}_IRQ_IRQn);
139-
%% endif
140-
151+
%% endif
141152
}
142153

143154
static void

0 commit comments

Comments
 (0)