RadioLib
Universal wireless communication library for Arduino
PicoHal.h
1 #ifndef PICO_HAL_H
2 #define PICO_HAL_H
3 
4 // include RadioLib
5 #include <RadioLib.h>
6 
7 // include the necessary Pico libraries
8 #include <pico/stdlib.h>
9 #include "hardware/spi.h"
10 #include "hardware/timer.h"
11 #include "hardware/pwm.h"
12 #include "hardware/clocks.h"
13 #include "pico/multicore.h"
14 
15 uint32_t toneLoopPin;
16 unsigned int toneLoopFrequency;
17 unsigned long toneLoopDuration;
18 
19 // pre-calculated pulse-widths for 1200 and 2200Hz
20 // we do this to save calculation time (see https://github.com/khoih-prog/RP2040_PWM/issues/6)
21 #define SLEEP_1200 416.666
22 #define SLEEP_2200 227.272
23 
24 // === NOTE ===
25 // The tone(...) implementation uses the second core on the RPi Pico. This is to diminish as much
26 // jitter in the output tones as possible.
27 
28 void toneLoop(){
29  gpio_set_dir(toneLoopPin, GPIO_OUT);
30 
31  uint32_t sleep_dur;
32  if (toneLoopFrequency == 1200) {
33  sleep_dur = SLEEP_1200;
34  } else if (toneLoopFrequency == 2200) {
35  sleep_dur = SLEEP_2200;
36  } else {
37  sleep_dur = 500000 / toneLoopFrequency;
38  }
39 
40 
41  // tone bitbang
42  while(1){
43  gpio_put(toneLoopPin, 1);
44  sleep_us(sleep_dur);
45  gpio_put(toneLoopPin, 0);
46  sleep_us(sleep_dur);
47  tight_loop_contents();
48  }
49 }
50 
51 // create a new Raspberry Pi Pico hardware abstraction
52 // layer using the Pico SDK
53 // the HAL must inherit from the base RadioLibHal class
54 // and implement all of its virtual methods
55 class PicoHal : public RadioLibHal {
56 public:
57  PicoHal(spi_inst_t *spiChannel, uint32_t misoPin, uint32_t mosiPin, uint32_t sckPin, uint32_t spiSpeed = 500 * 1000)
58  : RadioLibHal(GPIO_IN, GPIO_OUT, 0, 1, GPIO_IRQ_EDGE_RISE, GPIO_IRQ_EDGE_FALL),
59  _spiChannel(spiChannel),
60  _spiSpeed(spiSpeed),
61  _misoPin(misoPin),
62  _mosiPin(mosiPin),
63  _sckPin(sckPin){}
64 
65  void init() override {
66  stdio_init_all();
67  spiBegin();
68  }
69 
70  void term() override {
71  spiEnd();
72  }
73 
74  // GPIO-related methods (pinMode, digitalWrite etc.) should check
75  // RADIOLIB_NC as an alias for non-connected pins
76  void pinMode(uint32_t pin, uint32_t mode) override {
77  if (pin == RADIOLIB_NC) {
78  return;
79  }
80 
81  gpio_init(pin);
82  gpio_set_dir(pin, mode);
83  }
84 
85  void digitalWrite(uint32_t pin, uint32_t value) override {
86  if (pin == RADIOLIB_NC) {
87  return;
88  }
89 
90  gpio_put(pin, (bool)value);
91  }
92 
93  uint32_t digitalRead(uint32_t pin) override {
94  if (pin == RADIOLIB_NC) {
95  return 0;
96  }
97 
98  return gpio_get(pin);
99  }
100 
101  void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
102  if (interruptNum == RADIOLIB_NC) {
103  return;
104  }
105 
106  gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)interruptCb);
107  }
108 
109  void detachInterrupt(uint32_t interruptNum) override {
110  if (interruptNum == RADIOLIB_NC) {
111  return;
112  }
113 
114  gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, NULL);
115  }
116 
117  void delay(unsigned long ms) override {
118  sleep_ms(ms);
119  }
120 
121  void delayMicroseconds(unsigned long us) override {
122  sleep_us(us);
123  }
124 
125  unsigned long millis() override {
126  return to_ms_since_boot(get_absolute_time());
127  }
128 
129  unsigned long micros() override {
130  return to_us_since_boot(get_absolute_time());
131  }
132 
133  long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override {
134  if (pin == RADIOLIB_NC) {
135  return 0;
136  }
137 
138  this->pinMode(pin, GPIO_IN);
139  uint32_t start = this->micros();
140  uint32_t curtick = this->micros();
141 
142  while (this->digitalRead(pin) == state) {
143  if ((this->micros() - curtick) > timeout) {
144  return 0;
145  }
146  }
147 
148  return (this->micros() - start);
149  }
150 
151  void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) override {
152  // tones on the Pico are generated using bitbanging. This process is offloaded to the Pico's second core
153  multicore_reset_core1();
154  toneLoopPin = pin;
155  toneLoopFrequency = frequency;
156  toneLoopDuration = duration;
157  multicore_launch_core1(toneLoop);
158  }
159 
160  void noTone(uint32_t pin) override {
161  multicore_reset_core1();
162  }
163 
164  void spiBegin() {
165  spi_init(_spiChannel, _spiSpeed);
166  spi_set_format(_spiChannel, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
167 
168  gpio_set_function(_sckPin, GPIO_FUNC_SPI);
169  gpio_set_function(_mosiPin, GPIO_FUNC_SPI);
170  gpio_set_function(_misoPin, GPIO_FUNC_SPI);
171  }
172 
174 
175  void spiTransfer(uint8_t *out, size_t len, uint8_t *in) {
176  spi_write_read_blocking(_spiChannel, out, in, len);
177  }
178 
179  void yield() override {
180  tight_loop_contents();
181  }
182 
184 
185  void spiEnd() {
186  spi_deinit(_spiChannel);
187  }
188 
189 private:
190  // the HAL can contain any additional private members
191  spi_inst_t *_spiChannel;
192  uint32_t _spiSpeed;
193  uint32_t _misoPin;
194  uint32_t _mosiPin;
195  uint32_t _sckPin;
196 };
197 
198 #endif
Definition: PicoHal.h:55
void delay(unsigned long ms) override
Blocking wait function. Must be implemented by the platform-specific hardware abstraction!
Definition: PicoHal.h:117
uint32_t digitalRead(uint32_t pin) override
Digital read method. Must be implemented by the platform-specific hardware abstraction!
Definition: PicoHal.h:93
void term() override
Module termination method. This will be called by all radio modules when the destructor is called....
Definition: PicoHal.h:70
void spiBeginTransaction()
Method to start SPI transaction.
Definition: PicoHal.h:173
void detachInterrupt(uint32_t interruptNum) override
Method to detach function from an external interrupt. Must be implemented by the platform-specific ha...
Definition: PicoHal.h:109
unsigned long micros() override
Get number of microseconds since start. Must be implemented by the platform-specific hardware abstrac...
Definition: PicoHal.h:129
void spiBegin()
SPI initialization method.
Definition: PicoHal.h:164
void delayMicroseconds(unsigned long us) override
Blocking microsecond wait function. Must be implemented by the platform-specific hardware abstraction...
Definition: PicoHal.h:121
unsigned long millis() override
Get number of milliseconds since start. Must be implemented by the platform-specific hardware abstrac...
Definition: PicoHal.h:125
void digitalWrite(uint32_t pin, uint32_t value) override
Digital write method. Must be implemented by the platform-specific hardware abstraction!
Definition: PicoHal.h:85
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override
Measure the length of incoming digital pulse in microseconds. Must be implemented by the platform-spe...
Definition: PicoHal.h:133
void attachInterrupt(uint32_t interruptNum, void(*interruptCb)(void), uint32_t mode) override
Method to attach function to an external interrupt. Must be implemented by the platform-specific hard...
Definition: PicoHal.h:101
void init() override
Module initialization method. This will be called by all radio modules at the beginning of startup....
Definition: PicoHal.h:65
void tone(uint32_t pin, unsigned int frequency, unsigned long duration=0) override
Method to produce a square-wave with 50% duty cycle ("tone") of a given frequency at some pin.
Definition: PicoHal.h:151
void pinMode(uint32_t pin, uint32_t mode) override
GPIO pin mode (input/output/...) configuration method. Must be implemented by the platform-specific h...
Definition: PicoHal.h:76
void spiEnd()
SPI termination method.
Definition: PicoHal.h:185
void spiTransfer(uint8_t *out, size_t len, uint8_t *in)
Method to transfer buffer over SPI.
Definition: PicoHal.h:175
void yield() override
Yield method, called from long loops in multi-threaded environment (to prevent blocking other threads...
Definition: PicoHal.h:179
void spiEndTransaction()
Method to end SPI transaction.
Definition: PicoHal.h:183
void noTone(uint32_t pin) override
Method to stop producing a tone.
Definition: PicoHal.h:160
Hardware abstraction library base interface.
Definition: Hal.h:13
RadioLibHal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling)
Default constructor.
Definition: Hal.cpp:3