hx711-pico-c
util.c
Go to the documentation of this file.
1 // MIT License
2 //
3 // Copyright (c) 2023 Daniel Robertson
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 
23 #include <assert.h>
24 #include <stddef.h>
25 #include <stdint.h>
26 #include "hardware/dma.h"
27 #include "hardware/gpio.h"
28 #include "hardware/irq.h"
29 #include "hardware/pio.h"
30 #include "hardware/pio_instructions.h"
31 #include "hardware/regs/intctrl.h"
32 #include "hardware/regs/pio.h"
33 #include "hardware/structs/dma.h"
34 #include "hardware/timer.h"
35 #include "pico/platform.h"
36 #include "pico/time.h"
37 #include "pico/types.h"
38 #include "../include/util.h"
39 
40 #define UTIL_DEF_IN_RANGE_FUNC(TYPE) \
41  bool util_ ## TYPE ##_in_range( \
42  const TYPE val, \
43  const TYPE min, \
44  const TYPE max) { \
45  return val >= min && val <= max; \
46 }
47 
48 const uint8_t util_pio_to_irq_map[] = {
49  PIO0_IRQ_0,
50  PIO0_IRQ_1,
51  PIO1_IRQ_0,
52  PIO1_IRQ_1
53 };
54 
55 const uint8_t util_dma_to_irq_map[] = {
56  DMA_IRQ_0,
57  DMA_IRQ_1
58 };
59 
61 UTIL_DEF_IN_RANGE_FUNC(uint32_t)
64 
65 bool util_dma_irq_index_is_valid(const uint idx) {
66  return util_uint_in_range(
67  idx,
70 }
71 
72 uint util_dma_get_irq_from_index(const uint idx) {
73  assert(util_dma_irq_index_is_valid(idx));
74  assert(util_dma_to_irq_map != NULL);
75  return util_dma_to_irq_map[idx];
76 }
77 
78 int util_dma_get_index_from_irq(const uint irq_num) {
79 
80  check_irq_param(irq_num);
81  assert(util_dma_to_irq_map != NULL);
82 
83  switch(irq_num) {
84  case DMA_IRQ_0:
85  return 0;
86  case DMA_IRQ_1:
87  return 1;
88  default:
89  return -1;
90  }
91 
92 }
93 
95  const uint irq_index,
96  const uint channel,
97  const irq_handler_t handler,
98  const bool enabled) {
99 
100  assert(util_dma_irq_index_is_valid(irq_index));
101  check_dma_channel_param(channel);
102  assert(handler != NULL);
103 
104  const uint irq_num = util_dma_get_irqn(irq_index);
105 
106  dma_irqn_set_channel_enabled(
107  irq_index,
108  channel,
109  enabled);
110 
111  irq_set_exclusive_handler(
112  irq_num,
113  handler);
114 
115  irq_set_enabled(
116  irq_num,
117  enabled);
118 
119 }
120 
121 uint32_t util_dma_get_transfer_count(const uint channel) {
122  check_dma_channel_param(channel);
123  return (uint32_t)dma_hw->ch[channel].transfer_count;
124 }
125 
127  const uint channel,
128  const absolute_time_t* const end) {
129 
130  check_dma_channel_param(channel);
131  assert(end != NULL);
132  assert(!is_nil_time(*end));
133 
134  while(!time_reached(*end)) {
135  if(!dma_channel_is_busy(channel)) {
136  return true;
137  }
138  }
139 
140  return false;
141 
142 }
143 
144 uint util_dma_get_irqn(const uint irq_index) {
145 
146  assert(util_dma_to_irq_map != NULL);
147  assert(util_uint_in_range(
148  irq_index,
151 
152  const uint irq_num = util_dma_to_irq_map[
153  irq_index];
154 
155  check_irq_param(irq_num);
156 
157  return irq_num;
158 
159 }
160 
162  const uint channel,
163  const bool quiet) {
164  check_dma_channel_param(channel);
165  dma_channel_config cfg = dma_get_channel_config(channel);
166  channel_config_set_irq_quiet(&cfg, quiet);
167  dma_channel_set_config(channel, &cfg, false);
168 }
169 
171  const uint base,
172  const uint len) {
173 
174  assert(len > 0);
175 
176  const uint l = base + len - 1;
177 
178  for(uint i = base; i <= l; ++i) {
179  check_gpio_param(i);
180  gpio_set_input_enabled(i, true);
181  }
182 
183 }
184 
185 void util_gpio_set_output(const uint gpio) {
186  check_gpio_param(gpio);
187  gpio_init(gpio);
188  gpio_set_dir(gpio, true);
189 }
190 
192  PIO const pio,
193  const uint irq_index,
194  const uint pio_interrupt_num,
195  const irq_handler_t handler,
196  const bool enabled) {
197 
198  check_pio_param(pio);
199  assert(util_pio_irq_index_is_valid(irq_index));
200  assert(util_routable_pio_interrupt_num_is_valid(pio_interrupt_num));
201  assert(handler != NULL);
202 
203  const uint irq_num = util_pio_get_irq_from_index(
204  pio,
205  irq_index);
206 
208  pio_interrupt_num);
209 
210  pio_set_irqn_source_enabled(
211  pio,
212  irq_index,
213  pis,
214  enabled);
215 
216  irq_set_exclusive_handler(
217  irq_num,
218  handler);
219 
220  irq_set_enabled(
221  irq_num,
222  enabled);
223 
224 }
225 
226 bool util_pio_irq_index_is_valid(const uint idx) {
227  return util_uint_in_range(
228  idx,
231 }
232 
234  PIO const pio,
235  const uint irq_index) {
236 
237  check_pio_param(pio);
238  assert(util_pio_irq_index_is_valid(irq_index));
239  assert(util_pio_to_irq_map != NULL);
240 
241  const uint irq_num = util_pio_to_irq_map[
242  pio_get_index(pio) + irq_index];
243 
244  check_irq_param(irq_num);
245 
246  return irq_num;
247 
248 }
249 
251  PIO const pio,
252  const uint idx) {
253 
254  check_pio_param(pio);
255  assert(util_pio_irq_index_is_valid(idx));
256  assert(util_pio_to_irq_map != NULL);
257 
258  const uint irq_num = util_pio_to_irq_map[
259  pio_get_index(pio) + idx];
260 
261  check_irq_param(irq_num);
262 
263  return irq_num;
264 
265 }
266 
267 int util_pio_get_index_from_irq(const uint irq_num) {
268 
269  check_irq_param(irq_num);
270 
271  switch(irq_num) {
272  case PIO0_IRQ_0:
273  case PIO1_IRQ_0:
274  return 0;
275  case PIO0_IRQ_1:
276  case PIO1_IRQ_1:
277  return 1;
278  default:
279  return -1;
280  }
281 
282 }
283 
284 PIO const util_pio_get_pio_from_irq(const uint irq_num) {
285 
286  check_irq_param(irq_num);
287 
288  switch(irq_num) {
289  case PIO0_IRQ_0:
290  case PIO0_IRQ_1:
291  return pio0;
292  case PIO1_IRQ_0:
293  case PIO1_IRQ_1:
294  return pio1;
295  default:
296  return NULL;
297  }
298 
299 }
300 
302  const uint pio_interrupt_num) {
303 
305  pio_interrupt_num));
306 
307  const uint basePis = pis_interrupt0;
308  const uint pis = basePis + pio_interrupt_num;
309 
310  assert(util_uint_in_range(
311  pis, pis_interrupt0, pis_interrupt3));
312 
313  return pis;
314 
315 }
316 
318  PIO const pio,
319  const uint base,
320  const uint len) {
321 
322  check_pio_param(pio);
323  assert(len > 0);
324 
325  const uint l = base + len - 1;
326 
327  for(uint i = base; i <= l; ++i) {
328  check_gpio_param(i);
329  pio_gpio_init(pio, i);
330  }
331 
332 }
333 
335  PIO const pio,
336  const uint sm) {
337  check_pio_param(pio);
338  check_sm_param(sm);
339  while(!pio_sm_is_rx_fifo_empty(pio, sm)) {
340  pio_sm_get(pio, sm);
341  }
342 }
343 
345  PIO const pio,
346  const uint sm) {
347  check_pio_param(pio);
348  check_sm_param(sm);
349  const uint instr = pio_encode_push(false, false);
350  while(!pio_sm_is_rx_fifo_empty(pio, sm)) {
351  pio_sm_exec(pio, sm, instr);
352  }
353 }
354 
356  PIO const pio,
357  const uint sm) {
358  check_pio_param(pio);
359  check_sm_param(sm);
360  const uint instr = pio_encode_pull(false, false);
361  while(!pio_sm_is_tx_fifo_empty(pio, sm)) {
362  pio_sm_exec(pio, sm, instr);
363  }
364 }
365 
367  PIO const pio,
368  const uint sm) {
369  check_pio_param(pio);
370  check_sm_param(sm);
371  return (pio->ctrl & (1u << (PIO_CTRL_SM_ENABLE_LSB + sm))) != 0;
372 }
373 
375  const uint pio_interrupt_num) {
376  return util_uint_in_range(
377  pio_interrupt_num,
380 }
381 
383  const uint pio_interrupt_num) {
384  return util_uint_in_range(
385  pio_interrupt_num,
388 }
389 
391  PIO const pio,
392  const uint pio_interrupt_num) {
393  check_pio_param(pio);
394  assert(util_pio_interrupt_num_is_valid(pio_interrupt_num));
395  while(!pio_interrupt_get(pio, pio_interrupt_num)) {
396  tight_loop_contents();
397  }
398 }
399 
401  PIO const pio,
402  const uint pio_interrupt_num) {
403  check_pio_param(pio);
404  assert(util_pio_interrupt_num_is_valid(pio_interrupt_num));
405  while(pio_interrupt_get(pio, pio_interrupt_num)) {
406  tight_loop_contents();
407  }
408 }
409 
411  PIO const pio,
412  const uint pio_interrupt_num,
413  const absolute_time_t* const end) {
414 
415  check_pio_param(pio);
416  assert(util_pio_interrupt_num_is_valid(pio_interrupt_num));
417  assert(end != NULL);
418  assert(!is_nil_time(*end));
419 
420  while(!time_reached(*end)) {
421  if(!pio_interrupt_get(pio, pio_interrupt_num)) {
422  return true;
423  }
424  }
425 
426  return false;
427 
428 }
429 
431  PIO const pio,
432  const uint pio_interrupt_num) {
433  check_pio_param(pio);
434  assert(util_pio_interrupt_num_is_valid(pio_interrupt_num));
435  util_pio_interrupt_wait(pio, pio_interrupt_num);
436  pio_interrupt_clear(pio, pio_interrupt_num);
437 }
438 
440  PIO const pio,
441  const uint pio_interrupt_num,
442  const absolute_time_t* const end) {
443 
444  check_pio_param(pio);
445  assert(util_pio_interrupt_num_is_valid(pio_interrupt_num));
446  assert(end != NULL);
447  assert(!is_nil_time(*end));
448 
449  while(!time_reached(*end)) {
450  if(pio_interrupt_get(pio, pio_interrupt_num)) {
451  return true;
452  }
453  }
454 
455  return false;
456 
457 }
458 
460  PIO const pio,
461  const uint pio_interrupt_num,
462  const absolute_time_t* const end) {
463 
464  check_pio_param(pio);
465  assert(util_pio_interrupt_num_is_valid(pio_interrupt_num));
466  assert(end != NULL);
467  assert(!is_nil_time(*end));
468 
469  const bool ok = util_pio_interrupt_wait_timeout(
470  pio,
471  pio_interrupt_num,
472  end);
473 
474  if(ok) {
475  pio_interrupt_clear(
476  pio,
477  pio_interrupt_num);
478  }
479 
480  return ok;
481 
482 }
483 
485  PIO const pio,
486  const uint sm,
487  uint32_t* const word,
488  const uint threshold) {
489 
490  check_pio_param(pio);
491  check_sm_param(sm);
492  assert(word != NULL);
493 
494  if(pio_sm_get_rx_fifo_level(pio, sm) >= threshold) {
495  *word = pio_sm_get(pio, sm);
496  return true;
497  }
498 
499  return false;
500 
501 }
502 
503 #undef UTIL_DEF_IN_RANGE_FUNC
void util_irq_set_exclusive_pio_interrupt_num_handler(PIO const pio, const uint irq_index, const uint pio_interrupt_num, const irq_handler_t handler, const bool enabled)
Set and enable an exclusive interrupt handler for a given pio_interrupt_num.
Definition: util.c:191
void util_gpio_set_output(const uint gpio)
Initialises and sets GPIO pin to output.
Definition: util.c:185
bool util_pio_sm_is_enabled(PIO const pio, const uint sm)
Check whether a given state machine is enabled.
Definition: util.c:366
void util_pio_sm_clear_osr(PIO const pio, const uint sm)
Clears a given state machine's OSR.
Definition: util.c:344
const uint8_t util_pio_to_irq_map[]
Quick lookup for finding an NVIC IRQ number for a PIO and interrupt index number.
Definition: util.c:48
bool util_pio_interrupt_wait_timeout(PIO const pio, const uint pio_interrupt_num, const absolute_time_t *const end)
Waits for a given PIO to be set within the timeout period.
Definition: util.c:439
bool util_pio_interrupt_wait_clear_timeout(PIO const pio, const uint pio_interrupt_num, const absolute_time_t *const end)
Waits for a given PIO to be set within the timeout period and then clears it.
Definition: util.c:459
PIO const util_pio_get_pio_from_irq(const uint irq_num)
Gets the PIO using the NVIC IRQ number.
Definition: util.c:284
bool util_pio_irq_index_is_valid(const uint idx)
Check whether PIO IRQ index is valid.
Definition: util.c:226
bool util_routable_pio_interrupt_num_is_valid(const uint pio_interrupt_num)
Check whether a PIO interrupt number is a valid routable interrupt number.
Definition: util.c:382
int util_pio_get_index_from_irq(const uint irq_num)
Gets the PIO IRQ index using the NVIC IRQ number.
Definition: util.c:267
void util_pio_interrupt_wait_cleared(PIO const pio, const uint pio_interrupt_num)
Waits until a given PIO interrupt is cleared.
Definition: util.c:400
void util_pio_sm_clear_isr(PIO const pio, const uint sm)
Clears a given state machine's ISR.
Definition: util.c:355
void util_pio_sm_clear_rx_fifo(PIO const pio, const uint sm)
Clears a given state machine's RX FIFO.
Definition: util.c:334
int util_dma_get_index_from_irq(const uint irq_num)
Gets the DMA IRQ index using the NVIC IRQ number.
Definition: util.c:78
void util_pio_gpio_contiguous_init(PIO const pio, const uint base, const uint len)
Inits GPIO pins for PIO from base to base + len.
Definition: util.c:317
uint util_pio_get_pis_from_pio_interrupt_num(const uint pio_interrupt_num)
Definition: util.c:301
bool util_dma_channel_wait_for_finish_timeout(const uint channel, const absolute_time_t *const end)
Wait until channel has completed transferring up to a timeout.
Definition: util.c:126
void util_dma_channel_set_quiet(const uint channel, const bool quiet)
Sets a DMA channel's IRQ quiet mode.
Definition: util.c:161
void util_pio_interrupt_wait_clear(PIO const pio, const uint pio_interrupt_num)
Waits for a given PIO interrupt to be set and then clears it.
Definition: util.c:430
void util_gpio_set_contiguous_input_pins(const uint base, const uint len)
Sets GPIO pins from base to base + len to input.
Definition: util.c:170
uint util_dma_get_irqn(const uint irq_index)
Gets the NVIC IRQ number based on the DMA IRQ index.
Definition: util.c:144
uint util_pio_get_irq_from_index(PIO const pio, const uint idx)
Gets the NVIC PIO IRQ number using a PIO pointer and PIO IRQ index.
Definition: util.c:250
uint32_t util_dma_get_transfer_count(const uint channel)
Get the transfer count for a given DMA channel. When a DMA transfer is active, this count is the numb...
Definition: util.c:121
bool util_pio_interrupt_wait_cleared_timeout(PIO const pio, const uint pio_interrupt_num, const absolute_time_t *const end)
Waits until the given interrupt is cleared, up to a maximum timeout.
Definition: util.c:410
void util_pio_interrupt_wait(PIO const pio, const uint pio_interrupt_num)
Waits for a given PIO interrupt to be set.
Definition: util.c:390
bool util_pio_sm_try_get(PIO const pio, const uint sm, uint32_t *const word, const uint threshold)
Attempts to get a word from the state machine's RX FIFO if more than threshold words are in the buffe...
Definition: util.c:484
void util_dma_set_exclusive_channel_irq_handler(const uint irq_index, const uint channel, const irq_handler_t handler, const bool enabled)
Set and enable an exclusive handler for a DMA channel.
Definition: util.c:94
bool util_dma_irq_index_is_valid(const uint idx)
Check whether a DMA IRQ index is valid.
Definition: util.c:65
bool util_pio_interrupt_num_is_valid(const uint pio_interrupt_num)
Check whether a PIO interrupt number is valid.
Definition: util.c:374
const uint8_t util_dma_to_irq_map[]
Quick lookup for finding an NVIC IRQ number for a DMA interrupt index number.
Definition: util.c:55
#define UTIL_DEF_IN_RANGE_FUNC(TYPE)
Definition: util.c:40
uint util_dma_get_irq_from_index(const uint idx)
Gets the NVIC DMA IRQ number using the DMA IRQ index.
Definition: util.c:72
uint util_pion_get_irqn(PIO const pio, const uint irq_index)
Definition: util.c:233
#define UTIL_PIO_INTERRUPT_NUM_MIN
Definition: util.h:46
#define UTIL_PIO_IRQ_INDEX_MIN
Definition: util.h:43
#define UTIL_ROUTABLE_PIO_INTERRUPT_NUM_MAX
Definition: util.h:50
#define UTIL_PIO_IRQ_INDEX_MAX
Definition: util.h:44
#define UTIL_DMA_IRQ_INDEX_MIN
Definition: util.h:40
#define UTIL_DMA_IRQ_INDEX_MAX
Definition: util.h:41
#define UTIL_ROUTABLE_PIO_INTERRUPT_NUM_MIN
Definition: util.h:49
#define UTIL_PIO_INTERRUPT_NUM_MAX
Definition: util.h:47