Skip to content

Commit 04dc881

Browse files
andryblacksalkinium
authored andcommitted
[rp] Add GPIO module
1 parent ee6a512 commit 04dc881

File tree

14 files changed

+873
-10
lines changed

14 files changed

+873
-10
lines changed

src/modm/platform/gpio/common/connector.hpp.in

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2017, 2021, Niklas Hauser
3+
* Copyright (c) 2022, Andrey Kunitsyn
34
*
45
* This file is part of the modm project.
56
*
@@ -77,6 +78,15 @@ struct GpioConnector
7778
%% endif
7879
%% elif target.platform in ["avr"]
7980
static Connection check [[maybe_unused]];
81+
%% elif target.platform in ["rp"]
82+
using Pin = GpioStatic<typename Signal::Data>;
83+
if constexpr(Connection::func == -1) {
84+
Pin::setInput();
85+
Pin::disconnect();
86+
}
87+
if constexpr (Connection::func >= 0) {
88+
Pin::setFunction(Connection::func);
89+
}
8090
%% endif
8191
}
8292

src/modm/platform/gpio/common/pins.hpp.in

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2021, Niklas Hauser
3+
* Copyright (c) 2022, Andrey Kunitsyn
34
*
45
* This file is part of the modm project.
56
*
@@ -20,11 +21,14 @@ namespace modm::platform
2021
/// @ingroup modm_platform_gpio
2122
/// @{
2223
%% for gpio in gpios
23-
%% set port = gpio.gpio.port | upper
24-
%% set pin = gpio.gpio.pin
25-
using Gpio{{ port ~ pin }} = GpioStatic<detail::Data{{ port ~ pin }}>;
26-
using GpioOutput{{ port ~ pin }} = Gpio{{ port ~ pin }};
27-
using GpioInput{{ port ~ pin }} = Gpio{{ port ~ pin }};
24+
%% if target.platform in ["rp"]
25+
%% set name = gpio.gpio.name | capitalize
26+
%% else
27+
%% set name = gpio.gpio.port | upper ~ gpio.gpio.pin
28+
%% endif
29+
using Gpio{{ name }} = GpioStatic<detail::Data{{ name }}>;
30+
using GpioOutput{{ name }} = Gpio{{ name }};
31+
using GpioInput{{ name }} = Gpio{{ name }};
2832
%#
2933
%% endfor
3034
/// @}

src/modm/platform/gpio/common/unused.hpp.in

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2017-2018, 2021, Niklas Hauser
3+
* Copyright (c) 2022, Andrey Kunitsyn
34
*
45
* This file is part of the modm project.
56
*
@@ -70,6 +71,9 @@ protected:
7071
static void setAlternateFunction(uint8_t) {}
7172
static void setAlternateFunction() {}
7273
static void setAnalogInput() {}
74+
%% elif target.platform in ["rp"]
75+
static void setFunction(uint8_t) {}
76+
static void setDriveStrength(DriveStrength) {}
7377
%% endif
7478
public:
7579
// GpioOutput
@@ -108,7 +112,7 @@ public:
108112
using Data = detail::DataUnused;
109113
static constexpr platform::Gpio::Signal Signal = platform::Gpio::Signal::BitBang;
110114
};
111-
%% for name in all_signals
115+
%% for name in all_signals | sort
112116
struct {{ name }}
113117
{
114118
using Data = detail::DataUnused;

src/modm/platform/gpio/rp/base.hpp.in

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
* Copyright (c) 2022, Andrey Kunitsyn
3+
* Copyright (c) 2022, Niklas Hauser
4+
*
5+
* This file is part of the modm project.
6+
*
7+
* This Source Code Form is subject to the terms of the Mozilla Public
8+
* License, v. 2.0. If a copy of the MPL was not distributed with this
9+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
10+
*/
11+
// ----------------------------------------------------------------------------
12+
13+
#pragma once
14+
15+
#include <stdint.h>
16+
#include <tuple>
17+
#include <modm/platform/core/peripherals.hpp>
18+
%% for port in ports
19+
#include <hardware/structs/io{{port | lower}}.h>
20+
#include <hardware/structs/pads{{(pads_names[port] or port) | lower}}.h>
21+
%% endfor
22+
#include <hardware/structs/sio.h>
23+
24+
namespace modm::platform
25+
{
26+
27+
/// @ingroup modm_platform_gpio
28+
struct Gpio
29+
{
30+
enum class
31+
InputType
32+
{
33+
Floating = 0x0, ///< floating on input
34+
PullUp = 0x1, ///< pull-up on input
35+
PullDown = 0x2, ///< pull-down on input
36+
};
37+
38+
enum class
39+
OutputType
40+
{
41+
PushPull
42+
};
43+
44+
enum class
45+
OutputSpeed
46+
{
47+
Slow = 0,
48+
Fast = 1,
49+
};
50+
enum class
51+
DriveStrength
52+
{
53+
mA_2 = 0,
54+
mA_4 = 1,
55+
mA_8 = 2,
56+
mA_12 = 3,
57+
};
58+
59+
enum class
60+
Port
61+
{
62+
%% for port in ports
63+
{{ port }},
64+
%% endfor
65+
};
66+
67+
/// @cond
68+
enum class
69+
Signal
70+
{
71+
BitBang,
72+
%% for signal in all_signals | sort
73+
{{ signal }},
74+
%% endfor
75+
};
76+
77+
template <Port>
78+
struct PortRegs;
79+
/// @endcond
80+
};
81+
82+
/// @cond
83+
%% for port in ports
84+
template <>
85+
struct Gpio::PortRegs<Gpio::Port::{{ port | capitalize }}>
86+
{
87+
using status_ctrl_hw_t = io{{port | lower}}_status_ctrl_hw_t;
88+
static uint32_t sio_in() { return sio_hw->gpio{{sio_names[port]}}_in; }
89+
static uint32_t sio_out() { return sio_hw->gpio{{sio_names[port]}}_out; }
90+
static uint32_t sio_oe() { return sio_hw->gpio{{sio_names[port]}}_oe; }
91+
static void sio_set(uint32_t mask) { sio_hw->gpio{{sio_names[port]}}_set = mask; }
92+
static void sio_clr(uint32_t mask) { sio_hw->gpio{{sio_names[port]}}_clr = mask; }
93+
static void sio_togl(uint32_t mask) { sio_hw->gpio{{sio_names[port]}}_togl = mask; }
94+
static void sio_oe_set(uint32_t mask) { sio_hw->gpio{{sio_names[port]}}_oe_set = mask; }
95+
static void sio_oe_clr(uint32_t mask) { sio_hw->gpio{{sio_names[port]}}_oe_clr = mask; }
96+
static uint8_t funcsel(uint8_t pin)
97+
{ return (io{{port | lower}}_hw->io[pin].ctrl & IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS) >> IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB; }
98+
static void set_funcsel(uint8_t pin, uint32_t fn)
99+
{
100+
hw_write_masked(&pads{{(pads_names[port] or port) | lower}}_hw->io[pin],
101+
PADS_BANK0_GPIO0_IE_BITS,
102+
PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS
103+
);
104+
io{{port | lower}}_hw->io[pin].ctrl = fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
105+
}
106+
static void set_pue_pde(uint8_t pin, bool up, bool down)
107+
{
108+
hw_write_masked(
109+
&pads{{(pads_names[port] or port) | lower}}_hw->io[pin],
110+
((up?1:0) << PADS_BANK0_GPIO0_PUE_LSB) | ((down?1:0) << PADS_BANK0_GPIO0_PDE_LSB),
111+
PADS_BANK0_GPIO0_PUE_BITS | PADS_BANK0_GPIO0_PDE_BITS
112+
);
113+
}
114+
static void set_drive(uint8_t pin, uint8_t strength)
115+
{
116+
hw_write_masked(
117+
&pads{{(pads_names[port] or port) | lower}}_hw->io[pin],
118+
strength << PADS_BANK0_GPIO0_DRIVE_LSB,
119+
PADS_BANK0_GPIO0_DRIVE_BITS
120+
);
121+
}
122+
static void set_slewfast(uint8_t pin, bool fast)
123+
{
124+
hw_write_masked(
125+
&pads{{(pads_names[port] or port) | lower}}_hw->io[pin],
126+
(fast?1:0) << PADS_BANK0_GPIO0_SLEWFAST_LSB,
127+
PADS_BANK0_GPIO0_SLEWFAST_BITS
128+
);
129+
}
130+
};
131+
%% endfor
132+
/// @endcond
133+
134+
} // namespace modm::platform

src/modm/platform/gpio/rp/data.hpp.in

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) 2022, Andrey Kunitsyn
3+
* Copyright (c) 2022, Niklas Hauser
4+
*
5+
* This file is part of the modm project.
6+
*
7+
* This Source Code Form is subject to the terms of the Mozilla Public
8+
* License, v. 2.0. If a copy of the MPL was not distributed with this
9+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
10+
*/
11+
// ----------------------------------------------------------------------------
12+
13+
#pragma once
14+
15+
#include "base.hpp"
16+
17+
/// @cond
18+
namespace modm::platform::detail
19+
{
20+
21+
template<class Signal, Peripheral p> struct SignalConnection;
22+
23+
struct DataUnused {};
24+
%% for gpio in gpios
25+
%% set name = gpio.gpio.name | capitalize
26+
%#
27+
struct Data{{ name }}
28+
{
29+
static constexpr Gpio::Port port = Gpio::Port::{{ gpio.gpio.port | capitalize }};
30+
static constexpr uint8_t pin = {{ gpio.gpio.pin }};
31+
struct BitBang { using Data = Data{{ name }}; static constexpr Gpio::Signal Signal = Gpio::Signal::BitBang; };
32+
%% for signal in gpio.signals
33+
struct {{ signal }} { using Data = Data{{ name }}; static constexpr Gpio::Signal Signal = Gpio::Signal::{{ signal }}; };
34+
%% endfor
35+
};
36+
template<Peripheral p> struct SignalConnection<Data{{ name }}::BitBang, p> {
37+
static_assert(p == Peripheral::BitBang, "Gpio{{ name }}::BitBang only connects to software drivers!"); };
38+
%% for signal_name, signal_group in gpio.signals.items()
39+
template<Peripheral p> struct SignalConnection<Data{{ name }}::{{ signal_name }}, p> {
40+
static_assert((p == Peripheral::{{ signal_group | map(attribute="driver") | join(") or (p == Peripheral::") }}),{% if signal_group | length > 1 %}
41+
{% endif %}"Gpio{{ name }}::{{ signal_name }} only connects to {{ signal_group | map(attribute="driver") | join(" or ") }}!"); };
42+
%% endfor
43+
template<> struct SignalConnection<Data{{ name }}::BitBang, Peripheral::BitBang> { static constexpr int8_t func = -1; };
44+
%% for signal_group in gpio.signals.values()
45+
%% for signal in signal_group
46+
template<> struct SignalConnection<Data{{ name }}::{{ signal.name }}, Peripheral::{{ signal.driver }}> { static constexpr int8_t func = {{ signal.af }}; };
47+
%% endfor
48+
%% endfor
49+
%% endfor
50+
51+
} // namespace modm::platform::detail
52+
/// @endcond

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

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (c) 2022, Andrey Kunitsyn
5+
# Copyright (c) 2022, Niklas Hauser
6+
#
7+
# This file is part of the modm project.
8+
#
9+
# This Source Code Form is subject to the terms of the Mozilla Public
10+
# License, v. 2.0. If a copy of the MPL was not distributed with this
11+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
12+
# -----------------------------------------------------------------------------
13+
14+
import copy
15+
from collections import defaultdict, OrderedDict
16+
17+
def port_ranges(gpios):
18+
ports = {p: (32, 0) for p in set(p["port"] for p in gpios)}
19+
for gpio in gpios:
20+
pin = int(gpio["pin"])
21+
pmin, pmax = ports[gpio["port"]]
22+
ports[gpio["port"]] = (min(pin, pmin), max(pin, pmax))
23+
24+
ports = [{"name": k.capitalize(), "start": v[0], "width": v[1] - v[0] + 1} for k,v in ports.items()]
25+
ports.sort(key=lambda p: p["name"])
26+
return ports
27+
28+
def translate(s):
29+
return "".join(p.capitalize() for p in s.split("_"))
30+
# -----------------------------------------------------------------------------
31+
32+
33+
def init(module):
34+
module.name = ":platform:gpio"
35+
module.description = "General Purpose I/O (GPIO)"
36+
37+
38+
def prepare(module, options):
39+
module.depends(":architecture:gpio", ":cmsis:device", ":math:utils")
40+
return options[":target"].has_driver("gpio:rp*")
41+
42+
43+
def build(env):
44+
device = env[":target"]
45+
driver = device.get_driver("gpio")
46+
47+
subs = {
48+
"ranges": port_ranges(driver["gpio"]),
49+
"sio_names": {
50+
"Bank0": "",
51+
"Qspi": "_hi"
52+
},
53+
"pads_names": {
54+
"Bank0": "bank0",
55+
"Qspi": "_qspi"
56+
},
57+
"port_width": 32
58+
}
59+
subs["ports"] = OrderedDict([(k, i) for i, k in enumerate([p["name"].capitalize() for p in subs["ranges"]])])
60+
61+
peripherals = []
62+
all_drivers = [d for d in device._properties["driver"] if d["name"] not in ["gpio", "core"]]
63+
for d in all_drivers:
64+
dname = translate(d["name"])
65+
if "instance" in d:
66+
peripherals.extend([dname + translate(i) for i in d["instance"]])
67+
else:
68+
peripherals.append(dname)
69+
subs["all_peripherals"] = sorted(list(set(peripherals)))
70+
71+
all_signals = set()
72+
for gpio in driver["gpio"]:
73+
gpio["signals"] = set([translate(s["name"]) for s in gpio["signal"]])
74+
all_signals.update(gpio["signals"])
75+
signals = defaultdict(list)
76+
for sig in gpio["signal"]:
77+
signals[translate(sig["name"])].append(
78+
{"driver": sig["driver"].capitalize() + sig.get("instance", ""),
79+
"name": translate(sig["name"]),
80+
"af": sig["af"]})
81+
subs[gpio["name"].capitalize()] = {
82+
"gpio": gpio,
83+
"signals": signals,
84+
}
85+
86+
subs["target"] = device.identifier
87+
subs["all_signals"] = all_signals
88+
subs["gpios"] = [subs[gpio["name"].capitalize()] for gpio in driver["gpio"]]
89+
90+
env.substitutions = subs
91+
env.outbasepath = "modm/src/modm/platform/gpio"
92+
93+
env.template("base.hpp.in")
94+
env.template("data.hpp.in")
95+
env.template("static.hpp.in")
96+
env.template("set.hpp.in")
97+
env.template("software_port.hpp.in")
98+
env.template("port.hpp.in")
99+
100+
env.copy("../common/inverted.hpp", "inverted.hpp")
101+
env.copy("../common/open_drain.hpp", "open_drain.hpp")
102+
env.template("../common/connector.hpp.in", "connector.hpp",
103+
filters={"formatPeripheral": "", "printSignalMap": ""})
104+
env.template("../common/unused.hpp.in", "unused.hpp")
105+
env.template("../common/pins.hpp.in", "pins.hpp")
106+
env.template("../common/port_shim.hpp.in", "port_shim.hpp")
107+
108+
# FIXME: Move to modm:platform:core!
109+
env.outbasepath = "modm/src/modm/platform/core"
110+
env.template("peripherals.hpp.in")

0 commit comments

Comments
 (0)