generated from pimoroni/pico-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 5
/
logic.c
86 lines (77 loc) · 3.66 KB
/
logic.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <stdio.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "hardware/dma.h"
#include "hardware/structs/bus_ctrl.h"
static inline uint bits_packed_per_word(uint pin_count) {
// If the number of pins to be sampled divides the shift register size, we
// can use the full SR and FIFO width, and push when the input shift count
// exactly reaches 32. If not, we have to push earlier, so we use the FIFO
// a little less efficiently.
const uint SHIFT_REG_WIDTH = 32;
return SHIFT_REG_WIDTH - (SHIFT_REG_WIDTH % pin_count);
}
void logic_analyser_init(PIO pio, uint sm, uint pin_base, uint pin_count, float div) {
// Load a program to capture n pins. This is just a single `in pins, n`
// instruction with a wrap.
uint16_t capture_prog_instr = pio_encode_in(pio_pins, pin_count);
struct pio_program capture_prog = {
.instructions = &capture_prog_instr,
.length = 1,
.origin = -1
};
uint offset = pio_add_program(pio, &capture_prog);
// Configure state machine to loop over this `in` instruction forever,
// with autopush enabled.
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_in_pins(&c, pin_base);
sm_config_set_wrap(&c, offset, offset);
sm_config_set_clkdiv(&c, div);
// Note that we may push at a < 32 bit threshold if pin_count does not
// divide 32. We are using shift-to-right, so the sample data ends up
// left-justified in the FIFO in this case, with some zeroes at the LSBs.
sm_config_set_in_shift(&c, true, true, bits_packed_per_word(pin_count));
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
pio_sm_init(pio, sm, offset, &c);
}
void logic_analyser_arm(PIO pio, uint sm, uint dma_chan, uint32_t *capture_buf, size_t capture_size_words,
uint trigger_pin, bool trigger_level) {
pio_sm_set_enabled(pio, sm, false);
// Need to clear _input shift counter_, as well as FIFO, because there may be
// partial ISR contents left over from a previous run. sm_restart does this.
pio_sm_clear_fifos(pio, sm);
pio_sm_restart(pio, sm);
dma_channel_config c = dma_channel_get_default_config(dma_chan);
channel_config_set_read_increment(&c, false);
channel_config_set_write_increment(&c, true);
channel_config_set_dreq(&c, pio_get_dreq(pio, sm, false));
dma_channel_configure(dma_chan, &c,
capture_buf, // Destination pointer
&pio->rxf[sm], // Source pointer
capture_size_words, // Number of transfers
true // Start immediately
);
pio_sm_exec(pio, sm, pio_encode_wait_gpio(trigger_level, trigger_pin));
pio_sm_set_enabled(pio, sm, true);
}
void print_capture_buf(const uint32_t *buf, uint pin_base, uint pin_count, uint32_t n_samples) {
// Display the capture buffer in text form, like this:
// 00: __--__--__--__--__--__--
// 01: ____----____----____----
printf("Capture:\n");
// Each FIFO record may be only partially filled with bits, depending on
// whether pin_count is a factor of 32.
uint record_size_bits = bits_packed_per_word(pin_count);
for (int pin = 0; pin < pin_count; ++pin) {
printf("%02d: ", pin + pin_base);
for (int sample = 0; sample < n_samples; ++sample) {
uint bit_index = pin + sample * pin_count;
uint word_index = bit_index / record_size_bits;
// Data is left-justified in each FIFO entry, hence the (32 - record_size_bits) offset
uint word_mask = 1u << (bit_index % record_size_bits + 32 - record_size_bits);
printf(buf[word_index] & word_mask ? "-" : "_");
}
printf("\n");
}
}