Skip to content

Commit e62f4af

Browse files
kapacuksalkinium
authored andcommitted
[stm32] Implement UART buffers in C++ rather than lbuild
1 parent 55c88ba commit e62f4af

File tree

10 files changed

+415
-406
lines changed

10 files changed

+415
-406
lines changed

src/modm/architecture/interface/uart.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@ namespace modm
3030
*/
3131
class Uart : public ::modm::PeripheralDriver
3232
{
33-
#ifdef __DOXYGEN__
3433
public:
34+
struct RxBuffer { static constexpr bool HasRxBuffer = true; };
35+
struct TxBuffer { static constexpr bool HasTxBuffer = true; };
36+
37+
#ifdef __DOXYGEN__
3538
/// Size of the receive buffer.
3639
static constexpr size_t RxBufferSize = 16;
3740

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

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,6 @@ class Instance(Module):
2828

2929
def prepare(self, module, options):
3030
module.depends(":platform:uart")
31-
32-
module.add_option(
33-
NumericOption(
34-
name="buffer.tx",
35-
description="",
36-
minimum=0, maximum="64Ki-2",
37-
default=0))
38-
module.add_option(
39-
NumericOption(
40-
name="buffer.rx",
41-
description="",
42-
minimum=0, maximum="64Ki-2",
43-
default=0))
44-
4531
return True
4632

4733
def build(self, env):
@@ -53,7 +39,6 @@ class Instance(Module):
5339
props["uart_type"] = self.driver["name"].capitalize()
5440
props["name"] = self.driver["name"].capitalize() + str(self.instance)
5541
props["hal"] = self.driver["name"].capitalize() + "Hal" + str(self.instance)
56-
props["buffered"] = env["buffer.tx"] or env["buffer.rx"]
5742

5843
env.substitutions = props
5944
env.outbasepath = "modm/src/modm/platform/uart"
@@ -65,13 +50,8 @@ class Instance(Module):
6550

6651
env.template("uart_hal.hpp.in", "{}_hal_{}.hpp".format(uart, self.instance))
6752
env.template("uart_hal_impl.hpp.in", "{}_hal_{}_impl.hpp".format(uart, self.instance))
68-
env.template("uart.hpp.in", "{}_{}.hpp".format(uart, self.instance))
6953
env.template("uart.cpp.in", "{}_{}.cpp".format(uart, self.instance))
70-
71-
#props["instances"].append(props["name"])
72-
if props["buffered"]:
73-
props["buffered_instances"].append(props["name"])
74-
54+
props["instances"].append(props["name"])
7555

7656
def init(module):
7757
module.name = ":platform:uart"
@@ -92,15 +72,15 @@ def prepare(module, options):
9272
":math:algorithm",
9373
":cmsis:device",
9474
":platform:gpio",
95-
":platform:rcc")
75+
":platform:rcc",
76+
":utils")
9677

9778
global props
9879
drivers = (device.get_all_drivers("uart") + device.get_all_drivers("usart") + device.get_all_drivers("lpuart"))
9980
props["extended_driver"] = ("extended" in drivers[0]["type"])
10081
props["over8"] = ("feature" in drivers[0]) and ("over8" in drivers[0]["feature"])
10182
props["tcbgt"] = ("feature" in drivers[0]) and ("tcbgt" in drivers[0]["feature"])
10283
props["instances"] = []
103-
props["buffered_instances"] = []
10484

10585
for driver in drivers:
10686
for instance in driver["instance"]:
@@ -142,7 +122,7 @@ def build(env):
142122
env.template("uart_base.hpp.in")
143123

144124
props["uart_shared_irqs_data"] = dict()
145-
for name in props["buffered_instances"]:
125+
for name in props["instances"]:
146126
if name in props["shared_irqs"].keys():
147127
irq = props["shared_irqs"][name]
148128
if irq not in props["uart_shared_irqs_data"]:
@@ -154,3 +134,7 @@ def build(env):
154134
})
155135
if len(props["uart_shared_irqs_data"]):
156136
env.template("uart_shared.cpp.in")
137+
138+
env.copy("uart.hpp")
139+
env.copy("uart_buffer.hpp")
140+

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

Lines changed: 10 additions & 236 deletions
Original file line numberDiff line numberDiff line change
@@ -16,254 +16,28 @@
1616
*/
1717
// ----------------------------------------------------------------------------
1818

19-
#include "../device.hpp"
2019
%% if "Lpuart" in uart_type
21-
#include "lpuart_{{ id }}.hpp"
20+
#include "lpuart_hal_{{ id }}.hpp"
2221
%% else
23-
#include "uart_{{ id }}.hpp"
22+
#include "uart_hal_{{ id }}.hpp"
2423
%%endif
2524

26-
%% if buffered
27-
#include <modm/architecture/interface/atomic_lock.hpp>
28-
#include <modm/architecture/driver/atomic/queue.hpp>
29-
30-
namespace
31-
{
32-
%% if options["buffer.rx"]
33-
static modm::atomic::Queue<uint8_t, {{ options["buffer.rx"] }}> rxBuffer;
34-
%% endif
35-
%% if options["buffer.tx"]
36-
static modm::atomic::Queue<uint8_t, {{ options["buffer.tx"] }}> txBuffer;
37-
%% endif
38-
}
39-
%% endif
40-
41-
namespace modm::platform
42-
{
43-
44-
void
45-
{{ name }}::writeBlocking(uint8_t data)
46-
{
47-
while(!{{ hal }}::isTransmitRegisterEmpty());
48-
{{ hal }}::write(data);
49-
}
50-
51-
void
52-
{{ name }}::writeBlocking(const uint8_t *data, std::size_t length)
25+
%% if name in shared_irqs.keys()
26+
namespace modm::platform::{{ name }}
5327
{
54-
while (length-- != 0) {
55-
writeBlocking(*data++);
56-
}
57-
}
58-
5928
void
60-
{{ name }}::flushWriteBuffer()
61-
{
62-
%% if options["buffer.tx"]
63-
while(!isWriteFinished());
64-
%% else
65-
return;
66-
%% endif
67-
}
68-
69-
bool
70-
{{ name }}::write(uint8_t data)
71-
{
72-
%% if options["buffer.tx"]
73-
if(txBuffer.isEmpty() && {{ hal }}::isTransmitRegisterEmpty()) {
74-
{{ hal }}::write(data);
75-
} else {
76-
if (!txBuffer.push(data))
77-
return false;
78-
// Disable interrupts while enabling the transmit interrupt
79-
atomic::Lock lock;
80-
// Transmit Data Register Empty Interrupt Enable
81-
{{ hal }}::enableInterrupt(Interrupt::TxEmpty);
82-
}
83-
return true;
84-
%% else
85-
if({{ hal }}::isTransmitRegisterEmpty()) {
86-
{{ hal }}::write(data);
87-
return true;
88-
} else {
89-
return false;
90-
}
91-
%% endif
92-
}
93-
94-
std::size_t
95-
{{ name }}::write(const uint8_t *data, std::size_t length)
96-
{
97-
uint32_t i = 0;
98-
for (; i < length; ++i)
99-
{
100-
if (!write(*data++)) {
101-
return i;
102-
}
103-
}
104-
return i;
105-
}
106-
107-
bool
108-
{{ name }}::isWriteFinished()
109-
{
110-
%% if options["buffer.tx"]
111-
return txBuffer.isEmpty() && {{ hal }}::isTransmitRegisterEmpty();
112-
%% else
113-
return {{ hal }}::isTransmitRegisterEmpty();
114-
%% endif
115-
}
116-
117-
std::size_t
118-
{{ name }}::transmitBufferSize()
119-
{
120-
%% if options["buffer.tx"]
121-
return txBuffer.getSize();
122-
%% else
123-
return {{ hal }}::isTransmitRegisterEmpty() ? 0 : 1;
124-
%% endif
125-
}
126-
127-
std::size_t
128-
{{ name }}::discardTransmitBuffer()
129-
{
130-
%% if options["buffer.tx"]
131-
std::size_t count = 0;
132-
// disable interrupt since buffer will be cleared
133-
{{ hal }}::disableInterrupt({{ hal }}::Interrupt::TxEmpty);
134-
while(!txBuffer.isEmpty()) {
135-
++count;
136-
txBuffer.pop();
137-
}
138-
return count;
139-
%% else
140-
return 0;
141-
%% endif
142-
}
143-
144-
bool
145-
{{ name }}::read(uint8_t &data)
146-
{
147-
%% if options["buffer.rx"]
148-
if (rxBuffer.isEmpty()) {
149-
return false;
150-
} else {
151-
data = rxBuffer.get();
152-
rxBuffer.pop();
153-
return true;
154-
}
29+
irq()
15530
%% else
156-
if({{ hal }}::isReceiveRegisterNotEmpty()) {
157-
{{ hal }}::read(data);
158-
return true;
159-
} else {
160-
return false;
161-
}
31+
MODM_ISR({{ name | upper }})
16232
%% endif
163-
}
164-
165-
std::size_t
166-
{{ name }}::read(uint8_t *data, std::size_t length)
16733
{
168-
%% if options["buffer.rx"]
169-
uint32_t i = 0;
170-
for (; i < length; ++i)
34+
using namespace modm::platform;
35+
if ({{ hal }}::InterruptCallback)
17136
{
172-
if (rxBuffer.isEmpty()) {
173-
return i;
174-
} else {
175-
*data++ = rxBuffer.get();
176-
rxBuffer.pop();
177-
}
178-
}
179-
return i;
180-
%% else
181-
(void)length; // avoid compiler warning
182-
if(read(*data)) {
183-
return 1;
184-
} else {
185-
return 0;
37+
{{ hal }}::InterruptCallback(true);
18638
}
187-
%% endif
18839
}
18940

190-
std::size_t
191-
{{ name }}::receiveBufferSize()
192-
{
193-
%% if options["buffer.rx"]
194-
return rxBuffer.getSize();
195-
%% else
196-
return {{ hal }}::isReceiveRegisterNotEmpty() ? 1 : 0;
197-
%% endif
198-
}
199-
200-
std::size_t
201-
{{ name }}::discardReceiveBuffer()
202-
{
203-
%% if options["buffer.rx"]
204-
std::size_t count = 0;
205-
while(!rxBuffer.isEmpty()) {
206-
++count;
207-
rxBuffer.pop();
208-
}
209-
return count;
210-
%% else
211-
return 0;
212-
%% endif
213-
}
214-
215-
bool
216-
{{ name }}::hasError()
217-
{
218-
return {{ hal }}::getInterruptFlags().any(
219-
{{ hal }}::InterruptFlag::ParityError |
220-
#ifdef USART_ISR_NE
221-
{{ hal }}::InterruptFlag::NoiseError |
222-
#endif
223-
{{ hal }}::InterruptFlag::OverrunError | {{ hal }}::InterruptFlag::FramingError);
224-
}
225-
void
226-
{{ name }}::clearError()
227-
{
228-
return {{ hal }}::acknowledgeInterruptFlags(
229-
{{ hal }}::InterruptFlag::ParityError |
230-
#ifdef USART_ISR_NE
231-
{{ hal }}::InterruptFlag::NoiseError |
232-
#endif
233-
{{ hal }}::InterruptFlag::OverrunError | {{ hal }}::InterruptFlag::FramingError);
234-
}
235-
236-
} // namespace modm::platform
237-
238-
%% if buffered
23941
%% if name in shared_irqs.keys()
240-
void
241-
modm::platform::{{ name }}::irq()
242-
%% else
243-
MODM_ISR({{ name | upper }})
244-
%% endif
245-
{
246-
using namespace modm::platform;
247-
%% if options["buffer.rx"]
248-
if ({{ hal }}::isReceiveRegisterNotEmpty()) {
249-
// TODO: save the errors
250-
uint8_t data;
251-
{{ hal }}::read(data);
252-
rxBuffer.push(data);
253-
}
254-
%% endif
255-
%% if options["buffer.tx"]
256-
if ({{ hal }}::isTransmitRegisterEmpty()) {
257-
if (txBuffer.isEmpty()) {
258-
// transmission finished, disable TxEmpty interrupt
259-
{{ hal }}::disableInterrupt({{ hal }}::Interrupt::TxEmpty);
260-
}
261-
else {
262-
{{ hal }}::write(txBuffer.get());
263-
txBuffer.pop();
264-
}
265-
}
266-
%% endif
267-
{{ hal }}::acknowledgeInterruptFlags({{ hal }}::InterruptFlag::OverrunError);
268-
}
42+
} // namespace modm::platform::{{ name }}
26943
%% endif

0 commit comments

Comments
 (0)