VesiScan BASIC origin: Piezo + IMU firmware initial code

- nRF52840 + SoftDevice S140 BLE firmware
- Piezo ultrasound TX driver (2MHz, 8ch MUX)
- ICM42670P IMU 6-axis driver
- Echo AFE chain (ADA2200 + ADC121S051)
- BLE NUS command parser (mpa/mpc/mdc/mec/maa/msp)
- FDS flash config storage
- pc_firm parser and ADC driver included

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Charles Kwon
2026-03-11 10:40:20 +09:00
parent a8ba31871e
commit b3adfd42e6
49 changed files with 8459 additions and 2887 deletions

View File

@@ -0,0 +1,505 @@
/*******************************************************************************
* @file dr_adc121s051.h
* @brief ADC121S051 12-bit ADC Driver for nRF52840
* For 1.2MHz Piezo Echo Envelope Detection
* @author Charles KWON
* @date 2025-12-15
*
* @details This driver reads the envelope-detected DC level from piezo echo.
*
* Signal Flow:
*
* [Piezo TX] [Echo RX] [Envelope] [ADC] [MCU]
* 1.2MHz --> Reflect --> Detector --> DC Level --> Digital
* burst signal (hardware) reading value
*
* The envelope detector circuit converts the 1.2MHz echo burst
* into a DC voltage proportional to the echo amplitude.
* ADC samples this DC level for amplitude measurement.
*
* @note Hardware: Texas Instruments ADC121S051
* - 12-bit resolution (0-4095)
* - Sample rate: 200-500 ksps
* - Input range: 0V to VA
* - SPI interface (software bit-bang)
******************************************************************************/
#ifndef DR_ADC121S051_H
#define DR_ADC121S051_H
#include <stdint.h>
#include <stdbool.h>
#include "nrf_gpio.h"
/*==============================================================================
* PIN CONFIGURATION
*
* WARNING: Never hardcode pin numbers!
* Hardcoding may save a developer's time momentarily,
* but it will also shorten their lifespan.
*============================================================================*/
#define DR_ADC_PIN_SCLK NRF_GPIO_PIN_MAP(0, 14) /**< Serial Clock */
#define DR_ADC_PIN_SDATA NRF_GPIO_PIN_MAP(0, 15) /**< Serial Data (MISO) */
#define DR_ADC_PIN_CS NRF_GPIO_PIN_MAP(0, 19) /**< Chip Select P0.13 -> P0.19 */
/*==============================================================================
* ADC SPECIFICATIONS
*============================================================================*/
#define DR_ADC_RESOLUTION 12 /**< Bits */
#define DR_ADC_MAX_VALUE 4095 /**< 2^12 - 1 */
#define DR_ADC_VREF_MV 3300 /**< Reference voltage (mV) */
/*==============================================================================
* ECHO DETECTION CONFIGURATION
*
* Bladder Measurement Requirements:
* - Target measurement range: 20cm (200mm)
* - SCLK frequency: 8.6MHz (bit-bang SPI)
* - ADC121S051 requires 16 SCLK cycles per sample
* - Actual sample rate: 8.6MHz / 16 = 0.5375MHz = 537.5kHz
* - Actual sample interval: 16 / 8.6MHz = 1.86us
* - Sound speed in tissue: 1540m/s = 1.54mm/us
*
* Formula: samples = distance(mm) * 2 / (1.86us * 1.54mm/us)
* = distance(mm) * 2 / 2.86
* = distance(mm) * 0.7
*
* 10cm = 100mm -> 100 * 0.7 = 70 samples (round-trip 130us)
* 17cm = 170mm -> 170 * 0.7 = 119 samples (round-trip 221us)
* 20cm = 200mm -> 200 * 0.7 = 140 samples (round-trip 260us)
*
* Buffer size: 200 samples * 2 bytes = 400 bytes (RAM 256KB, OK)
* BLE transmission: 140 samples * 2 bytes = 280 bytes (16-bit raw, no packing)
*============================================================================*/
#define DR_ADC_SCLK_MHZ 8.6f /**< SPI bit-bang SCLK frequency */
#define DR_ADC_CLOCKS_PER_SAMPLE 16 /**< ADC121S051: 16 SCLK per sample */
#define DR_ADC_ECHO_SAMPLES_MAX 100 /**< Maximum samples */
#define DR_ADC_ECHO_SAMPLES_DEFAULT 100 /**< Default samples */
#define DR_ADC_SAMPLE_INTERVAL_US 1.86f /**< 16 / 8.6MHz = 1.86us per sample */
#define DR_ADC_SOUND_SPEED_MM_US 1.54f /**< Sound speed in tissue (mm/us) */
/*==============================================================================
* ERROR CODES
*============================================================================*/
typedef enum {
DR_ADC_OK = 0,
DR_ADC_ERR_NOT_INIT,
DR_ADC_ERR_INVALID_PARAM,
DR_ADC_ERR_NO_ECHO
} dr_adc_err_t;
/*==============================================================================
* DATA STRUCTURES
*============================================================================*/
/**
* @brief Single ADC reading result
*/
typedef struct {
uint16_t raw; /**< Raw 12-bit value (0-4095) */
uint32_t voltage_mv; /**< Voltage in millivolts */
} dr_adc_result_t;
/**
* @brief Echo measurement result
*/
typedef struct {
uint16_t peak_raw; /**< Peak amplitude (raw) */
uint32_t peak_mv; /**< Peak amplitude (mV) */
uint16_t peak_index; /**< Sample index of peak */
uint32_t peak_time_us; /**< Time to peak (us) */
uint16_t baseline_raw; /**< Baseline level before echo */
uint16_t num_samples; /**< Number of samples captured */
} dr_adc_echo_t;
/**
* @brief Echo capture configuration
*/
typedef struct {
uint16_t num_samples; /**< Samples to capture (1-200) */
uint16_t threshold_raw; /**< Minimum peak threshold */
uint16_t delay_us; /**< Delay before capture starts */
} dr_adc_echo_config_t;
/*==============================================================================
* INITIALIZATION
*============================================================================*/
/**
* @brief Initialize ADC driver
* @return dr_adc_err_t Error code
*/
dr_adc_err_t dr_adc_init(void);
/**
* @brief Uninitialize ADC driver
*/
void dr_adc_uninit(void);
/**
* @brief Check if initialized
*/
bool dr_adc_is_initialized(void);
/*==============================================================================
* BASIC READ FUNCTIONS
*============================================================================*/
/**
* @brief Read single ADC value
* @param result Pointer to result structure
* @return dr_adc_err_t Error code
*/
dr_adc_err_t dr_adc_read(dr_adc_result_t *result);
/**
* @brief Read raw 12-bit value only
* @param raw_value Pointer to store value
* @return dr_adc_err_t Error code
*/
dr_adc_err_t dr_adc_read_raw(uint16_t *raw_value);
/**
* @brief Read averaged value
* @param result Pointer to result structure
* @param num_samples Number of samples to average (1-256)
* @return dr_adc_err_t Error code
*/
dr_adc_err_t dr_adc_read_averaged(dr_adc_result_t *result, uint16_t num_samples);
/*==============================================================================
* ECHO DETECTION FUNCTIONS
*============================================================================*/
/**
* @brief Capture echo envelope after piezo burst
* @param buffer Array to store samples (must be pre-allocated)
* @param num_samples Number of samples to capture
* @return dr_adc_err_t Error code
*
* @note Call this immediately after dr_piezo_burst_sw()
*/
dr_adc_err_t dr_adc_capture_echo(uint16_t *buffer, uint16_t num_samples);
/**
* @brief Capture and analyze echo in one call
* @param echo Pointer to echo result structure
* @param config Pointer to capture configuration (NULL for defaults)
* @return dr_adc_err_t Error code
*/
dr_adc_err_t dr_adc_measure_echo(dr_adc_echo_t *echo, const dr_adc_echo_config_t *config);
/**
* @brief Piezo burst + Echo capture in one call
* @param cycles Number of burst cycles (3~9)
* @param delay_us Delay before capture (us)
* @param num_samples Number of samples to capture
* @param echo Pointer to echo result structure
* @return dr_adc_err_t Error code
*/
dr_adc_err_t dr_adc_burst_and_capture(uint8_t cycles, uint16_t delay_us,
uint16_t num_samples, dr_adc_echo_t *echo);
/**
* @brief Get pointer to last captured echo buffer
* @return Pointer to internal buffer (valid until next capture)
* @note Buffer contains num_samples values from last burst_and_capture call
*/
const uint16_t* dr_adc_get_echo_buffer(void);
/**
* @brief Analyze captured echo buffer
* @param buffer Sample buffer
* @param num_samples Number of samples in buffer
* @param echo Pointer to echo result structure
* @param threshold Minimum threshold for valid peak
* @return dr_adc_err_t Error code
*/
dr_adc_err_t dr_adc_analyze_echo(const uint16_t *buffer, uint16_t num_samples,
dr_adc_echo_t *echo, uint16_t threshold);
/**
* @brief Find peak in buffer
* @param buffer Sample buffer
* @param num_samples Number of samples
* @param peak_value Pointer to store peak value
* @param peak_index Pointer to store peak index (can be NULL)
*/
void dr_adc_find_peak(const uint16_t *buffer, uint16_t num_samples,
uint16_t *peak_value, uint16_t *peak_index);
/**
* @brief Calculate baseline (average of first N samples)
* @param buffer Sample buffer
* @param num_samples Number of samples to average for baseline
* @return Baseline value
*/
uint16_t dr_adc_calc_baseline(const uint16_t *buffer, uint16_t num_samples);
/*==============================================================================
* UTILITY FUNCTIONS
*============================================================================*/
/**
* @brief Convert raw value to millivolts
* @param raw_value Raw 12-bit value
* @return Voltage in millivolts
*/
uint32_t dr_adc_raw_to_mv(uint16_t raw_value);
/**
* @brief Set reference voltage
* @param vref_mv Reference voltage in millivolts
*/
void dr_adc_set_vref(uint32_t vref_mv);
/**
* @brief Get reference voltage
* @return Reference voltage in millivolts
*/
uint32_t dr_adc_get_vref(void);
/*==============================================================================
* DEBUG FUNCTIONS
*============================================================================*/
/**
* @brief Test ADC communication
* @return true if OK
*/
bool dr_adc_test(void);
/**
* @brief Print echo buffer to debug output
* @param buffer Sample buffer
* @param num_samples Number of samples
*/
void dr_adc_print_buffer(const uint16_t *buffer, uint16_t num_samples);
/*==============================================================================
* POWER CONTROL
*============================================================================*/
/*==============================================================================
* BLE TRANSMISSION CALLBACK
*============================================================================*/
/*==============================================================================
* INTEGRATED BURST + CAPTURE + TRANSMIT
*============================================================================*/
/**
* @brief Piezo burst + ADC capture + BLE transmission (all-in-one)
*
* This function performs the complete measurement cycle internally:
* 1. Power on ADC
* 2. Select piezo channel (0~7)
* 3. Execute piezo burst (frequency based on freq_option)
* 4. Capture echo samples (after delay_us) - repeated 'averaging' times
* 5. Average the captured samples (firmware-level noise reduction)
* 6. Analyze peak/baseline
* 7. Transmit data via BLE with proper packet timing
*
* @param freq_option Frequency option: 0=1.8MHz (default), 1=2.1MHz, 2=2.0MHz, 3=1.7MHz
* @param delay_us Delay before capture (us), default 20
* @param num_samples Number of samples to capture (1~200)
* @param cycles Number of burst cycles (3~7), default 5
* @param averaging Number of measurements to average (1~1000), default 1
* @param piezo_ch Piezo channel to use (0~7), default 0
* @param ble_buffer Working buffer for BLE packets (must be >= 240 bytes)
* @return dr_adc_err_t Error code
*
* @note Must call dr_adc_register_ble_tx() before using this function
* @note BLE packets: reb: (header), red: (data), ree: (end)
* @note Higher averaging reduces noise but increases measurement time (~0.3ms per avg)
*/
dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_us,
uint16_t num_samples, uint8_t cycles,
uint16_t averaging, uint8_t piezo_ch,
uint8_t *ble_buffer, uint8_t skip_raa);
/**
* @brief Select piezo channel (0~7)
* @param channel Piezo channel number (0~7)
*
* @note Hardware-dependent: requires MUX or individual GPIO control
* Currently uses placeholder - implement based on actual hardware
*/
void dr_piezo_select_channel(uint8_t channel);
/*==============================================================================
* 4-CHANNEL CAPTURE (maa? command support)
*============================================================================*/
/**
* @brief 8-channel echo buffer for maa? command
* Memory: 140 samples × 2 bytes × 8 channels = 2,240 bytes
*/
#define MAA_NUM_CHANNELS 8 /* 4 -> 8 jhChun 26.02.12*/
#define MAA_SAMPLES_MAX 200
/**
* @brief Echo data for one channel
*/
typedef struct {
uint16_t samples[MAA_SAMPLES_MAX]; /**< Raw sample data */
uint16_t num_samples; /**< Actual sample count */
uint16_t peak_raw; /**< Peak amplitude */
uint16_t peak_index; /**< Peak sample index */
uint16_t baseline_raw; /**< Baseline level */
} dr_maa_channel_t;
/**
* @brief Capture echo from one channel (no BLE transmission)
*
* Captures averaged echo data for a single channel and stores
* in the provided channel buffer. Does NOT transmit via BLE.
*
* @param freq_option Frequency: 0=1.8MHz, 1=2.1MHz, 2=2.0MHz, 3=1.7MHz
* @param delay_us Delay before capture (us)
* @param num_samples Number of samples (1~200)
* @param cycles Burst cycles (3~7)
* @param averaging Number of averages (1~1000)
* @param piezo_ch Piezo channel (0~7)
* @param out_channel Output channel data structure
* @return dr_adc_err_t Error code
*/
dr_adc_err_t dr_adc_capture_channel_only(uint8_t freq_option, uint16_t delay_us,
uint16_t num_samples, uint8_t cycles,
uint16_t averaging, uint8_t piezo_ch,
dr_maa_channel_t *out_channel);
/**
* @brief Transmit captured channel data via BLE
*
* Sends previously captured channel data using reb:/red:/ree: protocol.
*
* @param ch_data Pointer to captured channel data
* @param ble_buffer Working buffer for BLE packets (>= 240 bytes)
* @return dr_adc_err_t Error code
*/
dr_adc_err_t dr_adc_transmit_channel(const dr_maa_channel_t *ch_data,
uint8_t *ble_buffer);
/*==============================================================================
* DELTA COMPRESSION (maa? mode=1)
*
* Format:
* Byte 0-1: First sample (16-bit, little endian)
* Byte 2+: Delta values (8-bit signed)
* If delta > 127 or < -127: escape (0x80) + 16-bit value
*
* Expected compression: ~50% (280 bytes -> ~140 bytes)
*============================================================================*/
#define DELTA_ESCAPE_BYTE 0x80 /**< Escape marker for out-of-range delta */
/**
* @brief Compress sample data using delta encoding
*
* @param samples Input sample array (16-bit values)
* @param num_samples Number of samples
* @param out_buffer Output buffer for compressed data
* @param out_size Output: number of bytes written
* @return dr_adc_err_t Error code
*/
dr_adc_err_t dr_adc_delta_compress(const uint16_t *samples, uint16_t num_samples,
uint8_t *out_buffer, uint16_t *out_size);
/**
* @brief Transmit captured channel data via BLE with delta compression
*
* Uses rdb:/rdd:/rde: protocol (delta variant of reb:/red:/ree:)
*
* @param ch_data Pointer to captured channel data
* @param ble_buffer Working buffer for BLE packets (>= 240 bytes)
* @return dr_adc_err_t Error code
*/
dr_adc_err_t dr_adc_transmit_channel_delta(const dr_maa_channel_t *ch_data,
uint8_t *ble_buffer);
/*==============================================================================
* ASYNC MAA - Non-blocking 8-channel capture
*
* Design: State machine driven by BLE TX complete events
* Flow:
* maa? cmd -> maa_async_start() -> capture CH0 -> TX reb: -> TX red: ...
* BLE_NUS_EVT_TX_RDY -> maa_async_continue() -> TX next packet or next channel
* All done -> TX raa: -> state=IDLE
*============================================================================*/
/** @brief MAA async state machine states */
typedef enum {
MAA_ASYNC_IDLE = 0, /**< Not active */
MAA_ASYNC_CAPTURING, /**< ADC capture in progress */
MAA_ASYNC_TX_HEADER, /**< Sending reb: header */
MAA_ASYNC_TX_DATA, /**< Sending red: data packets */
MAA_ASYNC_NEXT_CHANNEL, /**< Preparing next channel */
MAA_ASYNC_COMPLETE /**< Sending raa: and finishing */
} maa_async_state_t;
/** @brief MAA async context */
typedef struct {
maa_async_state_t state; /**< Current state */
uint8_t current_ch; /**< Current channel (0~7) */
uint8_t current_pkt; /**< Current packet index */
uint16_t data_offset; /**< Bytes sent so far for current channel */
uint8_t freq_option; /**< Frequency option */
uint16_t delay_us; /**< Capture delay */
uint16_t num_samples; /**< Samples per channel */
uint8_t cycles; /**< Burst cycles */
uint16_t averaging; /**< Averaging count */
uint8_t *ble_buffer; /**< Working buffer for BLE packets */
dr_maa_channel_t channels[MAA_NUM_CHANNELS]; /**< Captured data for each channel */
uint16_t total_packets; /**< Total packets for current channel */
uint16_t data_packets; /**< Data packets for current channel */
} maa_async_ctx_t;
/**
* @brief Start async MAA 8-channel capture
*
* Initiates the async state machine. Captures CH0 and begins transmission.
* Subsequent packets are sent when maa_async_on_tx_ready() is called.
*
* @param freq_option Frequency: 0=1.8MHz, 1=2.1MHz, 2=2.0MHz, 3=1.7MHz
* @param delay_us Capture delay (us)
* @param num_samples Samples per channel (1~200)
* @param cycles Burst cycles (3~9)
* @param averaging Averaging count (1~1000)
* @param ble_buffer Working buffer (>= 240 bytes)
* @return dr_adc_err_t DR_ADC_OK if started successfully
*/
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);
/**
* @brief Handle BLE TX ready event
*
* Called from BLE_NUS_EVT_TX_RDY handler. Sends next packet or
* transitions to next state.
*
* @return true if more work pending, false if complete or idle
*/
bool maa_async_on_tx_ready(void);
/**
* @brief Check if async MAA is active
* @return true if state != IDLE
*/
bool maa_async_is_busy(void);
/**
* @brief Get current async state (for debugging)
* @return Current state
*/
maa_async_state_t maa_async_get_state(void);
/**
* @brief Abort async MAA operation
*/
void maa_async_abort(void);
#endif /* DR_ADC121S051_H */