CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
Loading...
Searching...
No Matches
platform-gpio.hh
1#pragma once
2#include <cdefs.h>
3#include <stdint.h>
4#include <utils.hh>
5
6/**
7 * A simple driver for the Sonata's GPIO. This struct represents a single
8 * GPIO instance, and the methods available to interact with that GPIO.
9 * This class should usually be used via one the aliases / subclasses defined
10 * below which are specialised to the GPIO instance. e.g. see SonataGpioBoard.
11 *
12 * Documentation source can be found at:
13 * https://github.com/lowRISC/sonata-system/blob/9f794fe3bd4eec8d1a01ee81da97a7f2cec0b452/doc/ip/gpio.md
14 *
15 * Rendered documentation is served from:
16 * https://lowrisc.org/sonata-system/doc/ip/gpio.html
17 */
18template<
19 /**
20 * The mask of bits of the `output` register that contain meaningful
21 * GPIO output.
22 */
23 uint32_t OutputMask = 0xFFFF'FFFF,
24 /**
25 * The mask of bits of the `input` and `debouncedInput` registers that
26 * contain meaningful GPIO input. This is usually the same as OutputMask
27 * if the instance has the same number of input and output pins.
28 */
29 uint32_t InputMask = OutputMask,
30 /**
31 * The mask of bits for the `output_enable` register, again this is usually
32 * the same as OutputMask.
33 */
34 uint32_t OutputEnableMask = OutputMask,
35 /**
36 * The mask of bits for the `pcint_mask` register, this is the same as the
37 * InputMask.
38 */
39 uint32_t PcIntMask = InputMask>
41{
42 uint32_t output;
43 uint32_t input;
44 uint32_t debouncedInput;
45 uint32_t outputEnable;
46 uint32_t control;
47 uint32_t status;
48 uint32_t pcintMask;
49
50 /// Control Register Fields
51 enum [[clang::flag_enum]] : uint32_t
52 {
53 /// Pin-change interrupt status. Write 1 to clear.
54 PcIntStatus = 1U << 31,
55 };
56
57 // Pin-change interrupt modes
58 enum [[clang::flag_enum]] PcIntMode : uint32_t
59 {
60 AnyEdge = 0,
61 RisingEdge = 1,
62 FallingEdge = 2,
63 LowLevel = 3,
64 };
65
66 static constexpr uint32_t PcIntModeBits = 2;
67 /// Status Register Fields
68 enum [[clang::flag_enum]] : uint32_t
69 {
70 /// Pin-change interrupt mode.
71 /// See PcIntMode enums.
72 PcIntModeSelect = PcIntModeBits << 0,
73 /// Select between the raw (0) and debounced input (1).
75 /// Enable the pin-change interrupt instance-wide.
76 PcIntEnable = 1U << 31,
77 };
78
79 /**
80 * Returns a mask with a single bit set corresponding to the given GPIO
81 * index or 0 if that bit is not set in mask.
82 */
83 constexpr static uint32_t gpio_bit(uint32_t index, uint32_t mask)
84 {
85 return (1 << index) & mask;
86 }
87
88 /**
89 * Set the output bit for a given GPIO pin index to a specified value.
90 * This will only have an effect if the corresponding bit is first set
91 * to `1` (i.e. output) in the `output_enable` register, and if the pin
92 * is a valid output pin.
93 */
94 void set_output(uint32_t index, bool value) volatile
95 {
96 const uint32_t Bit = gpio_bit(index, OutputMask);
97 if (value)
98 {
99 output = output | Bit;
100 }
101 else
102 {
103 output = output & ~Bit;
104 }
105 }
106
107 /**
108 * Set the output enable bit for a given GPIO pin index. If `enable` is
109 * true, the GPIO pin is set to output. If `false`, it is instead set to
110 * input mode.
111 */
112 void set_output_enable(uint32_t index, bool enable) volatile
113 {
114 const uint32_t Bit = gpio_bit(index, OutputEnableMask);
115 if (enable)
116 {
117 outputEnable = outputEnable | Bit;
118 }
119 else
120 {
121 outputEnable = outputEnable & ~Bit;
122 }
123 }
124
125 /**
126 * Enable GPIO pin-change interrupts for this instance.
127 */
128 void enable_interrupts(bool enable) volatile
129 {
130 if (enable)
131 {
132 control = control | PcIntEnable;
133 }
134 else
135 {
136 control = control & ~PcIntEnable;
137 }
138 }
139
140 /**
141 * Clear the GPIO pin-change interrupt mask.
142 */
143 void clear_interrupt_mask() volatile
144 {
145 pcintMask = 0;
146 }
147
148 /**
149 * Only GPIO pins explicitly enabled can trigger an interrupt. Enabling a
150 * GPIO pin for interrupts will set the corresponding bit in the pin-change
151 * interrupt mask.
152 */
153 void set_interrupt(uint32_t index, bool enable) volatile
154 {
155 const uint32_t Bit = gpio_bit(index, PcIntMask);
156 if (enable)
157 {
158 pcintMask = pcintMask | Bit;
159 }
160 else
161 {
162 pcintMask = pcintMask & ~Bit;
163 }
164 }
165
166 /**
167 * Whether to use the raw or debounced input for the GPIO pin-change
168 * interrupt.
169 */
170 void debounce_interrupt(bool debounce) volatile
171 {
172 if (debounce)
173 {
174 control = control | PcIntInputSelect;
175 }
176 else
177 {
178 control = control & ~PcIntInputSelect;
179 }
180 }
181
182 /**
183 * Select the pin-change interrupt mode.
184 */
185 void change_interrupt_mode(enum PcIntMode mode) volatile
186 {
187 control = (control & ~PcIntModeSelect) | (mode & PcIntModeBits);
188 }
189
190 void clear_interrupt_status() volatile
191 {
192 status = status | PcIntStatus;
193 }
194
195 /**
196 * Read the input value for a given GPIO pin index. For this to be
197 * meaningful, the corresponding pin must be configured to be an input
198 * first (set output enable to `false` for the given index). If given an
199 * invalid GPIO pin (outside the input mask), then this value will
200 * always be false.
201 */
202 bool read_input(uint32_t index) volatile
203 {
204 return (input & gpio_bit(index, InputMask)) > 0;
205 }
206
207 /**
208 * Read the debounced input value for a given GPIO pin index. For this
209 * to be meaningful, the corresponding pin must be configured to be an
210 * input first (set output enable to `false` for the given index). If
211 * given an invalid GPIO pin (outside the input mask), then this value
212 * will always be false.
213 */
214 bool read_debounced_input(uint32_t index) volatile
215 {
216 return (debouncedInput & gpio_bit(index, InputMask)) > 0;
217 }
218
219 bool read_interrupt_status() volatile
220 {
221 return (status & PcIntStatus) > 0;
222 }
223};
224
225/**
226 * A driver for Sonata's Board GPIO (instance 0). Example of usage:
227 *
228 * ```
229 * auto gpioBoard = MMIO_CAPABILITY(SonataGpioBoard, gpio_board);
230 * bool switch0 = gpioBoard->read_sitwich(0);
231 * ```
232 *
233 * Documentation source:
234 * https://lowrisc.org/sonata-system/doc/ip/gpio.html
235 */
236struct SonataGpioBoard : SonataGpioBase<0x0000'00FF, 0x0001'FFFF, 0x0000'0000>
237{
238 /**
239 * Represents the state of Sonata's joystick, where each possible input
240 * corresponds to a given bit in the General GPIO's input register.
241 *
242 * Note that up to 3 of these bits may be asserted at any given time:
243 * pressing down the joystick whilst pushing it in a diagonal direction
244 * (i.e. 2 cardinal directions).
245 *
246 */
247 enum [[clang::flag_enum]] JoystickDirection : uint16_t
248 {
249 Left = 1u << 8,
250 Up = 1u << 9,
251 Pressed = 1u << 10,
252 Down = 1u << 11,
253 Right = 1u << 12,
254 };
255
256 /**
257 * Class that wraps a JoystickDirection and provides convience wrappers
258 * to query the value.
259 */
260 class JoystickValue
261 {
262 JoystickDirection direction;
263
264 public:
265 JoystickValue(JoystickDirection direction) : direction(direction) {}
266
267 bool is_direction_pressed(JoystickDirection direction)
268 {
269 return this->direction & direction;
270 }
271
272 bool is_left()
273 {
274 return is_direction_pressed(JoystickDirection::Left);
275 }
276
277 bool is_up()
278 {
279 return is_direction_pressed(JoystickDirection::Up);
280 }
281
282 bool is_pressed()
283 {
284 return is_direction_pressed(JoystickDirection::Pressed);
285 }
286
287 bool is_down()
288 {
289 return is_direction_pressed(JoystickDirection::Down);
290 }
291
292 bool is_right()
293 {
294 return is_direction_pressed(JoystickDirection::Right);
295 }
296
297 /**
298 * Implicit conversion to bool. True if any direction is pressed.
299 */
300 operator bool()
301 {
302 return direction != static_cast<JoystickDirection>(0);
303 }
304 };
305
306 /**
307 * The bit mappings of the output GPIO pins available in Sonata's General
308 * GPIO.
309 *
310 * Source: https://lowrisc.github.io/sonata-system/doc/ip/gpio.html
311 */
312 enum Outputs : uint32_t
313 {
314 Leds = (0xFFu << 0),
315 };
316
317 /**
318 * The bit mappings of the input GPIO pins available in Sonata's General
319 * GPIO.
320 *
321 * Source: https://lowrisc.github.io/sonata-system/doc/ip/gpio.html
322 */
323 enum Inputs : uint32_t
324 {
325 DipSwitches = (0xFFu << 0),
326 Joystick = (0x1Fu << 8),
327 SoftwareSelectSwitches = (0x7u << 13),
328 MicroSdCardDetection = (0x1u << 16),
329 };
330
331 /**
332 * The bit index of the first GPIO pin connected to a user LED.
333 */
334 static constexpr uint32_t FirstLED = 0;
335 /**
336 * The bit index of the last GPIO pin connected to a user LED.
337 */
338 static constexpr uint32_t LastLED = 7;
339 /**
340 * The number of user LEDs.
341 */
342 static constexpr uint32_t LEDCount = LastLED - FirstLED + 1;
343 /**
344 * The mask covering the GPIO pins used for user LEDs.
345 */
346 static constexpr uint32_t LEDMask = static_cast<uint32_t>(Outputs::Leds);
347
348 /**
349 * The output bit mask for a given user LED index
350 */
351 constexpr static uint32_t led_bit(uint32_t index)
352 {
353 return gpio_bit(index + FirstLED, LEDMask);
354 }
355
356 /**
357 * Switches off the LED at the given user LED index
358 */
359 void led_on(uint32_t index) volatile
360 {
361 output = output | led_bit(index);
362 }
363
364 /**
365 * Switches on the LED at the given user LED index
366 */
367 void led_off(uint32_t index) volatile
368 {
369 output = output & ~led_bit(index);
370 }
371
372 /**
373 * Toggles the LED at the given user LED index
374 */
375 void led_toggle(uint32_t index) volatile
376 {
377 output = output ^ led_bit(index);
378 }
379
380 /**
381 * The bit index of the first GPIO pin connected to a user switch.
382 */
383 static constexpr uint32_t FirstSwitch = 0;
384 /**
385 * The bit index of the last GPIO pin connected to a user switch.
386 */
387 static constexpr uint32_t LastSwitch = 7;
388 /**
389 * The number of user switches.
390 */
391 static constexpr uint32_t SwitchCount = LastSwitch - FirstSwitch + 1;
392 /**
393 * The mask covering the GPIO pins used for user switches.
394 */
395 static constexpr uint32_t SwitchMask =
396 static_cast<uint32_t>(Inputs::DipSwitches);
397
398 /**
399 * The input bit mask for a given user switch index
400 */
401 constexpr static uint32_t switch_bit(uint32_t index)
402 {
403 return gpio_bit(index + FirstSwitch, SwitchMask);
404 }
405
406 /**
407 * Returns the value of the switch at the given user switch index.
408 */
409 bool read_switch(uint32_t index) volatile
410 {
411 return (input & switch_bit(index)) > 0;
412 }
413
414 /**
415 * Returns the state of the joystick.
416 */
417 JoystickValue read_joystick() volatile
418 {
419 return {static_cast<JoystickDirection>(input & Inputs::Joystick)};
420 }
421};
422
423using SonataGpioRaspberryPiHat = SonataGpioBase<0x0FFF'FFFF>;
424using SonataGpioArduinoShield = SonataGpioBase<0x0000'3FFF>;
425using SonataGpioPmod = SonataGpioBase<0x0000'00FF>;
426using SonataGpioPmod0 = SonataGpioPmod;
427using SonataGpioPmod1 = SonataGpioPmod;
428using SonataGpioPmodC = SonataGpioBase<0x0000'003F>;
429/**
430 * Alias for backwards compatibility with Sonata 0.2 driver.
431 */
432typedef SonataGpioBoard SonataGPIO;
Utility class to delete copy and move contructors.
Definition utils.hh:53
A simple driver for the Sonata's GPIO.
void set_interrupt(uint32_t index, bool enable) volatile
Only GPIO pins explicitly enabled can trigger an interrupt.
void change_interrupt_mode(enum PcIntMode mode) volatile
Select the pin-change interrupt mode.
void debounce_interrupt(bool debounce) volatile
Whether to use the raw or debounced input for the GPIO pin-change interrupt.
void set_output(uint32_t index, bool value) volatile
Set the output bit for a given GPIO pin index to a specified value.
void enable_interrupts(bool enable) volatile
Enable GPIO pin-change interrupts for this instance.
bool read_debounced_input(uint32_t index) volatile
Read the debounced input value for a given GPIO pin index.
void clear_interrupt_mask() volatile
Clear the GPIO pin-change interrupt mask.
static constexpr uint32_t gpio_bit(uint32_t index, uint32_t mask)
Returns a mask with a single bit set corresponding to the given GPIO index or 0 if that bit is not se...
void set_output_enable(uint32_t index, bool enable) volatile
Set the output enable bit for a given GPIO pin index.
bool read_input(uint32_t index) volatile
Read the input value for a given GPIO pin index.
Miscellaneous utility functions and classes.