logic-analyzer
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 
14 namespace logic_analyzer {
15 
24  public:
27  }
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();
56  waitForResult();
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  // Configure state machine to loop over this `in` instruction forever,
178  // with autopush enabled.
179  pio_sm_config c = pio_get_default_sm_config();
180  sm_config_set_in_pins(&c, pin_base);
181  sm_config_set_wrap(&c, offset, offset);
182  sm_config_set_clkdiv(&c, divider_value);
183  // Note that we may push at a < 32 bit threshold if pin_count does not
184  // divide 32. We are using shift-to-right, so the sample data ends up
185  // left-justified in the FIFO in this case, with some zeroes at the LSBs.
186  sm_config_set_in_shift(&c, true, true, 32);
187  sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
188  pio_sm_init(pio, sm, offset, &c);
189 
191  log("- Arming trigger");
192  pio_sm_set_enabled(pio, sm, false);
193  // Need to clear _input shift counter_, as well as FIFO, because there may be
194  // partial ISR contents left over from a previous run. sm_restart does this.
195  pio_sm_clear_fifos(pio, sm);
196  pio_sm_restart(pio, sm);
197 
198  dma_channel_config dma_config = dma_channel_get_default_config(dma_chan);
199  channel_config_set_read_increment(&dma_config, false);
200  channel_config_set_write_increment(&dma_config, true);
201  channel_config_set_transfer_data_size(&dma_config, DMA_SIZE_32);
202  channel_config_set_dreq(&dma_config, pio_get_dreq(pio, sm, false));
203 
204  n_transfers = n_samples /4 * sizeof(PinBitArray);
205  dma_channel_configure(dma_chan, &dma_config,
206  logicAnalyzer().buffer().data_ptr(), // Destination pointer
207  &pio->rxf[sm], // Source pointer
208  n_transfers, // Number of transfers
209  true // Start immediately
210  );
211 
214 
215  run_time_us = 0;
216  start_time = micros();
217  pio_sm_set_enabled(pio, sm, true);
218  }
219 
220  // /// Determines the dma channel tranfer size
221  // dma_channel_transfer_size transferSize(int bytes) {
222  // switch(bytes){
223  // case 1:
224  // return DMA_SIZE_8;
225  // case 2:
226  // return DMA_SIZE_16;
227  // case 4:
228  // return DMA_SIZE_32;
229  // default:
230  // return DMA_SIZE_32;
231  // }
232  // }
233 
234 
235  // /// determines the number of bits
236  // uint bit_count() {
237  // return sizeof(PinBitArray) * 8;
238  // }
239 
241  void dump() {
242  log("dump()");
243  // wait for result an print it
244  waitForResult();
245  // process result
246  if (!abort){
247  size_t count = logicAnalyzer().available();
248  write(logicAnalyzer().buffer().data_ptr(), count);
249  log("dump() - ended with %u records", count);
250  } else {
251  // unblock pulseview
252  write(0);
253  log("dump() - aborted");
254  }
255  }
256 
258  void waitForResult() {
259  log("waitForResult()");
260  dma_channel_wait_for_finish_blocking(dma_chan);
261  run_time_us = micros() - start_time;
262  size_t record_count = n_transfers * 4 / sizeof(PinBitArray);
263  logicAnalyzer().buffer().setAvailable(abort ? 0 : record_count);
264  log("waitForResult() -> result available with %u records",record_count);
265  }
266 
267 };
268 
269 } // namespace
270 
271 #endif
Abstract Class for Capturing Logic. Create your own subclass if you want to implement your own optimi...
Definition: logic_analyzer.h:300
LogicAnalyzer & logicAnalyzer()
Provides access to the LogicAnalyzer.
Definition: logic_analyzer.h:313
virtual void setStatus(Status status)
Sets the status.
Definition: logic_analyzer.h:323
size_t available()
returns the avialable buffer entries
Definition: logic_analyzer.h:719
uint16_t numberOfPins()
Provides the number of subsequent GPIO pins which will be used for capturing.
Definition: logic_analyzer.h:591
uint16_t startPin()
Provides the GPIO number of the start pin which is used for capturing.
Definition: logic_analyzer.h:586
RingBuffer & buffer()
Provides access to the buffer.
Definition: logic_analyzer.h:611
int readCount()
provides the read count
Definition: logic_analyzer.h:649
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:241
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:258
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:224