|
| 1 | +--- |
| 2 | +layout: default |
| 3 | +title: Regular ADC reads during FOC |
| 4 | +nav_order: 6 |
| 5 | +description: "Reading extra analog signals while low-side current sensing is running." |
| 6 | +permalink: /regular_adc_read |
| 7 | +parent: Practical guides |
| 8 | +grand_parent: Arduino <span class="simple">Simple<span class="foc">FOC</span>library</span> |
| 9 | +toc: true |
| 10 | +--- |
| 11 | + |
| 12 | +# Regular ADC reads during FOC |
| 13 | + |
| 14 | +Sometimes you want to read extra analog signals (bus voltage, temperature, potentiometers, etc.) while the motor is running with **low‑side current sensing**. On some MCUs, `analogRead()` can interfere with the ADC configuration used for current sensing, or it can be too slow and add jitter. The library provides MCU‑specific helpers that are safe to use during FOC. |
| 15 | + |
| 16 | +## STM32: `_readRegularADCVoltage()` |
| 17 | + |
| 18 | +On STM32, low‑side current sensing uses **injected ADC conversions**. Injected conversions have hardware priority and will pre‑empt regular conversions. The library exposes a helper that performs a **one‑shot regular conversion** while injected conversions are running: |
| 19 | + |
| 20 | +- Implemented as `_readRegularADCVoltage(const int pin)` in the STM32 backend. |
| 21 | +- If low‑side current sensing is already running, the ADC is already configured and this function reuses it. |
| 22 | +- If the pin belongs to another ADC, it initializes it for regular reads. |
| 23 | +- The function retries if the ADC is busy and returns **voltage in volts**. |
| 24 | + |
| 25 | +**Why `analogRead()` is a bad idea on STM32 during FOC** |
| 26 | + |
| 27 | +`analogRead()` can reconfigure the ADC each call and does not account for injected conversions. That can **break the current‑sensing configuration**, add latency, and introduce jitter in the control loop. The STM32 helper is still slower than injected reads (typically >10µs) but **much faster and safer than `analogRead()`**. |
| 28 | + |
| 29 | +**Example (STM32, low‑side current sensing already running)** |
| 30 | + |
| 31 | +```cpp |
| 32 | +#include <SimpleFOC.h> |
| 33 | +#include "current_sense/hardware_specific/stm32/stm32_mcu.h" |
| 34 | + |
| 35 | +// ... motor + driver setup omitted for brevity |
| 36 | +LowSideCurrentSense current_sense = LowSideCurrentSense(0.01f, 50.0f, A0, A1, A2); |
| 37 | + |
| 38 | +void setup() { |
| 39 | + // driver + motor init ... |
| 40 | + current_sense.init(); |
| 41 | + current_sense.linkDriver(&driver); |
| 42 | +} |
| 43 | + |
| 44 | +void loop() { |
| 45 | + motor.loopFOC(); |
| 46 | + motor.move(target); |
| 47 | + |
| 48 | + // Read an auxiliary ADC pin while low-side current sensing is active |
| 49 | + float vbus = _readRegularADCVoltage(A3); |
| 50 | + // use vbus... |
| 51 | + } |
| 52 | +``` |
| 53 | +
|
| 54 | +**Notes** |
| 55 | +- Use a pin that belongs to the same ADC as your current‑sense pins whenever possible. |
| 56 | +- If the pin belongs to another ADC, the helper will initialize it for regular reads. |
| 57 | +- The first time you call the helper for a new ADC it will be slower due to initialization, but subsequent calls will be faster. |
| 58 | +- Call this helper only when necessary (e.g., once per control loop) to avoid excessive overhead. |
| 59 | +
|
| 60 | +## ESP32: `adcRead()` |
| 61 | +
|
| 62 | +On ESP32, the library provides `adcRead(pin)` for fast ADC access using direct register reads. It is placed in IRAM and is designed to be safe inside fast control loops. This is the preferred way to read extra analog signals while current sensing is active. |
| 63 | +
|
| 64 | +**Why `analogRead()` is a bad idea on ESP32 during FOC** |
| 65 | +
|
| 66 | +`analogRead()` is slower and can add overhead or modify ADC configuration (attenuation, resolution). The library’s `adcRead()` keeps the conversion path fast and deterministic. |
| 67 | +
|
| 68 | +**Example (ESP32)** |
| 69 | +
|
| 70 | +```cpp |
| 71 | +#include <SimpleFOC.h> |
| 72 | +#include "current_sense/hardware_specific/esp32/esp32_adc_driver.h" |
| 73 | +
|
| 74 | +const int vbusPin = 34; // ADC pin |
| 75 | +
|
| 76 | +void setup() { |
| 77 | + adcInit(vbusPin); // configure ADC (attenuation + resolution) |
| 78 | +} |
| 79 | +
|
| 80 | +void loop() { |
| 81 | + // ... FOC loop |
| 82 | + uint16_t raw = adcRead(vbusPin); // 0–4095 |
| 83 | + float vbus = raw * (3.3f / 4096.0f); |
| 84 | + // use vbus... |
| 85 | +} |
| 86 | +``` |
| 87 | + |
| 88 | +**Notes** |
| 89 | +- Call `adcInit(pin)` once (e.g., in `setup()`), then use `adcRead(pin)` in the loop. |
| 90 | +- Call this function as little as possible (e.g., every 10–100ms) to avoid unnecessary overhead in the control loop. |
0 commit comments