44 changed files with 2933 additions and 2185 deletions
-
7.vscode/settings.json
-
279README.md
-
162app/app.uvoptx
-
10app/app.uvprojx
-
4app/config/sdk_config.h
-
57app/src/app_ble_service.c
-
13app/src/app_ble_service.h
-
35app/src/app_event.h
-
0app/src/bak/ble_cmd_process_service.c
-
0app/src/bak/ble_cmd_process_service.h
-
152app/src/bak/heart_wave_sample_service.c
-
15app/src/bak/heart_wave_sample_service.h
-
5app/src/bak/three_lead_board.c
-
1app/src/bak/three_lead_board.h
-
24app/src/basic/ads1293/ads1293.c
-
7app/src/basic/ads1293/ads1293.h
-
7app/src/basic/config.h
-
101app/src/board/TI_ADS1293_register_settings.h
-
148app/src/board/ads_cfg.h
-
0app/src/board/board.c
-
61app/src/board/board.h
-
36app/src/board/board_battery_state.c
-
15app/src/board/board_battery_state.h
-
93app/src/board/board_beep_ctrl.c
-
24app/src/board/board_beep_ctrl.h
-
24app/src/board/board_button.c
-
18app/src/board/board_button.h
-
70app/src/board/board_light_ctrl.c
-
23app/src/board/board_light_ctrl.h
-
176app/src/board/board_sdcard_driver.c
-
19app/src/board/board_sdcard_driver.h
-
13app/src/device_state.c
-
79app/src/device_state.h
-
342app/src/heart_wave_sample_service.c
-
34app/src/heart_wave_sample_service.h
-
372app/src/main.bak.c
-
361app/src/main.c
-
155app/src/sample_data_manager_service.c
-
78app/src/sample_data_manager_service.h
-
2libznordic
@ -0,0 +1,57 @@ |
|||
#include "app_ble_service.h" |
|||
|
|||
#include "app_scheduler.h" |
|||
#include "zdatachannel_service.h" |
|||
#include "znordic.h" |
|||
static zdatachannel_init_t zdatachannle_init; |
|||
|
|||
static uint8_t rxbufcache[256]; |
|||
static bool is_rxbufcache_used = false; |
|||
|
|||
static void prvf_process_ble_rx_data(void* p_event_data, uint16_t event_size); |
|||
|
|||
/******************************************************************************* |
|||
* 蓝牙服务注册 * |
|||
*******************************************************************************/ |
|||
ZDATACHANNEL_DEF(m_zhrs, 2 /*优先级*/, 1 /*client num*/); |
|||
/** |
|||
* @brief 蓝牙消息回调 |
|||
*/ |
|||
static void zdatachannel_data_handler(zdatachannel_evt_t* p_evt) { |
|||
if (p_evt->type != ZDATACHANNEL_EVT_RX_DATA) { |
|||
return; |
|||
} |
|||
|
|||
// 消息正在被处理中,丢弃新来的消息 |
|||
if (is_rxbufcache_used) return; |
|||
if (p_evt->params.rx_data.length > sizeof(rxbufcache)) return; |
|||
|
|||
memcpy(rxbufcache, p_evt->params.rx_data.p_data, p_evt->params.rx_data.length); |
|||
uint32_t suc = app_sched_event_put(rxbufcache, p_evt->params.rx_data.length, prvf_process_ble_rx_data); |
|||
if (suc == 0) { |
|||
is_rxbufcache_used = true; |
|||
} |
|||
} |
|||
|
|||
/******************************************************************************* |
|||
* 消息处理 * |
|||
*******************************************************************************/ |
|||
static void prvf_process_ble_rx_data(void* p_event_data, uint16_t data_size) { |
|||
ZLOGI("rx:"); |
|||
NRF_LOG_HEXDUMP_INFO(p_event_data, data_size); |
|||
} |
|||
|
|||
void AppBleService_startAdv() { zble_module_start_adv(); } |
|||
void AppBleService_stopAdv() { zble_module_stop_adv(); } |
|||
|
|||
void AppBleService_onServiceInitCB() { |
|||
ZLOGI("init zdatachannel service"); |
|||
zdatachannel_init_t zdatachannle_init; |
|||
memset(&zdatachannle_init, 0, sizeof(zdatachannle_init)); |
|||
zdatachannle_init.data_handler = zdatachannel_data_handler; |
|||
ZERROR_CHECK(zdatachannel_init(&m_zhrs, &zdatachannle_init)); |
|||
} |
|||
|
|||
void AppBleService_init() { |
|||
// |
|||
} |
@ -0,0 +1,13 @@ |
|||
#pragma once |
|||
#include <stdint.h> |
|||
|
|||
/** |
|||
* @brief |
|||
* zble_module_init 方法将此回调注册进去 |
|||
*/ |
|||
void AppBleService_onServiceInitCB(); |
|||
|
|||
|
|||
void AppBleService_init(); |
|||
void AppBleService_uninit(); |
|||
void AppBleService_startAdv(); |
@ -0,0 +1,35 @@ |
|||
#pragma once |
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#define LITTLE_DATA_BLOCK_FRAME_NUM 4 // 每四帧回调一次 |
|||
|
|||
typedef enum { |
|||
kevent_sensor_drop = 0, // 导联连接事件 |
|||
kevent_tmr_scheduler, // 定时器调度事件 |
|||
kevent_capture_data_block_event, // 每采集一定数据后回调一次 |
|||
kevent_capture_little_data_block_event, // 传感器小数据块回调事件 |
|||
} app_event_type_t; |
|||
|
|||
typedef struct { |
|||
uint32_t data0; |
|||
uint32_t data1; |
|||
uint32_t data2; |
|||
} one_frame_data_t; |
|||
|
|||
typedef struct { |
|||
app_event_type_t eventType; |
|||
union { |
|||
struct { |
|||
uint32_t frameIndex; |
|||
one_frame_data_t data[LITTLE_DATA_BLOCK_FRAME_NUM]; |
|||
} little_data_block; |
|||
|
|||
struct { |
|||
uint8_t* data; // 不保证数据对齐 |
|||
int len; |
|||
} block_sensor_data; |
|||
} val; |
|||
} app_event_t; |
|||
|
|||
void app_event_process_cb(void* p_event_data, uint16_t event_size); |
@ -0,0 +1,152 @@ |
|||
#include "heart_wave_sample_service.h" |
|||
|
|||
#include "app_event.h" |
|||
#include "nrfx_timer.h" |
|||
#include "one_conduction_board.h" |
|||
|
|||
static const nrfx_timer_t m_timer = NRFX_TIMER_INSTANCE(1); /**< Timer used for channel sweeps and tx with duty cycle. */ |
|||
static bool m_timer_started = false; /**< True if timer is running. */ |
|||
|
|||
static uint16_t m_capture_buffer_a[128]; |
|||
static uint16_t m_capture_buffer_b[128]; |
|||
|
|||
static uint16_t* m_capture_buffer; |
|||
static uint16_t m_capture_buffer_index = 0; |
|||
|
|||
volatile static float m_sensor_display_data = 0; // 0->100 |
|||
static uint32_t m_start_capture_tp; |
|||
static uint32_t m_frameindex = 0; |
|||
|
|||
static void swap_buffer() { |
|||
if (m_capture_buffer == NULL) { |
|||
m_capture_buffer = m_capture_buffer_a; |
|||
m_capture_buffer_index = 0; |
|||
return; |
|||
} |
|||
|
|||
if (m_capture_buffer == m_capture_buffer_a) { |
|||
m_capture_buffer = m_capture_buffer_b; |
|||
} else { |
|||
m_capture_buffer = m_capture_buffer_a; |
|||
} |
|||
m_capture_buffer_index = 0; |
|||
return; |
|||
} |
|||
static float amp_val(uint16_t val, uint16_t valcener, float amp) { |
|||
float valf = (float)val - valcener; |
|||
valf = valf * amp; |
|||
valf += valcener; |
|||
|
|||
if (valf >= 100) { |
|||
valf = 100; |
|||
} |
|||
|
|||
if (valf <= 0) { |
|||
valf = 0; |
|||
} |
|||
return valf; |
|||
} |
|||
|
|||
typedef struct { |
|||
float value; |
|||
float efectiveFactor; |
|||
} filter_t; |
|||
|
|||
filter_t m_filter = {0, 0.8}; |
|||
|
|||
static float Filter(filter_t* filter, float newInput) { |
|||
float newv = ((float)filter->value * (1.0f - filter->efectiveFactor)) + ((float)newInput * filter->efectiveFactor); |
|||
filter->value = newv; |
|||
return newv; |
|||
} |
|||
|
|||
void nrfx_timer_event_handler(nrf_timer_event_t event_type, void* p_context) { // |
|||
uint16_t val = SingleLeadECG_ecg_plod_get_ecg_val(); // 12bit |
|||
m_frameindex++; |
|||
|
|||
/******************************************************************************* |
|||
* 显示数据计算并赋值 * |
|||
*******************************************************************************/ |
|||
float val_af100 = (float)val / 4096.0f * 100; |
|||
val_af100 = amp_val(val_af100, 50, 1.8f); |
|||
val_af100 = Filter(&m_filter, val_af100); |
|||
m_sensor_display_data = val_af100; |
|||
|
|||
/******************************************************************************* |
|||
* 采样数据缓存 * |
|||
*******************************************************************************/ |
|||
if (m_capture_buffer == NULL) { |
|||
swap_buffer(); |
|||
} |
|||
|
|||
if (m_capture_buffer_index < 128) { |
|||
m_capture_buffer[m_capture_buffer_index++] = val; |
|||
} |
|||
|
|||
if (m_capture_buffer_index == 128) { |
|||
app_event_t evt; |
|||
evt.eventType = kevent_capture_256data_event; |
|||
evt.val.capture_data_cache = (uint8_t*)m_capture_buffer; |
|||
swap_buffer(); |
|||
app_sched_event_put(&evt, sizeof(evt), app_event_process_cb); |
|||
} |
|||
|
|||
/******************************************************************************* |
|||
* 实时采样数据事件上报 * |
|||
*******************************************************************************/ |
|||
{ |
|||
app_event_t evt; |
|||
evt.eventType = kevent_capture_1data_event; |
|||
evt.val.frame_data.frameIndex = m_frameindex; |
|||
evt.val.frame_data.data = val; |
|||
swap_buffer(); |
|||
app_sched_event_put(&evt, sizeof(evt), app_event_process_cb); |
|||
} |
|||
} |
|||
|
|||
void hwss_init(void) { |
|||
if (m_timer_started) { |
|||
return; |
|||
} |
|||
/** |
|||
* @brief 初始化定时器 |
|||
*/ |
|||
nrfx_err_t err; |
|||
nrfx_timer_config_t timer_cfg = { |
|||
.frequency = NRF_TIMER_FREQ_125kHz, |
|||
.mode = NRF_TIMER_MODE_TIMER, |
|||
.bit_width = NRF_TIMER_BIT_WIDTH_24, |
|||
.p_context = NULL, |
|||
.interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY, |
|||
}; |
|||
|
|||
err = nrfx_timer_init(&m_timer, &timer_cfg, nrfx_timer_event_handler); |
|||
if (err != NRFX_SUCCESS) { |
|||
NRF_LOG_ERROR("nrfx_timer_init failed with: %d\n", err); |
|||
} |
|||
uint32_t timer_ticks = nrfx_timer_ms_to_ticks(&m_timer, 5); // 200HZ |
|||
nrfx_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, timer_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true); |
|||
m_timer_started = true; |
|||
} |
|||
void hwss_uninit(void) { nrfx_timer_disable(&m_timer); } |
|||
|
|||
void hwss_start_capture(void) { |
|||
m_start_capture_tp = znordic_getpower_on_s(); |
|||
swap_buffer(); |
|||
m_frameindex = 0; |
|||
nrfx_timer_enable(&m_timer); |
|||
} |
|||
void hwss_stop_capture(void) { |
|||
nrfx_timer_disable(&m_timer); |
|||
m_frameindex = 0; |
|||
} |
|||
|
|||
float hwss_read_val(void) { |
|||
__disable_irq(); |
|||
float val = m_sensor_display_data; |
|||
__enable_irq(); |
|||
return val; |
|||
} |
|||
float hwss_read_heart_rate(void) { return 0; } |
|||
|
|||
int hwss_has_captured_time_ms() { return (znordic_getpower_on_s() - m_start_capture_tp) * 1000; } |
@ -0,0 +1,15 @@ |
|||
#pragma once |
|||
#include "one_conduction_board.h" |
|||
|
|||
// 每256个字节触发一次回调 |
|||
typedef void (*heart_wave_sample_service_callback_t)(uint16_t *p_data, uint16_t length); |
|||
|
|||
void hwss_init(void); |
|||
void hwss_uninit(void); |
|||
|
|||
void hwss_start_capture(void); |
|||
void hwss_stop_capture(void); |
|||
|
|||
float hwss_read_val(void); |
|||
float hwss_read_heart_rate(void); |
|||
int hwss_has_captured_time_ms(); |
@ -1,101 +0,0 @@ |
|||
//---------------------------------------------------------------------------- |
|||
// Description: This file contains the initialization values for the |
|||
// ADS1293 registers. |
|||
// |
|||
// MSP430/ADS1293 Interface Code Library v1.0 |
|||
// |
|||
// Vishy Natarajan |
|||
// Texas Instruments Inc. |
|||
// April 2013 |
|||
// Built with IAR Embedded Workbench Version: 5.5x |
|||
//------------------------------------------------------------------------------ |
|||
// Change Log: |
|||
//------------------------------------------------------------------------------ |
|||
// Version: 1.00 |
|||
// Comments: Initial Release Version |
|||
//------------------------------------------------------------------------------ |
|||
#ifndef HEADER_FILE_TI_ADS1293_REGISTER_SETTINGS_H |
|||
|
|||
#define HEADER_FILE_TI_ADS1293_REGISTER_SETTINGS_H |
|||
|
|||
/************************************************************ |
|||
* TI ADS1293 REGISTER SET INITIALIZATION VALUES |
|||
************************************************************/ |
|||
|
|||
#define TI_ADS1293_CONFIG_REG_VALUE (0x00) /* Main Configuration */ |
|||
|
|||
#define TI_ADS1293_FLEX_CH1_CN_REG_VALUE (0x0A) /* Flex Routing Swich Control for Channel 1 */ |
|||
#define TI_ADS1293_FLEX_CH2_CN_REG_VALUE (0x1A) /* Flex Routing Swich Control for Channel 2 */ |
|||
#define TI_ADS1293_FLEX_CH3_CN_REG_VALUE (0x00) /* Flex Routing Swich Control for Channel 3 */ |
|||
#define TI_ADS1293_FLEX_PACE_CN_REG_VALUE (0x00) /* Flex Routing Swich Control for Pace Channel */ |
|||
#define TI_ADS1293_FLEX_VBAT_CN_REG_VALUE (0x00) /* Flex Routing Swich Control for Battery Monitoriing */ |
|||
|
|||
#define TI_ADS1293_LOD_CN_REG_VALUE (0x08) /* Lead Off Detect Control */ |
|||
#define TI_ADS1293_LOD_EN_REG_VALUE (0x00) /* Lead Off Detect Enable */ |
|||
#define TI_ADS1293_LOD_CURRENT_REG_VALUE (0x00) /* Lead Off Detect Current */ |
|||
#define TI_ADS1293_LOD_AC_CN_REG_VALUE (0x00) /* AC Lead Off Detect Current */ |
|||
|
|||
#define TI_ADS1293_CMDET_EN_REG_VALUE (0x07) /* Common Mode Detect Enable */ |
|||
#define TI_ADS1293_CMDET_CN_REG_VALUE (0x00) /* Commond Mode Detect Control */ |
|||
#define TI_ADS1293_RLD_CN_REG_VALUE (0x04) /* Right Leg Drive Control */ |
|||
|
|||
#define TI_ADS1293_WILSON_EN1_REG_VALUE (0x00) /* Wilson Reference Input one Selection */ |
|||
#define TI_ADS1293_WILSON_EN2_REG_VALUE (0x00) /* Wilson Reference Input two Selection */ |
|||
#define TI_ADS1293_WILSON_EN3_REG_VALUE (0x00) /* Wilson Reference Input three Selection */ |
|||
#define TI_ADS1293_WILSON_CN_REG_VALUE (0x00) /* Wilson Reference Input Control */ |
|||
|
|||
#define TI_ADS1293_REF_CN_REG_VALUE (0x00) /* Internal Reference Voltage Control */ |
|||
|
|||
#define TI_ADS1293_OSC_CN_REG_VALUE (0x04) /* Clock Source and Output Clock Control */ |
|||
|
|||
#define TI_ADS1293_AFE_RES_REG_VALUE (0x00) /* Analog Front-End Frequency and Resolution */ |
|||
#define TI_ADS1293_AFE_SHDN_CN_REG_VALUE (0x00) /* Analog Front-End Shutdown Control */ |
|||
#define TI_ADS1293_AFE_FAULT_CN_REG_VALUE (0x00) /* Analog Front-End Fault Detection Control */ |
|||
#define TI_ADS1293_AFE_DITHER_EN_REG_VALUE (0x00) /* Enable Dithering in Signma-Delta */ |
|||
#define TI_ADS1293_AFE_PACE_CN_REG_VALUE (0x05) /* Analog Pace Channel Output Routing Control */ |
|||
|
|||
//#define TI_ADS1293_ERROR_LOD_REG_VALUE (0x00) /* Lead Off Detect Error Status */ |
|||
//#define TI_ADS1293_ERROR_STATUS_REG_VALUE (0x72) /* Other Error Status */ |
|||
//#define TI_ADS1293_ERROR_RANGE1_REG_VALUE (0x12) /* Channel 1 Amplifier Out of Range Status */ |
|||
//#define TI_ADS1293_ERROR_RANGE2_REG_VALUE (0x12) /* Channel 1 Amplifier Out of Range Status */ |
|||
//#define TI_ADS1293_ERROR_RANGE3_REG_VALUE (0x36) /* Channel 1 Amplifier Out of Range Status */ |
|||
//#define TI_ADS1293_ERROR_SYNC_REG_VALUE (0x00) /* Synchronization Error */ |
|||
|
|||
|
|||
#define TI_ADS1293_R2_RATE_REG_VALUE (0x02) /* R2 Decimation Rate */ |
|||
#define TI_ADS1293_R3_RATE1_REG_VALUE (0x02) /* R3 Decimation Rate for Channel 1 */ |
|||
#define TI_ADS1293_R3_RATE2_REG_VALUE (0x02) /* R3 Decimation Rate for Channel 2 */ |
|||
#define TI_ADS1293_R3_RATE3_REG_VALUE (0x02) /* R3 Decimation Rate for Channel 3 */ |
|||
#define TI_ADS1293_P_DRATE_REG_VALUE (0x00) /* 2x Pace Data Rate for all channels */ |
|||
#define TI_ADS1293_DIS_EFILTER_REG_VALUE (0x00) /* ECG Filters Disabled */ |
|||
#define TI_ADS1293_DRDYB_SRC_REG_VALUE (0x08) /* Data Ready Pin Source */ |
|||
#define TI_ADS1293_SYNCOUTB_SRC_REG_VALUE (0x00) /* Sync Out Pin Source */ |
|||
#define TI_ADS1293_MASK_DRDYB_REG_VALUE (0x00) /* Optional Mask Control for DRDYB Output */ |
|||
#define TI_ADS1293_MASK_ERR_REG_VALUE (0x00) /* Mask Error on ALARMB Pin */ |
|||
|
|||
#define TI_ADS1293_ALARM_FILTER_REG_VALUE (0x33) /* Digital Filter for Analog Alarm Signals */ |
|||
#define TI_ADS1293_CH_CNFG_REG_VALUE (0x30) /* Configure Channel for Loop Read Back Mode */ |
|||
|
|||
//#define TI_ADS1293_DATA_STATUS_REG_VALUE (0x00) /* ECG and Pace Data Ready Status */ |
|||
//#define TI_ADS1293_DATA_CH1_PACE_H_REG_VALUE (0x00) /* Channel1 Pace Data High [15:8] */ |
|||
//#define TI_ADS1293_DATA_CH1_PACE_L_REG_VALUE (0x00) /* Channel1 Pace Data Low [7:0] */ |
|||
//#define TI_ADS1293_DATA_CH2_PACE_H_REG_VALUE (0x00) /* Channel2 Pace Data High [15:8] */ |
|||
//#define TI_ADS1293_DATA_CH2_PACE_L_REG_VALUE (0x00) /* Channel2 Pace Data Low [7:0] */ |
|||
//#define TI_ADS1293_DATA_CH3_PACE_H_REG_VALUE (0x00) /* Channel3 Pace Data High [15:8] */ |
|||
//#define TI_ADS1293_DATA_CH3_PACE_L_REG_VALUE (0x00) /* Channel3 Pace Data Low [7:0] */ |
|||
//#define TI_ADS1293_DATA_CH1_ECG_H_REG_VALUE (0x00) /* Channel1 ECG Data High [23:16] */ |
|||
//#define TI_ADS1293_DATA_CH1_ECG_M_REG_VALUE (0x00) /* Channel1 ECG Data Medium [15:8] */ |
|||
//#define TI_ADS1293_DATA_CH1_ECG_L_REG_VALUE (0x00) /* Channel1 ECG Data Low [7:0] */ |
|||
//#define TI_ADS1293_DATA_CH2_ECG_H_REG_VALUE (0x00) /* Channel2 ECG Data High [23:16] */ |
|||
//#define TI_ADS1293_DATA_CH2_ECG_M_REG_VALUE (0x00) /* Channel2 ECG Data Medium [15:8] */ |
|||
//#define TI_ADS1293_DATA_CH2_ECG_L_REG_VALUE (0x00) /* Channel2 ECG Data Low [7:0] */ |
|||
//#define TI_ADS1293_DATA_CH3_ECG_H_REG_VALUE (0x00) /* Channel3 ECG Data High [23:16] */ |
|||
//#define TI_ADS1293_DATA_CH3_ECG_M_REG_VALUE (0x00) /* Channel3 ECG Data Medium [15:8] */ |
|||
//#define TI_ADS1293_DATA_CH3_ECG_L_REG_VALUE (0x00) /* Channel3 ECG Data Low [7:0] */ |
|||
|
|||
#define TI_ADS1293_REVID_REG_VALUE (0x40) /* Revision ID */ |
|||
#define TI_ADS1293_DATA_LOOP_REG_VALUE (0x50) /* Loop Read Back Address */ |
|||
|
|||
// Useful definitions |
|||
#define ADS1293_START_CONV (0x01) // Start Conversion Bit |
|||
#endif |
@ -1,148 +0,0 @@ |
|||
#pragma once |
|||
#include <stdint.h> |
|||
|
|||
typedef struct { |
|||
uint8_t add; |
|||
uint8_t data; |
|||
} adscfg_t; |
|||
#if 1 |
|||
static adscfg_t ads0cfg[] = { |
|||
{0x00, 0x00}, // |
|||
{0x01, 0x0a}, // |
|||
{0x02, 0x1a}, // |
|||
{0x03, 0x00}, // |
|||
{0x04, 0x00}, // |
|||
{0x05, 0x00}, // |
|||
{0x06, 0x04}, // |
|||
{0x07, 0x0f}, // |
|||
{0x08, 0xff}, // |
|||
{0x09, 0x00}, // |
|||
{0x0a, 0x07}, // |
|||
{0x0b, 0x00}, // |
|||
{0x0c, 0x04}, // |
|||
{0x0d, 0x00}, // |
|||
{0x0e, 0x00}, // |
|||
{0x0f, 0x00}, // |
|||
{0x10, 0x00}, // |
|||
{0x11, 0x00}, // |
|||
{0x12, 0x04}, // |
|||
{0x13, 0x00}, // |
|||
{0x14, 0x00}, // |
|||
{0x15, 0x00}, // |
|||
{0x16, 0x00}, // |
|||
{0x17, 0x05}, // |
|||
{0x18, 0x00}, // |
|||
{0x19, 0x00}, // |
|||
{0x1a, 0x00}, // |
|||
{0x1b, 0x00}, // |
|||
{0x1c, 0x00}, // |
|||
{0x1d, 0x00}, // |
|||
{0x21, 0x02}, // |
|||
{0x22, 0x02}, // |
|||
{0x23, 0x02}, // |
|||
{0x24, 0x02}, // |
|||
{0x25, 0x00}, // |
|||
{0x26, 0x00}, // |
|||
{0x27, 0x08}, // |
|||
{0x28, 0x00}, // |
|||
{0x29, 0x00}, // |
|||
{0x2a, 0x00}, // |
|||
{0x2b, 0x00}, // |
|||
{0x2c, 0x00}, // |
|||
{0x2d, 0x00}, // |
|||
{0x2e, 0x33}, // |
|||
{0x2f, 0x30}, // |
|||
{0x30, 0x00}, // |
|||
{0x31, 0x00}, // |
|||
{0x32, 0x00}, // |
|||
{0x33, 0x00}, // |
|||
{0x34, 0x00}, // |
|||
{0x35, 0x00}, // |
|||
{0x36, 0x00}, // |
|||
{0x37, 0x00}, // |
|||
{0x38, 0x00}, // |
|||
{0x39, 0x00}, // |
|||
{0x3a, 0x00}, // |
|||
{0x3b, 0x00}, // |
|||
{0x3c, 0x00}, // |
|||
{0x3d, 0x00}, // |
|||
{0x3e, 0x00}, // |
|||
{0x3f, 0x00}, // |
|||
{0x40, 0xff}, // |
|||
{0x50, 0x00}, // |
|||
{0x60, 0x00}, // |
|||
{0x62, 0x00}, // |
|||
}; |
|||
|
|||
static adscfg_t ads1cfg[] = { |
|||
{0x00, 0x00}, // |
|||
{0x01, 0x0c}, // |
|||
{0x02, 0x14}, // |
|||
{0x03, 0x04}, // |
|||
{0x04, 0x00}, // |
|||
{0x05, 0x00}, // |
|||
{0x06, 0x02}, // |
|||
{0x07, 0x0f}, // |
|||
{0x08, 0x13}, // |
|||
{0x09, 0x01}, // |
|||
{0x0a, 0x0f}, // |
|||
{0x0b, 0x00}, // |
|||
{0x0c, 0x00}, // |
|||
{0x0d, 0x00}, // |
|||
{0x0e, 0x00}, // |
|||
{0x0f, 0x00}, // |
|||
{0x10, 0x01}, // |
|||
|
|||
{0x11, 0x00}, // |
|||
{0x12, 0x07}, // |
|||
{0x13, 0x00}, // |
|||
{0x14, 0x00}, // |
|||
{0x15, 0x00}, // |
|||
{0x16, 0x00}, // |
|||
{0x17, 0x05}, // |
|||
{0x18, 0x00}, // |
|||
{0x19, 0x00}, // |
|||
{0x1a, 0x00}, // |
|||
{0x1b, 0x00}, // |
|||
{0x1c, 0x00}, // |
|||
{0x1d, 0x00}, // |
|||
{0x21, 0x02}, // |
|||
{0x22, 0x02}, // |
|||
{0x23, 0x02}, // |
|||
{0x24, 0x02}, // |
|||
|
|||
{0x25, 0x00}, // |
|||
{0x26, 0x00}, // |
|||
{0x27, 0x08}, // |
|||
{0x28, 0x08}, // |
|||
{0x29, 0x00}, // |
|||
{0x2a, 0x00}, // |
|||
{0x2b, 0x00}, // |
|||
{0x2c, 0x00}, // |
|||
{0x2d, 0x00}, // |
|||
{0x2e, 0x33}, // |
|||
{0x2f, 0x30}, // |
|||
{0x30, 0x00}, // |
|||
{0x31, 0x00}, // |
|||
{0x32, 0x00}, // |
|||
{0x33, 0x00}, // |
|||
{0x34, 0x00}, // |
|||
{0x35, 0x00}, // |
|||
|
|||
{0x36, 0x00}, // |
|||
{0x37, 0x00}, // |
|||
{0x38, 0x00}, // |
|||
{0x39, 0x00}, // |
|||
{0x3a, 0x00}, // |
|||
{0x3b, 0x00}, // |
|||
{0x3c, 0x00}, // |
|||
{0x3d, 0x00}, // |
|||
{0x3e, 0x00}, // |
|||
{0x3f, 0x00}, // |
|||
{0x40, 0xff}, // |
|||
{0x50, 0x00}, // |
|||
{0x60, 0x00}, // |
|||
{0x62, 0x00}, // |
|||
|
|||
}; |
|||
#endif |
@ -0,0 +1,61 @@ |
|||
#pragma once |
|||
|
|||
/******************************************************************************* |
|||
* ADS * |
|||
*******************************************************************************/ |
|||
|
|||
#define ADS1293_SPI_SCK_PIN (32 + 9) |
|||
#define ADS1293_SPI_MOSI_PIN 15 |
|||
#define ADS1293_SPI_MISO_PIN 20 |
|||
#define ADS1293_SPI_CS0_PIN 3 |
|||
#define ADS1293_SPI_CS1_PIN 29 |
|||
#define ADS1293_READY_PIN 31 |
|||
#define LINE_DET_PIN 10 |
|||
|
|||
/** |
|||
* @brief SDCARD |
|||
*/ |
|||
#define SDCARD_SPI_SCK_PIN 4 // SDCARD SCK |
|||
#define SDCARD_SPI_CS_PIN 5 // SDCARD CS |
|||
#define SDCARD_SPI_MISO_PIN 11 // SDCARD MISO |
|||
#define SDCARD_SPI_MOSI_PIN 17 // SDCARD MOSI |
|||
|
|||
#define SDCARD_USBDRIVER_IC_JUNCTION_CTRL_NOE_PIN 1 // flash连接控制引脚 |
|||
#define SDCARD_USBDRIVER_IC_RESET_PIN 28 // flash复位引脚 |
|||
#define SDCARD_POWER_CTRL_PIN 30 // flash供电控制引脚 |
|||
|
|||
/******************************************************************************* |
|||
* 外设分配 * |
|||
*******************************************************************************/ |
|||
#define ADS1293_SPI_INSTANCE 2 |
|||
#define BEEP_PWM_INSTANCE 0 |
|||
#define BATTERY_ADC_CHANNEL 1 // 不重复即可 |
|||
|
|||
/******************************************************************************* |
|||
* LIGHT * |
|||
*******************************************************************************/ |
|||
|
|||
#define LED_GREEN_PIN 9 |
|||
|
|||
/******************************************************************************* |
|||
* 按键 * |
|||
*******************************************************************************/ |
|||
#define BUTTON_PIN 0 |
|||
|
|||
/******************************************************************************* |
|||
* 蜂鸣器 * |
|||
*******************************************************************************/ |
|||
#define BEEP_PIN 18 |
|||
|
|||
/******************************************************************************* |
|||
* 电池电量 * |
|||
*******************************************************************************/ |
|||
#define BATTERY_ADC_PIN NRF_SAADC_INPUT_AIN0 |
|||
|
|||
/******************************************************************************* |
|||
* 应用程序配置 * |
|||
*******************************************************************************/ |
|||
|
|||
#define HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE (3 * 3 * 256) |
|||
#define FILE_MAX_COUNT 1 |
|||
#define SDCARD_MAX_FILE_SIZE (4 * 1024 * 1024) |
@ -0,0 +1,36 @@ |
|||
|
|||
#include "board_battery_state.h" |
|||
|
|||
void BoardBattery_init() {} |
|||
void BoardBattery_load() { |
|||
nrf_drv_saadc_config_t adccfg = NRFX_SAADC_DEFAULT_CONFIG; |
|||
adccfg.resolution = NRF_SAADC_RESOLUTION_12BIT; // 4096 等于满采样率 |
|||
ZERROR_CHECK(nrf_drv_saadc_init(&adccfg, NULL)); |
|||
|
|||
nrf_saadc_channel_config_t channel_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(BATTERY_ADC_PIN); |
|||
channel_config.acq_time = NRF_SAADC_ACQTIME_20US; |
|||
ZERROR_CHECK(nrfx_saadc_channel_init(BATTERY_ADC_CHANNEL, &channel_config)); |
|||
} |
|||
void BoardBattery_unload() { nrf_drv_saadc_uninit(); } |
|||
|
|||
int16_t BoardBattery_get_adc_val() { |
|||
int16_t val = znrf_adc_channel_read_val(BATTERY_ADC_CHANNEL); |
|||
return val; |
|||
} |
|||
int16_t BoardBattery_get_battery_level() { |
|||
static const float maxv = 4.0; |
|||
static const float minv = 3.3; |
|||
|
|||
float voltage = BoardBattery_get_adc_val() / 4096.0 * 3.3 / 2.0 * 3; |
|||
if (voltage > maxv) voltage = maxv; |
|||
if (voltage < minv) voltage = minv; |
|||
|
|||
float percent = (voltage - minv) / (maxv - minv) * 100 + (float)0.1 /*加0.1是为了避免999.999时显示电量为90*/; |
|||
int16_t percent_int = (int16_t)percent; |
|||
if (percent_int < 10 && percent_int != 0) { |
|||
percent_int = 3; |
|||
} else { |
|||
percent_int = percent_int / 10 * 10; |
|||
} |
|||
return percent_int; |
|||
} |
@ -0,0 +1,15 @@ |
|||
#pragma once |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "board/board.h" |
|||
#include "znordic.h" |
|||
|
|||
void BoardBattery_init(); |
|||
void BoardBattery_load(); |
|||
void BoardBattery_unload(); |
|||
|
|||
int16_t BoardBattery_get_adc_val(); |
|||
int16_t BoardBattery_val(); |
|||
int16_t BoardBattery_get_battery_level(); // 0->100 |
@ -0,0 +1,93 @@ |
|||
#include "board_beep_ctrl.h" |
|||
#define BEEP_TIMER_INTERVAL (200) |
|||
|
|||
APP_TIMER_DEF(m_beep_tmr); // |
|||
static nrf_drv_pwm_t m_beep_pwm0 = NRF_DRV_PWM_INSTANCE(BEEP_PWM_INSTANCE); |
|||
static nrf_pwm_values_individual_t m_beep_pwm0_seq_values = {0}; |
|||
static nrf_pwm_sequence_t const m_beep_pwm0_seq = { |
|||
.values.p_individual = &m_beep_pwm0_seq_values, |
|||
.length = NRF_PWM_VALUES_LENGTH(m_beep_pwm0_seq_values), |
|||
.repeats = 0, |
|||
.end_delay = 0, |
|||
}; |
|||
static nrf_drv_pwm_config_t const m_beep_pwm0_config0 = { |
|||
.output_pins = {BEEP_PIN}, |
|||
.irq_priority = APP_IRQ_PRIORITY_LOWEST, |
|||
.base_clock = NRF_PWM_CLK_125kHz, |
|||
.count_mode = NRF_PWM_MODE_UP, |
|||
.top_value = 46, // 125kHz / 46 = 2.717k |
|||
.load_mode = NRF_PWM_LOAD_INDIVIDUAL, |
|||
.step_mode = NRF_PWM_STEP_AUTO, |
|||
}; |
|||
BoardBeepEffect_t m_beep_effect = kBoardBeepEffect_none; |
|||
static m_beep_cnt = 0; |
|||
|
|||
static void beep_tmr_handler(void *context) { |
|||
if (m_beep_effect == kBoardBeepEffect_none) { |
|||
BoardBeepCtrl_set(false); |
|||
} else if (m_beep_effect == kBoardBeepEffect_oneShortBeep) { |
|||
if (m_beep_cnt == 0) { |
|||
BoardBeepCtrl_set(true); |
|||
} else if (m_beep_cnt >= 1) { |
|||
BoardBeepCtrl_set(false); |
|||
app_timer_stop(m_beep_tmr); |
|||
m_beep_effect = kBoardBeepEffect_none; |
|||
} |
|||
} else if (m_beep_effect == kBoardBeepEffect_threeShortBeep) { |
|||
if (m_beep_cnt % 2 == 0) { |
|||
BoardBeepCtrl_set(true); |
|||
} else if (m_beep_cnt % 2 == 1) { |
|||
BoardBeepCtrl_set(false); |
|||
} else if (m_beep_cnt >= 6) { |
|||
BoardBeepCtrl_set(false); |
|||
app_timer_stop(m_beep_tmr); |
|||
m_beep_effect = kBoardBeepEffect_none; |
|||
} |
|||
} else if (m_beep_effect == kBoardBeepEffect_continuousShortBeep) { |
|||
// 每隔1秒响三声 |
|||
ZASSERT(BEEP_TIMER_INTERVAL == 200); |
|||
if (m_beep_cnt <= 6) { |
|||
if (m_beep_cnt % 2 == 0) { |
|||
BoardBeepCtrl_set(true); |
|||
} else if (m_beep_cnt % 2 == 1) { |
|||
BoardBeepCtrl_set(false); |
|||
} |
|||
} else { |
|||
if (BEEP_TIMER_INTERVAL * m_beep_cnt >= 1000) { |
|||
m_beep_cnt = 0; |
|||
} |
|||
} |
|||
} |
|||
m_beep_cnt++; |
|||
} |
|||
|
|||
void BoardBeepCtrl_init(void) { app_timer_create(&m_beep_tmr, APP_TIMER_MODE_REPEATED, beep_tmr_handler); } |
|||
void BoardBeepCtrl_load() { APP_ERROR_CHECK(nrfx_pwm_init(&m_beep_pwm0, &m_beep_pwm0_config0, NULL)); } |
|||
|
|||
void BoardBeepCtrl_unload() { |
|||
BoardBeepCtrl_set(0); |
|||
nrfx_pwm_uninit(&m_beep_pwm0); |
|||
} |
|||
|
|||
void BoardBeepCtrl_set(uint8_t state) { |
|||
if (state) { |
|||
m_beep_pwm0_seq_values.channel_0 = m_beep_pwm0_config0.top_value / 2; // 设置占空比,数值最大不超过 top_value |
|||
nrfx_pwm_simple_playback(&m_beep_pwm0, &m_beep_pwm0_seq, 1, NRF_DRV_PWM_FLAG_LOOP); |
|||
} else { |
|||
nrfx_pwm_stop(&m_beep_pwm0, true); |
|||
} |
|||
} |
|||
|
|||
void BoardBeepCtrl_setEffect(BoardBeepEffect_t effect) { |
|||
m_beep_effect = effect; |
|||
|
|||
app_timer_stop(m_beep_tmr); |
|||
m_beep_cnt = 0; |
|||
if (m_beep_effect == kBoardBeepEffect_none) { |
|||
BoardBeepCtrl_set(false); |
|||
} |
|||
|
|||
else { |
|||
app_timer_start(m_beep_tmr, APP_TIMER_TICKS(BEEP_TIMER_INTERVAL), NULL); |
|||
} |
|||
} |
@ -0,0 +1,24 @@ |
|||
#pragma once |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "board/board.h" |
|||
#include "znordic.h" |
|||
|
|||
typedef enum { |
|||
kBoardBeepEffect_none = 0, |
|||
// 响一声 |
|||
kBoardBeepEffect_oneShortBeep, |
|||
// 响三声 |
|||
kBoardBeepEffect_threeShortBeep, |
|||
// 持续短鸣报警 |
|||
kBoardBeepEffect_continuousShortBeep, |
|||
} BoardBeepEffect_t; |
|||
|
|||
void BoardBeepCtrl_init(void); |
|||
void BoardBeepCtrl_load(); |
|||
void BoardBeepCtrl_unload(); |
|||
|
|||
void BoardBeepCtrl_set(uint8_t beep); |
|||
void BoardBeepCtrl_setEffect(BoardBeepEffect_t effect); |
@ -0,0 +1,24 @@ |
|||
#include "board_button.h" |
|||
|
|||
#include "app_button.h" |
|||
#include "board.h" |
|||
#include "znordic.h" |
|||
|
|||
#define BUTTON_DETECTION_DELAY APP_TIMER_TICKS(50) |
|||
static board_button_cb_t m_cb; |
|||
// |
|||
void button_process_handler(uint8_t pin_no, uint8_t button_action) {} |
|||
|
|||
static app_button_cfg_t buttons[] = { |
|||
{BUTTON_PIN, false, NRF_GPIO_PIN_PULLUP, button_process_handler}, |
|||
}; |
|||
void BoardButton_Init(board_button_cb_t cb) { // |
|||
ZASSERT(app_button_init(buttons, ARRAY_SIZE(buttons), BUTTON_DETECTION_DELAY)); |
|||
} |
|||
void BoardButton_load() { ZASSERT(app_button_enable()); } |
|||
void BoardButton_unload() { ZASSERT(app_button_disable()); } |
|||
|
|||
void BoardButton_enable_sense() { |
|||
app_button_disable(); |
|||
nrf_gpio_cfg_sense_input(BUTTON_PIN, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); |
|||
} |
@ -0,0 +1,18 @@ |
|||
#pragma once |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "board/board.h" |
|||
|
|||
typedef enum { |
|||
kButton_mainButton, |
|||
} ButtonIndex_t; |
|||
|
|||
typedef void (*board_button_cb_t)(ButtonIndex_t pin_no, uint8_t button_action); |
|||
|
|||
void BoardButton_Init(board_button_cb_t cb); // main中初始化一遍 |
|||
void BoardButton_load(); |
|||
void BoardButton_unload(); |
|||
|
|||
void BoardButton_enable_sense(); // 低功耗睡眠前调用该方法 |
@ -0,0 +1,70 @@ |
|||
#include "board_light_ctrl.h" |
|||
|
|||
#include "board.h" |
|||
#include "znordic.h" |
|||
|
|||
#define BLINK_CNT 1 |
|||
#define BLINK_PERIOD_MS (1000) |
|||
|
|||
static LightEffect m_light_effect; |
|||
static bool m_led_green_light_state; |
|||
static int m_blink_cnt; |
|||
APP_TIMER_DEF(m_green_light_effect_tmr); |
|||
|
|||
static void BoardLight_effect_tmr_handler(void *p_context) { // |
|||
if (m_light_effect == kLightEffect_close) { |
|||
if (m_led_green_light_state) { |
|||
BoardLight_setGreenLightState(false); |
|||
} |
|||
} else if (m_light_effect == kLightEffect_open) { |
|||
if (!m_led_green_light_state) { |
|||
BoardLight_setGreenLightState(true); |
|||
} |
|||
} else if (m_light_effect == kLightEffect_slowFlash) { |
|||
if (m_blink_cnt % 1 == 0) { |
|||
BoardLight_toggleGreenLightState(); |
|||
} |
|||
} |
|||
m_blink_cnt++; |
|||
} |
|||
|
|||
void BoardLight_Init() { |
|||
znrf_gpio_cfg_output(LED_GREEN_PIN, NRF_GPIO_PIN_NOPULL); |
|||
|
|||
ZERROR_CHECK(app_timer_create(&m_green_light_effect_tmr, APP_TIMER_MODE_REPEATED, BoardLight_effect_tmr_handler)); |
|||
} |
|||
void BoardLight_load() {} |
|||
void BoardLight_unload() {} |
|||
|
|||
void BoardLight_setGreenLightState(bool state) { |
|||
if (state) { |
|||
nrf_gpio_pin_set(LED_GREEN_PIN); |
|||
m_led_green_light_state = true; |
|||
} else { |
|||
nrf_gpio_pin_clear(LED_GREEN_PIN); |
|||
m_led_green_light_state = false; |
|||
} |
|||
} |
|||
|
|||
void BoardLight_toggleGreenLightState() { nrf_gpio_pin_toggle(LED_GREEN_PIN); } |
|||
|
|||
void BoardLight_setGreenLightEffect(LightEffect effect) { |
|||
m_light_effect = effect; |
|||
|
|||
switch (effect) { |
|||
case kLightEffect_close: |
|||
app_timer_stop(m_green_light_effect_tmr); |
|||
BoardLight_setGreenLightState(false); |
|||
break; |
|||
case kLightEffect_open: |
|||
app_timer_stop(m_green_light_effect_tmr); |
|||
BoardLight_setGreenLightState(true); |
|||
break; |
|||
case kLightEffect_slowFlash: |
|||
app_timer_start(m_green_light_effect_tmr, APP_TIMER_TICKS(BLINK_PERIOD_MS), NULL); |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
return; |
|||
} |
@ -0,0 +1,23 @@ |
|||
#pragma once |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "board/board.h" |
|||
|
|||
typedef enum { |
|||
|
|||
kLightEffect_close, |
|||
kLightEffect_open, |
|||
kLightEffect_slowFlash, |
|||
|
|||
} LightEffect; |
|||
|
|||
void BoardLight_Init(); // main中初始化一遍 |
|||
void BoardLight_load(); |
|||
void BoardLight_unload(); |
|||
|
|||
void BoardLight_setGreenLightState(bool state); // 尽量不要直接使用该函数 |
|||
void BoardLight_toggleGreenLightState(); // 尽量不要直接使用该函数 |
|||
|
|||
void BoardLight_setGreenLightEffect(LightEffect effect); |
@ -0,0 +1,176 @@ |
|||
#include "board/board_sdcard_driver.h" |
|||
|
|||
#include "board/board.h" |
|||
#include "znordic.h" |
|||
/******************************************************************************* |
|||
* 结构体定义 * |
|||
*******************************************************************************/ |
|||
typedef enum { |
|||
kConnectToInternal, |
|||
kConnectToExt, |
|||
} ConnectTo_t; |
|||
|
|||
FATFS m_fs; |
|||
ConnectTo_t m_connectTo = kConnectToNone; |
|||
static bool m_sdcard_inited; |
|||
|
|||
NRF_BLOCK_DEV_SDC_DEFINE( // |
|||
m_block_dev_sdc, // |
|||
NRF_BLOCK_DEV_SDC_CONFIG(SDC_SECTOR_SIZE, // |
|||
APP_SDCARD_CONFIG(SDCARD_SPI_MOSI_PIN, // |
|||
SDCARD_SPI_MISO_PIN, // |
|||
SDCARD_SPI_SCK_PIN, // |
|||
SDCARD_SPI_CS_PIN)), |
|||
NFR_BLOCK_DEV_INFO_CONFIG("IFLYTOP", "SDC", "1.00")); |
|||
|
|||
/** |
|||
* |
|||
* @warning: |
|||
* SD卡和单片机是一直连接着的,SD卡和读卡器是通过一个电子开关隔离开的的。 |
|||
* 所以如果SD卡切换到读卡器,单片机需要先将SPI引脚初始化成输入高阻,然后再切换到读卡器。避免引脚竞争。 |
|||
* 此处代码需要谨慎修改,容易造成硬件损坏。 |
|||
* |
|||
* SDCARD_POWER_CTRL_PIN:低电平有效 |
|||
* SDCARD_USBDRIVER_IC_JUNCTION_CTRL_NOE_PIN:0:连接读卡器 1:连接单片机 |
|||
* |
|||
*/ |
|||
void Board_sdcardInit() { |
|||
if (!m_sdcard_inited) return; |
|||
/** |
|||
* @brief SDCARD SPI 引脚初始化 |
|||
*/ |
|||
nrf_gpio_cfg_sense_input(SDCARD_SPI_CS_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); |
|||
nrf_gpio_cfg_sense_input(SDCARD_SPI_MISO_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); |
|||
nrf_gpio_cfg_sense_input(SDCARD_SPI_MOSI_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); |
|||
nrf_gpio_cfg_sense_input(SDCARD_SPI_SCK_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); |
|||
/** |
|||
* @brief SD卡 USB读卡器IC复位引脚 |
|||
* 引脚一直配置成高即可 |
|||
*/ |
|||
znrf_gpio_cfg_output(SDCARD_USBDRIVER_IC_RESET_PIN, NRF_GPIO_PIN_NOPULL); |
|||
nrf_gpio_pin_write(SDCARD_USBDRIVER_IC_RESET_PIN, 1); |
|||
/** |
|||
* @brief 初始化 SD卡连接切换引脚 |
|||
*/ |
|||
znrf_gpio_cfg_output(SDCARD_USBDRIVER_IC_JUNCTION_CTRL_NOE_PIN, NRF_GPIO_PIN_NOPULL); |
|||
nrf_gpio_pin_write(SDCARD_USBDRIVER_IC_JUNCTION_CTRL_NOE_PIN, 0); // OE = 0 |
|||
/** |
|||
* @brief SDCARD电源控制引脚 |
|||
*/ |
|||
znrf_gpio_cfg_output(SDCARD_POWER_CTRL_PIN, NRF_GPIO_PIN_NOPULL); |
|||
nrf_gpio_pin_write(SDCARD_POWER_CTRL_PIN, 0); // POWER = 0 打开电源 |
|||
m_connectTo = kConnectToExt; |
|||
|
|||
static diskio_blkdev_t drives[] = // |
|||
{DISKIO_BLOCKDEV_CONFIG(NRF_BLOCKDEV_BASE_ADDR(m_block_dev_sdc, block_dev), NULL)}; |
|||
diskio_blockdev_register(drives, ARRAY_SIZE(drives)); |
|||
m_sdcard_inited = true; |
|||
} |
|||
|
|||
void Board_sdcardConnectToExt() { |
|||
/** |
|||
* @brief |
|||
*/ |
|||
if (m_connectTo == kConnectToExt) { |
|||
return; |
|||
} |
|||
|
|||
/** |
|||
* @brief |
|||
* 0. 卸载文件系统 |
|||
* 2. 配置SPI引脚成输入 |
|||
* 3. 切换引脚连接 |
|||
* 4. 通过给SD卡重启上电,复位SD卡状态 |
|||
*/ |
|||
|
|||
/** |
|||
* @brief 卸载文件系统 |
|||
* |
|||
* PS:这里会自动卸载SPI驱动 |
|||
*/ |
|||
|
|||
f_mount(NULL, "", 1); // 卸载文件系统 |
|||
disk_uninitialize(0); // 卸载磁盘驱动 |
|||
|
|||
/** |
|||
* @brief 配置SPI引脚成输入 |
|||
*/ |
|||
nrf_gpio_cfg_sense_input(SDCARD_SPI_CS_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); |
|||
nrf_gpio_cfg_sense_input(SDCARD_SPI_MISO_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); |
|||
nrf_gpio_cfg_sense_input(SDCARD_SPI_MOSI_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); |
|||
nrf_gpio_cfg_sense_input(SDCARD_SPI_SCK_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE); |
|||
|
|||
/** |
|||
* @brief 关闭SD卡电源 |
|||
*/ |
|||
nrf_gpio_pin_write(SDCARD_POWER_CTRL_PIN, 1); |
|||
|
|||
/** |
|||
* @brief 切换引脚连接 |
|||
*/ |
|||
nrf_gpio_pin_write(SDCARD_USBDRIVER_IC_JUNCTION_CTRL_NOE_PIN, 0); |
|||
|
|||
/** |
|||
* @brief 打开SD卡电源 |
|||
*/ |
|||
nrf_delay_ms(30); // 让SD卡通过断电复位一会 |
|||
nrf_gpio_pin_write(SDCARD_POWER_CTRL_PIN, 0); // 开 |
|||
m_connectTo = kConnectToExt; |
|||
} |
|||
void Board_sdcardConnectToInternal() { |
|||
if (m_connectTo == kConnectToInternal) { |
|||
return; |
|||
} |
|||
|
|||
/** |
|||
* @brief |
|||
* 0. 断开SD卡电源 |
|||
* 1. 断开SD卡与读卡器的连接 |
|||
* 2. 打开SD电源 |
|||
* 3. 挂载SD卡 |
|||
*/ |
|||
|
|||
/** |
|||
* @brief 断开SD卡电源 |
|||
*/ |
|||
nrf_gpio_pin_write(SDCARD_POWER_CTRL_PIN, 1); |
|||
|
|||
/** |
|||
* @brief 断开SD卡与读卡器的连接 |
|||
*/ |
|||
nrf_gpio_pin_write(SDCARD_USBDRIVER_IC_JUNCTION_CTRL_NOE_PIN, 1); |
|||
|
|||
/** |
|||
* @brief 打开SD电源 |
|||
*/ |
|||
nrf_delay_ms(30); // 让SD卡通过断电复位一会 |
|||
nrf_gpio_pin_write(SDCARD_POWER_CTRL_PIN, 0); // 开 |
|||
|
|||
/** |
|||
* @brief 挂载SD卡 |
|||
*/ |
|||
DSTATUS disk_state = STA_NOINIT; |
|||
for (uint32_t retries = 3; retries && disk_state; --retries) { |
|||
disk_state = disk_initialize(0); |
|||
} |
|||
if (disk_state != 0) { |
|||
NRF_LOG_INFO("Disk initialization failed. %d", disk_state); |
|||
ZASSERT(0); |
|||
} |
|||
NRF_LOG_INFO("Disk initialization succeeded."); |
|||
FRESULT ff_result; |
|||
ff_result = f_mount(&m_fs, "", 1); |
|||
if (ff_result) { |
|||
NRF_LOG_INFO("Mount failed."); |
|||
ZASSERT(0); |
|||
} |
|||
uint32_t blocks_per_mb = (1024uL * 1024uL) / m_block_dev_sdc.block_dev.p_ops->geometry(&m_block_dev_sdc.block_dev)->blk_size; |
|||
uint32_t capacity = m_block_dev_sdc.block_dev.p_ops->geometry(&m_block_dev_sdc.block_dev)->blk_count / blocks_per_mb; |
|||
|
|||
ZLOGI("Mount success"); |
|||
NRF_LOG_INFO("Capacity: %d MB", capacity); |
|||
|
|||
m_connectTo == kConnectToInternal; |
|||
} |
|||
|
|||
BoardSdcardConnectTo_t Board_sdcardGetConnectTo() { return m_connectTo; } |
@ -0,0 +1,19 @@ |
|||
#pragma once |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "board/board.h" |
|||
|
|||
typedef enum { |
|||
kConnectToNone = 0, |
|||
kConnectToInternal, |
|||
kConnectToExt, |
|||
} BoardSdcardConnectTo_t; |
|||
|
|||
void Board_sdcardInit(); // main中初始化一遍 |
|||
|
|||
void Board_sdcardConnectToExt(); // SD卡连接到外部SD卡读卡器 |
|||
void Board_sdcardConnectToInternal(); // SD卡连接到单片机 |
|||
|
|||
BoardSdcardConnectTo_t Board_sdcardGetConnectTo(); |
@ -1,87 +1,28 @@ |
|||
#pragma once |
|||
#include <stdint.h> |
|||
#include <stdbool.h> |
|||
|
|||
typedef enum { |
|||
kplod_connected_event = 0, // 导联连接事件 |
|||
kplod_disconnected_event, // 导联断开事件 |
|||
kplod_connecting_event, // 导联连接中事件 |
|||
|
|||
kplod_start_charge_event, // 充电事件 |
|||
kplod_charging_event, // 充电中 |
|||
kplod_end_charge_event, // 充电结束事件 |
|||
|
|||
kevent_tmr_scheduler_event, // 定时器调度事件 |
|||
|
|||
kevent_capture_256data_event, // 采样数据回调 |
|||
kevent_capture_1data_event, // 单次采样数据回调 |
|||
} app_event_type_t; |
|||
|
|||
typedef struct { |
|||
app_event_type_t eventType; |
|||
union { |
|||
uint32_t plod_connected_accumulation_time; // 导联连接累计时间 |
|||
uint8_t* capture_data_cache; // 实时采样数据,数据长度为256字节 |
|||
struct { |
|||
uint32_t frameIndex; |
|||
uint16_t data; |
|||
} frame_data; |
|||
} val; |
|||
} app_event_t; |
|||
|
|||
#include <stdint.h> |
|||
typedef enum { |
|||
// 待机 |
|||
kdevice_state_standby = 0, |
|||
// 开机 |
|||
kdevice_state_poweron, |
|||
// 首页 |
|||
kdevice_state_home, |
|||
// 提示用户保持静止 |
|||
kdevice_state_keep_still, |
|||
// 采集中 |
|||
kdevice_state_sampling, |
|||
// 采集完成 |
|||
kdevice_state_sampling_complete, |
|||
// 采集异常 |
|||
kdevice_state_sampling_error, |
|||
// 充电中 |
|||
kdevice_state_charging, |
|||
// Ready |
|||
kdevice_state_ready = 1, |
|||
// sample |
|||
kdevice_state_sampling = 2, |
|||
} device_state_t; |
|||
|
|||
static const char* device_state_to_str(device_state_t ds) { |
|||
static const char* ds2str(device_state_t ds) { |
|||
switch (ds) { |
|||
case kdevice_state_standby: |
|||
return "standby"; |
|||
case kdevice_state_poweron: |
|||
return "poweron"; |
|||
case kdevice_state_home: |
|||
return "home"; |
|||
case kdevice_state_keep_still: |
|||
return "keep_still"; |
|||
case kdevice_state_ready: |
|||
return "ready"; |
|||
case kdevice_state_sampling: |
|||
return "sampling"; |
|||
case kdevice_state_sampling_complete: |
|||
return "sampling_complete"; |
|||
case kdevice_state_sampling_error: |
|||
return "sampling_error"; |
|||
case kdevice_state_charging: |
|||
return "charging"; |
|||
default: |
|||
return "unknow"; |
|||
return "unknown"; |
|||
} |
|||
} |
|||
|
|||
void app_event_process_cb(void* p_event_data, uint16_t event_size); |
|||
|
|||
void ds_change_to_state(device_state_t state); |
|||
uint32_t ds_cur_state_haspassed_ms(); |
|||
device_state_t ds_now_state(); |
|||
|
|||
typedef struct { |
|||
bool is_over30s; |
|||
} sample_capture_state_t; |
|||
|
|||
sample_capture_state_t* sample_capture_state_get(); |
|||
|
|||
void sample_capture_state_reset(); |
|||
void sample_capture_state_set_is_over30s(bool over30s); |
|||
device_state_t ds_now_state(); |
@ -1,152 +1,280 @@ |
|||
#include "heart_wave_sample_service.h" |
|||
|
|||
// |
|||
#include "znordic.h" |
|||
// |
|||
#include "app_button.h" |
|||
#include "app_event.h" |
|||
#include "basic/ads1293/ads1293.h" |
|||
#include "nrf_drv_gpiote.h" |
|||
#include "nrfx_timer.h" |
|||
#include "one_conduction_board.h" |
|||
|
|||
static const nrfx_timer_t m_timer = NRFX_TIMER_INSTANCE(1); /**< Timer used for channel sweeps and tx with duty cycle. */ |
|||
static bool m_timer_started = false; /**< True if timer is running. */ |
|||
#define SENSOR0_ID 0 |
|||
#define SENSOR1_ID 3 |
|||
#define SENSOR2_ID 4 |
|||
|
|||
static uint16_t m_capture_buffer_a[128]; |
|||
static uint16_t m_capture_buffer_b[128]; |
|||
/******************************************************************************* |
|||
* STRUCT * |
|||
*******************************************************************************/ |
|||
typedef struct { |
|||
uint8_t add; |
|||
uint8_t data; |
|||
} adscfg_t; |
|||
|
|||
static uint16_t* m_capture_buffer; |
|||
static uint16_t m_capture_buffer_index = 0; |
|||
/******************************************************************************* |
|||
* CONFIG * |
|||
*******************************************************************************/ |
|||
|
|||
volatile static float m_sensor_display_data = 0; // 0->100 |
|||
static uint32_t m_start_capture_tp; |
|||
static uint32_t m_frameindex = 0; |
|||
static adscfg_t m_prvads0cfg[] = // |
|||
{{0x00, 0x00}, {0x01, 0x19}, {0x02, 0x11}, {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x0f}, {0x08, 0xff}, {0x09, 0x00}, {0x0a, 0x07}, {0x0b, 0x07}, {0x0c, 0x74}, {0x0d, 0x01}, {0x0e, 0x02}, {0x0f, 0x03}, {0x10, 0x04}, |
|||
{0x11, 0x00}, {0x12, 0x05}, {0x13, 0x39}, {0x14, 0x36}, {0x15, 0x06}, {0x16, 0x00}, {0x17, 0x05}, {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00}, {0x1c, 0x00}, {0x1d, 0x00}, {0x21, 0x01}, {0x22, 0x20}, {0x23, 0x20}, {0x24, 0x02}, |
|||
{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x08}, {0x28, 0x08}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00}, {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x33}, {0x2f, 0x30}, {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0x00}, {0x35, 0x00}, |
|||
{0x36, 0x00}, {0x37, 0x00}, {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00}, {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00}, {0x40, 0xff}, {0x50, 0x00}, {0x60, 0x00}, {0x62, 0x00}}; |
|||
|
|||
static void swap_buffer() { |
|||
if (m_capture_buffer == NULL) { |
|||
m_capture_buffer = m_capture_buffer_a; |
|||
m_capture_buffer_index = 0; |
|||
return; |
|||
} |
|||
static adscfg_t m_prvads1cfg[] = // |
|||
{{0x00, 0x00}, {0x01, 0x19}, {0x02, 0x11}, {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x0f}, {0x08, 0xff}, {0x09, 0x00}, {0x0a, 0x07}, {0x0b, 0x07}, {0x0c, 0x74}, {0x0d, 0x01}, {0x0e, 0x02}, {0x0f, 0x03}, {0x10, 0x04}, |
|||
{0x11, 0x00}, {0x12, 0x05}, {0x13, 0x39}, {0x14, 0x36}, {0x15, 0x06}, {0x16, 0x00}, {0x17, 0x05}, {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00}, {0x1c, 0x00}, {0x1d, 0x00}, {0x21, 0x01}, {0x22, 0x20}, {0x23, 0x20}, {0x24, 0x02}, |
|||
{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x08}, {0x28, 0x08}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00}, {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x33}, {0x2f, 0x30}, {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0x00}, {0x35, 0x00}, |
|||
{0x36, 0x00}, {0x37, 0x00}, {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00}, {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00}, {0x40, 0xff}, {0x50, 0x00}, {0x60, 0x00}, {0x62, 0x00}}; |
|||
/******************************************************************************* |
|||
* VARIABLE * |
|||
*******************************************************************************/ |
|||
static ads1293_t m_ads1293_0; // U2 |
|||
static ads1293_t m_ads1293_1; // U3 |
|||
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(ADS1293_SPI_INSTANCE); /**< SPI instance. */ |
|||
static bool m_ads1293_driver_is_inited = false; |
|||
static uint32_t m_frame_index; |
|||
static bool m_work_flag; |
|||
|
|||
static uint8_t m_frame_buffer_a[HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE]; |
|||
static uint8_t m_frame_buffer_b[HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE]; |
|||
static uint8_t* m_frame_buffer; |
|||
static int32_t m_frame_buffer_index; |
|||
|
|||
static one_frame_data_t m_sensor_little_frame_cache[LITTLE_DATA_BLOCK_FRAME_NUM]; |
|||
static uint32_t m_little_frame_index; |
|||
|
|||
/******************************************************************************* |
|||
* 函数声明 * |
|||
*******************************************************************************/ |
|||
|
|||
// READY_PIN 中断回调函数 |
|||
static void ads1293_ready_pin_irq(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action); |
|||
// 缓冲区切换BUFFER |
|||
static void prvf_buffer_switch(void); |
|||
|
|||
if (m_capture_buffer == m_capture_buffer_a) { |
|||
m_capture_buffer = m_capture_buffer_b; |
|||
/******************************************************************************* |
|||
* FUNCTION * |
|||
*******************************************************************************/ |
|||
static void prvf_buffer_switch(void) { |
|||
if (m_frame_buffer == m_frame_buffer_a) { |
|||
m_frame_buffer = m_frame_buffer_b; |
|||
m_frame_buffer_index = 0; |
|||
} else { |
|||
m_capture_buffer = m_capture_buffer_a; |
|||
m_frame_buffer = m_frame_buffer_a; |
|||
m_frame_buffer_index = 0; |
|||
} |
|||
m_capture_buffer_index = 0; |
|||
return; |
|||
} |
|||
static float amp_val(uint16_t val, uint16_t valcener, float amp) { |
|||
float valf = (float)val - valcener; |
|||
valf = valf * amp; |
|||
valf += valcener; |
|||
|
|||
if (valf >= 100) { |
|||
valf = 100; |
|||
static inline bool prvf_buffer_is_full(void) { |
|||
if (m_frame_buffer_index >= HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE) { |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
if (valf <= 0) { |
|||
valf = 0; |
|||
static inline void prvf_buffer_push_one_byte(uint8_t byte) { |
|||
if (m_frame_buffer_index >= HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE) { |
|||
return; |
|||
} |
|||
return valf; |
|||
m_frame_buffer[m_frame_buffer_index] = byte; |
|||
m_frame_buffer_index++; |
|||
} |
|||
|
|||
typedef struct { |
|||
float value; |
|||
float efectiveFactor; |
|||
} filter_t; |
|||
static inline void prvf_trigger_capture_data_block_event(uint8_t* data, int datalen) { |
|||
static app_event_t event; |
|||
event.eventType = kevent_capture_data_block_event; |
|||
event.val.block_sensor_data.data = data; |
|||
event.val.block_sensor_data.len = datalen; |
|||
app_sched_event_put(&event, sizeof(app_event_t), app_event_process_cb); |
|||
} |
|||
|
|||
filter_t m_filter = {0, 0.8}; |
|||
static inline void prvf_little_block_cache_push_one_frame(uint32_t data0, uint32_t data1, uint32_t data2) { |
|||
if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { |
|||
return; |
|||
} |
|||
m_sensor_little_frame_cache[m_little_frame_index].data0 = data0; |
|||
m_sensor_little_frame_cache[m_little_frame_index].data1 = data1; |
|||
m_sensor_little_frame_cache[m_little_frame_index].data2 = data2; |
|||
m_little_frame_index++; |
|||
} |
|||
|
|||
static float Filter(filter_t* filter, float newInput) { |
|||
float newv = ((float)filter->value * (1.0f - filter->efectiveFactor)) + ((float)newInput * filter->efectiveFactor); |
|||
filter->value = newv; |
|||
return newv; |
|||
static inline bool prvf_light_block_cache_is_full(void) { |
|||
if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
static inline void prvf_light_block_cache_clear(void) { m_little_frame_index = 0; } |
|||
static inline void prvf_light_block_trigger_event() { |
|||
static app_event_t event; |
|||
event.eventType = kevent_capture_little_data_block_event; |
|||
memcpy(event.val.little_data_block.data, m_sensor_little_frame_cache, LITTLE_DATA_BLOCK_FRAME_NUM); |
|||
event.val.little_data_block.frameIndex = m_frame_index - LITTLE_DATA_BLOCK_FRAME_NUM; |
|||
app_sched_event_put(&event, sizeof(app_event_t), app_event_process_cb); |
|||
} |
|||
static void ads1293_spi_tx_rx_0(uint8_t* tx, uint8_t* rx, uint8_t len) { |
|||
if (!m_ads1293_driver_is_inited) { |
|||
return; |
|||
} |
|||
|
|||
void nrfx_timer_event_handler(nrf_timer_event_t event_type, void* p_context) { // |
|||
uint16_t val = SingleLeadECG_ecg_plod_get_ecg_val(); // 12bit |
|||
m_frameindex++; |
|||
nrf_gpio_pin_clear(ADS1293_SPI_CS0_PIN); |
|||
nrf_drv_spi_transfer(&spi, tx, len, rx, len); |
|||
nrf_gpio_pin_set(ADS1293_SPI_CS0_PIN); |
|||
} |
|||
static void ads1293_spi_tx_rx_1(uint8_t* tx, uint8_t* rx, uint8_t len) { |
|||
if (!m_ads1293_driver_is_inited) { |
|||
return; |
|||
} |
|||
|
|||
nrf_gpio_pin_clear(ADS1293_SPI_CS1_PIN); |
|||
nrf_drv_spi_transfer(&spi, tx, len, rx, len); |
|||
nrf_gpio_pin_set(ADS1293_SPI_CS1_PIN); |
|||
} |
|||
static ads1293_init() { |
|||
/******************************************************************************* |
|||
* 显示数据计算并赋值 * |
|||
* SPI初始化 * |
|||
*******************************************************************************/ |
|||
float val_af100 = (float)val / 4096.0f * 100; |
|||
val_af100 = amp_val(val_af100, 50, 1.8f); |
|||
val_af100 = Filter(&m_filter, val_af100); |
|||
m_sensor_display_data = val_af100; |
|||
static nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; |
|||
spi_config.ss_pin = NRF_DRV_SPI_PIN_NOT_USED; // NRF_DRV_SPI_PIN_NOT_USED |
|||
spi_config.miso_pin = ADS1293_SPI_MISO_PIN; |
|||
spi_config.mosi_pin = ADS1293_SPI_MOSI_PIN; |
|||
spi_config.sck_pin = ADS1293_SPI_SCK_PIN; |
|||
spi_config.frequency = NRF_DRV_SPI_FREQ_8M; |
|||
spi_config.mode = NRF_DRV_SPI_MODE_3; |
|||
// spi_config.mode = |
|||
ZERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, NULL, NULL)); |
|||
|
|||
/******************************************************************************* |
|||
* 采样数据缓存 * |
|||
*******************************************************************************/ |
|||
if (m_capture_buffer == NULL) { |
|||
swap_buffer(); |
|||
} |
|||
znrf_gpio_cfg_output(ADS1293_SPI_CS0_PIN, NRF_GPIO_PIN_NOPULL); |
|||
znrf_gpio_cfg_output(ADS1293_SPI_CS1_PIN, NRF_GPIO_PIN_NOPULL); |
|||
nrf_gpio_pin_set(ADS1293_SPI_CS0_PIN); |
|||
nrf_gpio_pin_set(ADS1293_SPI_CS1_PIN); |
|||
|
|||
if (m_capture_buffer_index < 128) { |
|||
m_capture_buffer[m_capture_buffer_index++] = val; |
|||
} |
|||
m_ads1293_0.spi_tx_rx = ads1293_spi_tx_rx_0; |
|||
m_ads1293_0.id = 0; |
|||
m_ads1293_1.spi_tx_rx = ads1293_spi_tx_rx_1; |
|||
m_ads1293_1.id = 1; |
|||
|
|||
ads1293_spi_init(&m_ads1293_0, ads1293_spi_tx_rx_0); |
|||
ads1293_spi_init(&m_ads1293_1, ads1293_spi_tx_rx_1); |
|||
|
|||
uint8_t revid = ads1293_spi_readreg(&m_ads1293_0, TI_ADS1293_REVID_REG); |
|||
ZLOGI("ads1293_0 revid: %d\n", revid); |
|||
revid = ads1293_spi_readreg(&m_ads1293_1, TI_ADS1293_REVID_REG); |
|||
ZLOGI("ads1293_1 revid: %d\n", revid); |
|||
|
|||
if (m_capture_buffer_index == 128) { |
|||
app_event_t evt; |
|||
evt.eventType = kevent_capture_256data_event; |
|||
evt.val.capture_data_cache = (uint8_t*)m_capture_buffer; |
|||
swap_buffer(); |
|||
app_sched_event_put(&evt, sizeof(evt), app_event_process_cb); |
|||
ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_CONFIG_REG, 0); |
|||
|
|||
for (uint16_t i = 0; i < ZARRAY_SIZE(m_prvads0cfg); i++) { |
|||
ads1293_spi_writereg_and_check(&m_ads1293_0, m_prvads0cfg[i].add, m_prvads0cfg[i].data); |
|||
} |
|||
for (uint16_t i = 0; i < ZARRAY_SIZE(m_prvads1cfg); i++) { |
|||
ads1293_spi_writereg_and_check(&m_ads1293_1, m_prvads1cfg[i].add, m_prvads1cfg[i].data); |
|||
} |
|||
m_ads1293_driver_is_inited = true; |
|||
|
|||
/******************************************************************************* |
|||
* 实时采样数据事件上报 * |
|||
*******************************************************************************/ |
|||
/** |
|||
* @brief READY引脚中断初始化 |
|||
*/ |
|||
{ |
|||
app_event_t evt; |
|||
evt.eventType = kevent_capture_1data_event; |
|||
evt.val.frame_data.frameIndex = m_frameindex; |
|||
evt.val.frame_data.data = val; |
|||
swap_buffer(); |
|||
app_sched_event_put(&evt, sizeof(evt), app_event_process_cb); |
|||
// nrf_gpio_cfg_input(ADS1293_READY_PIN, NRF_GPIO_PIN_PULLUP); |
|||
ZERROR_CHECK(nrfx_gpiote_init()); |
|||
nrf_drv_gpiote_in_config_t inConfig = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false); // 双边沿中断触发 |
|||
inConfig.pull = NRF_GPIO_PIN_PULLUP; // 默认上拉 |
|||
inConfig.sense = NRF_GPIOTE_POLARITY_LOTOHI; // 上升沿触发 |
|||
|
|||
ZERROR_CHECK(nrfx_gpiote_in_init(ADS1293_READY_PIN, &inConfig, ads1293_ready_pin_irq)); |
|||
nrfx_gpiote_in_event_enable(ADS1293_READY_PIN, true); |
|||
} |
|||
} |
|||
|
|||
void hwss_init(void) { |
|||
if (m_timer_started) { |
|||
/** |
|||
* @brief 数据准备号中断回调函数 |
|||
* |
|||
* @param pin |
|||
* @param action |
|||
*/ |
|||
static void ads1293_ready_pin_irq(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { |
|||
if (!m_work_flag) { |
|||
return; |
|||
} |
|||
m_frame_index++; |
|||
// 检查缓冲区是否为空 |
|||
if (!m_frame_buffer) prvf_buffer_switch(); |
|||
|
|||
static uint32_t sample[6]; |
|||
ads1293_read_ecgs(&m_ads1293_0, &sample[0]); |
|||
ads1293_read_ecgs(&m_ads1293_1, &sample[3]); |
|||
|
|||
static uint8_t cache[9]; |
|||
cache[0] = (sample[SENSOR0_ID] >> 0) & 0xff; |
|||
cache[1] = (sample[SENSOR0_ID] >> 8) & 0xff; |
|||
cache[2] = (sample[SENSOR0_ID] >> 16) & 0xff; |
|||
|
|||
cache[3] = (sample[SENSOR1_ID] >> 0) & 0xff; |
|||
cache[4] = (sample[SENSOR1_ID] >> 8) & 0xff; |
|||
cache[5] = (sample[SENSOR1_ID] >> 16) & 0xff; |
|||
|
|||
cache[6] = (sample[SENSOR2_ID] >> 0) & 0xff; |
|||
cache[7] = (sample[SENSOR2_ID] >> 8) & 0xff; |
|||
cache[8] = (sample[SENSOR2_ID] >> 16) & 0xff; |
|||
|
|||
/** |
|||
* @brief 初始化定时器 |
|||
* @brief 缓存数据,并触发数据块事件 |
|||
*/ |
|||
nrfx_err_t err; |
|||
nrfx_timer_config_t timer_cfg = { |
|||
.frequency = NRF_TIMER_FREQ_125kHz, |
|||
.mode = NRF_TIMER_MODE_TIMER, |
|||
.bit_width = NRF_TIMER_BIT_WIDTH_24, |
|||
.p_context = NULL, |
|||
.interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY, |
|||
}; |
|||
|
|||
err = nrfx_timer_init(&m_timer, &timer_cfg, nrfx_timer_event_handler); |
|||
if (err != NRFX_SUCCESS) { |
|||
NRF_LOG_ERROR("nrfx_timer_init failed with: %d\n", err); |
|||
for (int i = 0; i < 9; i++) { |
|||
if (prvf_buffer_is_full()) { |
|||
prvf_trigger_capture_data_block_event(m_frame_buffer, HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE); |
|||
prvf_buffer_switch(); |
|||
} |
|||
prvf_buffer_push_one_byte(cache[i]); |
|||
} |
|||
uint32_t timer_ticks = nrfx_timer_ms_to_ticks(&m_timer, 5); // 200HZ |
|||
nrfx_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, timer_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true); |
|||
m_timer_started = true; |
|||
} |
|||
void hwss_uninit(void) { nrfx_timer_disable(&m_timer); } |
|||
|
|||
void hwss_start_capture(void) { |
|||
m_start_capture_tp = znordic_getpower_on_s(); |
|||
swap_buffer(); |
|||
m_frameindex = 0; |
|||
nrfx_timer_enable(&m_timer); |
|||
/** |
|||
* @brief 缓存数据,并触发小数据块事件 |
|||
*/ |
|||
prvf_little_block_cache_push_one_frame(sample[SENSOR0_ID], sample[SENSOR1_ID], sample[SENSOR2_ID]); |
|||
if (prvf_light_block_cache_is_full()) { |
|||
prvf_light_block_trigger_event(); |
|||
prvf_light_block_cache_clear(); |
|||
} |
|||
} |
|||
void hwss_stop_capture(void) { |
|||
nrfx_timer_disable(&m_timer); |
|||
m_frameindex = 0; |
|||
|
|||
static ads1293_uninit() { |
|||
hwss_stop_capture(); |
|||
m_ads1293_driver_is_inited = false; |
|||
nrf_drv_spi_uninit(&spi); |
|||
} |
|||
|
|||
float hwss_read_val(void) { |
|||
__disable_irq(); |
|||
float val = m_sensor_display_data; |
|||
__enable_irq(); |
|||
return val; |
|||
void hwss_init(void) { |
|||
/** |
|||
* @brief 初始化ads1293硬件接口 |
|||
*/ |
|||
ads1293_init(); |
|||
} |
|||
void hwss_uninit(void) { |
|||
/** |
|||
* @brief 反初始化ads1293硬件接口 |
|||
*/ |
|||
ads1293_uninit(); |
|||
} |
|||
float hwss_read_heart_rate(void) { return 0; } |
|||
|
|||
int hwss_has_captured_time_ms() { return (znordic_getpower_on_s() - m_start_capture_tp) * 1000; } |
|||
void hwss_start_capture(void) { |
|||
m_work_flag = true; |
|||
ads1293_start_conversion(&m_ads1293_0); |
|||
ads1293_start_conversion(&m_ads1293_1); |
|||
} |
|||
void hwss_stop_capture(void) { |
|||
m_work_flag = false; |
|||
ads1293_stop_conversion(&m_ads1293_0); |
|||
ads1293_stop_conversion(&m_ads1293_1); |
|||
} |
@ -1,15 +1,31 @@ |
|||
/** |
|||
* @file heart_wave_sample_service.h |
|||
* @author zhaohe (h_zhaohe@163.com) |
|||
* @brief 心电波形采样服务 |
|||
* @version 0.1 |
|||
* @date 2024-02-01 |
|||
* |
|||
* @copyright Copyright (c) 2024 |
|||
* |
|||
*/ |
|||
#pragma once |
|||
#include "one_conduction_board.h" |
|||
|
|||
// 每256个字节触发一次回调 |
|||
typedef void (*heart_wave_sample_service_callback_t)(uint16_t *p_data, uint16_t length); |
|||
#include "app_event.h" |
|||
#include "board/board.h" |
|||
|
|||
/** |
|||
* @brief 初始化 |
|||
*/ |
|||
void hwss_init(void); |
|||
/** |
|||
* @brief unint |
|||
*/ |
|||
void hwss_uninit(void); |
|||
|
|||
/** |
|||
* @brief 开始采集 |
|||
*/ |
|||
void hwss_start_capture(void); |
|||
void hwss_stop_capture(void); |
|||
|
|||
float hwss_read_val(void); |
|||
float hwss_read_heart_rate(void); |
|||
int hwss_has_captured_time_ms(); |
|||
/** |
|||
* @brief 停止采集 |
|||
*/ |
|||
void hwss_stop_capture(void); |
@ -0,0 +1,372 @@ |
|||
#include "znordic.h" |
|||
// |
|||
#include <stdarg.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
// |
|||
#include "app_uart.h" |
|||
#include "basic/ads1293/ads1293.h" |
|||
#include "zble_module.h" |
|||
#include "zdatachannel_service.h" |
|||
#include "znordic_device_info_mgr.h" |
|||
|
|||
#if defined(UART_PRESENT) |
|||
#include "nrf_uart.h" |
|||
#endif |
|||
#if defined(UARTE_PRESENT) |
|||
#include "nrf_uarte.h" |
|||
#endif |
|||
|
|||
#if 0 |
|||
|
|||
int main() { return 0; } |
|||
#endif |
|||
|
|||
#if 1 |
|||
|
|||
#define ADS1293_SPI_SCK_PIN (32 + 9) |
|||
#define ADS1293_SPI_MOSI_PIN 15 |
|||
#define ADS1293_SPI_MISO_PIN 20 |
|||
#define ADS1293_SPI_CS0_PIN 3 |
|||
#define ADS1293_SPI_CS1_PIN 29 |
|||
#define ADS1293_READY_PIN 31 |
|||
#define LINE_DET_PIN 10 |
|||
|
|||
#define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */ |
|||
#define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */ |
|||
|
|||
#include "board/ads_cfg.h" |
|||
void uart_error_handle(app_uart_evt_t* p_event) {} |
|||
|
|||
/**@brief Function for initializing the UART. */ |
|||
static void uart_init(void) { |
|||
ret_code_t err_code; |
|||
|
|||
app_uart_comm_params_t const comm_params = { |
|||
.rx_pin_no = UART_PIN_DISCONNECTED, |
|||
.tx_pin_no = 0, |
|||
.rts_pin_no = UART_PIN_DISCONNECTED, |
|||
.cts_pin_no = UART_PIN_DISCONNECTED, |
|||
.flow_control = APP_UART_FLOW_CONTROL_DISABLED, |
|||
.use_parity = false, |
|||
.baud_rate = UART_BAUDRATE_BAUDRATE_Baud115200, |
|||
}; |
|||
APP_UART_FIFO_INIT(&comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE, uart_error_handle, APP_IRQ_PRIORITY_HIGHEST, err_code); |
|||
APP_ERROR_CHECK(err_code); |
|||
} |
|||
|
|||
/******************************************************************************* |
|||
* 3µ¼Áª-ADS1293-²âÊÔ * |
|||
*******************************************************************************/ |
|||
APP_TIMER_DEF(m_init_tmr); |
|||
APP_TIMER_DEF(m_report_tmr); |
|||
ZDATACHANNEL_DEF(m_zhrs, 2 /**/, 1 /*client num*/); |
|||
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(2); /**< SPI instance. */ |
|||
static ads1293_t m_ads1293_0; // U2 |
|||
static ads1293_t m_ads1293_1; // U3 |
|||
static void zdatachanel_send_log(const char* fmt, ...); |
|||
static void three_lead_ecg_ecg_init(); |
|||
|
|||
uint32_t get_ready_pin_state_get() { return nrf_gpio_pin_read(ADS1293_READY_PIN); } |
|||
|
|||
static void on_service_init(void) { |
|||
ZLOGI("init zdatachannel service"); |
|||
zdatachannel_init_t zdatachannle_init; |
|||
memset(&zdatachannle_init, 0, sizeof(zdatachannle_init)); |
|||
zdatachannle_init.data_handler = NULL; |
|||
ZERROR_CHECK(zdatachannel_init(&m_zhrs, &zdatachannle_init)); |
|||
} |
|||
static int changecount = 0; |
|||
void dump_state() { |
|||
static uint32_t last = 0; |
|||
uint32_t nows = znordic_rtc_gettime_s(); |
|||
if (nows != last) { |
|||
zdatachanel_send_log("%d\n", changecount); |
|||
|
|||
uint8_t leadoffstate = ads1293_spi_readreg(&m_ads1293_0, TI_ADS1293_ERROR_LOD_REG); |
|||
zdatachanel_send_log("%d%d%d%d_%d%d%d%d\n", // |
|||
leadoffstate >> 7 & 0x1, leadoffstate >> 6 & 0x1, leadoffstate >> 5 & 0x1, leadoffstate >> 4 & 0x1, // |
|||
leadoffstate >> 3 & 0x1, leadoffstate >> 2 & 0x1, leadoffstate >> 1 & 0x1, leadoffstate >> 0 & 0x1); // |
|||
|
|||
last = nows; |
|||
changecount = 0; |
|||
} |
|||
} |
|||
|
|||
int main() { |
|||
APP_SCHED_INIT(APP_TIMER_SCHED_EVENT_DATA_SIZE, 20); |
|||
znordic_init(); |
|||
static zble_module_cfg_t cfg = // |
|||
{ |
|||
.deviceName = "ThreeLeadECG", |
|||
.on_service_init = on_service_init, |
|||
}; |
|||
zble_module_init(&cfg); |
|||
NRF_LOG_INFO("compile time :%s", __TIME__); |
|||
uart_init(); |
|||
|
|||
nrf_gpio_cfg_input(LINE_DET_PIN, NRF_GPIO_PIN_PULLUP); |
|||
three_lead_ecg_ecg_init(); |
|||
ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_CONFIG_REG, 0x01); |
|||
ads1293_spi_writereg(&m_ads1293_1, TI_ADS1293_CONFIG_REG, 0x01); |
|||
|
|||
while (true) { |
|||
app_sched_execute(); |
|||
if (NRF_LOG_PROCESS() == false) { |
|||
// nrf_pwr_mgmt_run(); |
|||
} |
|||
static bool state = false; |
|||
bool now = get_ready_pin_state_get(); |
|||
if (state != now) { |
|||
state = now; |
|||
changecount++; |
|||
|
|||
if (now) { |
|||
uint32_t val = 0; |
|||
ads1293_read_ecg(&m_ads1293_0, 1, &val); |
|||
zdatachanel_send_log("%d\n", val); |
|||
} |
|||
} |
|||
// dump_state(); |
|||
} |
|||
} |
|||
|
|||
static void ads1293_spi_tx_rx_0(uint8_t* tx, uint8_t* rx, uint8_t len) { |
|||
nrf_gpio_pin_clear(ADS1293_SPI_CS0_PIN); |
|||
nrf_drv_spi_transfer(&spi, tx, len, rx, len); |
|||
nrf_gpio_pin_set(ADS1293_SPI_CS0_PIN); |
|||
} |
|||
static void ads1293_spi_tx_rx_1(uint8_t* tx, uint8_t* rx, uint8_t len) { |
|||
nrf_gpio_pin_clear(ADS1293_SPI_CS1_PIN); |
|||
nrf_drv_spi_transfer(&spi, tx, len, rx, len); |
|||
nrf_gpio_pin_set(ADS1293_SPI_CS1_PIN); |
|||
} |
|||
|
|||
static void ads1293_spi_writereg_and_check(ads1293_t* ads, uint8_t addr, uint8_t data) { |
|||
uint8_t readbak = 0; |
|||
// readonly add |
|||
if (addr == 0x19 || addr == 0x1a || addr == 0x1b || addr == 0x1c || addr == 0x40 || addr == 0x30) { |
|||
return; |
|||
} |
|||
ads1293_spi_writereg_and_readbak(ads, addr, data, &readbak); |
|||
if (readbak != data) { |
|||
zdatachanel_send_log("ads_%d write %x failed,w:%x readbak:%x\n", ads->id, addr, data, readbak); |
|||
} |
|||
} |
|||
|
|||
static adscfg_t prvads0cfg[] = { |
|||
{0x00, 0x00}, // |
|||
{0x01, 0x19}, // |
|||
{0x02, 0x11}, // |
|||
{0x03, 0x00}, // |
|||
{0x04, 0x00}, // |
|||
{0x05, 0x00}, // |
|||
{0x06, 0x00}, // |
|||
{0x07, 0x0f}, // |
|||
{0x08, 0xff}, // |
|||
{0x09, 0x00}, // |
|||
{0x0a, 0x07}, // |
|||
{0x0b, 0x07}, // |
|||
{0x0c, 0x74}, // |
|||
{0x0d, 0x01}, // |
|||
{0x0e, 0x02}, // |
|||
{0x0f, 0x03}, // |
|||
{0x10, 0x04}, // |
|||
{0x11, 0x00}, // |
|||
{0x12, 0x05}, // |
|||
{0x13, 0x39}, // |
|||
{0x14, 0x36}, // |
|||
{0x15, 0x06}, // |
|||
{0x16, 0x00}, // |
|||
{0x17, 0x05}, // |
|||
{0x18, 0x00}, // |
|||
{0x19, 0x00}, // |
|||
{0x1a, 0x00}, // |
|||
{0x1b, 0x00}, // |
|||
{0x1c, 0x00}, // |
|||
{0x1d, 0x00}, // |
|||
{0x21, 0x01}, // |
|||
{0x22, 0x20}, // |
|||
{0x23, 0x20}, // |
|||
{0x24, 0x02}, // |
|||
{0x25, 0x00}, // |
|||
{0x26, 0x00}, // |
|||
{0x27, 0x08}, // |
|||
{0x28, 0x08}, // |
|||
{0x29, 0x00}, // |
|||
{0x2a, 0x00}, // |
|||
{0x2b, 0x00}, // |
|||
{0x2c, 0x00}, // |
|||
{0x2d, 0x00}, // |
|||
{0x2e, 0x33}, // |
|||
{0x2f, 0x30}, // |
|||
{0x30, 0x00}, // |
|||
{0x31, 0x00}, // |
|||
{0x32, 0x00}, // |
|||
{0x33, 0x00}, // |
|||
{0x34, 0x00}, // |
|||
{0x35, 0x00}, // |
|||
{0x36, 0x00}, // |
|||
{0x37, 0x00}, // |
|||
{0x38, 0x00}, // |
|||
{0x39, 0x00}, // |
|||
{0x3a, 0x00}, // |
|||
{0x3b, 0x00}, // |
|||
{0x3c, 0x00}, // |
|||
{0x3d, 0x00}, // |
|||
{0x3e, 0x00}, // |
|||
{0x3f, 0x00}, // |
|||
{0x40, 0xff}, // |
|||
{0x50, 0x00}, // |
|||
{0x60, 0x00}, // |
|||
{0x62, 0x00} // |
|||
}; |
|||
|
|||
static adscfg_t prvads1cfg[] = { |
|||
{0x00, 0x00}, // |
|||
{0x01, 0x0c}, // |
|||
{0x02, 0x14}, // |
|||
{0x03, 0x00}, // |
|||
{0x04, 0x00}, // |
|||
{0x05, 0x00}, // |
|||
{0x06, 0x00}, // |
|||
{0x07, 0x0f}, // |
|||
{0x08, 0xff}, // |
|||
{0x09, 0x00}, // |
|||
{0x0a, 0x00}, // |
|||
{0x0b, 0x07}, // |
|||
{0x0c, 0x78}, // |
|||
{0x0d, 0x00}, // |
|||
{0x0e, 0x00}, // |
|||
{0x0f, 0x00}, // |
|||
{0x10, 0x04}, // |
|||
{0x11, 0x00}, // |
|||
{0x12, 0x07}, // |
|||
{0x13, 0x3b}, // |
|||
{0x14, 0x24}, // |
|||
{0x15, 0x04}, // |
|||
{0x16, 0x00}, // |
|||
{0x17, 0x05}, // |
|||
{0x18, 0x00}, // |
|||
{0x19, 0x00}, // |
|||
{0x1a, 0x00}, // |
|||
{0x1b, 0x00}, // |
|||
{0x1c, 0x00}, // |
|||
{0x1d, 0x00}, // |
|||
{0x21, 0x01}, // |
|||
{0x22, 0x20}, // |
|||
{0x23, 0x20}, // |
|||
{0x24, 0x02}, // |
|||
{0x25, 0x00}, // |
|||
{0x26, 0x00}, // |
|||
{0x27, 0x08}, // |
|||
{0x28, 0x40}, // |
|||
{0x29, 0x00}, // |
|||
{0x2a, 0x00}, // |
|||
{0x2b, 0x00}, // |
|||
{0x2c, 0x00}, // |
|||
{0x2d, 0x00}, // |
|||
{0x2e, 0x33}, // |
|||
{0x2f, 0x30}, // |
|||
{0x30, 0x00}, // |
|||
{0x31, 0x00}, // |
|||
{0x32, 0x00}, // |
|||
{0x33, 0x00}, // |
|||
{0x34, 0x00}, // |
|||
{0x35, 0x00}, // |
|||
{0x36, 0x00}, // |
|||
{0x37, 0x00}, // |
|||
{0x38, 0x00}, // |
|||
{0x39, 0x00}, // |
|||
{0x3a, 0x00}, // |
|||
{0x3b, 0x00}, // |
|||
{0x3c, 0x00}, // |
|||
{0x3d, 0x00}, // |
|||
{0x3e, 0x00}, // |
|||
{0x3f, 0x00}, // |
|||
{0x40, 0xff}, // |
|||
{0x50, 0x00}, // |
|||
{0x60, 0x00}, // |
|||
{0x62, 0x00}, // |
|||
}; |
|||
|
|||
void config_lod(uint8_t aclvl_lod, uint8_t selac_lod, uint8_t shdn_lod, uint8_t acad_lod) { |
|||
uint8_t reg = 0; |
|||
reg |= aclvl_lod; |
|||
reg |= selac_lod << 2; |
|||
reg |= shdn_lod << 3; |
|||
reg |= acad_lod << 4; |
|||
ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_LOD_CN_REG, reg); |
|||
} |
|||
|
|||
void enable_lod(void) { |
|||
uint8_t reg = ads1293_spi_readreg(&m_ads1293_0, TI_ADS1293_CONFIG_REG); |
|||
reg |= 1 << 3; |
|||
ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_LOD_EN_REG, reg); |
|||
} |
|||
|
|||
void three_lead_ecg_ecg_init() { |
|||
nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; |
|||
spi_config.ss_pin = NRF_DRV_SPI_PIN_NOT_USED; // NRF_DRV_SPI_PIN_NOT_USED |
|||
spi_config.miso_pin = ADS1293_SPI_MISO_PIN; |
|||
spi_config.mosi_pin = ADS1293_SPI_MOSI_PIN; |
|||
spi_config.sck_pin = ADS1293_SPI_SCK_PIN; |
|||
spi_config.frequency = NRF_DRV_SPI_FREQ_8M; |
|||
spi_config.mode = NRF_DRV_SPI_MODE_3; |
|||
// spi_config.mode = |
|||
ZERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, NULL, NULL)); |
|||
|
|||
znrf_gpio_cfg_output(ADS1293_SPI_CS0_PIN, NRF_GPIO_PIN_NOPULL); |
|||
znrf_gpio_cfg_output(ADS1293_SPI_CS1_PIN, NRF_GPIO_PIN_NOPULL); |
|||
nrf_gpio_cfg_input(ADS1293_READY_PIN, NRF_GPIO_PIN_PULLUP); |
|||
|
|||
nrf_gpio_pin_set(ADS1293_SPI_CS0_PIN); |
|||
nrf_gpio_pin_set(ADS1293_SPI_CS1_PIN); |
|||
|
|||
m_ads1293_0.spi_tx_rx = ads1293_spi_tx_rx_0; |
|||
m_ads1293_0.id = 0; |
|||
// m_ads1293_1.spi_tx_rx = ads1293_spi_tx_rx_1; |
|||
// m_ads1293_1.id = 1; |
|||
|
|||
ads1293_spi_init(&m_ads1293_0, ads1293_spi_tx_rx_0); |
|||
ads1293_spi_init(&m_ads1293_1, ads1293_spi_tx_rx_1); |
|||
|
|||
uint8_t revid = ads1293_spi_readreg(&m_ads1293_0, TI_ADS1293_REVID_REG); |
|||
zdatachanel_send_log("ads1293_0 revid: %d\n", revid); |
|||
revid = ads1293_spi_readreg(&m_ads1293_1, TI_ADS1293_REVID_REG); |
|||
zdatachanel_send_log("ads1293_1 revid: %d\n", revid); |
|||
|
|||
zdatachanel_send_log("reset ads1293_0\n"); |
|||
ads1293_spi_writereg(&m_ads1293_0, TI_ADS1293_CONFIG_REG, 0); |
|||
nrf_delay_ms(1000); |
|||
|
|||
for (uint16_t i = 0; i < ZARRAY_SIZE(prvads0cfg); i++) { |
|||
ads1293_spi_writereg_and_check(&m_ads1293_0, prvads0cfg[i].add, prvads0cfg[i].data); |
|||
} |
|||
for (uint16_t i = 0; i < ZARRAY_SIZE(prvads1cfg); i++) { |
|||
ads1293_spi_writereg_and_check(&m_ads1293_1, prvads1cfg[i].add, prvads1cfg[i].data); |
|||
} |
|||
|
|||
// ads1293_spi_writereg(&m_ads1293_1, TI_ADS1293_CONFIG_REG, 0x01); |
|||
} |
|||
|
|||
static void zdatachanel_send_log(const char* fmt, ...) { |
|||
static char tx[256] = {0}; |
|||
int len = 0; |
|||
va_list args; |
|||
va_start(args, fmt); |
|||
len = vsprintf(tx, fmt, args); |
|||
len = strlen(tx); |
|||
int ret_val; |
|||
if (len >= 0) { |
|||
for (uint16_t i = 0; i < len; i++) { |
|||
do { |
|||
ret_val = app_uart_put(tx[i]); |
|||
} while (ret_val != NRF_SUCCESS); |
|||
} |
|||
return; |
|||
} |
|||
va_end(args); |
|||
} |
|||
#endif |
@ -0,0 +1,155 @@ |
|||
#include "sample_data_manager_service.h" |
|||
|
|||
#include "board/board.h" |
|||
#include "board/board_sdcard_driver.h" |
|||
#include "znordic.h" |
|||
/******************************************************************************* |
|||
* 全局变量 * |
|||
*******************************************************************************/ |
|||
static FIL m_default_file_handler; |
|||
static sample_data_fileinfo_list_t m_sample_fileinfo_list; |
|||
static sample_data_fileinfo_t m_sample_fileinfo[FILE_MAX_COUNT]; |
|||
|
|||
/******************************************************************************* |
|||
* 接口层 * |
|||
*******************************************************************************/ |
|||
|
|||
static void read_file_info() { |
|||
/** |
|||
* @brief |
|||
* |
|||
* fdate: |
|||
* bit15:9 |
|||
* Year origin from 1980 (0..127) |
|||
* bit8:5 |
|||
* Month (1..12) |
|||
* bit4:0 |
|||
* Day of the month(1..31) |
|||
* ftime: |
|||
* bit15:11 |
|||
* Hour (0..23) |
|||
* bit10:5 |
|||
* Minute (0..59) |
|||
* bit4:0 |
|||
* Second / 2 (0..29) |
|||
*/ |
|||
FILINFO fno; |
|||
FRESULT ff_result = f_stat("0.bin", &fno); |
|||
m_sample_fileinfo_list.fileinfo[0] = &m_sample_fileinfo[0]; |
|||
|
|||
if (ff_result == FR_OK) { |
|||
static sample_data_filename_t _filename; |
|||
_filename.year = (fno.fdate >> 9) + 1980 - 2000; |
|||
_filename.month = (fno.fdate >> 5) & 0x0F; |
|||
_filename.day = fno.fdate & 0x1F; |
|||
_filename.hour = (fno.ftime >> 11); |
|||
_filename.min = (fno.ftime >> 5) & 0x3F; |
|||
_filename.sec = (fno.ftime & 0x1F) * 2; |
|||
m_sample_fileinfo_list.fileinfo[0]->size = fno.fsize; |
|||
m_sample_fileinfo_list.count = 1; |
|||
} else { |
|||
m_sample_fileinfo_list.fileinfo[0]->size = 0; |
|||
m_sample_fileinfo_list.count = 0; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @brief 文件驱动管理 |
|||
*/ |
|||
void sample_data_mgr_init() { |
|||
Board_sdcardInit(); |
|||
|
|||
// 先连接到单片机,读取下文件状态信息 |
|||
sample_data_mgr_change_to_local_mode(); |
|||
sample_data_mgr_change_to_ext_mode(); |
|||
} |
|||
void sample_data_mgr_loadDriver() { |
|||
// donothing |
|||
} |
|||
void sample_data_mgr_unloadDriver() { |
|||
// donothin |
|||
} |
|||
typedef struct { |
|||
uint8_t filename[8]; |
|||
uint32_t filesize; |
|||
|
|||
} disk_state_t; |
|||
|
|||
/** |
|||
* @brief 存储器连接单片机 |
|||
*/ |
|||
void sample_data_mgr_change_to_local_mode() { |
|||
Board_sdcardConnectToInternal(); |
|||
read_file_info(); |
|||
} |
|||
/** |
|||
* @brief 存储器连接外部typec |
|||
*/ |
|||
void sample_data_mgr_change_to_ext_mode() { |
|||
if (Board_sdcardGetConnectTo() == kConnectToInternal) { |
|||
read_file_info(); |
|||
return; |
|||
} |
|||
Board_sdcardConnectToExt(); |
|||
} |
|||
|
|||
/** |
|||
* @brief 打开文件 |
|||
* |
|||
* @param filename |
|||
* @param flag |
|||
* @return int32_t |
|||
*/ |
|||
|
|||
static FIL m_default_file_handler; |
|||
static bool m_is_open; |
|||
int32_t sample_data_mgr_open(sample_data_filename_t* filename, wrflag_t flag) { |
|||
FRESULT ff_result = f_open(&m_default_file_handler, (const TCHAR*)"0.bin", FA_CREATE_ALWAYS | FA_READ | FA_WRITE); |
|||
ZASSERT(ff_result == FR_OK); |
|||
m_is_open = true; |
|||
return 1; |
|||
} |
|||
int32_t sample_data_mgr_close(int32_t fd) { |
|||
ZASSERT(m_is_open); |
|||
FRESULT ff_result = f_close(&m_default_file_handler); |
|||
ZASSERT(ff_result == FR_OK); |
|||
m_is_open = false; |
|||
return 0; |
|||
} |
|||
int32_t sample_data_mgr_write(int32_t fd, const uint8_t* data, int32_t size) { |
|||
ZASSERT(m_is_open); |
|||
UINT write_size; |
|||
FRESULT ff_result = f_write(&m_default_file_handler, data, size, &write_size); |
|||
ZASSERT(ff_result == FR_OK); |
|||
return write_size; |
|||
} |
|||
int32_t sample_data_mgr_read(int32_t fd, uint8_t* data, int32_t size) { |
|||
ZASSERT(m_is_open); |
|||
UINT read_size; |
|||
FRESULT ff_result = f_read(&m_default_file_handler, data, size, &read_size); |
|||
ZASSERT(ff_result == FR_OK); |
|||
return read_size; |
|||
} |
|||
int32_t sample_data_mgr_get_file_size_by_fd(int32_t fd) { |
|||
ZASSERT(m_is_open); |
|||
return f_size(&m_default_file_handler); |
|||
} |
|||
|
|||
int32_t sample_data_mgr_delete_file(sample_data_filename_t* filename) { |
|||
if (Board_sdcardGetConnectTo() == kConnectToExt) { |
|||
/** |
|||
* @brief |
|||
* 由于设备空闲阶段,SD卡连接的是外部读卡器,所以无法删除文件 |
|||
*/ |
|||
ZLOGW("unsupport now"); |
|||
return 0; |
|||
} |
|||
f_unlink((const TCHAR*)"0.bin"); |
|||
return 0; |
|||
} |
|||
|
|||
sample_data_fileinfo_list_t* sample_data_mgr_get_fileinfo_list() { // |
|||
return &m_sample_fileinfo_list; |
|||
} |
|||
bool sample_data_mgr_storage_is_full() { return m_sample_fileinfo_list.count >= FILE_MAX_COUNT; } |
|||
int32_t sample_data_mgr_get_file_num() { return m_sample_fileinfo_list.count; } |
@ -0,0 +1,78 @@ |
|||
/** |
|||
* @file sample_data_manager_service.h |
|||
* @author zhaohe (h_zhaohe@domain.com) |
|||
* @brief 采样数据存储服务 |
|||
* @version 0.1 |
|||
* @date 2024-02-01 |
|||
* |
|||
* @copyright Copyright (c) 2024 |
|||
* |
|||
*/ |
|||
#pragma once |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "board/board.h" |
|||
|
|||
typedef struct { |
|||
uint8_t year; // from 2000 |
|||
uint8_t month; // 1-12 |
|||
uint8_t day; // 1-31 |
|||
uint8_t hour; // 0-23 |
|||
uint8_t min; // 0-59 |
|||
uint8_t sec; // 0-59 |
|||
uint8_t placeholder[2]; |
|||
} sample_data_filename_t; |
|||
|
|||
typedef struct { |
|||
uint8_t filename[8]; |
|||
int32_t fileuuid; |
|||
int32_t size; |
|||
} sample_data_fileinfo_t; |
|||
|
|||
typedef enum { |
|||
kwrflag_read_only, |
|||
kwrflag_write_only, |
|||
} wrflag_t; |
|||
|
|||
typedef struct { |
|||
sample_data_fileinfo_t* fileinfo[FILE_MAX_COUNT]; |
|||
int count; |
|||
} sample_data_fileinfo_list_t; |
|||
|
|||
/** |
|||
* @brief 文件驱动管理 |
|||
*/ |
|||
void sample_data_mgr_init(); |
|||
void sample_data_mgr_loadDriver(); |
|||
void sample_data_mgr_unloadDriver(); |
|||
/******************************************************************************* |
|||
* 模式切换操作 * |
|||
*******************************************************************************/ |
|||
|
|||
/** |
|||
* @brief 存储器连接单片机 |
|||
*/ |
|||
void sample_data_mgr_change_to_local_mode(); |
|||
/** |
|||
* @brief 存储器连接外部typec |
|||
*/ |
|||
void sample_data_mgr_change_to_ext_mode(); |
|||
|
|||
/******************************************************************************* |
|||
* FILE_OPERATION * |
|||
*******************************************************************************/ |
|||
int32_t sample_data_mgr_open(sample_data_filename_t* filename, wrflag_t flag); |
|||
int32_t sample_data_mgr_close(int32_t fd); |
|||
int32_t sample_data_mgr_write(int32_t fd, const uint8_t* data, int32_t size); |
|||
int32_t sample_data_mgr_read(int32_t fd, uint8_t* data, int32_t size); |
|||
int32_t sample_data_mgr_get_file_size_by_fd(int32_t fd); |
|||
|
|||
/******************************************************************************* |
|||
* 文件管理操作 * |
|||
*******************************************************************************/ |
|||
int32_t sample_data_mgr_delete_file(sample_data_filename_t* filename); |
|||
sample_data_fileinfo_list_t* sample_data_mgr_get_fileinfo_list(); |
|||
bool sample_data_mgr_storage_is_full(); |
|||
int32_t sample_data_mgr_get_file_num(); |
@ -1 +1 @@ |
|||
Subproject commit 92a15d47cbe16579d92ba8385ddbeaeb37778506 |
|||
Subproject commit 2e46516dec82a92dd796312c6787f35e5adf7922 |
Write
Preview
Loading…
Cancel
Save
Reference in new issue