From 39806d8b1611d48ff725ab7c02bfcf1524b33fac Mon Sep 17 00:00:00 2001 From: Thomas Flayols Date: Wed, 27 Aug 2025 18:28:08 +0200 Subject: [PATCH 01/11] Add a PIO program for ADC bu79100g, work in progress --- src/current/rp2350/README.md | 12 +++++ src/current/rp2350/RP2350PIOCurrentSense.cpp | 50 ++++++++++++++++-- src/current/rp2350/RP2350PIOCurrentSense.h | 13 ++++- src/current/rp2350/bu79100g_parallel3.pio | 30 +++++++++++ src/current/rp2350/bu79100g_parallel3.pio.h | 55 ++++++++++++++++++++ 5 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 src/current/rp2350/bu79100g_parallel3.pio create mode 100644 src/current/rp2350/bu79100g_parallel3.pio.h diff --git a/src/current/rp2350/README.md b/src/current/rp2350/README.md index 0f37358..30937b9 100644 --- a/src/current/rp2350/README.md +++ b/src/current/rp2350/README.md @@ -6,4 +6,16 @@ Implementation of current sensing on RP2350 using the PIO to read SPI based ADCs. +Temporarly, for this to work, we need to add a PWM chanell in Arduino-FOC rp2040 hardware specific files. The duty cyctle needs to be computed to trigger the ADC at the right-time. +The PWM pin is hardcoded to GPIO11 for now. + + +## Compilling the PIO program +To manually compile the PIO files (generating a .pio.h from a pio), you need to instal pioasm. +Note for self, on my setup: + +``` +export PIOASM="$HOME/.arduino15/packages/rp2040/tools/pqt-pioasm/4.1.0-1aec55e/pioasm" +"$PIOASM" -v 1 bu79100g_parallel3.pio bu79100g_parallel3.pio.h +``` \ No newline at end of file diff --git a/src/current/rp2350/RP2350PIOCurrentSense.cpp b/src/current/rp2350/RP2350PIOCurrentSense.cpp index cddc569..836e45d 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.cpp +++ b/src/current/rp2350/RP2350PIOCurrentSense.cpp @@ -1,13 +1,16 @@ #include "RP2350PIOCurrentSense.h" - RP2350PIOCurrentSense::RP2350PIOCurrentSense(float gain, uint32_t max_adc_value, int pinA, int pinB, int pinC) : CurrentSense() { - this->pinA = pinA; - this->pinB = pinB; - this->pinC = pinC; + RP2350PIOCurrentSense::RP2350PIOCurrentSense(float gain, uint32_t max_adc_value, int pinSCK, int pinCSB, int pinD0) : CurrentSense() { + this->pinSCK = pinSCK; + this->pinCSB = pinCSB; + this->pinD0 = pinD0; + this->pinD1 = pinD0+1; + this->pinD2 = pinD0+2; this->gain_a = gain; this->gain_b = gain; this->gain_c = gain; this->max_adc_value = max_adc_value; + }; @@ -19,13 +22,50 @@ // TODO check that pins are valid for PIO use (e.g. consecutive pins on same bank) // TODO check that driver is linked - // TODO init PIO + // Done init PIO // TODO init ADC via SPI // TODO init DMA to transfer ADC data to memory buffer // TODO init timer to trigger PIO conversions at required frequency (check driver settings) // TDB: do we need config input to know which timer slice and channel to use? or can we pick automatically? // TODO start everything up + + float sck_hz = 20e6; + PIO pio = pio0; + int sm = pio_claim_unused_sm(pio0, false); + if (sm < 0) { pio = pio1; sm = pio_claim_unused_sm(pio1, true); } + + uint off = pio_add_program(pio, &bu79100g_parallel3_program); + pio_sm_config c = bu79100g_parallel3_program_get_default_config(off); + + // Map pins to the SM + sm_config_set_in_pins(&c, this->pinD0); // reads D0..D2 + sm_config_set_set_pins(&c, this->pinCSB, 1); // CSB (1 pin) + sm_config_set_sideset_pins(&c, this->pinSCK); // SCK (sideset) + + // Put pins into PIO control + pio_gpio_init(pio, this->pinSCK); + pio_gpio_init(pio, this->pinCSB); + pio_gpio_init(pio, this->pinD0); + pio_gpio_init(pio, this->pinD1); + pio_gpio_init(pio, this->pinD2); + + // Directions (from the SM’s point of view) + pio_sm_set_consecutive_pindirs(pio, sm, this->pinSCK, 1, true); // SCK out + pio_sm_set_consecutive_pindirs(pio, sm, this->pinCSB, 1, true); // CS out + pio_sm_set_consecutive_pindirs(pio, sm, this->pinD0, 3, false); // D0..D2 in + + // Shift config: right, autopush every 24 bits (two pushes per conversion) + sm_config_set_in_shift(&c, true, true, 24); + + // SCK ≈ clk_sys / (2 * clkdiv) because each SCK period = 2 instructions + float div = (float)clock_get_hz(clk_sys) / (2.0f * sck_hz); + sm_config_set_clkdiv(&c, div); + + // Init & start the SM + pio_sm_init(pio, sm, off, &c); + pio_sm_set_enabled(pio, sm, true); + return 0; }; diff --git a/src/current/rp2350/RP2350PIOCurrentSense.h b/src/current/rp2350/RP2350PIOCurrentSense.h index 3bcadd8..5d5371a 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.h +++ b/src/current/rp2350/RP2350PIOCurrentSense.h @@ -2,11 +2,11 @@ #pragma once #include "common/base_classes/CurrentSense.h" - +#include "bu79100g_parallel3.pio.h" class RP2350PIOCurrentSense: public CurrentSense { public: - RP2350PIOCurrentSense(float gain, uint32_t max_adc_value, int pinA, int pinB, int pinC = _NC); + RP2350PIOCurrentSense(float gain, uint32_t max_adc_value, int pinSCK, int pinCSB, int pinD0); ~RP2350PIOCurrentSense(); int init() override; @@ -14,4 +14,13 @@ class RP2350PIOCurrentSense: public CurrentSense { PhaseCurrent_s getPhaseCurrents() override; protected: uint32_t max_adc_value; //!< maximum ADC value (e.g. 4096 for 12 bit ADC) + int pinCSB; + int pinSCK; + int pinD0; + int pinD1; + int pinD2; + int gain_a; + int gain_b; + int gain_c; + }; diff --git a/src/current/rp2350/bu79100g_parallel3.pio b/src/current/rp2350/bu79100g_parallel3.pio new file mode 100644 index 0000000..e242011 --- /dev/null +++ b/src/current/rp2350/bu79100g_parallel3.pio @@ -0,0 +1,30 @@ +.program bu79100g_parallel3 +; BU79100G-LA parallel read of 3 ADCs with a trigger GPIO +; sideset pin: SCK (1 pin), CPOL=1 idle HIGH +; set pin: CSB (1 pin) +; in_base: D0..D2 (3 contiguous input pins) + +.side_set 1 opt ; 1 sideset bit to drive SCK + +.wrap_target + set pins, 1 side 1 ; CSB=1, SCK=1 + ; -------- wait external falling edge on absolute GPIO ---------- + wait 1 gpio 11 ; TODO, we will need to have this pin setable from the C code. direcetly edit the program? + wait 0 gpio 11 + set pins, 0 side 1 ; CS=0, SCK=1 + set x, 15 side 1 ; prepare loop cpt + ; -------- 16 dummy clocks (no sampling) ----------------------- +dummy_loop: + nop side 0 ; SCK=0 + jmp x--, dummy_loop side 1 ; SCK=1 + set pins, 1 side 1 ; CSB=0, keep SCK=HIGH at CSB falling (datasheet rec.) + set x, 15 side 1 + set pins, 0 + ; -------- 16 real clocks, sample on SCK rising edge ----------- +read_loop: + nop side 1 ;DEBUG so we don't have to wait for autopush. + ;in pins, 3 side 1 ; SCK=1, sample D2..D0 on rising edge + jmp x--, read_loop side 0 ; SCK=0 + ; -------- finish conversion ----------------------------------- + set pins, 1 side 1 ; CSB=1, SCK=1 +.wrap \ No newline at end of file diff --git a/src/current/rp2350/bu79100g_parallel3.pio.h b/src/current/rp2350/bu79100g_parallel3.pio.h new file mode 100644 index 0000000..a8e3401 --- /dev/null +++ b/src/current/rp2350/bu79100g_parallel3.pio.h @@ -0,0 +1,55 @@ +// -------------------------------------------------- // +// This file is autogenerated by pioasm; do not edit! // +// -------------------------------------------------- // + +#pragma once + +#if !PICO_NO_HARDWARE +#include "hardware/pio.h" +#endif + +// ------------------ // +// bu79100g_parallel3 // +// ------------------ // + +#define bu79100g_parallel3_wrap_target 0 +#define bu79100g_parallel3_wrap 12 +#define bu79100g_parallel3_pio_version 1 + +static const uint16_t bu79100g_parallel3_program_instructions[] = { + // .wrap_target + 0xf801, // 0: set pins, 1 side 1 + 0x208b, // 1: wait 1 gpio, 11 + 0x200b, // 2: wait 0 gpio, 11 + 0xf800, // 3: set pins, 0 side 1 + 0xf82f, // 4: set x, 15 side 1 + 0xb042, // 5: nop side 0 + 0x1845, // 6: jmp x--, 5 side 1 + 0xf801, // 7: set pins, 1 side 1 + 0xf82f, // 8: set x, 15 side 1 + 0xe000, // 9: set pins, 0 + 0xb842, // 10: nop side 1 + 0x104a, // 11: jmp x--, 10 side 0 + 0xf801, // 12: set pins, 1 side 1 + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program bu79100g_parallel3_program = { + .instructions = bu79100g_parallel3_program_instructions, + .length = 13, + .origin = -1, + .pio_version = bu79100g_parallel3_pio_version, +#if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x1 +#endif +}; + +static inline pio_sm_config bu79100g_parallel3_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + bu79100g_parallel3_wrap_target, offset + bu79100g_parallel3_wrap); + sm_config_set_sideset(&c, 2, true, false); + return c; +} +#endif + From 9268cf372ad60d48b157d7a92caa8d29fff67b2b Mon Sep 17 00:00:00 2001 From: Thomas Flayols Date: Wed, 27 Aug 2025 19:20:04 +0200 Subject: [PATCH 02/11] add the option to select any trigger pin. --- src/current/rp2350/RP2350PIOCurrentSense.cpp | 14 ++++++++++++-- src/current/rp2350/RP2350PIOCurrentSense.h | 3 ++- src/current/rp2350/bu79100g_parallel3.pio | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/current/rp2350/RP2350PIOCurrentSense.cpp b/src/current/rp2350/RP2350PIOCurrentSense.cpp index 836e45d..fcee9c6 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.cpp +++ b/src/current/rp2350/RP2350PIOCurrentSense.cpp @@ -1,11 +1,12 @@ #include "RP2350PIOCurrentSense.h" - RP2350PIOCurrentSense::RP2350PIOCurrentSense(float gain, uint32_t max_adc_value, int pinSCK, int pinCSB, int pinD0) : CurrentSense() { + RP2350PIOCurrentSense::RP2350PIOCurrentSense(float gain, uint32_t max_adc_value, int pinSCK, int pinCSB, int pinD0, int pinTRIG) : CurrentSense() { this->pinSCK = pinSCK; this->pinCSB = pinCSB; this->pinD0 = pinD0; this->pinD1 = pinD0+1; this->pinD2 = pinD0+2; + this->pinTRIG = pinTRIG; this->gain_a = gain; this->gain_b = gain; this->gain_c = gain; @@ -35,7 +36,16 @@ int sm = pio_claim_unused_sm(pio0, false); if (sm < 0) { pio = pio1; sm = pio_claim_unused_sm(pio1, true); } - uint off = pio_add_program(pio, &bu79100g_parallel3_program); + // --- patch program instructions with chosen trigger pin --- + size_t prog_len = bu79100g_parallel3_program.length; + uint16_t insns[prog_len]; + memcpy(insns, bu79100g_parallel3_program_instructions, sizeof(insns)); + insns[1] = (insns[1] & ~0x1Fu) | (this->pinTRIG & 0x1Fu); + insns[2] = (insns[2] & ~0x1Fu) | (this->pinTRIG & 0x1Fu); + struct pio_program prog = bu79100g_parallel3_program; // copy metadata + prog.instructions = insns; + + uint off = pio_add_program(pio, &prog); pio_sm_config c = bu79100g_parallel3_program_get_default_config(off); // Map pins to the SM diff --git a/src/current/rp2350/RP2350PIOCurrentSense.h b/src/current/rp2350/RP2350PIOCurrentSense.h index 5d5371a..e74d1a4 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.h +++ b/src/current/rp2350/RP2350PIOCurrentSense.h @@ -6,7 +6,7 @@ class RP2350PIOCurrentSense: public CurrentSense { public: - RP2350PIOCurrentSense(float gain, uint32_t max_adc_value, int pinSCK, int pinCSB, int pinD0); + RP2350PIOCurrentSense(float gain, uint32_t max_adc_value, int pinSCK, int pinCSB, int pinD0, int pinTRIG); ~RP2350PIOCurrentSense(); int init() override; @@ -19,6 +19,7 @@ class RP2350PIOCurrentSense: public CurrentSense { int pinD0; int pinD1; int pinD2; + int pinTRIG; int gain_a; int gain_b; int gain_c; diff --git a/src/current/rp2350/bu79100g_parallel3.pio b/src/current/rp2350/bu79100g_parallel3.pio index e242011..279ea71 100644 --- a/src/current/rp2350/bu79100g_parallel3.pio +++ b/src/current/rp2350/bu79100g_parallel3.pio @@ -9,8 +9,8 @@ .wrap_target set pins, 1 side 1 ; CSB=1, SCK=1 ; -------- wait external falling edge on absolute GPIO ---------- - wait 1 gpio 11 ; TODO, we will need to have this pin setable from the C code. direcetly edit the program? - wait 0 gpio 11 + wait 1 gpio 11 ;THIS INSTRUCTION WILL BE PATCHED AT RUNTIME TO CHANGE GPIO. DO NOT MOVE IT WITHOUT CHANGING PIO INIT. + wait 0 gpio 11 ;THIS INSTRUCTION WILL BE PATCHED AT RUNTIME TO CHANGE GPIO. DO NOT MOVE IT WITHOUT CHANGING PIO INIT. set pins, 0 side 1 ; CS=0, SCK=1 set x, 15 side 1 ; prepare loop cpt ; -------- 16 dummy clocks (no sampling) ----------------------- From 3f815f839867c1c35c395e26981a3c8394f7ed05 Mon Sep 17 00:00:00 2001 From: Thomas Flayols Date: Wed, 27 Aug 2025 19:32:32 +0200 Subject: [PATCH 03/11] add a bit more info and dev status in readme. --- src/current/rp2350/README.md | 53 +++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/current/rp2350/README.md b/src/current/rp2350/README.md index 30937b9..42e550f 100644 --- a/src/current/rp2350/README.md +++ b/src/current/rp2350/README.md @@ -4,12 +4,63 @@ *warning* Work in progress Implementation of current sensing on RP2350 using the PIO to read SPI based ADCs. +Wiring: +* SCK_PIN -> Clock pin shared with 3 ADCs +* CSB_PIN -> Chip Select pin shared with 3 ADCs +* D0, D1 D2 -> The 3 data output from the ADCs. Needs to be contigus (D1=D0+1 D2=D1+1) Temporarly, for this to work, we need to add a PWM chanell in Arduino-FOC rp2040 hardware specific files. The duty cyctle needs to be computed to trigger the ADC at the right-time. -The PWM pin is hardcoded to GPIO11 for now. +TODO: +* Init a the DMA or IRQ to read samples from PIO. +* Activate the push of adc data in PIO program (disabled for tests) +* Find a way to setup the trigger PWM from the driver, or change the arduino-foc lib. + + + +# Example: +``` +// Open loop motor control example With current readings (work in progress) +#include +#include "pico/stdlib.h" +#include "hardware/pio.h" +#include "hardware/clocks.h" +#include +#include "current/rp2350/RP2350PIOCurrentSense.h" + +static const uint SCK_PIN = 2; // sideset pin +static const uint CSB_PIN = 3; // set pin +static const uint D0_PIN = 4; // D0..D2 must be contiguous (D1=D0+1, D2=D0+2) +static const uint TRIG_PIN = 8; // This need to be also configure as an extra PWM output with custom fixed duty cycle. For now let's just one of the phase as the trigger. + +BLDCMotor motor = BLDCMotor(11); +BLDCDriver3PWM driver = BLDCDriver3PWM(7, 8, 9); +RP2350PIOCurrentSense curr = RP2350PIOCurrentSense(1.0, 4096,SCK_PIN, CSB_PIN, D0_PIN, TRIG_PIN); + +float target_velocity = 0.2; + +void setup() { + Serial.begin(115200); + SimpleFOCDebug::enable(&Serial); + driver.voltage_power_supply = 12; + driver.voltage_limit = 12; + driver.init(); + motor.linkDriver(&driver); + motor.voltage_limit = 2; // [V] + motor.controller = MotionControlType::velocity_openloop; + motor.init(); + Serial.println("Motor ready!"); + _delay(100); + curr.init(); +} + +void loop() { + motor.move(target_velocity); +} +``` + ## Compilling the PIO program To manually compile the PIO files (generating a .pio.h from a pio), you need to instal pioasm. From cc97db0503c7871d38fce109dad04508a6d97c57 Mon Sep 17 00:00:00 2001 From: Thomas Flayols Date: Tue, 2 Sep 2025 18:19:20 +0200 Subject: [PATCH 04/11] 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. --- src/current/rp2350/RP2350PIOCurrentSense.cpp | 55 ++++++++++++++++---- src/current/rp2350/RP2350PIOCurrentSense.h | 20 ++++++- src/current/rp2350/bu79100g_parallel3.pio | 11 ++-- src/current/rp2350/bu79100g_parallel3.pio.h | 8 +-- 4 files changed, 77 insertions(+), 17 deletions(-) diff --git a/src/current/rp2350/RP2350PIOCurrentSense.cpp b/src/current/rp2350/RP2350PIOCurrentSense.cpp index fcee9c6..c6208f4 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.cpp +++ b/src/current/rp2350/RP2350PIOCurrentSense.cpp @@ -11,7 +11,6 @@ this->gain_b = gain; this->gain_c = gain; this->max_adc_value = max_adc_value; - }; @@ -24,17 +23,16 @@ // TODO check that driver is linked // Done init PIO - // TODO init ADC via SPI - // TODO init DMA to transfer ADC data to memory buffer + // TODO init ADC via SPI (Only for ADC with MOSI input) + // Done init DMA to transfer ADC data to memory buffer // TODO init timer to trigger PIO conversions at required frequency (check driver settings) // TDB: do we need config input to know which timer slice and channel to use? or can we pick automatically? // TODO start everything up - float sck_hz = 20e6; PIO pio = pio0; - int sm = pio_claim_unused_sm(pio0, false); - if (sm < 0) { pio = pio1; sm = pio_claim_unused_sm(pio1, true); } + int sm = pio_claim_unused_sm(pio0, true); + //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 // --- patch program instructions with chosen trigger pin --- size_t prog_len = bu79100g_parallel3_program.length; @@ -65,17 +63,56 @@ pio_sm_set_consecutive_pindirs(pio, sm, this->pinCSB, 1, true); // CS out pio_sm_set_consecutive_pindirs(pio, sm, this->pinD0, 3, false); // D0..D2 in - // Shift config: right, autopush every 24 bits (two pushes per conversion) - sm_config_set_in_shift(&c, true, true, 24); + // Shift config: right, autopush every 32 bits (two pushes per conversion) + sm_config_set_in_shift(&c, true, true, 32); // SCK ≈ clk_sys / (2 * clkdiv) because each SCK period = 2 instructions float div = (float)clock_get_hz(clk_sys) / (2.0f * sck_hz); sm_config_set_clkdiv(&c, div); - // Init & start the SM + // Init the SM pio_sm_init(pio, sm, off, &c); + + //DMA Setup + //dma_a is set to read from PIO RX FIFO and write to 'buff' buffer memory + dma_a = dma_claim_unused_channel(true); + dma_b = dma_claim_unused_channel(true); + // ---------------------- DMA A: PIO RX FIFO -> buff[] with WRITE ring ---------------------- + dma_channel_config ca = dma_channel_get_default_config(dma_a); + channel_config_set_read_increment(&ca, false); + channel_config_set_write_increment(&ca, true); + channel_config_set_transfer_data_size(&ca, DMA_SIZE_32); + channel_config_set_dreq(&ca, DREQ_PIO0_RX0 + sm); + channel_config_set_chain_to(&ca, dma_b); // A -> B when count hits 0 + + // Enable WRITE-side ring over the whole buffer span (power-of-two bytes) + // size_bits = log2(RING_BYTES) + channel_config_set_ring(&ca, /*write=*/true, /*size_bits=*/__builtin_ctz(RING_BYTES)); + + dma_channel_set_config(dma_a, &ca, false); + dma_channel_set_read_addr(dma_a, &pio->rxf[sm], false); + dma_channel_set_write_addr(dma_a, (void*)buff, false); + dma_channel_set_trans_count(dma_a, RING_WORDS, false); + + // ---------------------- DMA B: rearm A with ONE 32-bit write ---------------------- + dma_channel_config cb = dma_channel_get_default_config(dma_b); + channel_config_set_read_increment(&cb, false); + channel_config_set_write_increment(&cb, false); + channel_config_set_transfer_data_size(&cb, DMA_SIZE_32); + + // Write 1 word to A.AL1_TRANSFER_COUNT_TRIG (this sets count and re-starts A) + dma_channel_configure( + dma_b, &cb, + (void*)&dma_hw->ch[dma_a].al1_transfer_count_trig, + (const void*)&reload_count, + 1, false + ); + + // Go! + dma_channel_start(dma_a); pio_sm_set_enabled(pio, sm, true); + return 0; }; diff --git a/src/current/rp2350/RP2350PIOCurrentSense.h b/src/current/rp2350/RP2350PIOCurrentSense.h index e74d1a4..585a3cb 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.h +++ b/src/current/rp2350/RP2350PIOCurrentSense.h @@ -3,6 +3,8 @@ #include "common/base_classes/CurrentSense.h" #include "bu79100g_parallel3.pio.h" +#include "hardware/dma.h" +#include "hardware/sync.h" class RP2350PIOCurrentSense: public CurrentSense { public: @@ -12,7 +14,21 @@ class RP2350PIOCurrentSense: public CurrentSense { int init() override; PhaseCurrent_s getPhaseCurrents() override; - protected: + + static constexpr uint32_t RING_WORDS = 16; // ring span (needs to be a power of two) + static constexpr uint32_t RING_BYTES = RING_WORDS * 4; + + // Buffer base must be aligned to ring span for write-ring: + alignas(RING_BYTES) volatile uint32_t buff[RING_WORDS]; + + // Single word used by DMA B to rearm A: + alignas(4) volatile uint32_t reload_count = RING_WORDS; + + + int dma_a = -1; // PIO RX -> ring (streamer) + int dma_b = -1; // reloader + + uint32_t max_adc_value; //!< maximum ADC value (e.g. 4096 for 12 bit ADC) int pinCSB; int pinSCK; @@ -23,5 +39,5 @@ class RP2350PIOCurrentSense: public CurrentSense { int gain_a; int gain_b; int gain_c; - + protected: //For debug, all public }; diff --git a/src/current/rp2350/bu79100g_parallel3.pio b/src/current/rp2350/bu79100g_parallel3.pio index 279ea71..cb3c52c 100644 --- a/src/current/rp2350/bu79100g_parallel3.pio +++ b/src/current/rp2350/bu79100g_parallel3.pio @@ -5,7 +5,6 @@ ; in_base: D0..D2 (3 contiguous input pins) .side_set 1 opt ; 1 sideset bit to drive SCK - .wrap_target set pins, 1 side 1 ; CSB=1, SCK=1 ; -------- wait external falling edge on absolute GPIO ---------- @@ -22,9 +21,15 @@ dummy_loop: set pins, 0 ; -------- 16 real clocks, sample on SCK rising edge ----------- read_loop: - nop side 1 ;DEBUG so we don't have to wait for autopush. - ;in pins, 3 side 1 ; SCK=1, sample D2..D0 on rising edge + ;nop side 1 ;DEBUG so we don't have to wait for autopush. + 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 jmp x--, read_loop side 0 ; SCK=0 ; -------- finish conversion ----------------------------------- set pins, 1 side 1 ; CSB=1, SCK=1 + ; -------- Pad with 0 ------------------------------------------ + ;set x, 0 ; Clear x + ;mov x, ~x + ;in x, 16 ; Push 16 bits of 1 into ISR + + ;push .wrap \ No newline at end of file diff --git a/src/current/rp2350/bu79100g_parallel3.pio.h b/src/current/rp2350/bu79100g_parallel3.pio.h index a8e3401..63f06d5 100644 --- a/src/current/rp2350/bu79100g_parallel3.pio.h +++ b/src/current/rp2350/bu79100g_parallel3.pio.h @@ -13,7 +13,7 @@ // ------------------ // #define bu79100g_parallel3_wrap_target 0 -#define bu79100g_parallel3_wrap 12 +#define bu79100g_parallel3_wrap 14 #define bu79100g_parallel3_pio_version 1 static const uint16_t bu79100g_parallel3_program_instructions[] = { @@ -28,16 +28,18 @@ static const uint16_t bu79100g_parallel3_program_instructions[] = { 0xf801, // 7: set pins, 1 side 1 0xf82f, // 8: set x, 15 side 1 0xe000, // 9: set pins, 0 - 0xb842, // 10: nop side 1 + 0x5804, // 10: in pins, 4 side 1 0x104a, // 11: jmp x--, 10 side 0 0xf801, // 12: set pins, 1 side 1 + 0xe020, // 13: set x, 0 + 0xa029, // 14: mov x, ~x // .wrap }; #if !PICO_NO_HARDWARE static const struct pio_program bu79100g_parallel3_program = { .instructions = bu79100g_parallel3_program_instructions, - .length = 13, + .length = 15, .origin = -1, .pio_version = bu79100g_parallel3_pio_version, #if PICO_PIO_VERSION > 0 From 5e54639f6cee8b5d4d3e6e81e116c92bcf819a72 Mon Sep 17 00:00:00 2001 From: Thomas Flayols Date: Wed, 3 Sep 2025 14:50:58 +0200 Subject: [PATCH 05/11] add code to read the current from last measurement in buffer. --- src/current/rp2350/RP2350PIOCurrentSense.cpp | 38 ++++++++++++++++++-- src/current/rp2350/RP2350PIOCurrentSense.h | 10 +++--- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/current/rp2350/RP2350PIOCurrentSense.cpp b/src/current/rp2350/RP2350PIOCurrentSense.cpp index c6208f4..90aa516 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.cpp +++ b/src/current/rp2350/RP2350PIOCurrentSense.cpp @@ -112,14 +112,46 @@ dma_channel_start(dma_a); pio_sm_set_enabled(pio, sm, true); - return 0; }; + void extract_bit_interleaved(const uint32_t w0, const uint32_t w1, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) { + *a = 0; + *b = 0; + *c = 0; + *d = 0; + for (int i = 0; i < 64; i += 4) { + uint32_t w = (i < 32) ? w1 : w0; + int shift = 28 - (i % 32); // 28, 24, ..., 0 for each group of 4 bits + + uint32_t group = (w >> shift) & 0xF; // extract aN bN cN dN + + *a = (*a << 1) | ((group >> 0) & 0x1); + *b = (*b << 1) | ((group >> 1) & 0x1); + *c = (*c << 1) | ((group >> 2) & 0x1); + *d = (*d << 1) | ((group >> 3) & 0x1); + } + } + PhaseCurrent_s RP2350PIOCurrentSense::getPhaseCurrents() { PhaseCurrent_s current; - // TODO copy values from latest ADC reading - // TODO process raw values to get currents in mAmps + + const uintptr_t base = (uintptr_t)buff; + //Get the index the DMA is about to write + const uint32_t i_dma = (dma_hw->ch[dma_a].write_addr - base)>>2; + //For a safe read, get the one that is an even number and at least <2.wi, manage looping + const uint32_t i_last = (i_dma <= 1) ? RING_WORDS -2 : ((i_dma / 2)*2 - 2); + //copy them quickly (before print!) + const uint32_t w0 = buff[i_last]; + const uint32_t w1 = buff[i_last+1]; + //Reconstruct the 3 current from interleaved data + uint32_t a,b,c,d = 0; + extract_bit_interleaved(w0,w1, &a, &b, &c, &d); + + current.a = (0x00000fff & a) * gain_a; + current.b = (0x00000fff & b) * gain_b; + current.c = (0x00000fff & c) * gain_c; + return current; }; diff --git a/src/current/rp2350/RP2350PIOCurrentSense.h b/src/current/rp2350/RP2350PIOCurrentSense.h index 585a3cb..0100172 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.h +++ b/src/current/rp2350/RP2350PIOCurrentSense.h @@ -15,7 +15,7 @@ class RP2350PIOCurrentSense: public CurrentSense { PhaseCurrent_s getPhaseCurrents() override; - static constexpr uint32_t RING_WORDS = 16; // ring span (needs to be a power of two) + static constexpr uint32_t RING_WORDS = 64; // ring span (needs to be a power of two) static constexpr uint32_t RING_BYTES = RING_WORDS * 4; // Buffer base must be aligned to ring span for write-ring: @@ -24,11 +24,9 @@ class RP2350PIOCurrentSense: public CurrentSense { // Single word used by DMA B to rearm A: alignas(4) volatile uint32_t reload_count = RING_WORDS; - int dma_a = -1; // PIO RX -> ring (streamer) int dma_b = -1; // reloader - uint32_t max_adc_value; //!< maximum ADC value (e.g. 4096 for 12 bit ADC) int pinCSB; int pinSCK; @@ -36,8 +34,8 @@ class RP2350PIOCurrentSense: public CurrentSense { int pinD1; int pinD2; int pinTRIG; - int gain_a; - int gain_b; - int gain_c; + float gain_a; + float gain_b; + float gain_c; protected: //For debug, all public }; From 4aa83b6eec5d7fa6aa828f98629ba83f8bab6570 Mon Sep 17 00:00:00 2001 From: Thomas Flayols Date: Wed, 3 Sep 2025 15:15:42 +0200 Subject: [PATCH 06/11] make interleaving inline, todo optim (2.27us to read and decode the adc values from buffer) --- src/current/rp2350/RP2350PIOCurrentSense.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/current/rp2350/RP2350PIOCurrentSense.cpp b/src/current/rp2350/RP2350PIOCurrentSense.cpp index 90aa516..50856a0 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.cpp +++ b/src/current/rp2350/RP2350PIOCurrentSense.cpp @@ -115,7 +115,7 @@ return 0; }; - void extract_bit_interleaved(const uint32_t w0, const uint32_t w1, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) { + static inline void extract_bit_interleaved(const uint32_t w0, const uint32_t w1, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) { *a = 0; *b = 0; *c = 0; From b3730969d4e4b0eb58ba9631cfb43eaba49276b6 Mon Sep 17 00:00:00 2001 From: Thomas Flayols Date: Thu, 4 Sep 2025 18:54:45 +0200 Subject: [PATCH 07/11] Fix bit order, edge sampling and deinterleaving, First working version, validated on RP2350 with 3 ADCs --- src/current/rp2350/RP2350PIOCurrentSense.cpp | 4 ++-- src/current/rp2350/bu79100g_parallel3.pio | 9 ++++----- src/current/rp2350/bu79100g_parallel3.pio.h | 10 ++++------ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/current/rp2350/RP2350PIOCurrentSense.cpp b/src/current/rp2350/RP2350PIOCurrentSense.cpp index 50856a0..0f6c0ab 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.cpp +++ b/src/current/rp2350/RP2350PIOCurrentSense.cpp @@ -64,7 +64,7 @@ pio_sm_set_consecutive_pindirs(pio, sm, this->pinD0, 3, false); // D0..D2 in // Shift config: right, autopush every 32 bits (two pushes per conversion) - sm_config_set_in_shift(&c, true, true, 32); + sm_config_set_in_shift(&c, false, true, 32); // SCK ≈ clk_sys / (2 * clkdiv) because each SCK period = 2 instructions float div = (float)clock_get_hz(clk_sys) / (2.0f * sck_hz); @@ -121,7 +121,7 @@ *c = 0; *d = 0; for (int i = 0; i < 64; i += 4) { - uint32_t w = (i < 32) ? w1 : w0; + uint32_t w = (i < 32) ? w0 : w1; int shift = 28 - (i % 32); // 28, 24, ..., 0 for each group of 4 bits uint32_t group = (w >> shift) & 0xF; // extract aN bN cN dN diff --git a/src/current/rp2350/bu79100g_parallel3.pio b/src/current/rp2350/bu79100g_parallel3.pio index cb3c52c..b8ca40b 100644 --- a/src/current/rp2350/bu79100g_parallel3.pio +++ b/src/current/rp2350/bu79100g_parallel3.pio @@ -17,13 +17,12 @@ dummy_loop: nop side 0 ; SCK=0 jmp x--, dummy_loop side 1 ; SCK=1 set pins, 1 side 1 ; CSB=0, keep SCK=HIGH at CSB falling (datasheet rec.) - set x, 15 side 1 + set x, 15 side 1 set pins, 0 - ; -------- 16 real clocks, sample on SCK rising edge ----------- + ; -------- 16 real clocks, sample on SCK falling edge ----------- read_loop: - ;nop side 1 ;DEBUG so we don't have to wait for autopush. - 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 - jmp x--, read_loop side 0 ; SCK=0 + in pins, 4 side 0 ; SCK=0, sample D2..D0 on falling 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 + jmp x--, read_loop side 1 ; SCK=1 ; -------- finish conversion ----------------------------------- set pins, 1 side 1 ; CSB=1, SCK=1 ; -------- Pad with 0 ------------------------------------------ diff --git a/src/current/rp2350/bu79100g_parallel3.pio.h b/src/current/rp2350/bu79100g_parallel3.pio.h index 63f06d5..4208b85 100644 --- a/src/current/rp2350/bu79100g_parallel3.pio.h +++ b/src/current/rp2350/bu79100g_parallel3.pio.h @@ -13,7 +13,7 @@ // ------------------ // #define bu79100g_parallel3_wrap_target 0 -#define bu79100g_parallel3_wrap 14 +#define bu79100g_parallel3_wrap 12 #define bu79100g_parallel3_pio_version 1 static const uint16_t bu79100g_parallel3_program_instructions[] = { @@ -28,18 +28,16 @@ static const uint16_t bu79100g_parallel3_program_instructions[] = { 0xf801, // 7: set pins, 1 side 1 0xf82f, // 8: set x, 15 side 1 0xe000, // 9: set pins, 0 - 0x5804, // 10: in pins, 4 side 1 - 0x104a, // 11: jmp x--, 10 side 0 + 0x5004, // 10: in pins, 4 side 0 + 0x184a, // 11: jmp x--, 10 side 1 0xf801, // 12: set pins, 1 side 1 - 0xe020, // 13: set x, 0 - 0xa029, // 14: mov x, ~x // .wrap }; #if !PICO_NO_HARDWARE static const struct pio_program bu79100g_parallel3_program = { .instructions = bu79100g_parallel3_program_instructions, - .length = 15, + .length = 13, .origin = -1, .pio_version = bu79100g_parallel3_pio_version, #if PICO_PIO_VERSION > 0 From 23859156d15ed8b9711a0cedeb30c35e4f19202e Mon Sep 17 00:00:00 2001 From: Thomas Flayols Date: Fri, 5 Sep 2025 13:23:56 +0200 Subject: [PATCH 08/11] Optimize de-interleaving (getPhaseCurrents() < 1uS on Rp2350), Unroll the loop, only do abc, only 12bits --- src/current/rp2350/RP2350PIOCurrentSense.cpp | 51 ++++++++++---------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/current/rp2350/RP2350PIOCurrentSense.cpp b/src/current/rp2350/RP2350PIOCurrentSense.cpp index 0f6c0ab..8c53612 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.cpp +++ b/src/current/rp2350/RP2350PIOCurrentSense.cpp @@ -115,24 +115,6 @@ return 0; }; - static inline void extract_bit_interleaved(const uint32_t w0, const uint32_t w1, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) { - *a = 0; - *b = 0; - *c = 0; - *d = 0; - for (int i = 0; i < 64; i += 4) { - uint32_t w = (i < 32) ? w0 : w1; - int shift = 28 - (i % 32); // 28, 24, ..., 0 for each group of 4 bits - - uint32_t group = (w >> shift) & 0xF; // extract aN bN cN dN - - *a = (*a << 1) | ((group >> 0) & 0x1); - *b = (*b << 1) | ((group >> 1) & 0x1); - *c = (*c << 1) | ((group >> 2) & 0x1); - *d = (*d << 1) | ((group >> 3) & 0x1); - } - } - PhaseCurrent_s RP2350PIOCurrentSense::getPhaseCurrents() { PhaseCurrent_s current; @@ -141,16 +123,35 @@ const uint32_t i_dma = (dma_hw->ch[dma_a].write_addr - base)>>2; //For a safe read, get the one that is an even number and at least <2.wi, manage looping const uint32_t i_last = (i_dma <= 1) ? RING_WORDS -2 : ((i_dma / 2)*2 - 2); - //copy them quickly (before print!) + //copy them quickly (before any print!) const uint32_t w0 = buff[i_last]; const uint32_t w1 = buff[i_last+1]; - //Reconstruct the 3 current from interleaved data - uint32_t a,b,c,d = 0; - extract_bit_interleaved(w0,w1, &a, &b, &c, &d); - current.a = (0x00000fff & a) * gain_a; - current.b = (0x00000fff & b) * gain_b; - current.c = (0x00000fff & c) * gain_c; + //Reconstruct the 3 current from interleaved data + uint32_t a,b,c = 0; + uint32_t g; + + //g = (w0 >> 28) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u); d = (d<<1)|((g>>3)&1u); + //g = (w0 >> 24) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u); d = (d<<1)|((g>>3)&1u); + //g = (w0 >> 20) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u); d = (d<<1)|((g>>3)&1u); + //g = (w0 >> 16) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u); d = (d<<1)|((g>>3)&1u); + g = (w0 >> 12) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u);// d = (d<<1)|((g>>3)&1u); + g = (w0 >> 8) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u);// d = (d<<1)|((g>>3)&1u); + g = (w0 >> 4) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u);// d = (d<<1)|((g>>3)&1u); + g = (w0 >> 0) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u);// d = (d<<1)|((g>>3)&1u); + + g = (w1 >> 28) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u);// d = (d<<1)|((g>>3)&1u); + g = (w1 >> 24) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u);// d = (d<<1)|((g>>3)&1u); + g = (w1 >> 20) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u);// d = (d<<1)|((g>>3)&1u); + g = (w1 >> 16) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u);// d = (d<<1)|((g>>3)&1u); + g = (w1 >> 12) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u);// d = (d<<1)|((g>>3)&1u); + g = (w1 >> 8) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u);// d = (d<<1)|((g>>3)&1u); + g = (w1 >> 4) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u);// d = (d<<1)|((g>>3)&1u); + g = (w1 >> 0) & 0xFu; a = (a<<1)|((g>>0)&1u); b = (b<<1)|((g>>1)&1u); c = (c<<1)|((g>>2)&1u);// d = (d<<1)|((g>>3)&1u); + + current.a = a * gain_a; + current.b = b * gain_b; + current.c = c * gain_c; return current; }; From 2d8b529ffc83d00177d9404ffeff7d01aae738ab Mon Sep 17 00:00:00 2001 From: Thomas Flayols Date: Mon, 8 Sep 2025 11:38:28 +0200 Subject: [PATCH 09/11] Document the internal design in readme --- src/current/rp2350/README.md | 63 +++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/src/current/rp2350/README.md b/src/current/rp2350/README.md index 42e550f..2cdc6f9 100644 --- a/src/current/rp2350/README.md +++ b/src/current/rp2350/README.md @@ -14,10 +14,8 @@ Temporarly, for this to work, we need to add a PWM chanell in Arduino-FOC rp2040 TODO: -* Init a the DMA or IRQ to read samples from PIO. -* Activate the push of adc data in PIO program (disabled for tests) * Find a way to setup the trigger PWM from the driver, or change the arduino-foc lib. - +* Select an available PIO and state machine automaticaly. # Example: @@ -58,6 +56,8 @@ void setup() { void loop() { motor.move(target_velocity); + PhaseCurrent_s phaseCurrents = curr.getPhaseCurrents(); + Serial.printf("%d, %3.3lf, %3.3lf, %3.3lf\r\n", micros(), phaseCurrents.a, phaseCurrents.b, phaseCurrents.c); } ``` @@ -69,4 +69,59 @@ Note for self, on my setup: ``` export PIOASM="$HOME/.arduino15/packages/rp2040/tools/pqt-pioasm/4.1.0-1aec55e/pioasm" "$PIOASM" -v 1 bu79100g_parallel3.pio bu79100g_parallel3.pio.h -``` \ No newline at end of file +``` + +# Internal Design + +This library uses: +- One PIO state machine +- Two DMA channels +- One PWM (and associated GPIO) + + +## Trigger Pin + +For low-side current measurement, the ADC must sample at the center of the low pulse of the phase PWM signals. +To achieve this, a *trigger pin* is configured as an auxiliary PWM output, synchronized with the motor PWM but with a fixed duty cycle. + +- This PWM can be mapped to any pin. +- It does **not** need to be connected to external hardware. +- The duty cycle is tuned to compensate for the dummy sampling enforced by the BU79100G-LA ADC. + +In the future, this trigger mechanism could also be used to synchronize other types of ADCs. + +**Note (TODO/WIP):** Trigger pin handling is not yet implemented in the driver. Proper synchronization during driver initialization still needs to be added. + + +## PIO + +The PIO waits for a rising edge on the trigger pin to start two SPI transfers: +1. A **dummy conversion** (required by the BU79100G-LA when operating at low frequency). +2. The **actual ADC conversion**. + +Data is captured from 3 SPI data lines in parallel. A 4th line is also sampled but discarded; it can be freely repurposed as a normal GPIO (input or output). + +The PIO writes results to its FIFO as two interleaved 32-bit words in the format: [a1 b1 c1 d1 a2 b2 c2 d2 .... ] + +## DMA + +Two DMA channels are configured to move data from the PIO FIFO into system memory: + +- **dma_a** transfers incoming 32-bit words into a ring buffer. + - The buffer size must be a power of two. + - The buffer address must be aligned with its total size. + +- **dma_b** is chained to **dma_a**. It resets the transfer count of **dma_a** by performing a single 32-bit transfer. +- **dma_a** is then chained back to **dma_b**, creating a self-sustaining loop without CPU intervention. + + +## CPU Access to Samples + +The CPU can asynchronously access the most recent samples by reading the current DMA write address. + +- If the address is **even**, read samples at positions *n-2* and *n-1*. +- If the address is **odd**, read samples at positions *n-3* and *n-2*. +- Address wraparound is handled. + +Since the PIO delivers interleaved data, the CPU must de-interleave it. On an RP2350, de-interleaving and copying takes approximately **1 µs** per sample set. + From ff1108cdfdf27f8d81278d2c963c239a6ac7f66c Mon Sep 17 00:00:00 2001 From: Thomas Flayols Date: Thu, 11 Sep 2025 15:31:51 +0200 Subject: [PATCH 10/11] Make pio number a settable parameter, so we can have multiple motor using the same PIO with different state machine, ans also be compatible with other library that uses other PIOs (encoder for example) --- src/current/rp2350/RP2350PIOCurrentSense.cpp | 22 ++++++++++---------- src/current/rp2350/RP2350PIOCurrentSense.h | 8 +++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/current/rp2350/RP2350PIOCurrentSense.cpp b/src/current/rp2350/RP2350PIOCurrentSense.cpp index 8c53612..092f38f 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.cpp +++ b/src/current/rp2350/RP2350PIOCurrentSense.cpp @@ -1,6 +1,7 @@ #include "RP2350PIOCurrentSense.h" - RP2350PIOCurrentSense::RP2350PIOCurrentSense(float gain, uint32_t max_adc_value, int pinSCK, int pinCSB, int pinD0, int pinTRIG) : CurrentSense() { + RP2350PIOCurrentSense::RP2350PIOCurrentSense(PIO pio, float gain, uint32_t max_adc_value, int pinSCK, int pinCSB, int pinD0, int pinTRIG) : CurrentSense() { + this->pio = pio; this->pinSCK = pinSCK; this->pinCSB = pinCSB; this->pinD0 = pinD0; @@ -28,12 +29,11 @@ // TODO init timer to trigger PIO conversions at required frequency (check driver settings) // TDB: do we need config input to know which timer slice and channel to use? or can we pick automatically? // TODO start everything up - + // TODO implement offset and calibration like other current sensor classes. float sck_hz = 20e6; - PIO pio = pio0; - int sm = pio_claim_unused_sm(pio0, true); + int sm = pio_claim_unused_sm(this->pio, true); //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 - + // --- patch program instructions with chosen trigger pin --- size_t prog_len = bu79100g_parallel3_program.length; uint16_t insns[prog_len]; @@ -43,7 +43,7 @@ struct pio_program prog = bu79100g_parallel3_program; // copy metadata prog.instructions = insns; - uint off = pio_add_program(pio, &prog); + uint off = pio_add_program(this->pio, &prog); pio_sm_config c = bu79100g_parallel3_program_get_default_config(off); // Map pins to the SM @@ -52,11 +52,11 @@ sm_config_set_sideset_pins(&c, this->pinSCK); // SCK (sideset) // Put pins into PIO control - pio_gpio_init(pio, this->pinSCK); - pio_gpio_init(pio, this->pinCSB); - pio_gpio_init(pio, this->pinD0); - pio_gpio_init(pio, this->pinD1); - pio_gpio_init(pio, this->pinD2); + pio_gpio_init(this->pio, this->pinSCK); + pio_gpio_init(this->pio, this->pinCSB); + pio_gpio_init(this->pio, this->pinD0); + pio_gpio_init(this->pio, this->pinD1); + pio_gpio_init(this->pio, this->pinD2); // Directions (from the SM’s point of view) pio_sm_set_consecutive_pindirs(pio, sm, this->pinSCK, 1, true); // SCK out diff --git a/src/current/rp2350/RP2350PIOCurrentSense.h b/src/current/rp2350/RP2350PIOCurrentSense.h index 0100172..ee7aed7 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.h +++ b/src/current/rp2350/RP2350PIOCurrentSense.h @@ -8,7 +8,7 @@ class RP2350PIOCurrentSense: public CurrentSense { public: - RP2350PIOCurrentSense(float gain, uint32_t max_adc_value, int pinSCK, int pinCSB, int pinD0, int pinTRIG); + RP2350PIOCurrentSense(PIO pio, float gain, uint32_t max_adc_value, int pinSCK, int pinCSB, int pinD0, int pinTRIG); ~RP2350PIOCurrentSense(); int init() override; @@ -27,6 +27,8 @@ class RP2350PIOCurrentSense: public CurrentSense { int dma_a = -1; // PIO RX -> ring (streamer) int dma_b = -1; // reloader + PIO pio; + uint32_t max_adc_value; //!< maximum ADC value (e.g. 4096 for 12 bit ADC) int pinCSB; int pinSCK; @@ -34,8 +36,6 @@ class RP2350PIOCurrentSense: public CurrentSense { int pinD1; int pinD2; int pinTRIG; - float gain_a; - float gain_b; - float gain_c; + protected: //For debug, all public }; From 488eff6b2a90e21f929f892ca6c874c93ae51f45 Mon Sep 17 00:00:00 2001 From: Thomas Flayols Date: Thu, 11 Sep 2025 16:32:18 +0200 Subject: [PATCH 11/11] #if defined(ARDUINO_ARCH_RP2040) --- src/current/rp2350/RP2350PIOCurrentSense.cpp | 4 ++-- src/current/rp2350/RP2350PIOCurrentSense.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/current/rp2350/RP2350PIOCurrentSense.cpp b/src/current/rp2350/RP2350PIOCurrentSense.cpp index 092f38f..8c7a7d7 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.cpp +++ b/src/current/rp2350/RP2350PIOCurrentSense.cpp @@ -1,5 +1,5 @@ #include "RP2350PIOCurrentSense.h" - + #if defined(ARDUINO_ARCH_RP2040) RP2350PIOCurrentSense::RP2350PIOCurrentSense(PIO pio, float gain, uint32_t max_adc_value, int pinSCK, int pinCSB, int pinD0, int pinTRIG) : CurrentSense() { this->pio = pio; this->pinSCK = pinSCK; @@ -155,6 +155,6 @@ return current; }; - + #endif diff --git a/src/current/rp2350/RP2350PIOCurrentSense.h b/src/current/rp2350/RP2350PIOCurrentSense.h index ee7aed7..1b31eeb 100644 --- a/src/current/rp2350/RP2350PIOCurrentSense.h +++ b/src/current/rp2350/RP2350PIOCurrentSense.h @@ -1,6 +1,6 @@ #pragma once - +#if defined(ARDUINO_ARCH_RP2040) #include "common/base_classes/CurrentSense.h" #include "bu79100g_parallel3.pio.h" #include "hardware/dma.h" @@ -39,3 +39,4 @@ class RP2350PIOCurrentSense: public CurrentSense { protected: //For debug, all public }; +#endif \ No newline at end of file