Skip to content

Commit 11cf507

Browse files
andryblacksalkinium
authored andcommitted
[rp] Add UART module
1 parent e3d3333 commit 11cf507

File tree

3 files changed

+533
-0
lines changed

3 files changed

+533
-0
lines changed

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

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (c) 2022, Andrey Kunitsyn
5+
#
6+
# This file is part of the modm project.
7+
#
8+
# This Source Code Form is subject to the terms of the Mozilla Public
9+
# License, v. 2.0. If a copy of the MPL was not distributed with this
10+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
11+
# -----------------------------------------------------------------------------
12+
13+
14+
class Instance(Module):
15+
def __init__(self, instance):
16+
self.instance = instance
17+
18+
def init(self, module):
19+
module.name = str(self.instance)
20+
module.description = "UART {} instance".format(self.instance)
21+
22+
def prepare(self, module, options):
23+
module.add_option(
24+
NumericOption(
25+
name="buffer.tx",
26+
description="",
27+
minimum=32, maximum=2 ** 16 - 2,
28+
default=32))
29+
module.add_option(
30+
NumericOption(
31+
name="buffer.rx",
32+
description="",
33+
minimum=32, maximum=2 ** 16 - 2,
34+
default=32))
35+
36+
return True
37+
38+
def build(self, env):
39+
properties = {
40+
"id": self.instance,
41+
"fifo_size": 32,
42+
}
43+
env.substitutions = properties
44+
env.outbasepath = "modm/src/modm/platform/uart"
45+
46+
env.template("uart.hpp.in", "uart_{}.hpp".format(self.instance))
47+
env.template("uart.cpp.in", "uart_{}.cpp".format(self.instance))
48+
49+
50+
def init(module):
51+
module.name = ":platform:uart"
52+
module.description = "Universal Asynchronous Receiver Transmitter (UART)"
53+
54+
def prepare(module, options):
55+
device = options[":target"]
56+
if not device.has_driver("uart:rp*"):
57+
return False
58+
59+
module.depends(
60+
":math:algorithm",
61+
":platform:gpio",
62+
":platform:clockgen",
63+
":architecture:uart",
64+
":architecture:interrupt")
65+
66+
for instance in listify(device.get_driver("uart")["instance"]):
67+
module.add_submodule(Instance(instance))
68+
69+
return True
70+
71+
def build(env):
72+
pass

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

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
/*
2+
* Copyright (c) 2012, 2016-2017, Sascha Schade
3+
* Copyright (c) 2013-2014, Kevin Läufer
4+
* Copyright (c) 2013-2017, Niklas Hauser
5+
* Copyright (c) 2017, Fabian Greif
6+
* Copyright (c) 2022, Andrey Kunitsyn
7+
*
8+
* This file is part of the modm project.
9+
*
10+
* This Source Code Form is subject to the terms of the Mozilla Public
11+
* License, v. 2.0. If a copy of the MPL was not distributed with this
12+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
13+
*/
14+
// ----------------------------------------------------------------------------
15+
16+
#include <modm/architecture/driver/atomic/queue.hpp>
17+
#include <modm/architecture/interface/atomic_lock.hpp>
18+
#include <modm/architecture/interface/interrupt.hpp>
19+
#include <modm/platform/core/resets.hpp>
20+
21+
#include "../device.hpp"
22+
23+
#include "uart_{{ id }}.hpp"
24+
25+
// ----------------------------------------------------------------------------
26+
27+
namespace
28+
{
29+
// If requested buffer size is larger than hardware buffer size create a
30+
// software queue for the remaining bytes.
31+
%% if options["buffer.rx"] > fifo_size
32+
static modm::atomic::Queue<uint8_t, modm::platform::Uart{{ id }}::RxBufferSize - {{ fifo_size }}> rxBuffer;
33+
%% endif
34+
%% if options["buffer.tx"] > fifo_size
35+
static modm::atomic::Queue<uint8_t, modm::platform::Uart{{ id }}::TxBufferSize - {{ fifo_size }}> txBuffer;
36+
%% endif
37+
38+
}
39+
40+
static inline bool tx_fifo_full()
41+
{
42+
return uart{{ id }}_hw->fr & UART_UARTFR_TXFF_BITS;
43+
}
44+
45+
static inline bool rx_fifo_empty()
46+
{
47+
return uart{{ id }}_hw->fr & UART_UARTFR_RXFE_BITS;
48+
}
49+
50+
void modm::platform::Uart{{ id }}::reset()
51+
{
52+
Resets::reset(RESETS_RESET_UART{{ id }}_BITS);
53+
}
54+
55+
void modm::platform::Uart{{ id }}::unreset()
56+
{
57+
Resets::unresetWait(RESETS_RESET_UART{{ id }}_BITS);
58+
}
59+
60+
void
61+
modm::platform::Uart{{ id }}::writeBlocking(uint8_t data)
62+
{
63+
while (not write(data));
64+
}
65+
66+
void
67+
modm::platform::Uart{{ id }}::writeBlocking(const uint8_t *data, std::size_t length)
68+
{
69+
while (length--) writeBlocking(*data++);
70+
}
71+
72+
void
73+
modm::platform::Uart{{ id }}::flushWriteBuffer()
74+
{
75+
while(!isWriteFinished());
76+
}
77+
78+
// ----------------------------------------------------------------------------
79+
bool
80+
modm::platform::Uart{{ id }}::write(uint8_t data)
81+
{
82+
%% if options["buffer.tx"] <= fifo_size
83+
// No software buffer necessary, use hardware buffer only.
84+
if (tx_fifo_full()) return false;
85+
uart{{ id }}_hw->dr = data;
86+
return true;
87+
%% else
88+
atomic::Lock lock;
89+
// Use hardware buffer and additional software buffer.
90+
uart{{ id }}_hw->imsc |= UART_UARTIMSC_TXIM_BITS;
91+
92+
if (txBuffer.isEmpty() and !tx_fifo_full())
93+
{
94+
// If software buffer is empty try to write to hardware buffer directly.
95+
// Do not write to hardware buffer while there is some data in the
96+
// software buffer to maintain byte order.
97+
// There is at least charsLeft bytes free in the FIFO
98+
uart{{ id }}_hw->dr = data;
99+
return true; // success
100+
}
101+
102+
// Hardware buffer is full, so try software buffer.
103+
// Software buffer is empty so this will succeed.
104+
// Hardware buffer is not empty so at least one Tx interrupt
105+
// will be generated soon.
106+
107+
return txBuffer.push(data);
108+
%% endif
109+
}
110+
111+
// ----------------------------------------------------------------------------
112+
std::size_t
113+
modm::platform::Uart{{ id }}::write(const uint8_t *buffer, std::size_t length)
114+
{
115+
std::size_t written(0);
116+
117+
%% if options["buffer.tx"] <= fifo_size
118+
// No software buffer necessary, use hardware buffer only.
119+
while ( !tx_fifo_full() and written<length )
120+
{
121+
uart{{ id }}_hw->dr = *buffer++;
122+
written++;
123+
}
124+
%% else
125+
atomic::Lock lock;
126+
// Use hardware buffer and additional software buffer.
127+
uart{{ id }}_hw->imsc |= UART_UARTIMSC_TXIM_BITS;
128+
129+
if (txBuffer.isEmpty())
130+
{
131+
// If software buffer is completly empty try to write to hardware buffer directly.
132+
// Do not write to hardware buffer while there is some data in the
133+
// software buffer to maintain byte order.
134+
135+
// First Copy max(length) chars from buffer to hardware FIFO.
136+
while (written < length and !tx_fifo_full())
137+
{
138+
uart{{ id }}_hw->dr = *buffer++;
139+
written++;
140+
}
141+
}
142+
143+
// If there is remaining data, put it into the software buffer
144+
while (written < length)
145+
{
146+
if (not txBuffer.push(*buffer++)) break;
147+
written++;
148+
}
149+
%% endif
150+
return written;
151+
}
152+
153+
bool
154+
modm::platform::Uart{{ id }}::isWriteFinished()
155+
{
156+
%% if options["buffer.tx"] > fifo_size
157+
return txBuffer.isEmpty() and ((uart{{ id }}_hw->fr & UART_UARTFR_BUSY_BITS) == 0);
158+
%% else
159+
return (uart{{ id }}_hw->fr & UART_UARTFR_BUSY_BITS) == 0;
160+
%% endif
161+
}
162+
163+
std::size_t
164+
modm::platform::Uart{{ id }}::discardTransmitBuffer()
165+
{
166+
%% if options["buffer.tx"] > fifo_size
167+
atomic::Lock lock;
168+
std::size_t count(0);
169+
// disable interrupt since buffer will be cleared
170+
uart{{ id }}_hw->imsc &= UART_UARTIMSC_TXIM_BITS;
171+
while(not txBuffer.isEmpty())
172+
{
173+
++count;
174+
txBuffer.pop();
175+
}
176+
return count;
177+
%% else
178+
return 0;
179+
%% endif
180+
}
181+
182+
bool
183+
modm::platform::Uart{{ id }}::read(uint8_t& data)
184+
{
185+
%% if options["buffer.rx"] > fifo_size
186+
if (not rxBuffer.isEmpty())
187+
{
188+
data = rxBuffer.get();
189+
rxBuffer.pop();
190+
// if the hardware buffer has been used, copy all into rxBuffer
191+
while(!rx_fifo_empty() and rxBuffer.isNotFull())
192+
{
193+
rxBuffer.push(uart{{ id }}_hw->dr);
194+
}
195+
if (rxBuffer.isNotFull())
196+
{
197+
atomic::Lock lock;
198+
uart{{ id }}_hw->imsc |= UART_UARTIMSC_RXIM_BITS;
199+
}
200+
return true;
201+
}
202+
%% else
203+
if ((uart{{ id }}_hw->fr & UART_UARTFR_RXFE_BITS) == 0)
204+
{
205+
// Receive data available
206+
data = uart{{ id }}_hw->dr;
207+
return true;
208+
}
209+
%% endif
210+
return false;
211+
}
212+
213+
std::size_t
214+
modm::platform::Uart{{ id }}::read(uint8_t *buffer, std::size_t length)
215+
{
216+
std::size_t ret = 0;
217+
218+
while (ret < length)
219+
{
220+
if (not read(*buffer++)) break;
221+
ret++;
222+
}
223+
224+
return ret;
225+
}
226+
227+
std::size_t
228+
modm::platform::Uart{{ id }}::discardReceiveBuffer()
229+
{
230+
std::size_t count(0);
231+
%% if options["buffer.rx"] > fifo_size
232+
while(!rxBuffer.isEmpty())
233+
{
234+
++count;
235+
rxBuffer.pop();
236+
}
237+
%% endif
238+
while(!rx_fifo_empty())
239+
{
240+
(void)uart{{ id }}_hw->dr;
241+
++count;
242+
}
243+
return count;
244+
}
245+
246+
// ----------------------------------------------------------------------------
247+
MODM_ISR(UART{{ id }}_IRQ)
248+
{
249+
// read Masked Interrupt Status Register, UARTMIS
250+
uint32_t IValue = uart{{ id }}_hw->mis;
251+
// clear
252+
uart{{ id }}_hw->icr = IValue;
253+
%% if options["buffer.tx"] > fifo_size
254+
if (IValue & UART_UARTMIS_TXMIS_BITS)
255+
{
256+
while (!txBuffer.isEmpty() and !tx_fifo_full())
257+
{
258+
// Write to the hardware buffer
259+
uart{{ id }}_hw->dr = txBuffer.get();
260+
txBuffer.pop();
261+
}
262+
}
263+
%% endif
264+
%% if options["buffer.rx"] > fifo_size
265+
if (IValue & UART_UARTMIS_RXMIS_BITS)
266+
{
267+
while(!rx_fifo_empty()) {
268+
rxBuffer.push(uart{{ id }}_hw->dr);
269+
}
270+
if (rxBuffer.isFull()) {
271+
uart{{ id }}_hw->imsc &= ~UART_UARTIMSC_RXIM_BITS;
272+
}
273+
}
274+
%% endif
275+
}

0 commit comments

Comments
 (0)