Skip to content

Commit 6e9f000

Browse files
mcbridejcsalkinium
authored andcommitted
Add UART driver for SAMG
1 parent 4dec359 commit 6e9f000

File tree

9 files changed

+416
-3
lines changed

9 files changed

+416
-3
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
437437
<td align="center">✅</td>
438438
<td align="center">✅</td>
439439
<td align="center">✅</td>
440-
<td align="center"></td>
440+
<td align="center"></td>
441441
<td align="center">○</td>
442442
<td align="center">✅</td>
443443
<td align="center">✅</td>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2021, Jeff McBride
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
11+
#include <modm/board.hpp>
12+
#include <modm/io/iostream.hpp>
13+
14+
using namespace modm::platform;
15+
using namespace modm::literals;
16+
17+
// Create IO wrapper for the debug UART, which is connected to the built-in
18+
// USB debugger virtual COM port
19+
modm::IODeviceWrapper<Board::DebugUart, modm::IOBuffer::BlockIfFull> debugDevice;
20+
modm::IOStream debugStream(debugDevice);
21+
22+
int
23+
main()
24+
{
25+
Board::initialize();
26+
27+
uint32_t cycle = 0;
28+
while (true)
29+
{
30+
modm::delay(1s);
31+
debugStream.printf("Cycle: %lu\r\n", cycle);
32+
}
33+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<library>
2+
<extends>modm:samg55-xplained-pro</extends>
3+
<options>
4+
<option name="modm:build:build.path">../../../build/samg55_xplained_pro/uart</option>
5+
</options>
6+
<modules>
7+
<module>modm:build:scons</module>
8+
</modules>
9+
</library>

src/modm/board/samg55_xplained_pro/board.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ struct SystemClock
2525
// Chosen to achieve 48MHz USB clock
2626
static constexpr uint32_t PllBMult = 1465;
2727

28-
static constexpr uint32_t Frequency = PllAMult * SlowClkFreqHz;
28+
static constexpr uint32_t Frequency = PllAMult * SlowClkFreqHz; // CPU core frequency
2929
static constexpr uint32_t Usb = PllBMult * SlowClkFreqHz;
30+
static constexpr uint32_t Mck = Frequency; // Master clock, used by most peripherals
31+
3032
static bool inline
3133
enable()
3234
{
@@ -50,6 +52,9 @@ struct SystemClock
5052

5153
using Led = GpioA6;
5254
using Button = GpioA2;
55+
using DebugUart = Uart7;
56+
using TxPin = GpioA28;
57+
using RxPin = GpioA27;
5358

5459
inline void
5560
initialize()
@@ -60,6 +65,9 @@ initialize()
6065
SystemClock::enable();
6166
SysTickTimer::initialize<SystemClock>();
6267

68+
DebugUart::initialize<SystemClock, 115200>();
69+
DebugUart::connect<TxPin::Tx, RxPin::Rx>();
70+
6371
Led::setOutput(modm::Gpio::Low);
6472

6573
Button::setInput();

src/modm/board/samg55_xplained_pro/module.lb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@ def prepare(module, options):
1818
if not options[":target"].partname == "samg55j19a-au":
1919
return False
2020

21-
module.depends(":platform:clockgen", ":platform:gpio", ":platform:core", ":platform:usb");
21+
module.depends(
22+
":platform:clockgen",
23+
":platform:uart:7",
24+
":platform:gpio",
25+
":platform:core",
26+
":platform:usb",
27+
":io")
2228
return True
2329

2430
def build(env):

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

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (c) 2021, Jeff McBride
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+
props = {}
14+
15+
class Instance(Module):
16+
def __init__(self, driver, instance):
17+
self.driver = driver
18+
self.instance = int(instance)
19+
20+
def init(self, module):
21+
module.name = str(self.instance)
22+
module.description = "Instance {}".format(self.instance)
23+
24+
def prepare(self, module, options):
25+
module.depends(":platform:uart")
26+
27+
module.add_option(
28+
NumericOption(
29+
name="buffer.tx",
30+
description="Size of transmit buffer",
31+
minimum=1, maximum=2 ** 16 - 2,
32+
default=64))
33+
module.add_option(
34+
NumericOption(
35+
name="buffer.rx",
36+
description="Size of receive buffer",
37+
minimum=1, maximum=2 ** 16 - 2,
38+
default=64))
39+
40+
return True
41+
42+
def build(self, env):
43+
device = env[":target"].identifier
44+
global props
45+
props["id"] = self.instance
46+
47+
env.substitutions = props
48+
env.outbasepath = "modm/src/modm/platform/uart"
49+
50+
env.template("uart.hpp.in", "uart_{}.hpp".format(self.instance))
51+
env.template("uart.cpp.in", "uart_{}.cpp".format(self.instance))
52+
53+
54+
def init(module):
55+
module.name = ":platform:uart"
56+
module.description = "Universal Synchronous Asynchronous Receiver Transmitter (UART)"
57+
58+
def prepare(module, options):
59+
device = options[":target"]
60+
if not (device.has_driver("usart:samg*")):
61+
return False
62+
63+
module.depends(
64+
":architecture:uart",
65+
":math:algorithm",
66+
":cmsis:device",
67+
":platform:gpio",
68+
":platform:clockgen")
69+
70+
global props
71+
drivers = options[":target"].get_all_drivers("usart")
72+
for driver in drivers:
73+
for instance in driver["instance"]:
74+
module.add_submodule(Instance(driver, instance))
75+
76+
props["target"] = device.identifier
77+
return True
78+
79+
def build(env):
80+
global props
81+
env.substitutions = props
82+
env.outbasepath = "modm/src/modm/platform/uart"
83+
env.copy("uart_base.hpp")
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright (c) 2021, Jeff McBride
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
// ----------------------------------------------------------------------------
11+
12+
#include "uart_{{ id }}.hpp"
13+
14+
#include <modm/architecture/driver/atomic/queue.hpp>
15+
16+
namespace
17+
{
18+
static modm::atomic::Queue<uint8_t, {{ options["buffer.rx"] }}> rxBuffer;
19+
static modm::atomic::Queue<uint8_t, {{ options["buffer.tx"] }}> txBuffer;
20+
}
21+
22+
MODM_ISR(FLEXCOM{{ id }})
23+
{
24+
using namespace modm::platform;
25+
if(Uart{{ id }}::isReceiveReady()) {
26+
uint8_t data = (uint8_t)USART{{ id }}->US_RHR;
27+
Uart{{ id }}::read(data);
28+
rxBuffer.push(data);
29+
}
30+
31+
if(Uart{{ id }}::isTransmitReady()) {
32+
if(txBuffer.isEmpty()) {
33+
USART{{ id }}->US_IDR = US_IDR_TXRDY;
34+
} else {
35+
USART{{ id }}->US_THR = txBuffer.get();
36+
txBuffer.pop();
37+
}
38+
}
39+
}
40+
41+
namespace modm::platform
42+
{
43+
44+
bool
45+
Uart{{ id }}::read(uint8_t &dataOut) {
46+
if(rxBuffer.isEmpty()) {
47+
return false;
48+
} else {
49+
dataOut = rxBuffer.get();
50+
rxBuffer.pop();
51+
return true;
52+
}
53+
}
54+
55+
std::size_t
56+
Uart{{ id }}::read(uint8_t *data, std::size_t length) {
57+
uint32_t i = 0;
58+
for(; i < length; i++) {
59+
if(rxBuffer.isEmpty()) {
60+
return i;
61+
} else {
62+
data[i] = rxBuffer.get();
63+
rxBuffer.pop();
64+
}
65+
}
66+
return i;
67+
}
68+
69+
bool
70+
Uart{{ id }}::write(uint8_t data)
71+
{
72+
if(txBuffer.isEmpty() && isTransmitReady()) {
73+
USART{{ id }}->US_THR = data;
74+
} else {
75+
if(!txBuffer.push(data)) {
76+
return false;
77+
}
78+
// Enable tx interrupt
79+
USART{{ id }}->US_IER = US_IER_TXRDY;
80+
}
81+
return true;
82+
}
83+
84+
std::size_t
85+
Uart{{ id }}::write(const uint8_t *data, std::size_t length)
86+
{
87+
uint32_t i = 0;
88+
for(; i < length; i++) {
89+
if(!write(data[i])) {
90+
return i;
91+
}
92+
}
93+
return i;
94+
}
95+
96+
bool
97+
Uart{{ id }}::isWriteFinished()
98+
{
99+
return txBuffer.isEmpty() && isTransmitReady();
100+
}
101+
102+
void
103+
Uart{{ id }}::flushWriteBuffer()
104+
{
105+
while(!isWriteFinished());
106+
}
107+
108+
void
109+
Uart{{ id }}::setParity(Parity parity)
110+
{
111+
USART{{ id }}->US_MR = (USART{{ id }}->US_MR & ~US_MR_PAR_Msk) | (uint32_t)parity;
112+
}
113+
114+
void
115+
Uart{{ id }}::setWordLength(WordLength length)
116+
{
117+
if(length == WordLength::Bit9) {
118+
USART{{ id }}->US_MR |= US_MR_MODE9;
119+
} else {
120+
USART{{ id }}->US_MR &= ~US_MR_MODE9;
121+
USART{{ id }}->US_MR =
122+
(USART{{ id }}->US_MR & ~US_MR_CHRL_Msk)
123+
| US_MR_CHRL((uint32_t)length);
124+
}
125+
}
126+
127+
} // namespace modm::platform

0 commit comments

Comments
 (0)