RadioLib
Universal wireless communication library for Arduino
Loading...
Searching...
No Matches
PicoHal.h
1#ifndef PICO_HAL_H
2#define PICO_HAL_H
3
4#if defined(RADIOLIB_BUILD_RPI_PICO)
5
6// include RadioLib
7#include <RadioLib.h>
8
9// include the necessary Pico libraries
10#include <pico/stdlib.h>
11#include "hardware/spi.h"
12#include "hardware/timer.h"
13#include "hardware/pwm.h"
14#include "hardware/clocks.h"
15#include "hardware/gpio.h"
16#include "pico/multicore.h"
17
18#define PI_PICO_MAX_USER_GPIO (48)
19
20// because the Pico SDK does not allow to pass user data into interrupt handlers,
21// we keep it as a global here. This is hacky and means that multiple PicoHal
22// instances share the same interrupts, which is weird and will probably break.
23// However, there seems to be no real use case for creating multiple intances of the HAL
24static irq_handler_t picoHalUserCallbacks[PI_PICO_MAX_USER_GPIO] = { 0 };
25static uint32_t picoHalIrqEventMasks[PI_PICO_MAX_USER_GPIO] = { 0 };
26static uint64_t picoHalIrqMask = 0;
27
28static void picoInterruptHandler(void) {
29 for(int gpio = 0; gpio < PI_PICO_MAX_USER_GPIO; gpio++) {
30 if(gpio_get_irq_event_mask(gpio) == picoHalIrqEventMasks[gpio]) {
31 gpio_acknowledge_irq(gpio, picoHalIrqEventMasks[gpio]);
32 if(picoHalUserCallbacks[gpio]) {
33 picoHalUserCallbacks[gpio]();
34 }
35 }
36 }
37}
38
39// create a new Raspberry Pi Pico hardware abstraction
40// layer using the Pico SDK
41// the HAL must inherit from the base RadioLibHal class
42// and implement all of its virtual methods
43class PicoHal : public RadioLibHal {
44public:
45 PicoHal(spi_inst_t *spiChannel, uint32_t misoPin, uint32_t mosiPin, uint32_t sckPin, uint32_t spiSpeed = 500 * 1000)
46 : RadioLibHal(GPIO_IN, GPIO_OUT, 0, 1, GPIO_IRQ_EDGE_RISE, GPIO_IRQ_EDGE_FALL),
47 _spiChannel(spiChannel),
48 _spiSpeed(spiSpeed),
49 _misoPin(misoPin),
50 _mosiPin(mosiPin),
51 _sckPin(sckPin){}
52
53 void init() override {
54 stdio_init_all();
55 spiBegin();
56 }
57
58 void term() override {
59 spiEnd();
60 }
61
62 // GPIO-related methods (pinMode, digitalWrite etc.) should check
63 // RADIOLIB_NC as an alias for non-connected pins
64 void pinMode(uint32_t pin, uint32_t mode) override {
65 if (pin == RADIOLIB_NC) {
66 return;
67 }
68
69 gpio_init(pin);
70 gpio_set_dir(pin, mode);
71 }
72
73 void digitalWrite(uint32_t pin, uint32_t value) override {
74 if (pin == RADIOLIB_NC) {
75 return;
76 }
77
78 gpio_put(pin, (bool)value);
79 }
80
81 uint32_t digitalRead(uint32_t pin) override {
82 if (pin == RADIOLIB_NC) {
83 return 0;
84 }
85
86 return gpio_get(pin);
87 }
88
89 void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
90 if (interruptNum == RADIOLIB_NC) {
91 return;
92 }
93
94 // set callbacks
95 picoHalUserCallbacks[interruptNum] = (irq_handler_t)interruptCb;
96 picoHalIrqEventMasks[interruptNum] = mode;
97
98 // is it a new interrupt for us to grab ?
99 if (!(picoHalIrqMask & (1ULL << interruptNum))) {
100 // if we have a handler in place, we must remove it to avoid 'assert' in the PDK
101 // and we must disable interrupt to make sure we don't miss anything during that
102 // shuffling
103 if (picoHalIrqMask) {
104 irq_set_enabled(IO_IRQ_BANK0, false);
105 gpio_remove_raw_irq_handler_masked64(picoHalIrqMask, picoInterruptHandler);
106 }
107
108 // (re-)add shared handler with the new mask
109 picoHalIrqMask |= (1ULL << interruptNum);
110 gpio_add_raw_irq_handler_masked64(picoHalIrqMask, picoInterruptHandler);
111 irq_set_enabled(IO_IRQ_BANK0, true);
112 }
113
114 // enable GPIO to generate interrupt
115 gpio_set_irq_enabled(interruptNum, mode, true);
116 }
117
118 void detachInterrupt(uint32_t interruptNum) override {
119 if (interruptNum == RADIOLIB_NC) {
120 return;
121 }
122
123 // disable the IRQ
124 gpio_set_irq_enabled(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
125
126 // clear callbacks
127 picoHalUserCallbacks[interruptNum] = NULL;
128 picoHalIrqEventMasks[interruptNum] = 0;
129 }
130
131 void delay(unsigned long ms) override {
132 sleep_ms(ms);
133 }
134
135 void delayMicroseconds(unsigned long us) override {
136 sleep_us(us);
137 }
138
139 unsigned long millis() override {
140 return to_ms_since_boot(get_absolute_time());
141 }
142
143 unsigned long micros() override {
144 return to_us_since_boot(get_absolute_time());
145 }
146
147 long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override {
148 if (pin == RADIOLIB_NC) {
149 return 0;
150 }
151
152 this->pinMode(pin, GPIO_IN);
153 uint32_t start = this->micros();
154 uint32_t curtick = this->micros();
155
156 while (this->digitalRead(pin) == state) {
157 if ((this->micros() - curtick) > timeout) {
158 return 0;
159 }
160 }
161
162 return (this->micros() - start);
163 }
164
165 void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) override;
166
167 void noTone(uint32_t pin) override {
168 multicore_reset_core1();
169 }
170
171 void spiBegin() {
172 spi_init(_spiChannel, _spiSpeed);
173 spi_set_format(_spiChannel, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
174
175 gpio_set_function(_sckPin, GPIO_FUNC_SPI);
176 gpio_set_function(_mosiPin, GPIO_FUNC_SPI);
177 gpio_set_function(_misoPin, GPIO_FUNC_SPI);
178 }
179
180 void spiBeginTransaction() {}
181
182 void spiTransfer(uint8_t *out, size_t len, uint8_t *in) {
183 spi_write_read_blocking(_spiChannel, out, in, len);
184 }
185
186 void yield() override {
187 tight_loop_contents();
188 }
189
190 void spiEndTransaction() {}
191
192 void spiEnd() {
193 spi_deinit(_spiChannel);
194 }
195
196private:
197 // the HAL can contain any additional private members
198 spi_inst_t *_spiChannel;
199 uint32_t _spiSpeed;
200 uint32_t _misoPin;
201 uint32_t _mosiPin;
202 uint32_t _sckPin;
203};
204
205#endif
206
207#endif
Hardware abstraction library base interface.
Definition Hal.h:16
virtual uint32_t digitalRead(uint32_t pin)=0
Digital read method. Must be implemented by the platform-specific hardware abstraction!
virtual void yield()
Yield method, called from long loops in multi-threaded environment (to prevent blocking other threads...
Definition Hal.cpp:35
virtual void detachInterrupt(uint32_t interruptNum)=0
Method to detach function from an external interrupt. Must be implemented by the platform-specific ha...
virtual long pulseIn(uint32_t pin, uint32_t state, RadioLibTime_t timeout)=0
Measure the length of incoming digital pulse in microseconds. Must be implemented by the platform-spe...
virtual void spiEnd()=0
SPI termination method.
virtual void init()
Module initialization method. This will be called by all radio modules at the beginning of startup....
Definition Hal.cpp:17
virtual RadioLibTime_t millis()=0
Get number of milliseconds since start. Must be implemented by the platform-specific hardware abstrac...
virtual void digitalWrite(uint32_t pin, uint32_t value)=0
Digital write method. Must be implemented by the platform-specific hardware abstraction!
virtual void tone(uint32_t pin, unsigned int frequency, RadioLibTime_t duration=0)
Method to produce a square-wave with 50% duty cycle ("tone") of a given frequency at some pin.
Definition Hal.cpp:25
virtual RadioLibTime_t micros()=0
Get number of microseconds since start. Must be implemented by the platform-specific hardware abstrac...
virtual void spiEndTransaction()=0
Method to end SPI transaction.
virtual void noTone(uint32_t pin)
Method to stop producing a tone.
Definition Hal.cpp:31
virtual void spiBegin()=0
SPI initialization method.
virtual void delay(RadioLibTime_t ms)=0
Blocking wait function. Must be implemented by the platform-specific hardware abstraction!
virtual void term()
Module termination method. This will be called by all radio modules when the destructor is called....
Definition Hal.cpp:21
virtual void delayMicroseconds(RadioLibTime_t us)=0
Blocking microsecond wait function. Must be implemented by the platform-specific hardware abstraction...
virtual void spiBeginTransaction()=0
Method to start SPI transaction.
virtual void spiTransfer(uint8_t *out, size_t len, uint8_t *in)=0
Method to transfer buffer over SPI.
virtual void pinMode(uint32_t pin, uint32_t mode)=0
GPIO pin mode (input/output/...) configuration method. Must be implemented by the platform-specific h...
virtual void attachInterrupt(uint32_t interruptNum, void(*interruptCb)(void), uint32_t mode)=0
Method to attach function to an external interrupt. Must be implemented by the platform-specific hard...