Bit-bang SPI(8MHz)에서 HW SPI(SPIM3, 16MHz)로 변경
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,9 @@
|
||||
* @author Charles KWON
|
||||
* @date 2025-12-15
|
||||
*
|
||||
* @details Software SPI (bit-bang) implementation for ADC121S051.
|
||||
* @details Hardware SPI (nrfx_spim, SPIM2) implementation for ADC121S051.
|
||||
* Replaces bit-bang SPI to eliminate __disable_irq() and prevent
|
||||
* SoftDevice assertion failures during BLE connection events.
|
||||
* Optimized for reading envelope-detected echo signals.
|
||||
*
|
||||
* ADC121S051 Serial Interface:
|
||||
@@ -32,6 +34,8 @@
|
||||
|
||||
#include "dr_adc121s051.h"
|
||||
#include "dr_util.h"
|
||||
#include "nrfx_spim.h"
|
||||
#include "nrf52840.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "nrf_delay.h"
|
||||
#include <string.h> /* memset */
|
||||
@@ -72,17 +76,6 @@ extern void dr_piezo_power_off(void);
|
||||
#define DR_PIN_NUM(pin) ((pin) & 0x1F)
|
||||
#define DR_PIN_PORT(pin) (((pin) >> 5) & 0x01)
|
||||
|
||||
/* SPI bit masks for direct register access */
|
||||
#define CS_MASK (1UL << DR_PIN_NUM(DR_ADC_PIN_CS))
|
||||
#define SCLK_MASK (1UL << DR_PIN_NUM(DR_ADC_PIN_SCLK))
|
||||
#define SDATA_MASK (1UL << DR_PIN_NUM(DR_ADC_PIN_SDATA))
|
||||
|
||||
/* Get port register based on pin */
|
||||
#define DR_GET_PORT(pin) (DR_PIN_PORT(pin) ? NRF_P1 : NRF_P0)
|
||||
|
||||
/* ADC timing constants */
|
||||
#define SCLK_CYCLES 16 /**< Clock cycles per conversion */
|
||||
|
||||
/*==============================================================================
|
||||
* PRIVATE VARIABLES
|
||||
*============================================================================*/
|
||||
@@ -90,247 +83,85 @@ extern void dr_piezo_power_off(void);
|
||||
static bool m_initialized = false;
|
||||
static uint32_t m_vref_mv = DR_ADC_VREF_MV;
|
||||
|
||||
/* Hardware SPI instance (SPIM3 - supports up to 32MHz, 16MHz for ADC121S051) */
|
||||
static nrfx_spim_t m_spim = NRFX_SPIM_INSTANCE(3);
|
||||
|
||||
/* Echo capture buffer (module-level for external access) */
|
||||
static uint16_t m_echo_buffer[DR_ADC_ECHO_SAMPLES_MAX];
|
||||
|
||||
/* Port registers for fast access (currently unused - using direct NRF_P0) */
|
||||
/* static NRF_GPIO_Type *m_port_cs; */
|
||||
/* static NRF_GPIO_Type *m_port_sclk; */
|
||||
/* static NRF_GPIO_Type *m_port_sdata; */
|
||||
|
||||
/*==============================================================================
|
||||
* PRIVATE FUNCTION PROTOTYPES
|
||||
*============================================================================*/
|
||||
|
||||
static void adc_gpio_init(void);
|
||||
/* adc_transfer is always_inline, no prototype needed */
|
||||
|
||||
/*==============================================================================
|
||||
* INLINE GPIO FUNCTIONS (for speed)
|
||||
*============================================================================*/
|
||||
|
||||
/* cs_low() unused - using ADC_TRANSFER_16BITS macro with direct register access
|
||||
static inline void cs_low(void)
|
||||
{
|
||||
NRF_P0->OUTCLR = CS_MASK;
|
||||
}
|
||||
*/
|
||||
|
||||
static inline void cs_high(void)
|
||||
{
|
||||
NRF_P0->OUTSET = CS_MASK;
|
||||
}
|
||||
|
||||
/* sclk_low() unused - using direct register access in macro
|
||||
static inline void sclk_low(void)
|
||||
{
|
||||
NRF_P0->OUTCLR = SCLK_MASK;
|
||||
}
|
||||
*/
|
||||
|
||||
static inline void sclk_high(void)
|
||||
{
|
||||
NRF_P0->OUTSET = SCLK_MASK;
|
||||
}
|
||||
|
||||
/* read_sdata() unused - using direct register access in macro
|
||||
static inline uint32_t read_sdata(void)
|
||||
{
|
||||
return (NRF_P0->IN & SDATA_MASK) ? 1 : 0;
|
||||
}
|
||||
*/
|
||||
|
||||
/*==============================================================================
|
||||
* PRIVATE FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initialize GPIO pins for ADC
|
||||
* @brief Perform one ADC121S051 conversion via hardware SPI (SPIM2).
|
||||
* @return 12-bit ADC value (0–4095)
|
||||
*
|
||||
* @details ADC121S051 serial frame (16 bits, MSB first):
|
||||
* Bit 15-13: Leading zeros (Z2, Z1, Z0)
|
||||
* Bit 12-1: Data bits D11-D0
|
||||
* Bit 0: Don't care
|
||||
* Extract: (raw16 >> 1) & 0x0FFF
|
||||
*
|
||||
* SPI Mode 2 (CPOL=1, CPHA=0):
|
||||
* - SCLK idle HIGH
|
||||
* - Data valid on SCLK falling edge (sampled by SPIM on falling edge)
|
||||
* - CS falling edge starts ADC conversion
|
||||
*/
|
||||
static void adc_gpio_init(void)
|
||||
static uint16_t spim_read_raw(void)
|
||||
{
|
||||
/* Port pointers removed - using direct NRF_P0 access for speed */
|
||||
volatile uint8_t rx_buf[2] = {0, 0};
|
||||
NRF_SPIM_Type *spim = m_spim.p_reg;
|
||||
|
||||
/* CS: Output, HIGH (idle) */
|
||||
nrf_gpio_cfg_output(DR_ADC_PIN_CS);
|
||||
nrf_gpio_pin_set(DR_ADC_PIN_CS);
|
||||
nrf_gpio_pin_clear(DR_ADC_PIN_CS); /* CS LOW */
|
||||
spim->RXD.PTR = (uint32_t)rx_buf;
|
||||
spim->RXD.MAXCNT = 2;
|
||||
spim->EVENTS_END = 0;
|
||||
spim->TASKS_START = 1;
|
||||
while (!spim->EVENTS_END) {}
|
||||
nrf_gpio_pin_set(DR_ADC_PIN_CS); /* CS HIGH */
|
||||
|
||||
/* SCLK: Output, HIGH (idle) - per Figure 4 */
|
||||
nrf_gpio_cfg_output(DR_ADC_PIN_SCLK);
|
||||
nrf_gpio_pin_set(DR_ADC_PIN_SCLK);
|
||||
|
||||
/* SDATA: Input (ADC has push-pull output) */
|
||||
nrf_gpio_cfg_input(DR_ADC_PIN_SDATA, NRF_GPIO_PIN_NOPULL);
|
||||
|
||||
ADC_LOG("ADC GPIO: CS=P%d.%02d SCLK=P%d.%02d SDATA=P%d.%02d",
|
||||
DR_PIN_PORT(DR_ADC_PIN_CS), DR_PIN_NUM(DR_ADC_PIN_CS),
|
||||
DR_PIN_PORT(DR_ADC_PIN_SCLK), DR_PIN_NUM(DR_ADC_PIN_SCLK),
|
||||
DR_PIN_PORT(DR_ADC_PIN_SDATA), DR_PIN_NUM(DR_ADC_PIN_SDATA));
|
||||
uint16_t raw16 = ((uint16_t)rx_buf[0] << 8) | rx_buf[1];
|
||||
return (raw16 >> 1) & 0x0FFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform one ADC conversion (16 clock cycles)
|
||||
* @return Raw 16-bit data (includes leading zeros)
|
||||
*
|
||||
* @details Timing optimized for maximum speed (~500ksps).
|
||||
* At 64MHz CPU: 1 NOP = 15.625ns
|
||||
*
|
||||
* ADC specs (@ 3.3V):
|
||||
* - tACC (data access time): 40ns max
|
||||
* - tH (hold time): 7ns min
|
||||
* - fSCLK: 4-10 MHz
|
||||
*
|
||||
* MUST be inlined to eliminate function call overhead for consistent timing.
|
||||
*/
|
||||
/*
|
||||
* ADC_TRANSFER_BIT macro - one SCLK cycle for bit-bang SPI
|
||||
* Captures data on falling edge, processes on rising edge
|
||||
*
|
||||
* Target: 10MHz (100ns cycle) = 50ns LOW + 50ns HIGH
|
||||
* ADC121S051 timing requirements:
|
||||
* - tCL (SCLK low time): 40ns min
|
||||
* - tCH (SCLK high time): 40ns min
|
||||
* - tACC (data access): 40ns max (data valid after SCLK falling)
|
||||
*
|
||||
* LOW phase: OUTCLR(~15ns) + NOP(~16ns) + IN read(~30ns) = ~61ns (meets tCL, tACC)
|
||||
* HIGH phase: OUTSET(~15ns) + shift/OR(~40ns) = ~55ns (meets tCH)
|
||||
* Total: ~116ns (~8.6MHz)
|
||||
*
|
||||
* Note: Removing HIGH phase NOP to reduce cycle time
|
||||
*/
|
||||
#define ADC_TRANSFER_BIT(data, in_reg) \
|
||||
do { \
|
||||
NRF_P0->OUTCLR = SCLK_MASK; \
|
||||
__NOP(); \
|
||||
in_reg = NRF_P0->IN; \
|
||||
NRF_P0->OUTSET = SCLK_MASK; \
|
||||
data = (data << 1) | ((in_reg & SDATA_MASK) ? 1 : 0); \
|
||||
} while(0)
|
||||
|
||||
#define ADC_TRANSFER_BIT_LAST(data, in_reg) \
|
||||
do { \
|
||||
NRF_P0->OUTCLR = SCLK_MASK; \
|
||||
__NOP(); \
|
||||
in_reg = NRF_P0->IN; \
|
||||
NRF_P0->OUTSET = SCLK_MASK; \
|
||||
data = (data << 1) | ((in_reg & SDATA_MASK) ? 1 : 0); \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
* ADC_TRANSFER_16BITS macro - Complete 16-bit transfer
|
||||
* Use this instead of adc_transfer() function for consistent first bit timing.
|
||||
* Variables data and in_reg MUST be declared and initialized before calling.
|
||||
*
|
||||
* IMPORTANT: Call ADC_PREHEAT(data, in_reg) before cs_low() to warm up pipeline.
|
||||
*/
|
||||
#define ADC_TRANSFER_16BITS(data, in_reg) \
|
||||
do { \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 15 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 14 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 13 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 12 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 11 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 10 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 9 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 8 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 7 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 6 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 5 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 4 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 3 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 2 */ \
|
||||
ADC_TRANSFER_BIT(data, in_reg); /* Bit 1 */ \
|
||||
ADC_TRANSFER_BIT_LAST(data, in_reg); /* Bit 0 */ \
|
||||
NRF_P0->OUTSET = CS_MASK; \
|
||||
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); \
|
||||
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); \
|
||||
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); \
|
||||
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
* ADC_PREHEAT - Warm up instruction pipeline before timing-critical section
|
||||
* This prevents the first SCLK cycle from being longer than others.
|
||||
*
|
||||
* CRITICAL: Must perform ACTUAL SCLK toggle to prime the GPIO write path!
|
||||
* CS is still HIGH (idle), so this dummy toggle doesn't affect ADC.
|
||||
*
|
||||
* Sequence:
|
||||
* 1. Dummy SCLK LOW/HIGH cycle (exact same code as ADC_TRANSFER_BIT)
|
||||
* 2. SCLK remains HIGH (ready for cs_low)
|
||||
*/
|
||||
#define ADC_PREHEAT(data, in_reg) \
|
||||
do { \
|
||||
/* Dummy SCLK cycle - CS still HIGH, so ADC ignores this */ \
|
||||
/* Must match ADC_TRANSFER_BIT timing exactly */ \
|
||||
NRF_P0->OUTCLR = SCLK_MASK; \
|
||||
__NOP(); \
|
||||
in_reg = NRF_P0->IN; \
|
||||
NRF_P0->OUTSET = SCLK_MASK; \
|
||||
data = (data << 1) | ((in_reg & SDATA_MASK) ? 1 : 0); \
|
||||
/* Second dummy cycle for better pipeline warm-up */ \
|
||||
NRF_P0->OUTCLR = SCLK_MASK; \
|
||||
__NOP(); \
|
||||
in_reg = NRF_P0->IN; \
|
||||
NRF_P0->OUTSET = SCLK_MASK; \
|
||||
data = (data << 1) | ((in_reg & SDATA_MASK) ? 1 : 0); \
|
||||
/* Reset data after priming */ \
|
||||
data = 0; \
|
||||
} while(0)
|
||||
|
||||
/* adc_transfer() function replaced by ADC_TRANSFER_16BITS macro for speed
|
||||
* Kept here for reference but commented out to eliminate warning
|
||||
*/
|
||||
#if 0
|
||||
/**
|
||||
* @brief Perform one ADC conversion (16 clock cycles)
|
||||
* @param data Pre-initialized to 0 by caller
|
||||
* @param in_reg Pre-declared register variable by caller
|
||||
* @return Raw 16-bit data (includes leading zeros)
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline uint16_t adc_transfer(uint16_t data, register uint32_t in_reg)
|
||||
{
|
||||
/* Implementation moved to ADC_TRANSFER_16BITS macro */
|
||||
return data;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*==============================================================================
|
||||
* PUBLIC FUNCTIONS - INITIALIZATION
|
||||
*============================================================================*/
|
||||
|
||||
dr_adc_err_t dr_adc_init(void)
|
||||
{
|
||||
ADC_LOG("ADC121S051 init...");
|
||||
|
||||
/* Initialize GPIO */
|
||||
adc_gpio_init();
|
||||
|
||||
/* Ensure idle state (SCLK idle HIGH per Figure 4) */
|
||||
cs_high();
|
||||
sclk_high();
|
||||
|
||||
/* Wait for power stabilization */
|
||||
nrf_delay_us(10);
|
||||
nrfx_err_t err;
|
||||
|
||||
/* Dummy read to wake up and clear stale data */
|
||||
ADC_LOG("ADC121S051 init (HW SPI, SPIM3)...");
|
||||
|
||||
nrfx_spim_config_t config = NRFX_SPIM_DEFAULT_CONFIG;
|
||||
config.sck_pin = DR_ADC_PIN_SCLK; /* P0.14 */
|
||||
config.mosi_pin = NRFX_SPIM_PIN_NOT_USED;/* not used (read-only ADC) */
|
||||
config.miso_pin = DR_ADC_PIN_SDATA; /* P0.15 */
|
||||
config.ss_pin = DR_ADC_PIN_CS; /* P0.19 */
|
||||
config.frequency = NRF_SPIM_FREQ_16M;
|
||||
config.mode = NRF_SPIM_MODE_3; /* CPOL=1 (idle HIGH), CPHA=1 (sample on rising - ADC presents on falling, stable on rising) */
|
||||
config.bit_order = NRF_SPIM_BIT_ORDER_MSB_FIRST;
|
||||
config.ss_active_high = false; /* CS active LOW */
|
||||
|
||||
err = nrfx_spim_init(&m_spim, &config, NULL, NULL);
|
||||
ADC_LOG("SPIM3 init result: 0x%08X (%s)", err, (err == NRFX_SUCCESS) ? "OK" : "FAIL");
|
||||
if (err != NRFX_SUCCESS)
|
||||
{
|
||||
uint16_t dummy_data = 0;
|
||||
register uint32_t dummy_reg = 0;
|
||||
ADC_PREHEAT(dummy_data, dummy_reg);
|
||||
NRF_P0->OUTCLR = CS_MASK;
|
||||
__NOP(); __NOP(); __NOP(); __NOP(); /* tSU: CS setup time */
|
||||
ADC_TRANSFER_16BITS(dummy_data, dummy_reg);
|
||||
return DR_ADC_ERR_NOT_INIT;
|
||||
}
|
||||
|
||||
/* Quiet time between conversions */
|
||||
__NOP(); __NOP(); __NOP(); __NOP();
|
||||
|
||||
/* Wait for ADC power stabilization */
|
||||
nrf_delay_us(10);
|
||||
|
||||
/* Dummy read to wake up ADC and clear stale conversion data */
|
||||
(void)spim_read_raw();
|
||||
|
||||
m_initialized = true;
|
||||
|
||||
ADC_LOG("ADC121S051 ready (VREF=%dmV)", m_vref_mv);
|
||||
|
||||
|
||||
ADC_LOG("ADC121S051 ready (VREF=%dmV, HW SPI)", m_vref_mv);
|
||||
|
||||
return DR_ADC_OK;
|
||||
}
|
||||
|
||||
@@ -338,15 +169,10 @@ void dr_adc_uninit(void)
|
||||
{
|
||||
if (!m_initialized) return;
|
||||
|
||||
cs_high();
|
||||
sclk_high(); /* Idle HIGH per Figure 4 */
|
||||
|
||||
nrf_gpio_cfg_default(DR_ADC_PIN_CS);
|
||||
nrf_gpio_cfg_default(DR_ADC_PIN_SCLK);
|
||||
nrf_gpio_cfg_default(DR_ADC_PIN_SDATA);
|
||||
|
||||
nrfx_spim_uninit(&m_spim);
|
||||
|
||||
m_initialized = false;
|
||||
|
||||
|
||||
ADC_LOG("ADC121S051 uninitialized");
|
||||
}
|
||||
|
||||
@@ -364,40 +190,7 @@ dr_adc_err_t dr_adc_read_raw(uint16_t *raw_value)
|
||||
if (!m_initialized) return DR_ADC_ERR_NOT_INIT;
|
||||
if (raw_value == NULL) return DR_ADC_ERR_INVALID_PARAM;
|
||||
|
||||
uint16_t data = 0;
|
||||
register uint32_t in_reg = 0;
|
||||
|
||||
/* Critical section for precise timing */
|
||||
__disable_irq();
|
||||
|
||||
/* Preheat pipeline before timing-critical section */
|
||||
ADC_PREHEAT(data, in_reg);
|
||||
|
||||
/* CS LOW - starts conversion, samples VIN on this edge */
|
||||
NRF_P0->OUTCLR = CS_MASK;
|
||||
__NOP(); /* Match timing with other SCLK cycles */
|
||||
|
||||
/* Transfer 16 bits + CS HIGH (macro for consistent timing) */
|
||||
ADC_TRANSFER_16BITS(data, in_reg);
|
||||
|
||||
__enable_irq();
|
||||
|
||||
/*
|
||||
* Extract 12-bit data from 16-bit frame:
|
||||
* Bit 15-13: Leading zeros (Z2, Z1, Z0) - must be 0
|
||||
* Bit 12-1: Data bits (D11-D0)
|
||||
* Bit 0: Don't care (trailing)
|
||||
*
|
||||
* Result = (data >> 1) & 0x0FFF
|
||||
*/
|
||||
|
||||
/* Verify leading zeros (upper 3 bits should be 0) */
|
||||
if ((data & 0xE000) != 0)
|
||||
{
|
||||
ADC_LOG("ADC frame error: leading zeros invalid (0x%04X)", data);
|
||||
}
|
||||
|
||||
*raw_value = (data >> 1) & 0x0FFF;
|
||||
*raw_value = spim_read_raw();
|
||||
|
||||
return DR_ADC_OK;
|
||||
}
|
||||
@@ -444,37 +237,32 @@ dr_adc_err_t dr_adc_read_averaged(dr_adc_result_t *result, uint16_t num_samples)
|
||||
|
||||
dr_adc_err_t dr_adc_capture_echo(uint16_t *buffer, uint16_t num_samples)
|
||||
{
|
||||
volatile uint8_t rx_buf[2];
|
||||
uint32_t cs_mask = (1UL << DR_PIN_NUM(DR_ADC_PIN_CS));
|
||||
uint16_t raw16;
|
||||
uint16_t i;
|
||||
NRF_SPIM_Type *spim = m_spim.p_reg;
|
||||
|
||||
if (!m_initialized) return DR_ADC_ERR_NOT_INIT;
|
||||
if (buffer == NULL) return DR_ADC_ERR_INVALID_PARAM;
|
||||
if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX)
|
||||
return DR_ADC_ERR_INVALID_PARAM;
|
||||
|
||||
uint16_t data = 0;
|
||||
register uint32_t in_reg = 0;
|
||||
spim->RXD.MAXCNT = 2;
|
||||
|
||||
/* Disable interrupts for continuous high-speed capture */
|
||||
__disable_irq();
|
||||
|
||||
/* Preheat pipeline once before the loop */
|
||||
ADC_PREHEAT(data, in_reg);
|
||||
|
||||
for (uint16_t i = 0; i < num_samples; i++)
|
||||
for (i = 0; i < num_samples; i++)
|
||||
{
|
||||
data = 0; /* Reset for each sample */
|
||||
NRF_P0->OUTCLR = cs_mask;
|
||||
spim->RXD.PTR = (uint32_t)rx_buf;
|
||||
spim->EVENTS_END = 0;
|
||||
spim->TASKS_START = 1;
|
||||
while (!spim->EVENTS_END) {}
|
||||
NRF_P0->OUTSET = cs_mask;
|
||||
|
||||
/* CS LOW - starts conversion, samples VIN */
|
||||
NRF_P0->OUTCLR = CS_MASK;
|
||||
__NOP(); /* Match timing with other SCLK cycles */
|
||||
|
||||
/* Transfer 16 bits + CS HIGH (macro for consistent timing) */
|
||||
ADC_TRANSFER_16BITS(data, in_reg);
|
||||
|
||||
/* Store 12-bit value */
|
||||
buffer[i] = (data >> 1) & 0x0FFF;
|
||||
raw16 = ((uint16_t)rx_buf[0] << 8) | rx_buf[1];
|
||||
buffer[i] = (raw16 >> 1) & 0x0FFF;
|
||||
}
|
||||
|
||||
__enable_irq();
|
||||
|
||||
return DR_ADC_OK;
|
||||
}
|
||||
|
||||
@@ -1485,6 +1273,9 @@ dr_adc_err_t maa_async_start(uint8_t freq_option, uint16_t delay_us,
|
||||
uint16_t num_samples, uint8_t cycles,
|
||||
uint16_t averaging, uint8_t *ble_buffer)
|
||||
{
|
||||
dr_adc_err_t err;
|
||||
uint8_t ch;
|
||||
|
||||
if (g_maa_ctx.state != MAA_ASYNC_IDLE)
|
||||
{
|
||||
ADC_LOG("maa_async_start: busy");
|
||||
@@ -1510,16 +1301,25 @@ dr_adc_err_t maa_async_start(uint8_t freq_option, uint16_t delay_us,
|
||||
ADC_LOG("maa_async_start: freq=%u delay=%u samples=%u cycles=%u avg=%u",
|
||||
freq_option, delay_us, num_samples, g_maa_ctx.cycles, g_maa_ctx.averaging);
|
||||
|
||||
/* Capture CH0 */
|
||||
/* 전채널 캡처: BLE 전송 없이 6채널 전부 캡처 완료 후 TX 시작 */
|
||||
g_maa_ctx.state = MAA_ASYNC_CAPTURING;
|
||||
dr_adc_err_t err = maa_async_capture_channel(0);
|
||||
|
||||
if (err != DR_ADC_OK)
|
||||
for (ch = 0; ch < MAA_NUM_CHANNELS; ch++)
|
||||
{
|
||||
ADC_LOG("maa_async_start: CH0 capture failed (%d)", err);
|
||||
maa_async_send_completion(0xFFF0);
|
||||
return err;
|
||||
err = maa_async_capture_channel(ch);
|
||||
if (err != DR_ADC_OK)
|
||||
{
|
||||
//ADC_LOG("maa_async_start: CH%u capture failed (%d)", ch, err);
|
||||
if (g_plat.log) g_plat.log("[maa] maa_async_start: CH%u capture failed (%d)", ch, err);
|
||||
maa_async_send_completion(0xFFF0 | ch);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
//ADC_LOG("maa_async_start: all channels captured, starting TX");
|
||||
if (g_plat.log) g_plat.log("[maa] maa_async_start: all channels captured, starting TX");
|
||||
|
||||
/* 캡처 완료 → 피에조 전원 OFF (BLE 전송 중 불필요) */
|
||||
dr_piezo_power_off();
|
||||
g_maa_ctx.auto_powered = false; /* 이미 껐으므로 완료 후 중복 OFF 방지 */
|
||||
|
||||
/* Send CH0 header - this will trigger TX_RDY for subsequent packets */
|
||||
maa_async_send_header();
|
||||
@@ -1551,17 +1351,8 @@ bool maa_async_on_tx_ready(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Capture next channel */
|
||||
/* 이미 전채널 캡처됨, 바로 헤더 전송 */
|
||||
g_maa_ctx.state = MAA_ASYNC_CAPTURING;
|
||||
dr_adc_err_t err = maa_async_capture_channel(g_maa_ctx.current_ch);
|
||||
|
||||
if (err != DR_ADC_OK)
|
||||
{
|
||||
ADC_LOG("maa_async: CH%u capture failed", g_maa_ctx.current_ch);
|
||||
maa_async_send_completion(0xFFF0 | g_maa_ctx.current_ch);
|
||||
return false;
|
||||
}
|
||||
/* Send header for new channel */
|
||||
maa_async_send_header();
|
||||
}
|
||||
}
|
||||
@@ -1589,6 +1380,11 @@ bool maa_async_is_busy(void)
|
||||
return (g_maa_ctx.state != MAA_ASYNC_IDLE);
|
||||
}
|
||||
|
||||
void maa_async_set_pre_capture_all(bool on)
|
||||
{
|
||||
g_maa_ctx.pre_capture_all = on;
|
||||
}
|
||||
|
||||
maa_async_state_t maa_async_get_state(void)
|
||||
{
|
||||
return g_maa_ctx.state;
|
||||
@@ -1612,3 +1408,4 @@ void maa_async_set_on_complete(void (*cb)(void))
|
||||
g_maa_ctx.on_complete_cb = cb;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user