initial commit

This commit is contained in:
jhChun
2026-04-08 16:58:54 +09:00
commit 82e33d8bf9
2578 changed files with 1590432 additions and 0 deletions

View File

@@ -0,0 +1,905 @@
/*******************************************************************************
* @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));
}