logic-analyzer
Loading...
Searching...
No Matches
capture_raspberry_pico.h
1#pragma once
2#ifdef ARDUINO_ARCH_RP2040
3
4#include <stdio.h>
5#include <stdlib.h>
6
7#include "hardware/pio.h"
8#include "hardware/dma.h"
9#include "hardware/structs/bus_ctrl.h"
10
11// Some logic to analyse:
12#include "logic_analyzer.h"
13
14namespace logic_analyzer {
15
24 public:
28
30 virtual void capture(){
31 log("capture()");
32 start();
33 dump();
34 // signal end of processing
35 setStatus(STOPPED);
36
37 log("Number of samples: %d", n_samples);
38 log("Time in us: %lu", run_time_us);
39 log("Measured capturing frequency in Hz is %f", frequencyMeasured());
40 }
41
43 void cancel() {
44 log("cancel()");
45 if (!abort){
46 abort = true;
47 pio_sm_set_enabled(pio, sm, false);
48 dma_channel_abort(dma_chan);
49 }
50 }
51
53 virtual void captureAll(){
54 log("captureAll()");
55 start();
57 }
58
60 unsigned long runtimeUs(){
61 return run_time_us;
62 }
63
66 float measured_freq = run_time_us == 0 ? 0 : 1000000.0 * n_samples / run_time_us;
67 return measured_freq;
68 }
69
70 float maxFrequency(int warmup=1, int repeat=2) {
71 log("determine maxFrequency");
72 if (max_frequecy_value<=0.0) {
73 pin_base = logicAnalyzer().startPin();
74 pin_count = logicAnalyzer().numberOfPins();
75 n_samples = logicAnalyzer().readCount();
76 divider_value = 1.0;
77
78 // warm up
79 for (int j=0;j<warmup;j++){
80 arm();
81 dma_channel_wait_for_finish_blocking(dma_chan);
82 }
83
84 // measure
85 float freqTotal = 0;
86 for (int j=0;j<repeat;j++){
87 arm();
88 dma_channel_wait_for_finish_blocking(dma_chan);
89 run_time_us = micros() - start_time;
90 freqTotal += frequencyMeasured();
91 }
92 max_frequecy_value = freqTotal / repeat;
93 log("maxFrequency: %f", max_frequecy_value);
94 }
95 return max_frequecy_value;
96 }
97
98 float divider() {
99 return divider_value;
100 }
101
102
103 protected:
104 PIO pio = pio0;
105 uint sm = 0;
106 uint dma_chan = 0;
107
108 uint pin_base;
109 uint pin_count;
110 uint32_t n_samples;
111 uint32_t n_transfers;
112 size_t capture_size_words;
113 uint trigger_pin;
114 bool trigger_level;
115 float divider_value;
116 uint64_t frequecy_value;
117 float max_frequecy_value = -1.0; // in hz
118 bool abort = false;
119 unsigned long start_time;
120 unsigned long run_time_us;
121 float test_duty_cycle;
122 int test_pin=-1;
123
125 void start() {
126 log("start()");
127 // if we are well above the limit we do not capture at all
128 if (logicAnalyzer().captureFrequency() > (1.5 * maxFrequency())){
129 setStatus(STOPPED);
130 // Send some dummy data to stop pulseview
131 write(0);
132 log("The frequency %u is not supported!", logicAnalyzer().captureFrequency () );
133 return;
134 }
135
136 // Get SUMP values
137 abort = false;
138 pin_base = logicAnalyzer().startPin();
139 pin_count = logicAnalyzer().numberOfPins();
140 n_samples = logicAnalyzer().readCount();
141 divider_value = calculateDivider(logicAnalyzer().captureFrequency());
142
143 arm();
144 }
145
146
148 float calculateDivider(uint32_t frequecy_value_hz){
149 // 1.0 => maxCaptureFrequency()
150 float result = static_cast<float>(maxFrequency()) / static_cast<float>(frequecy_value_hz) ;
151 log("divider: %f", result);
152 return result < 1.0 ? 1.0 : result;
153 }
154
156 void arm() {
157 log("arm()");
158
159 log("- Init trigger");
160
161 // Grant high bus priority to the DMA, so it can shove the processors out
162 // of the way. This should only be needed if you are pushing things up to
163 // >16bits/clk here, i.e. if you need to saturate the bus completely.
164 bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_DMA_W_BITS | BUSCTRL_BUS_PRIORITY_DMA_R_BITS;
165
166 // Load a program to capture n pins. This is just a single `in pins, n`
167 // instruction with a wrap.
168 uint16_t capture_prog_instr = pio_encode_in(pio_pins, pin_count);
169 struct pio_program capture_prog = {
170 .instructions = &capture_prog_instr,
171 .length = 1,
172 .origin = -1
173 };
174
175 uint offset = pio_add_program(pio, &capture_prog);
176
177 // Route the requested GPIOs to the PIO block and set them as inputs.
178 // Without this the state machine never sees the external pin levels
179 // (it stays connected to SIO), so the capture just reads zeros.
180 for (uint i = 0; i < pin_count; i++) {
181 pio_gpio_init(pio, pin_base + i);
182 }
183 pio_sm_set_consecutive_pindirs(pio, sm, pin_base, pin_count, false);
184
185 // Configure state machine to loop over this `in` instruction forever,
186 // with autopush enabled.
187 pio_sm_config c = pio_get_default_sm_config();
188 sm_config_set_in_pins(&c, pin_base);
189 sm_config_set_wrap(&c, offset, offset);
190 sm_config_set_clkdiv(&c, divider_value);
191 // Note that we may push at a < 32 bit threshold if pin_count does not
192 // divide 32. We are using shift-to-right, so the sample data ends up
193 // left-justified in the FIFO in this case, with some zeroes at the LSBs.
194 sm_config_set_in_shift(&c, true, true, 32);
195 sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
196 pio_sm_init(pio, sm, offset, &c);
197
199 log("- Arming trigger");
200 pio_sm_set_enabled(pio, sm, false);
201 // Need to clear _input shift counter_, as well as FIFO, because there may be
202 // partial ISR contents left over from a previous run. sm_restart does this.
203 pio_sm_clear_fifos(pio, sm);
204 pio_sm_restart(pio, sm);
205
206 dma_channel_config dma_config = dma_channel_get_default_config(dma_chan);
207 channel_config_set_read_increment(&dma_config, false);
208 channel_config_set_write_increment(&dma_config, true);
209 channel_config_set_transfer_data_size(&dma_config, DMA_SIZE_32);
210 channel_config_set_dreq(&dma_config, pio_get_dreq(pio, sm, false));
211
212 n_transfers = n_samples /4 * sizeof(PinBitArray);
213 dma_channel_configure(dma_chan, &dma_config,
214 logicAnalyzer().buffer().data_ptr(), // Destination pointer
215 &pio->rxf[sm], // Source pointer
216 n_transfers, // Number of transfers
217 true // Start immediately
218 );
219
222
223 run_time_us = 0;
224 start_time = micros();
225 pio_sm_set_enabled(pio, sm, true);
226 }
227
228 // /// Determines the dma channel tranfer size
229 // dma_channel_transfer_size transferSize(int bytes) {
230 // switch(bytes){
231 // case 1:
232 // return DMA_SIZE_8;
233 // case 2:
234 // return DMA_SIZE_16;
235 // case 4:
236 // return DMA_SIZE_32;
237 // default:
238 // return DMA_SIZE_32;
239 // }
240 // }
241
242
243 // /// determines the number of bits
244 // uint bit_count() {
245 // return sizeof(PinBitArray) * 8;
246 // }
247
249 void dump() {
250 log("dump()");
251 // wait for result an print it
253 // process result
254 if (!abort){
255 size_t count = logicAnalyzer().available();
256 write(logicAnalyzer().buffer().data_ptr(), count);
257 log("dump() - ended with %u records", count);
258 } else {
259 // unblock pulseview
260 write(0);
261 log("dump() - aborted");
262 }
263 }
264
267 log("waitForResult()");
268 dma_channel_wait_for_finish_blocking(dma_chan);
269 run_time_us = micros() - start_time;
270 size_t record_count = n_transfers * 4 / sizeof(PinBitArray);
271 logicAnalyzer().buffer().setAvailable(abort ? 0 : record_count);
272 log("waitForResult() -> result available with %u records",record_count);
273 }
274
275};
276
277} // namespace
278
279#endif
Abstract Class for Capturing Logic. Create your own subclass if you want to implement your own optimi...
Definition logic_analyzer.h:316
LogicAnalyzer & logicAnalyzer()
Provides access to the LogicAnalyzer.
Definition logic_analyzer.h:329
virtual void setStatus(Status status)
Sets the status.
Definition logic_analyzer.h:339
RingBuffer & buffer()
Provides access to the buffer.
Definition logic_analyzer.h:626
size_t available()
returns the avialable buffer entries
Definition logic_analyzer.h:734
uint16_t numberOfPins()
Provides the number of subsequent GPIO pins which will be used for capturing.
Definition logic_analyzer.h:606
uint16_t startPin()
Provides the GPIO number of the start pin which is used for capturing.
Definition logic_analyzer.h:601
int readCount()
provides the read count
Definition logic_analyzer.h:664
First version of Capture implementation for Raspberry Pico using the PIO. Based on https://github....
Definition capture_raspberry_pico.h:23
void arm()
intitialize the PIO
Definition capture_raspberry_pico.h:156
float calculateDivider(uint32_t frequecy_value_hz)
determines the divider value
Definition capture_raspberry_pico.h:148
virtual void captureAll()
Used to test the speed.
Definition capture_raspberry_pico.h:53
void cancel()
cancels the capturing which is ccurrently in progress
Definition capture_raspberry_pico.h:43
void start()
starts the processing
Definition capture_raspberry_pico.h:125
void dump()
Dumps the result to PuleView (SUMP software)
Definition capture_raspberry_pico.h:249
float frequencyMeasured()
Provides the measured capturing frequency.
Definition capture_raspberry_pico.h:65
PicoCapturePIO()
Default Constructor.
Definition capture_raspberry_pico.h:26
virtual void capture()
starts the capturing of the data
Definition capture_raspberry_pico.h:30
void waitForResult()
Wait for result and update run_time_us and buffer available.
Definition capture_raspberry_pico.h:266
unsigned long runtimeUs()
provides the runtime in microseconds from the capturing start to when the data is available
Definition capture_raspberry_pico.h:60
void setAvailable(size_t avail)
Usualy you must not use this function. However for the RP PIO it is quite usefull to indicated that t...
Definition logic_analyzer.h:240
Generic implementation of SUMP based logic analyzer.
void write(PinBitArray bits)
writes the status of all activated pins to the capturing device
Definition logic_analyzer.h:64
void log(const char *fmt,...)
Prints the content to the logger output stream.
Definition logic_analyzer.h:104