906 lines
32 KiB
C
906 lines
32 KiB
C
/*******************************************************************************
|
|
* @file meas_pd_48.c
|
|
* @brief M48 LED-PD measurement module for NIRS system
|
|
* @author Charles KWON <charleskwon@medithings.co.kr>
|
|
* @version V2.0.0
|
|
* @date 2025-12-31
|
|
*
|
|
* Copyright (c) 2025 Medithings Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This module implements the M48 (24/48 LED) measurement sequence for the
|
|
* NIRS bladder monitoring system. It handles sequential LED activation,
|
|
* ADC sampling via PPI-triggered SAADC, and data transmission over BLE.
|
|
*
|
|
* ============================================================================
|
|
* MEASUREMENT FLOW (mcj? command example - ADC_PD_MODE 2)
|
|
* ============================================================================
|
|
*
|
|
* 1. Command Reception (parser.c - Cmd_mcj):
|
|
* - BLE/UART receives "mcj?" command
|
|
* - Sets ADC_PD_MODE = 2 (Half 0-23, single shot)
|
|
* - Sets info4 = true (include batt, temp, IMU, pressure data)
|
|
* - Calls m48_adc_start_init() to begin measurement
|
|
*
|
|
* 2. Initialization (m48_adc_start_init):
|
|
* - Stops battery timer (to prevent ADC conflict)
|
|
* - Copies LED_list_m48_1h[24] -> CURRENT_list_m48[24]
|
|
* - Sets CURRENT_LED_NO = 24
|
|
* - Initializes I2C, SAADC, GPIOTE, PPI
|
|
* - Configures first LED (LED0) via CAT9532 I2C
|
|
* - Sets MCP4725 DAC value from led_pd_dac_v[0] (from EEPROM/AGC)
|
|
* - Starts ADC sampling
|
|
*
|
|
* 3. ADC Sampling Loop (m48_voltage_handler - called 24 times):
|
|
* For each LED[i] (i = 0 to 23):
|
|
* a) PPI triggers 32 SAADC samples on ADA2200 SYNCO rising edge
|
|
* b) When buffer full, m48_voltage_handler() interrupt fires:
|
|
* - Averages 32 samples -> m48_led_pd_data[i]
|
|
* - Turns off current LED
|
|
* - If more LEDs remain:
|
|
* * Increments m_pd_adc_cnt
|
|
* * Configures next LED via CAT9532
|
|
* * Sets DAC value for next LED
|
|
* * Calls m48_adc_start() for next measurement
|
|
* - If last LED done:
|
|
* * Calls m48_adc_end_final()
|
|
*
|
|
* 4. Finalization (m48_adc_end_final):
|
|
* - Disables PPI, GPIOTE, SAADC
|
|
* - Uninitializes peripherals
|
|
* - If info4 == true, reads:
|
|
* * Battery voltage (uint16_t)
|
|
* * Temperature (uint16_t)
|
|
* * IMU data (6 x uint16_t)
|
|
* * Pressure P1, P2 (2 x uint16_t)
|
|
* - Formats response with "rcj:" tag
|
|
* - Sends via BLE: [batt, temp, imu[6], p1, p2, led_data[24]]
|
|
* - Restarts battery timer
|
|
* - Clears processing flag
|
|
*
|
|
* ============================================================================
|
|
* RESPONSE DATA FORMAT (rcj: tag - 72 bytes total)
|
|
* ============================================================================
|
|
*
|
|
* Byte[0-3]: "rcj:" tag (4 bytes)
|
|
* Byte[4-5]: Battery voltage (uint16_t, big-endian)
|
|
* Byte[6-7]: Temperature (uint16_t, big-endian)
|
|
* Byte[8-19]: IMU data (6 x uint16_t = 12 bytes)
|
|
* Byte[20-21]: Pressure P1 (uint16_t)
|
|
* Byte[22-23]: Pressure P2 (uint16_t)
|
|
* Byte[24-71]: LED measurement data (24 x uint16_t = 48 bytes)
|
|
*
|
|
* ============================================================================
|
|
* Measurement Modes (ADC_PD_MODE):
|
|
* ============================================================================
|
|
* 0: Full 48 LED measurement (single shot)
|
|
* 1: Full 48 LED measurement (continuous)
|
|
* 2: Half measurement - LEDs 0-23 (single shot) - mcj? command
|
|
* 3: Half measurement - LEDs 0-23 (continuous)
|
|
* 4: Half measurement - LEDs 24-47 (single shot)
|
|
* 5: Half measurement - LEDs 24-47 (continuous)
|
|
*
|
|
* Hardware Dependencies:
|
|
* - ADA2200 Lock-in Amplifier (SYNCO pin P0.17 for PPI trigger)
|
|
* - MCP4725 DAC for PD gain control (I2C)
|
|
* - CAT9532 LED driver (I2C)
|
|
* - SAADC for differential ADC measurement (AIN0/AIN1)
|
|
* - EEPROM for storing AGC calibration values (addr 0x0480)
|
|
******************************************************************************/
|
|
|
|
#include "sdk_common.h"
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "nrf.h"
|
|
#include "boards.h"
|
|
#include "app_error.h"
|
|
#include "nrf_drv_saadc.h"
|
|
#include "nrfx_gpiote.h"
|
|
#include "app_timer.h"
|
|
#include "nrf_drv_timer.h"
|
|
#include "nrf_delay.h"
|
|
#include "nrf_drv_ppi.h"
|
|
#include "ada2200_spi.h"
|
|
#include "ble_nus.h"
|
|
#include "measurements.h"
|
|
#include "meas_pd_48.h"
|
|
#include "mcp4725_i2c.h"
|
|
//#include "ad5272_i2c.h"
|
|
#include "main_timer.h"
|
|
#include "battery_saadc.h"
|
|
#include "tmp235_q1.h"
|
|
#include "main.h"
|
|
#include "app_raw_main.h"
|
|
#include <cmd_parse.h>
|
|
#include "debug_print.h"
|
|
|
|
/*============================================================================*/
|
|
/* External Variables - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/** @brief Flag to include additional sensor data (batt, temp, IMU, pressure) */
|
|
extern bool info4;
|
|
|
|
/*============================================================================*/
|
|
/* Configuration Variables - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/**
|
|
* @brief Current measurement mode
|
|
* - Charles KWON
|
|
*
|
|
* Values:
|
|
* 0: Full 48 LED (single) 1: Full 48 LED (continuous)
|
|
* 2: Half 0-23 (single) 3: Half 0-23 (continuous)
|
|
* 4: Half 24-47 (single) 5: Half 24-47 (continuous)
|
|
*/
|
|
uint8_t ADC_PD_MODE = 0;
|
|
|
|
/** @brief Number of ADC samples per LED measurement */
|
|
uint8_t m48_samples_in_buffer = 8;
|
|
|
|
/** @brief Current number of LEDs to measure */
|
|
uint8_t CURRENT_LED_NO = 24;
|
|
|
|
/** @brief Working LED index list for current measurement */
|
|
uint8_t CURRENT_list_m48[m48_LED_NO] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23};
|
|
|
|
/*============================================================================*/
|
|
/* LED Configuration Arrays - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/** @brief Full LED list (0-23) */
|
|
static const uint8_t LED_list_m48[m48_LED_NO] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23};
|
|
|
|
/** @brief First half LED list (0-23) for modes 2,3 */
|
|
static const uint8_t LED_list_m48_1h[m48_LED_NO_H] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23};
|
|
|
|
/** @brief Second half LED list (24-47) for modes 4,5 */
|
|
static const uint8_t LED_list_m48_2h[m48_LED_NO_H] = {24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47};
|
|
|
|
/** @brief PD delay in microseconds */
|
|
extern uint16_t m_pd_delay_us;
|
|
|
|
/*============================================================================*/
|
|
/* State Variables - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/** @brief Command processing flag */
|
|
extern volatile bool processing;
|
|
|
|
/** @brief BLE TX in progress flag */
|
|
extern volatile bool data_tx_in_progress;
|
|
|
|
/** @brief BLE connection status */
|
|
extern volatile bool ble_connection_st;
|
|
|
|
/** @brief Temperature measurement trigger */
|
|
extern bool go_temp;
|
|
|
|
/** @brief Battery measurement trigger */
|
|
extern bool go_batt;
|
|
|
|
/*============================================================================*/
|
|
/* Sensor Data Storage - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/** @brief Battery level (mV) */
|
|
uint16_t volatile info_batt = 0;
|
|
|
|
/** @brief Temperature reading */
|
|
uint16_t volatile info_temp = 0;
|
|
|
|
/** @brief IMU data array [accX, accY, accZ, gyrX, gyrY, gyrZ] */
|
|
uint16_t volatile info_imu[6] = {0, 1, 2, 3, 4, 5};
|
|
|
|
/** @brief Pressure sensor 1 value */
|
|
uint16_t volatile info_p1 = 0;
|
|
|
|
/** @brief Pressure sensor 2 value */
|
|
uint16_t volatile info_p2 = 0;
|
|
|
|
/*============================================================================*/
|
|
/* Measurement State Machine Variables - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/** @brief Measurement cycle counter */
|
|
uint32_t m48_cnt;
|
|
|
|
/** @brief Current PD index (-1 = not started) */
|
|
static int8_t pd_no = -1;
|
|
|
|
/** @brief Current LED index (-1 = not started) */
|
|
static int8_t led_no = -1;
|
|
|
|
/** @brief Current buffer index */
|
|
static int8_t buf_no = 0;
|
|
|
|
/** @brief Elapsed time in milliseconds */
|
|
static int32_t t_ms = 0;
|
|
|
|
/** @brief Order counter for response sequencing */
|
|
uint8_t order_pd = 0;
|
|
|
|
/*============================================================================*/
|
|
/* ADC Data Buffers - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/**
|
|
* @brief Raw ADC sample buffer for each LED
|
|
* - Charles KWON
|
|
*
|
|
* Dimensions: [24 LEDs][32 samples max per LED]
|
|
*/
|
|
int16_t buff_m48_cycle[m48_LED_NO][m48_CYCLE_CNT] = {0};
|
|
|
|
/** @brief Summed ADC values for each LED (signed) */
|
|
int16_t m48_cycle_send_buff[m48_LED_NO] = {0};
|
|
|
|
/** @brief Summed ADC values for each LED (unsigned, for BLE TX) */
|
|
uint16_t single_bi_m48_cycle_send_buff[m48_LED_NO] = {0};
|
|
|
|
/** @brief ADC buffer size including delay samples */
|
|
#define SAMPLES_IN_BUFFER (4095 + 32)
|
|
|
|
/** @brief Double-buffered ADC sample storage */
|
|
static nrf_saadc_value_t pd_m48_adc_buf[2][SAMPLES_IN_BUFFER];
|
|
|
|
/**
|
|
* @brief Combined sensor + LED data buffer for BLE transmission
|
|
* - Charles KWON
|
|
*
|
|
* Layout: [batt, temp, imu[6], p1, p2, led_data[24]]
|
|
*/
|
|
uint16_t single_info_m48_cycle_send_buff[m48_LED_NO] = {0};
|
|
|
|
/*============================================================================*/
|
|
/* Measurement State Flags - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/** @brief M48 measurement start trigger */
|
|
bool pd_adc_m48_start = false;
|
|
|
|
/** @brief M48 continuous measurement running */
|
|
bool pd_adc_m48_running = false;
|
|
|
|
/** @brief M48 measurement in progress */
|
|
bool m48_testing = false;
|
|
|
|
/** @brief New BLE data received flag */
|
|
extern bool ble_got_new_data;
|
|
|
|
/** @brief IMU raw data enabled flag */
|
|
extern bool motion_raw_data_enabled;
|
|
|
|
/*============================================================================*/
|
|
/* Communication Buffers - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/** @brief BLE binary transmission buffer */
|
|
uint8_t m48_bin_buffer[BLE_NUS_MAX_DATA_LEN];
|
|
|
|
/** @brief Command source type */
|
|
extern which_cmd_t cmd_type_t;
|
|
|
|
/*============================================================================*/
|
|
/* Timer Definitions - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/** @brief Timer for measurement time tracking */
|
|
APP_TIMER_DEF(m_m48_check_loop_timer_id);
|
|
|
|
/** @brief Send interval for delayed transmission */
|
|
#if FEATURE_DELAY
|
|
#define m48_SEND_LOOP_INTERVAL 500
|
|
#else
|
|
#define m48_SEND_LOOP_INTERVAL 100
|
|
#endif
|
|
|
|
/** @brief Check loop interval (1ms) */
|
|
#define m48_CHECK_LOOP_INTERVAL 1
|
|
|
|
/** @brief PPI channel for SYNCO->SAADC trigger */
|
|
static nrf_ppi_channel_t m_ppi_channel;
|
|
|
|
/*============================================================================*/
|
|
/* PPI Configuration - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
#if !FEATURE_PRINTF
|
|
/**
|
|
* @brief Initialize PPI for ADA2200 SYNCO triggered ADC sampling
|
|
* - Charles KWON
|
|
*
|
|
* Connects ADA2200 SYNCO rising edge to SAADC sample task.
|
|
*/
|
|
void m48_ppi_init(void)
|
|
{
|
|
ret_code_t err_code;
|
|
|
|
err_code = nrf_drv_ppi_init();
|
|
APP_ERROR_CHECK(err_code);
|
|
|
|
uint32_t gpiote_event_addr = nrf_drv_gpiote_in_event_addr_get(ADA2200_SYNCO_PIN);
|
|
uint32_t saadc_sample_task_addr = nrf_drv_saadc_sample_task_get();
|
|
|
|
err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
|
|
APP_ERROR_CHECK(err_code);
|
|
|
|
err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
|
|
gpiote_event_addr,
|
|
saadc_sample_task_addr);
|
|
APP_ERROR_CHECK(err_code);
|
|
}
|
|
|
|
/**
|
|
* @brief Uninitialize PPI
|
|
* - Charles KWON
|
|
*/
|
|
void m48_ppi_uninit(void)
|
|
{
|
|
ret_code_t err_code;
|
|
err_code = nrf_drv_ppi_uninit();
|
|
APP_ERROR_CHECK(err_code);
|
|
}
|
|
|
|
/**
|
|
* @brief Enable PPI channel for ADC sampling
|
|
* - Charles KWON
|
|
*/
|
|
void m48_sampling_event_enable(void)
|
|
{
|
|
ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);
|
|
APP_ERROR_CHECK(err_code);
|
|
}
|
|
|
|
/**
|
|
* @brief Disable PPI channel
|
|
* - Charles KWON
|
|
*/
|
|
void m48_sampling_event_disable(void)
|
|
{
|
|
ret_code_t err_code = nrf_drv_ppi_channel_disable(m_ppi_channel);
|
|
APP_ERROR_CHECK(err_code);
|
|
}
|
|
#endif
|
|
|
|
/*============================================================================*/
|
|
/* ADC Interrupt Handler - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/**
|
|
* @brief SAADC event handler for M48 measurement
|
|
* - Charles KWON
|
|
*
|
|
* Implements the LED-PD measurement state machine:
|
|
* 1. On first call: activate first LED and set DAC gain
|
|
* 2. Store ADC samples for current LED
|
|
* 3. Advance to next LED or complete measurement
|
|
* 4. On completion: sum samples, format response, send via BLE
|
|
*
|
|
* Response tags by mode:
|
|
* - Mode 0: rsj: (Full with sensor data)
|
|
* - Mode 2: rcj: (Half 0-23 with sensor data)
|
|
* - Mode 3: rdj: (Half 0-23 continuous)
|
|
* - Mode 4: rej: (Half 24-47 with sensor data)
|
|
* - Mode 5: rfj: (Half 24-47 continuous)
|
|
*
|
|
* @param[in] p_event Pointer to SAADC event structure
|
|
*/
|
|
static void m48_voltage_handler(nrf_drv_saadc_evt_t const * p_event)
|
|
{
|
|
ret_code_t err_code;
|
|
int16_t sum = 0;
|
|
uint32_t m48_clk_delay = m_pd_delay_us / 16;
|
|
|
|
/* Handle BLE disconnection during measurement */
|
|
if (ble_connection_st == 0) {
|
|
DBG_PRINTF("m48 ADC STOP 1\r\n");
|
|
led_off(99);
|
|
pd_off(99);
|
|
pd_adc_m48_start = false;
|
|
pd_adc_m48_running = false;
|
|
m48_testing = false;
|
|
info4 = false;
|
|
DBG_PRINTF("LOST_AT48\r\n");
|
|
processing = false;
|
|
go_batt = false;
|
|
go_temp = false;
|
|
m48_adc_end_final();
|
|
} else {
|
|
if (p_event->type == NRF_DRV_SAADC_EVT_DONE) {
|
|
err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer,
|
|
m48_samples_in_buffer + m48_clk_delay);
|
|
APP_ERROR_CHECK(err_code);
|
|
|
|
/*----------------------------------------------------------------*/
|
|
/* First call: Initialize LED/PD */
|
|
/*----------------------------------------------------------------*/
|
|
if (led_no == -1) {
|
|
led_no = 0;
|
|
pd_no = 0;
|
|
led_on(CURRENT_list_m48[led_no]);
|
|
led_pd_matching_value_set(CURRENT_list_m48[led_no]);
|
|
} else {
|
|
/*------------------------------------------------------------*/
|
|
/* Store ADC samples for current LED */
|
|
/*------------------------------------------------------------*/
|
|
for (uint16_t i = m48_clk_delay; i < m48_clk_delay + m48_samples_in_buffer; i++) {
|
|
buff_m48_cycle[buf_no][i - m48_clk_delay] = p_event->data.done.p_buffer[i];
|
|
}
|
|
#if FEATURE_PRINTF
|
|
DBG_PRINTF("-----------------Read ADC // led_no = %d(%d), pd_no = %d(%d), buf_no = %d\r\n\r\n",
|
|
led_no, LED_list_m48[led_no], pd_no, PD_list_m48[pd_no], buf_no);
|
|
#endif
|
|
buf_no++;
|
|
|
|
/*------------------------------------------------------------*/
|
|
/* Advance to next LED or complete */
|
|
/*------------------------------------------------------------*/
|
|
if (pd_no >= -1) {
|
|
if (led_no < CURRENT_LED_NO - 1) {
|
|
/* Next LED */
|
|
led_no++;
|
|
led_on(CURRENT_list_m48[led_no]);
|
|
led_pd_matching_value_set(CURRENT_list_m48[led_no]);
|
|
} else if (led_no >= CURRENT_LED_NO - 1) {
|
|
/*----------------------------------------------------*/
|
|
/* All LEDs measured - process and send results */
|
|
/*----------------------------------------------------*/
|
|
pd_no = -1;
|
|
led_no = -1;
|
|
#if FEATURE_PRINTF
|
|
DBG_PRINTF("\r\nEnded\r\n");
|
|
#endif
|
|
/* Sum samples for each LED */
|
|
uint8_t k = 0;
|
|
sum = 0;
|
|
for (uint16_t i = 0; i < CURRENT_LED_NO; i++) {
|
|
for (uint16_t j = 0; j < m48_samples_in_buffer; j++) {
|
|
sum += buff_m48_cycle[i][j];
|
|
}
|
|
m48_cycle_send_buff[k++] = sum;
|
|
sum = 0;
|
|
}
|
|
buf_no = 0;
|
|
|
|
if (ble_connection_st == 0) {
|
|
DBG_PRINTF("m24 ADC STOP 1");
|
|
} else {
|
|
pd_adc_m48_start = false;
|
|
DBG_PRINTF("FINISH SEND\r\n");
|
|
m48_testing = false;
|
|
|
|
if (cmd_type_t == CMD_UART) {
|
|
/* UART response handled elsewhere */
|
|
} else if (cmd_type_t == CMD_BLE) {
|
|
/* Convert to unsigned for BLE transmission */
|
|
for (uint16_t i = 0; i < CURRENT_LED_NO; i++) {
|
|
DBG_PRINTF("%d,", m48_cycle_send_buff[i]);
|
|
single_bi_m48_cycle_send_buff[i] = (uint16_t)(m48_cycle_send_buff[i]);
|
|
}
|
|
|
|
/*--------------------------------------------*/
|
|
/* Format response with sensor data */
|
|
/*--------------------------------------------*/
|
|
if (info4 == true) {
|
|
single_info_m48_cycle_send_buff[0] = info_batt;
|
|
single_info_m48_cycle_send_buff[1] = info_temp;
|
|
for (uint16_t i = 0; i < 6; i++) {
|
|
single_info_m48_cycle_send_buff[i + 2] = info_imu[i];
|
|
}
|
|
single_info_m48_cycle_send_buff[8] = info_p1;
|
|
single_info_m48_cycle_send_buff[9] = info_p2;
|
|
|
|
for (uint16_t i = 0; i < CURRENT_LED_NO; i++) {
|
|
single_info_m48_cycle_send_buff[i + 10] = single_bi_m48_cycle_send_buff[i];
|
|
}
|
|
|
|
/* Send response based on mode */
|
|
if (ADC_PD_MODE == 0) {
|
|
format_data(m48_bin_buffer, "rsj:", single_info_m48_cycle_send_buff, 56);
|
|
binary_tx_handler(m48_bin_buffer, 58);
|
|
} else if (ADC_PD_MODE == 2) {
|
|
format_data(m48_bin_buffer, "rcj:", single_info_m48_cycle_send_buff, 34);
|
|
binary_tx_handler(m48_bin_buffer, 36);
|
|
} else if (ADC_PD_MODE == 3) {
|
|
format_data(m48_bin_buffer, "rdj:", single_info_m48_cycle_send_buff, 34);
|
|
binary_tx_handler(m48_bin_buffer, 36);
|
|
} else if (ADC_PD_MODE == 4) {
|
|
format_data(m48_bin_buffer, "rej:", single_info_m48_cycle_send_buff, 34);
|
|
binary_tx_handler(m48_bin_buffer, 36);
|
|
} else if (ADC_PD_MODE == 5) {
|
|
format_data(m48_bin_buffer, "rfj:", single_info_m48_cycle_send_buff, 34);
|
|
binary_tx_handler(m48_bin_buffer, 36);
|
|
}
|
|
} else {
|
|
/* Send LED data only (no sensor data) */
|
|
char resp[4];
|
|
|
|
if (ADC_PD_MODE == 2) {
|
|
format_data(m48_bin_buffer, "rdj:", single_bi_m48_cycle_send_buff, 24);
|
|
binary_tx_handler(m48_bin_buffer, 26);
|
|
} else if (ADC_PD_MODE == 4) {
|
|
format_data(m48_bin_buffer, "rfj:", single_bi_m48_cycle_send_buff, 24);
|
|
binary_tx_handler(m48_bin_buffer, 26);
|
|
} else if (ADC_PD_MODE == 3) {
|
|
sprintf(resp, "rd%01X:", order_pd);
|
|
format_data(m48_bin_buffer, resp, single_bi_m48_cycle_send_buff, 24);
|
|
binary_tx_handler(m48_bin_buffer, 26);
|
|
} else if (ADC_PD_MODE == 5) {
|
|
sprintf(resp, "rf%01X:", order_pd);
|
|
format_data(m48_bin_buffer, resp, single_bi_m48_cycle_send_buff, 24);
|
|
binary_tx_handler(m48_bin_buffer, 26);
|
|
}
|
|
}
|
|
|
|
DBG_PRINTF("\r\n %d ms \r\n", t_ms);
|
|
}
|
|
|
|
/*------------------------------------------------*/
|
|
/* Handle continuous mode or cleanup */
|
|
/*------------------------------------------------*/
|
|
if (pd_adc_m48_running == true) {
|
|
if (info4 == true) {
|
|
m48_adc_end_final();
|
|
pd_adc_m48_start = true;
|
|
go_batt = true;
|
|
main_timer_start();
|
|
} else {
|
|
t_ms = 0;
|
|
m48_cnt = 0;
|
|
m48_testing = true;
|
|
m48_adc_start();
|
|
}
|
|
} else {
|
|
/* Single shot - cleanup */
|
|
if (info4 == true) {
|
|
info4 = false;
|
|
}
|
|
led_off(99);
|
|
pd_off(99);
|
|
processing = false;
|
|
m48_adc_end_final();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*============================================================================*/
|
|
/* Timer Callback - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/**
|
|
* @brief Check timer callback for measurement timing
|
|
* - Charles KWON
|
|
*
|
|
* Tracks elapsed time during measurement.
|
|
*
|
|
* @param[in] p_context Unused timer context
|
|
*/
|
|
void m48_check_loop(void * p_context)
|
|
{
|
|
UNUSED_PARAMETER(p_context);
|
|
m48_check_timer_stop();
|
|
|
|
if (m48_testing == false) {
|
|
DBG_PRINTF("%d ms \r\n", t_ms);
|
|
} else {
|
|
t_ms++;
|
|
m48_check_timer_start();
|
|
}
|
|
}
|
|
|
|
/*============================================================================*/
|
|
/* Measurement Control Functions - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/**
|
|
* @brief Initialize and start M48 measurement based on mode
|
|
* - Charles KWON
|
|
*
|
|
* Called from main_timer to begin measurement sequence.
|
|
* Configures LED list based on ADC_PD_MODE setting.
|
|
*/
|
|
void m48_adc_start_init(void)
|
|
{
|
|
/* Handle new data received during continuous mode */
|
|
if (ble_got_new_data == true) {
|
|
if (pd_adc_m48_running == true) {
|
|
led_off(99);
|
|
pd_off(99);
|
|
pd_adc_m48_start = false;
|
|
pd_adc_m48_running = false;
|
|
DBG_PRINTF("FINISH NEWDATA\r\n");
|
|
processing = false;
|
|
go_batt = false;
|
|
go_temp = false;
|
|
motion_raw_data_enabled = false;
|
|
m48_testing = false;
|
|
|
|
if (info4 == true) {
|
|
info4 = false;
|
|
} else {
|
|
m48_adc_end_final();
|
|
}
|
|
}
|
|
} else if (pd_adc_m48_start == true) {
|
|
/* Configure measurement based on mode */
|
|
switch (ADC_PD_MODE) {
|
|
case 0: /* Full 48 LED (single) */
|
|
pd_adc_m48_running = false;
|
|
CURRENT_LED_NO = m48_LED_NO;
|
|
for (uint16_t i = 0; i < CURRENT_LED_NO; i++) {
|
|
CURRENT_list_m48[i] = LED_list_m48[i];
|
|
}
|
|
break;
|
|
|
|
case 1: /* Full 48 LED (continuous) */
|
|
pd_adc_m48_running = true;
|
|
CURRENT_LED_NO = m48_LED_NO;
|
|
for (uint16_t i = 0; i < CURRENT_LED_NO; i++) {
|
|
CURRENT_list_m48[i] = LED_list_m48[i];
|
|
}
|
|
break;
|
|
|
|
case 2: /* Half 0-23 (single) - mcj? */
|
|
pd_adc_m48_running = false;
|
|
CURRENT_LED_NO = m48_LED_NO_H;
|
|
for (uint16_t i = 0; i < CURRENT_LED_NO; i++) {
|
|
CURRENT_list_m48[i] = LED_list_m48_1h[i];
|
|
}
|
|
break;
|
|
|
|
case 3: /* Half 0-23 (continuous) */
|
|
pd_adc_m48_running = true;
|
|
CURRENT_LED_NO = m48_LED_NO_H;
|
|
for (uint16_t i = 0; i < CURRENT_LED_NO; i++) {
|
|
CURRENT_list_m48[i] = LED_list_m48_1h[i];
|
|
}
|
|
break;
|
|
|
|
case 4: /* Half 24-47 (single) */
|
|
pd_adc_m48_running = false;
|
|
CURRENT_LED_NO = m48_LED_NO_H;
|
|
for (uint16_t i = 0; i < CURRENT_LED_NO; i++) {
|
|
CURRENT_list_m48[i] = LED_list_m48_2h[i];
|
|
DBG_PRINTF("%d,", CURRENT_list_m48[i]);
|
|
}
|
|
break;
|
|
|
|
case 5: /* Half 24-47 (continuous) */
|
|
pd_adc_m48_running = true;
|
|
CURRENT_LED_NO = m48_LED_NO_H;
|
|
for (uint16_t i = 0; i < CURRENT_LED_NO; i++) {
|
|
CURRENT_list_m48[i] = LED_list_m48_2h[i];
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pd_adc_m48_running = false;
|
|
CURRENT_LED_NO = m48_LED_NO;
|
|
for (uint16_t i = 0; i < CURRENT_LED_NO; i++) {
|
|
CURRENT_list_m48[i] = LED_list_m48[i];
|
|
}
|
|
break;
|
|
}
|
|
|
|
t_ms = 0;
|
|
m48_cnt = 0;
|
|
pd_adc_m48_start = false;
|
|
m48_testing = true;
|
|
|
|
m48_adc_start2();
|
|
m48_check_timer_start();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize measurement buffers and state
|
|
* - Charles KWON
|
|
*/
|
|
void m48_adc_start(void)
|
|
{
|
|
pd_no = -1;
|
|
led_no = -1;
|
|
buf_no = 0;
|
|
|
|
/* Clear measurement buffers */
|
|
for (uint16_t i = 0; i < m48_LED_NO; i++) {
|
|
for (uint16_t j = 0; j < m48_CYCLE_CNT; j++) {
|
|
buff_m48_cycle[i][j] = 0;
|
|
|
|
if (ble_got_new_data == true) {
|
|
if (pd_adc_m48_running == true) {
|
|
pd_adc_m48_start = false;
|
|
pd_adc_m48_running = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Update order counter for continuous mode */
|
|
if (order_pd >= 15) {
|
|
order_pd = 0;
|
|
} else {
|
|
order_pd++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Start M48 measurement with full initialization
|
|
* - Charles KWON
|
|
*/
|
|
void m48_adc_start2(void)
|
|
{
|
|
m48_adc_start();
|
|
m48_adc_init();
|
|
m48_irq_init();
|
|
m48_ppi_init();
|
|
m48_sampling_event_enable();
|
|
}
|
|
|
|
/**
|
|
* @brief Stop ADC sampling (partial cleanup)
|
|
* - Charles KWON
|
|
*/
|
|
void m48_adc_end(void)
|
|
{
|
|
DBG_PRINTF("m48_adc_end\r\n");
|
|
m48_sampling_event_disable();
|
|
}
|
|
|
|
/**
|
|
* @brief Complete measurement cleanup
|
|
* - Charles KWON
|
|
*
|
|
* Disables PPI, uninitializes SAADC, restarts battery timer.
|
|
*/
|
|
void m48_adc_end_final(void)
|
|
{
|
|
DBG_PRINTF("adc_end_final\r\n");
|
|
m48_sampling_event_disable();
|
|
m48_irq_uninit();
|
|
m48_ppi_uninit();
|
|
m48_adc_uninit();
|
|
battery_timer_start();
|
|
}
|
|
|
|
/*============================================================================*/
|
|
/* SAADC Configuration - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/**
|
|
* @brief Initialize SAADC for M48 measurement
|
|
* - Charles KWON
|
|
*
|
|
* Configures differential ADC on AIN0/AIN1 with 10-bit resolution.
|
|
*/
|
|
void m48_adc_init(void)
|
|
{
|
|
#if FEATURE_PRINTF
|
|
DBG_PRINTF("m48_adc_init\r\n");
|
|
#endif
|
|
|
|
static nrfx_saadc_config_t default_config;
|
|
default_config.resolution = (nrf_saadc_resolution_t)NRFX_SAADC_CONFIG_RESOLUTION;
|
|
default_config.oversample = (nrf_saadc_oversample_t)NRFX_SAADC_CONFIG_OVERSAMPLE;
|
|
default_config.interrupt_priority = NRFX_SAADC_CONFIG_IRQ_PRIORITY;
|
|
default_config.low_power_mode = NRFX_SAADC_CONFIG_LP_MODE;
|
|
|
|
static nrf_saadc_channel_config_t config;
|
|
config.resistor_p = NRF_SAADC_RESISTOR_DISABLED;
|
|
config.resistor_n = NRF_SAADC_RESISTOR_DISABLED;
|
|
config.gain = NRF_SAADC_GAIN1_6;
|
|
config.reference = NRF_SAADC_REFERENCE_INTERNAL;
|
|
config.acq_time = NRF_SAADC_ACQTIME_3US;
|
|
config.mode = NRF_SAADC_MODE_DIFFERENTIAL;
|
|
config.burst = NRF_SAADC_BURST_DISABLED;
|
|
config.pin_p = (nrf_saadc_input_t)(NRF_SAADC_INPUT_AIN0);
|
|
config.pin_n = (nrf_saadc_input_t)(NRF_SAADC_INPUT_AIN1);
|
|
|
|
ret_code_t err_code = nrf_drv_saadc_init(&default_config, m48_voltage_handler);
|
|
APP_ERROR_CHECK(err_code);
|
|
|
|
err_code = nrf_drv_saadc_channel_init(0, &config);
|
|
APP_ERROR_CHECK(err_code);
|
|
|
|
err_code = nrf_drv_saadc_buffer_convert(pd_m48_adc_buf[0],
|
|
m48_samples_in_buffer + m_pd_delay_us / 16);
|
|
APP_ERROR_CHECK(err_code);
|
|
}
|
|
|
|
/**
|
|
* @brief Uninitialize SAADC
|
|
* - Charles KWON
|
|
*/
|
|
void m48_adc_uninit(void)
|
|
{
|
|
#if FEATURE_PRINTF
|
|
DBG_PRINTF("pd_m48_adc_uninit\r\n");
|
|
#endif
|
|
|
|
nrf_drv_saadc_uninit();
|
|
nrf_drv_saadc_channel_uninit(0);
|
|
}
|
|
|
|
/*============================================================================*/
|
|
/* GPIO Interrupt Configuration - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
#if !FEATURE_PRINTF
|
|
/**
|
|
* @brief Initialize GPIOTE for ADA2200 SYNCO pin
|
|
* - Charles KWON
|
|
*
|
|
* Configures rising edge detection on SYNCO for PPI trigger.
|
|
*/
|
|
void m48_irq_init(void)
|
|
{
|
|
ret_code_t err_code;
|
|
|
|
if (!nrfx_gpiote_is_init()) {
|
|
err_code = nrfx_gpiote_init();
|
|
APP_ERROR_CHECK(err_code);
|
|
}
|
|
|
|
nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
|
|
in_config.pull = NRF_GPIO_PIN_PULLDOWN;
|
|
|
|
err_code = nrfx_gpiote_in_init(ADA2200_SYNCO_PIN, &in_config, NULL);
|
|
APP_ERROR_CHECK(err_code);
|
|
|
|
nrfx_gpiote_in_event_enable(ADA2200_SYNCO_PIN, true);
|
|
}
|
|
|
|
/**
|
|
* @brief Uninitialize GPIOTE for SYNCO pin
|
|
* - Charles KWON
|
|
*/
|
|
void m48_irq_uninit(void)
|
|
{
|
|
nrfx_gpiote_in_event_disable(ADA2200_SYNCO_PIN);
|
|
nrfx_gpiote_in_uninit(ADA2200_SYNCO_PIN);
|
|
}
|
|
#endif
|
|
|
|
/*============================================================================*/
|
|
/* Timer Control Functions - Charles KWON */
|
|
/*============================================================================*/
|
|
|
|
/**
|
|
* @brief Start measurement check timer
|
|
* - Charles KWON
|
|
*/
|
|
void m48_check_timer_start(void)
|
|
{
|
|
APP_ERROR_CHECK(app_timer_start(m_m48_check_loop_timer_id,
|
|
APP_TIMER_TICKS(m48_CHECK_LOOP_INTERVAL), NULL));
|
|
}
|
|
|
|
/**
|
|
* @brief Stop measurement check timer
|
|
* - Charles KWON
|
|
*/
|
|
void m48_check_timer_stop(void)
|
|
{
|
|
APP_ERROR_CHECK(app_timer_stop(m_m48_check_loop_timer_id));
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize measurement check timer
|
|
* - Charles KWON
|
|
*/
|
|
void m48_check_timer_init(void)
|
|
{
|
|
APP_ERROR_CHECK(app_timer_create(&m_m48_check_loop_timer_id,
|
|
APP_TIMER_MODE_SINGLE_SHOT, m48_check_loop));
|
|
}
|