Skip to content

Commit cc97db0

Browse files
committed
first working version of a PIO to DMA setup without CPU calls. Transmitting 64bits per samples, in a ring buffer from witch the CPU can take the last samples.
1 parent 3f815f8 commit cc97db0

File tree

4 files changed

+77
-17
lines changed

4 files changed

+77
-17
lines changed

src/current/rp2350/RP2350PIOCurrentSense.cpp

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
this->gain_b = gain;
1212
this->gain_c = gain;
1313
this->max_adc_value = max_adc_value;
14-
1514
};
1615

1716

@@ -24,17 +23,16 @@
2423
// TODO check that driver is linked
2524

2625
// Done init PIO
27-
// TODO init ADC via SPI
28-
// TODO init DMA to transfer ADC data to memory buffer
26+
// TODO init ADC via SPI (Only for ADC with MOSI input)
27+
// Done init DMA to transfer ADC data to memory buffer
2928
// TODO init timer to trigger PIO conversions at required frequency (check driver settings)
3029
// TDB: do we need config input to know which timer slice and channel to use? or can we pick automatically?
3130
// TODO start everything up
3231

33-
3432
float sck_hz = 20e6;
3533
PIO pio = pio0;
36-
int sm = pio_claim_unused_sm(pio0, false);
37-
if (sm < 0) { pio = pio1; sm = pio_claim_unused_sm(pio1, true); }
34+
int sm = pio_claim_unused_sm(pio0, true);
35+
//if (sm < 0) { pio = pio1; sm = pio_claim_unused_sm(pio1, true); } //For now, let say we have to use PIO0, this is simpler for quick DMA setup
3836

3937
// --- patch program instructions with chosen trigger pin ---
4038
size_t prog_len = bu79100g_parallel3_program.length;
@@ -65,17 +63,56 @@
6563
pio_sm_set_consecutive_pindirs(pio, sm, this->pinCSB, 1, true); // CS out
6664
pio_sm_set_consecutive_pindirs(pio, sm, this->pinD0, 3, false); // D0..D2 in
6765

68-
// Shift config: right, autopush every 24 bits (two pushes per conversion)
69-
sm_config_set_in_shift(&c, true, true, 24);
66+
// Shift config: right, autopush every 32 bits (two pushes per conversion)
67+
sm_config_set_in_shift(&c, true, true, 32);
7068

7169
// SCK ≈ clk_sys / (2 * clkdiv) because each SCK period = 2 instructions
7270
float div = (float)clock_get_hz(clk_sys) / (2.0f * sck_hz);
7371
sm_config_set_clkdiv(&c, div);
7472

75-
// Init & start the SM
73+
// Init the SM
7674
pio_sm_init(pio, sm, off, &c);
75+
76+
//DMA Setup
77+
//dma_a is set to read from PIO RX FIFO and write to 'buff' buffer memory
78+
dma_a = dma_claim_unused_channel(true);
79+
dma_b = dma_claim_unused_channel(true);
80+
// ---------------------- DMA A: PIO RX FIFO -> buff[] with WRITE ring ----------------------
81+
dma_channel_config ca = dma_channel_get_default_config(dma_a);
82+
channel_config_set_read_increment(&ca, false);
83+
channel_config_set_write_increment(&ca, true);
84+
channel_config_set_transfer_data_size(&ca, DMA_SIZE_32);
85+
channel_config_set_dreq(&ca, DREQ_PIO0_RX0 + sm);
86+
channel_config_set_chain_to(&ca, dma_b); // A -> B when count hits 0
87+
88+
// Enable WRITE-side ring over the whole buffer span (power-of-two bytes)
89+
// size_bits = log2(RING_BYTES)
90+
channel_config_set_ring(&ca, /*write=*/true, /*size_bits=*/__builtin_ctz(RING_BYTES));
91+
92+
dma_channel_set_config(dma_a, &ca, false);
93+
dma_channel_set_read_addr(dma_a, &pio->rxf[sm], false);
94+
dma_channel_set_write_addr(dma_a, (void*)buff, false);
95+
dma_channel_set_trans_count(dma_a, RING_WORDS, false);
96+
97+
// ---------------------- DMA B: rearm A with ONE 32-bit write ----------------------
98+
dma_channel_config cb = dma_channel_get_default_config(dma_b);
99+
channel_config_set_read_increment(&cb, false);
100+
channel_config_set_write_increment(&cb, false);
101+
channel_config_set_transfer_data_size(&cb, DMA_SIZE_32);
102+
103+
// Write 1 word to A.AL1_TRANSFER_COUNT_TRIG (this sets count and re-starts A)
104+
dma_channel_configure(
105+
dma_b, &cb,
106+
(void*)&dma_hw->ch[dma_a].al1_transfer_count_trig,
107+
(const void*)&reload_count,
108+
1, false
109+
);
110+
111+
// Go!
112+
dma_channel_start(dma_a);
77113
pio_sm_set_enabled(pio, sm, true);
78114

115+
79116
return 0;
80117
};
81118

src/current/rp2350/RP2350PIOCurrentSense.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include "common/base_classes/CurrentSense.h"
55
#include "bu79100g_parallel3.pio.h"
6+
#include "hardware/dma.h"
7+
#include "hardware/sync.h"
68

79
class RP2350PIOCurrentSense: public CurrentSense {
810
public:
@@ -12,7 +14,21 @@ class RP2350PIOCurrentSense: public CurrentSense {
1214
int init() override;
1315

1416
PhaseCurrent_s getPhaseCurrents() override;
15-
protected:
17+
18+
static constexpr uint32_t RING_WORDS = 16; // ring span (needs to be a power of two)
19+
static constexpr uint32_t RING_BYTES = RING_WORDS * 4;
20+
21+
// Buffer base must be aligned to ring span for write-ring:
22+
alignas(RING_BYTES) volatile uint32_t buff[RING_WORDS];
23+
24+
// Single word used by DMA B to rearm A:
25+
alignas(4) volatile uint32_t reload_count = RING_WORDS;
26+
27+
28+
int dma_a = -1; // PIO RX -> ring (streamer)
29+
int dma_b = -1; // reloader
30+
31+
1632
uint32_t max_adc_value; //!< maximum ADC value (e.g. 4096 for 12 bit ADC)
1733
int pinCSB;
1834
int pinSCK;
@@ -23,5 +39,5 @@ class RP2350PIOCurrentSense: public CurrentSense {
2339
int gain_a;
2440
int gain_b;
2541
int gain_c;
26-
42+
protected: //For debug, all public
2743
};

src/current/rp2350/bu79100g_parallel3.pio

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
; in_base: D0..D2 (3 contiguous input pins)
66

77
.side_set 1 opt ; 1 sideset bit to drive SCK
8-
98
.wrap_target
109
set pins, 1 side 1 ; CSB=1, SCK=1
1110
; -------- wait external falling edge on absolute GPIO ----------
@@ -22,9 +21,15 @@ dummy_loop:
2221
set pins, 0
2322
; -------- 16 real clocks, sample on SCK rising edge -----------
2423
read_loop:
25-
nop side 1 ;DEBUG so we don't have to wait for autopush.
26-
;in pins, 3 side 1 ; SCK=1, sample D2..D0 on rising edge
24+
;nop side 1 ;DEBUG so we don't have to wait for autopush.
25+
in pins, 4 side 1 ; SCK=1, sample D2..D0 on rising edge ;Note, Here I had to read 4 pins instead of 3. It seems that with 3, a bit is lost after the first push. Need to read the doc again
2726
jmp x--, read_loop side 0 ; SCK=0
2827
; -------- finish conversion -----------------------------------
2928
set pins, 1 side 1 ; CSB=1, SCK=1
29+
; -------- Pad with 0 ------------------------------------------
30+
;set x, 0 ; Clear x
31+
;mov x, ~x
32+
;in x, 16 ; Push 16 bits of 1 into ISR
33+
34+
;push
3035
.wrap

src/current/rp2350/bu79100g_parallel3.pio.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// ------------------ //
1414

1515
#define bu79100g_parallel3_wrap_target 0
16-
#define bu79100g_parallel3_wrap 12
16+
#define bu79100g_parallel3_wrap 14
1717
#define bu79100g_parallel3_pio_version 1
1818

1919
static const uint16_t bu79100g_parallel3_program_instructions[] = {
@@ -28,16 +28,18 @@ static const uint16_t bu79100g_parallel3_program_instructions[] = {
2828
0xf801, // 7: set pins, 1 side 1
2929
0xf82f, // 8: set x, 15 side 1
3030
0xe000, // 9: set pins, 0
31-
0xb842, // 10: nop side 1
31+
0x5804, // 10: in pins, 4 side 1
3232
0x104a, // 11: jmp x--, 10 side 0
3333
0xf801, // 12: set pins, 1 side 1
34+
0xe020, // 13: set x, 0
35+
0xa029, // 14: mov x, ~x
3436
// .wrap
3537
};
3638

3739
#if !PICO_NO_HARDWARE
3840
static const struct pio_program bu79100g_parallel3_program = {
3941
.instructions = bu79100g_parallel3_program_instructions,
40-
.length = 13,
42+
.length = 15,
4143
.origin = -1,
4244
.pio_version = bu79100g_parallel3_pio_version,
4345
#if PICO_PIO_VERSION > 0

0 commit comments

Comments
 (0)