diff --git a/.vscode/settings.json b/.vscode/settings.json index 277d677..898c4cb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -215,7 +215,9 @@ "beep_ctrl.h": "c", "hardware_power_mgr.h": "c", "nrf_fstorage_sd.h": "c", - "nrf_fstorage.h": "c" + "nrf_fstorage.h": "c", + "zdata_statistics.h": "c", + "iflytop_simple_filter.h": "c" }, "files.encoding": "gbk" } \ No newline at end of file diff --git a/app/app.uvoptx b/app/app.uvoptx index 1f4e742..d4029d7 100644 --- a/app/app.uvoptx +++ b/app/app.uvoptx @@ -1746,8 +1746,8 @@ 0 0 0 - .\src\app_service\ecg_service\algo\ecg_data_analyszer.c - ecg_data_analyszer.c + .\src\app_service\ecg_service\algo\iflytop_simple_filter.c + iflytop_simple_filter.c 0 0 @@ -1758,8 +1758,8 @@ 0 0 0 - .\src\app_service\ecg_service\algo\iflytop_simple_filter.c - iflytop_simple_filter.c + .\src\app_service\ecg_service\algo\iflytop_simple_filter_ext.c + iflytop_simple_filter_ext.c 0 0 @@ -1770,8 +1770,8 @@ 0 0 0 - .\src\app_service\ecg_service\algo\iflytop_simple_filter_ext.c - iflytop_simple_filter_ext.c + .\src\app_service\ecg_service\algo\zsimple_qrs.c + zsimple_qrs.c 0 0 @@ -1782,8 +1782,8 @@ 0 0 0 - .\src\app_service\ecg_service\algo\iflytop_simple_qrs.c - iflytop_simple_qrs.c + .\src\app_service\ecg_service\algo\zdata_statistics.c + zdata_statistics.c 0 0 diff --git a/app/app.uvprojx b/app/app.uvprojx index 325084f..c6e96d1 100644 --- a/app/app.uvprojx +++ b/app/app.uvprojx @@ -3886,11 +3886,6 @@ .\src\app_service\ecg_service\ecg_data_mgr.c - ecg_data_analyszer.c - 1 - .\src\app_service\ecg_service\algo\ecg_data_analyszer.c - - iflytop_simple_filter.c 1 .\src\app_service\ecg_service\algo\iflytop_simple_filter.c @@ -3901,9 +3896,14 @@ .\src\app_service\ecg_service\algo\iflytop_simple_filter_ext.c - iflytop_simple_qrs.c + zsimple_qrs.c + 1 + .\src\app_service\ecg_service\algo\zsimple_qrs.c + + + zdata_statistics.c 1 - .\src\app_service\ecg_service\algo\iflytop_simple_qrs.c + .\src\app_service\ecg_service\algo\zdata_statistics.c @@ -7795,11 +7795,6 @@ .\src\app_service\ecg_service\ecg_data_mgr.c - ecg_data_analyszer.c - 1 - .\src\app_service\ecg_service\algo\ecg_data_analyszer.c - - iflytop_simple_filter.c 1 .\src\app_service\ecg_service\algo\iflytop_simple_filter.c @@ -7810,9 +7805,14 @@ .\src\app_service\ecg_service\algo\iflytop_simple_filter_ext.c - iflytop_simple_qrs.c + zsimple_qrs.c + 1 + .\src\app_service\ecg_service\algo\zsimple_qrs.c + + + zdata_statistics.c 1 - .\src\app_service\ecg_service\algo\iflytop_simple_qrs.c + .\src\app_service\ecg_service\algo\zdata_statistics.c diff --git a/app/src/app_basic_service/basic/event.h b/app/src/app_basic_service/basic/event.h index ee7b30a..3357438 100644 --- a/app/src/app_basic_service/basic/event.h +++ b/app/src/app_basic_service/basic/event.h @@ -8,13 +8,13 @@ #define ECG_DATA_REPORT_FRAME_NUM 64 // ecg每次上报的帧数 typedef enum { - kevent_tmr_scheduler_event, + kappevent_tmr_scheduler_event, kappevent_battery_start_charge, // 开始充电事件 kappevent_battery_end_charge, // 停止充电事件 - kappevent_start_capture, - kappevent_stop_capture, + kappevent_start_capture, // 开始采集 + kappevent_stop_capture, // 停止采集 kecg_data_report_event, // ecg数据上报事件 } app_event_type_t; diff --git a/app/src/app_basic_service/zapp.c b/app/src/app_basic_service/zapp.c index cf263bc..1326e68 100644 --- a/app/src/app_basic_service/zapp.c +++ b/app/src/app_basic_service/zapp.c @@ -54,7 +54,7 @@ static void state_machine_driver_tmr_cb(void* p_context) { // wd_feed(); static app_event_t appevent; static uint8_t event_hang_up = 0; - appevent.eventType = kevent_tmr_scheduler_event; + appevent.eventType = kappevent_tmr_scheduler_event; zapp_ebus_push_event_ext(&event_hang_up, &appevent); } @@ -199,6 +199,9 @@ void zapp_gstate_set_preview_state(bool is_preview) { p_gstate->is_preview = is_preview; } +/*********************************************************************************************************************** + * zapp_exec_in_main_context * + ***********************************************************************************************************************/ typedef struct { uint8_t* hang_up_flag; void (*handler)(void*); diff --git a/app/src/app_service/ecg_service/algo/ecg_data_analyszer.c b/app/src/app_service/ecg_service/algo/ecg_data_analyszer.c deleted file mode 100644 index 6138b2a..0000000 --- a/app/src/app_service/ecg_service/algo/ecg_data_analyszer.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "ecg_data_analyszer.h" - -void ecg_data_analyszer_init() {} -void ecg_data_analyszer_push_data(int32_t data) {} - -float ecg_data_analyszer_get_display_data() { return 50; } -float ecg_data_analyszer_get_heart_rate() { return 50; } \ No newline at end of file diff --git a/app/src/app_service/ecg_service/algo/ecg_data_analyszer.h b/app/src/app_service/ecg_service/algo/ecg_data_analyszer.h deleted file mode 100644 index ac04d7f..0000000 --- a/app/src/app_service/ecg_service/algo/ecg_data_analyszer.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -void ecg_data_analyszer_init(); -void ecg_data_analyszer_push_data(int32_t data); - -float ecg_data_analyszer_get_display_data(); -float ecg_data_analyszer_get_heart_rate(); \ No newline at end of file diff --git a/app/src/app_service/ecg_service/algo/iflytop_simple_filter.c b/app/src/app_service/ecg_service/algo/iflytop_simple_filter.c index 9a8d8f9..c9ccc1c 100644 --- a/app/src/app_service/ecg_service/algo/iflytop_simple_filter.c +++ b/app/src/app_service/ecg_service/algo/iflytop_simple_filter.c @@ -5,6 +5,7 @@ #include #include #include +#include #define PI 3.141592653 @@ -140,36 +141,43 @@ typedef struct { #endif void median_filter_init(median_filter_t *filter, int medianSize) { - filter->valStartPos = 0; - filter->valEndPos = 0; - filter->medianSize = medianSize; + filter->medianSize = medianSize; + filter->numVal = 0; for (int i = 0; i < MEDIAN_FILTER_MAX_SIZE; i++) { filter->val[i] = 0; } } float median_filter_update(median_filter_t *filter, float val) { - filter->val[filter->valEndPos] = val; - filter->valEndPos++; - if (filter->valEndPos >= filter->medianSize) { - filter->valEndPos = 0; + if (filter->numVal >= filter->medianSize) { + memmove(filter->val, filter->val + 1, (filter->medianSize - 1) * sizeof(float)); + filter->numVal--; } - if (filter->valEndPos == filter->valStartPos) { - filter->valStartPos++; - if (filter->valStartPos >= filter->medianSize) { - filter->valStartPos = 0; - } - } - for (int i = 0; i < filter->medianSize; i++) { + + filter->val[filter->numVal] = val; + filter->numVal++; + + for (int i = 0; i < filter->numVal; i++) { filter->temp[i] = filter->val[i]; } - for (int i = 0; i < filter->medianSize; i++) { - for (int j = i + 1; j < filter->medianSize; j++) { + + for (int i = 0; i < filter->numVal; i++) { + for (int j = i + 1; j < filter->numVal; j++) { if (filter->temp[i] > filter->temp[j]) { - float t = filter->temp[i]; + float temp = filter->temp[i]; filter->temp[i] = filter->temp[j]; - filter->temp[j] = t; + filter->temp[j] = temp; } } } - return filter->temp[filter->medianSize / 2]; + + // 4 --> 1,2 + // 3 --> 1 + // 2 --> 0,1 + // 1 --> 0 + + if (filter->numVal % 2 == 0) { + return (filter->temp[filter->numVal / 2 - 1] + filter->temp[filter->numVal / 2]) / 2; + } else { + return filter->temp[filter->numVal / 2]; + } } diff --git a/app/src/app_service/ecg_service/algo/iflytop_simple_filter.h b/app/src/app_service/ecg_service/algo/iflytop_simple_filter.h index edd1239..04627eb 100644 --- a/app/src/app_service/ecg_service/algo/iflytop_simple_filter.h +++ b/app/src/app_service/ecg_service/algo/iflytop_simple_filter.h @@ -67,15 +67,14 @@ float NOTCHFilter_Update(NOTCHFilter_t *filter, float vin); // #ifdef __cplusplus // } // #endif -#define MEDIAN_FILTER_MAX_SIZE 100 +#define MEDIAN_FILTER_MAX_SIZE 50 typedef struct { float val[MEDIAN_FILTER_MAX_SIZE]; float temp[MEDIAN_FILTER_MAX_SIZE]; - int valStartPos; - int valEndPos; int medianSize; + int numVal; } median_filter_t; void median_filter_init(median_filter_t *filter, int medianSize); diff --git a/app/src/app_service/ecg_service/algo/iflytop_simple_qrs.c b/app/src/app_service/ecg_service/algo/iflytop_simple_qrs.c deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/app_service/ecg_service/algo/iflytop_simple_qrs.h b/app/src/app_service/ecg_service/algo/iflytop_simple_qrs.h deleted file mode 100644 index f7e94aa..0000000 --- a/app/src/app_service/ecg_service/algo/iflytop_simple_qrs.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include -#include - - -typedef struct -{ - //计算数据的滑动平均值 - //计算数据的滑动最大值 - // -// 1. 原始数据的滑动窗口(滤波后的) -// 2. 窗口选择多大? -// 3. 均值,最大值 -// 4. 正负? -// 5. 零点 -}iflytop_simple_qrs_t; - - - diff --git a/app/src/app_service/ecg_service/algo/zdata_statistics.c b/app/src/app_service/ecg_service/algo/zdata_statistics.c new file mode 100644 index 0000000..630b5a1 --- /dev/null +++ b/app/src/app_service/ecg_service/algo/zdata_statistics.c @@ -0,0 +1,38 @@ +#include "zdata_statistics.h" + +void zdata_statistics_init(zdata_statistics_t* p_analyzer, int32_t* buf, int32_t bufsize) { + p_analyzer->buf = buf; + p_analyzer->bufsize = bufsize; + p_analyzer->head = 0; + p_analyzer->tail = 0; + p_analyzer->avg = 0; + p_analyzer->max = 0; + p_analyzer->min = 0; +} +void zdata_statistics_push(zdata_statistics_t* p_analyzer, int32_t data) { + p_analyzer->buf[p_analyzer->head] = data; + p_analyzer->head = (p_analyzer->head + 1) % p_analyzer->bufsize; + if (p_analyzer->head == p_analyzer->tail) { + p_analyzer->tail = (p_analyzer->tail + 1) % p_analyzer->bufsize; + p_analyzer->sum -= p_analyzer->buf[p_analyzer->tail]; + } + p_analyzer->sum += data; + p_analyzer->avg = p_analyzer->sum / p_analyzer->bufsize; + p_analyzer->max = p_analyzer->max > data ? p_analyzer->max : data; + p_analyzer->min = p_analyzer->min < data ? p_analyzer->min : data; +} + +void zdata_statistics_clear(zdata_statistics_t* p_analyzer) { + p_analyzer->head = 0; + p_analyzer->tail = 0; + p_analyzer->sum = 0; + p_analyzer->avg = 0; + p_analyzer->max = 0; + p_analyzer->min = 0; +} + +float zdata_statistics_get_avg(zdata_statistics_t* p_analyzer) { return p_analyzer->avg; } +float zdata_statistics_get_max(zdata_statistics_t* p_analyzer) { return p_analyzer->max; } +float zdata_statistics_get_min(zdata_statistics_t* p_analyzer) { return p_analyzer->min; } + +bool zdata_statistics_is_full(zdata_statistics_t* p_analyzer) { return p_analyzer->head == p_analyzer->tail; } diff --git a/app/src/app_service/ecg_service/algo/zdata_statistics.h b/app/src/app_service/ecg_service/algo/zdata_statistics.h new file mode 100644 index 0000000..22ef9b6 --- /dev/null +++ b/app/src/app_service/ecg_service/algo/zdata_statistics.h @@ -0,0 +1,28 @@ +#pragma once +#include +#include + +typedef struct { + int32_t* buf; + int32_t bufsize; + + float sum; + + float avg; + float max; + float min; + + uint32_t head; + uint32_t tail; + +} zdata_statistics_t; + +void zdata_statistics_init(zdata_statistics_t* p_analyzer, int32_t* buf, int32_t bufsize); +void zdata_statistics_push(zdata_statistics_t* p_analyzer, int32_t data); +void zdata_statistics_clear(zdata_statistics_t* p_analyzer); + +float zdata_statistics_get_avg(zdata_statistics_t* p_analyzer); +float zdata_statistics_get_max(zdata_statistics_t* p_analyzer); +float zdata_statistics_get_min(zdata_statistics_t* p_analyzer); + +bool zdata_statistics_is_full(zdata_statistics_t* p_analyzer); \ No newline at end of file diff --git a/app/src/app_service/ecg_service/algo/zsimple_qrs.c b/app/src/app_service/ecg_service/algo/zsimple_qrs.c new file mode 100644 index 0000000..b0d2507 --- /dev/null +++ b/app/src/app_service/ecg_service/algo/zsimple_qrs.c @@ -0,0 +1,42 @@ +#include "zsimple_qrs.h" + +void zsimple_qrs_init(zsimple_qrs_t* p_qrs, float sample_rate_s) { + p_qrs->last_peak_pos = 0; + p_qrs->sample_rate_s = sample_rate_s; + p_qrs->heartrate = 0; + + p_qrs->index = 0; + p_qrs->hasfindpeak = false; + + median_filter_init(&p_qrs->heart_rate_filter, 10); +} +void zsimple_qrs_clear(zsimple_qrs_t* p_qrs) { + p_qrs->last_peak_pos = 0; + p_qrs->heartrate = 0; + p_qrs->index = 0; + p_qrs->hasfindpeak = false; + median_filter_init(&p_qrs->heart_rate_filter, 10); + +} +void zsimple_qrs_process_data(zsimple_qrs_t* p_qrs, int32_t indata, float min, float max, float refavg) { // + p_qrs->index++; + + int judge_threshold = min + (max - min) * QRS_PEAK_THRESHOLD; + + if (!p_qrs->hasfindpeak) { + if (indata > judge_threshold) { + float peak_interval_s = (p_qrs->index - p_qrs->last_peak_pos) * p_qrs->sample_rate_s; + if (peak_interval_s > PEAK_MIN_INTERVAL) { + p_qrs->hasfindpeak = true; + p_qrs->last_peak_pos = p_qrs->index; + float heartrate = 60 / peak_interval_s; + p_qrs->heartrate = median_filter_update(&p_qrs->heart_rate_filter, heartrate); + } + } + } else { + if (indata < judge_threshold) { + p_qrs->hasfindpeak = false; + } + } +} +float zsimple_qrs_get_heartrate(zsimple_qrs_t* p_qrs) { return p_qrs->heartrate; } diff --git a/app/src/app_service/ecg_service/algo/zsimple_qrs.h b/app/src/app_service/ecg_service/algo/zsimple_qrs.h new file mode 100644 index 0000000..1b307d4 --- /dev/null +++ b/app/src/app_service/ecg_service/algo/zsimple_qrs.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include + +#include "iflytop_simple_filter.h" +#include "zdata_statistics.h" + +#define QRS_PEAK_THRESHOLD (0.5f) + +/** + * @brief + * 假设心率为200,此时两个峰之间的间隔为0.3s,这里设置最小间隔为0.15s + * + */ +#define PEAK_MIN_INTERVAL 0.15 + +#define HEART_RATE_BUF_SIZE 10 + +typedef struct { + int32_t last_peak_pos; + float sample_rate_s; + float heartrate; + uint32_t index; + bool hasfindpeak; + + median_filter_t heart_rate_filter; +} zsimple_qrs_t; + +void zsimple_qrs_init(zsimple_qrs_t* p_qrs, float sample_rate_s); +void zsimple_qrs_clear(); +void zsimple_qrs_process_data(zsimple_qrs_t* p_qrs, int32_t indata, float min, float max, float refavg); +float zsimple_qrs_get_heartrate(zsimple_qrs_t* p_qrs); diff --git a/app/src/app_service/ecg_service/ecg_algo.c b/app/src/app_service/ecg_service/ecg_algo.c index 002fe14..844142a 100644 --- a/app/src/app_service/ecg_service/ecg_algo.c +++ b/app/src/app_service/ecg_service/ecg_algo.c @@ -1,28 +1,62 @@ #include "ecg_algo.h" #include "algo/iflytop_simple_filter_ext.h" +#include "algo/zdata_statistics.h" +#include "algo/zsimple_qrs.h" +#include "znordic.h" LPFilterExt_t m_lp_filter; HPFilterExt_t m_hp_filter; NOTCHFilterExt_t m_notch_filter; +int32_t m_data_statistics_buf[STATISTICS_BUF_SIZE]; // 心率判断 +zdata_statistics_t m_data_statistics; +zsimple_qrs_t m_qrs; + int32_t reportdata; int32_t displaydata; -void ecg_algo_init() { ecg_algo_reset(); } +void ecg_algo_init() { + ecg_algo_reset(); + + zsimple_qrs_init(&m_qrs, SAMPLE_RATE); + zdata_statistics_init(&m_data_statistics, m_data_statistics_buf, ZARRAY_SIZE(m_data_statistics_buf)); +} void ecg_algo_process_data(int32_t indata) { int32_t data = indata; data = LPFilterExt_update(&m_lp_filter, data); data = HPFilterExt_update(&m_hp_filter, data); data = NOTCHFilterExt_update(&m_notch_filter, data); reportdata = data; + + zdata_statistics_push(&m_data_statistics, data); + if (zdata_statistics_is_full(&m_data_statistics)) { + zsimple_qrs_process_data(&m_qrs, data, zdata_statistics_get_min(&m_data_statistics), zdata_statistics_get_max(&m_data_statistics), + zdata_statistics_get_avg(&m_data_statistics)); + + /** + * @brief + */ + int32_t max = zdata_statistics_get_max(&m_data_statistics); + int32_t min = zdata_statistics_get_min(&m_data_statistics); + + + int32_t nowvaloff = data - min; + int32_t nowval100 = nowvaloff * 100 / (max - min); + displaydata = nowval100; + + } else { + displaydata = 50; + } } void ecg_algo_reset() { - LPFilterExt_init(&m_lp_filter, 40, 0.002, 5, true); - HPFilterExt_init(&m_hp_filter, 1, 0.002, 3, true); - NOTCHFilterExt_init(&m_notch_filter, 50, 1, 0.002, 1, true); + LPFilterExt_init(&m_lp_filter, 40, SAMPLE_RATE, 5, true); + HPFilterExt_init(&m_hp_filter, 1, SAMPLE_RATE, 3, true); + NOTCHFilterExt_init(&m_notch_filter, 50, 1, SAMPLE_RATE, 1, true); + zdata_statistics_clear(&m_data_statistics); + zsimple_qrs_clear(); } int32_t ecg_algo_get_report_data() { return reportdata; } -int32_t ecg_algo_get_display_data() { return 50; } -int32_t ecg_algo_get_heart_rate() { return 100; } +int32_t ecg_algo_get_display_data() { return displaydata; } +int32_t ecg_algo_get_heart_rate() { return zsimple_qrs_get_heartrate(&m_qrs); } diff --git a/app/src/app_service/ecg_service/ecg_algo.h b/app/src/app_service/ecg_service/ecg_algo.h index c08c751..9ffe3c5 100644 --- a/app/src/app_service/ecg_service/ecg_algo.h +++ b/app/src/app_service/ecg_service/ecg_algo.h @@ -4,6 +4,9 @@ #include "app_basic_service/zapp.h" +#define SAMPLE_PERIOD_S ( (float)(1.0/SAMPLE_RATE)) +#define STATISTICS_BUF_SIZE ((int32_t)(2 / SAMPLE_PERIOD_S)) + void ecg_algo_init(); void ecg_algo_process_data(int32_t indata); void ecg_algo_reset(); diff --git a/app/src/app_service/ecg_service/ecg_service.c b/app/src/app_service/ecg_service/ecg_service.c index 50351da..e54d670 100644 --- a/app/src/app_service/ecg_service/ecg_service.c +++ b/app/src/app_service/ecg_service/ecg_service.c @@ -12,36 +12,19 @@ static nrf_drv_spi_t ads129x_spi = NRF_DRV_SPI_INSTANCE(ADS1291_SPI_INSTANCE); // global static nrf_drv_spi_config_t ads129x_spi_config; - -// uint8_t port_spi_transmit_receive(uint8_t tx); -// int32_t i24toi32(uint8_t* p_i32); -// uint8_t ads129x_send_cmd(uint8_t cmd); -// uint8_t ads129x_rw_reg(uint8_t cmd, uint8_t data); -// void ads129x_write_multiregs(uint8_t reg, uint8_t* ch, uint8_t size); -// void ads129x_read_multiregs(uint8_t reg, uint8_t* ch, uint8_t size); -// void ads129x_readback_regs(ads129x_regs_t* regcache); -// void ads129x_dump_regs(ads129x_regs_t* regcache); -// bool ads129x_write_regs(ads129x_regs_t* writeval); -// void ads129x_read_data(ads129x_capture_data_t* capture_data); +static bool m_testmode_flag; /*********************************************************************************************************************** * PRIVATE_FUNC * ***********************************************************************************************************************/ -#define ADS129X_CS_SET() nrf_gpio_pin_set(ADS1291_SPI_CS0_PIN); -#define ADS129X_CS_RESET() nrf_gpio_pin_clear(ADS1291_SPI_CS0_PIN); -#define ADS129X_START_SET() nrf_gpio_pin_set(ADS1291_START_PIN); -#define ADS129X_START_RESET() nrf_gpio_pin_clear(ADS1291_START_PIN); -#define ADS129X_REST_SET() nrf_gpio_pin_set(ADS1291_PWDN_PIN); -#define ADS129X_REST_RESET() nrf_gpio_pin_clear(ADS1291_PWDN_PIN); -#define ADS129X_DRDY_GET() nrf_gpio_pin_read(ADS1291_READY_PIN) -uint8_t port_spi_transmit_receive(uint8_t tx) { +static uint8_t port_spi_transmit_receive(uint8_t tx) { uint8_t data; nrf_drv_spi_transfer(&ads129x_spi, &tx, 1, &data, 1); return data; } -int32_t i24toi32(uint8_t* p_i32) { +static int32_t i24toi32(uint8_t* p_i32) { int32_t rev = 0; rev = (((int32_t)p_i32[0]) << 16) | (((int32_t)p_i32[1]) << 8) | ((int32_t)p_i32[2]); if ((p_i32[0] & 0x80) == 0x80) { @@ -51,25 +34,25 @@ int32_t i24toi32(uint8_t* p_i32) { } /* ads129X发送指令 */ -uint8_t ads129x_send_cmd(uint8_t cmd) { +static uint8_t ads129x_send_cmd(uint8_t cmd) { uint8_t rx = 0; - ADS129X_CS_RESET(); /* 选中设备 */ + nrf_gpio_pin_clear(ADS1291_SPI_CS0_PIN); /* 选中设备 */ nrf_delay_us(100); rx = port_spi_transmit_receive(cmd); nrf_delay_us(100); - ADS129X_CS_SET(); /* 释放设备 */ + nrf_gpio_pin_set(ADS1291_SPI_CS0_PIN); /* 释放设备 */ return rx; } /* ads129X读写寄存器,自动根据指令类型区分读和写操作 */ -uint8_t ads129x_rw_reg(uint8_t cmd, uint8_t data) { +static uint8_t ads129x_rw_reg(uint8_t cmd, uint8_t data) { uint8_t rx = 0; - ADS129X_CS_RESET(); /* 选中设备 */ + nrf_gpio_pin_clear(ADS1291_SPI_CS0_PIN); /* 选中设备 */ nrf_delay_us(1); port_spi_transmit_receive(cmd); /* 发送读写指令 */ @@ -81,16 +64,16 @@ uint8_t ads129x_rw_reg(uint8_t cmd, uint8_t data) { rx = port_spi_transmit_receive(data); /* 写入数值 */ nrf_delay_us(1); - ADS129X_CS_SET(); /* 释放设备 */ + nrf_gpio_pin_set(ADS1291_SPI_CS0_PIN); /* 释放设备 */ return rx; } /* 从指定寄存器开始读写一定数量的寄存器 */ -void ads129x_write_multiregs(uint8_t reg, uint8_t* ch, uint8_t size) { +static void ads129x_write_multiregs(uint8_t reg, uint8_t* ch, uint8_t size) { uint8_t i; - ADS129X_CS_RESET(); /* 选中设备 */ + nrf_gpio_pin_clear(ADS1291_SPI_CS0_PIN); /* 选中设备 */ nrf_delay_us(100); port_spi_transmit_receive(ADS129X_COMMAND_WREG | reg); @@ -104,14 +87,14 @@ void ads129x_write_multiregs(uint8_t reg, uint8_t* ch, uint8_t size) { } nrf_delay_us(100); - ADS129X_CS_SET(); + nrf_gpio_pin_set(ADS1291_SPI_CS0_PIN); } /* 从指定寄存器开始读写一定数量的寄存器 */ -void ads129x_read_multiregs(uint8_t reg, uint8_t* ch, uint8_t size) { +static void ads129x_read_multiregs(uint8_t reg, uint8_t* ch, uint8_t size) { uint8_t i; - ADS129X_CS_RESET(); /* 选中设备 */ + nrf_gpio_pin_clear(ADS1291_SPI_CS0_PIN); /* 选中设备 */ nrf_delay_us(100); port_spi_transmit_receive(ADS129X_COMMAND_RREG | reg); @@ -125,11 +108,11 @@ void ads129x_read_multiregs(uint8_t reg, uint8_t* ch, uint8_t size) { } nrf_delay_us(100); - ADS129X_CS_SET(); + nrf_gpio_pin_set(ADS1291_SPI_CS0_PIN); } -void ads129x_readback_regs(ads129x_regs_t* regcache) { ads129x_read_multiregs(ADS129X_REG_ID, (uint8_t*)regcache, sizeof(ads129x_regs_t)); } -void ads129x_dump_regs(ads129x_regs_t* regcache) { +static void ads129x_readback_regs(ads129x_regs_t* regcache) { ads129x_read_multiregs(ADS129X_REG_ID, (uint8_t*)regcache, sizeof(ads129x_regs_t)); } +static void ads129x_dump_regs(ads129x_regs_t* regcache) { ZLOGI("id : %x", regcache->id); ZLOGI("cfg1 : %x", regcache->cfg1); ZLOGI("cfg2 : %x", regcache->cfg2); @@ -144,7 +127,7 @@ void ads129x_dump_regs(ads129x_regs_t* regcache) { ZLOGI("gpio : %x", regcache->gpio); } -bool ads129x_write_regs(ads129x_regs_t* writeval) { +static bool ads129x_write_regs(ads129x_regs_t* writeval) { static ads129x_regs_t rdbak; ads129x_write_multiregs(ADS129X_REG_ID, (uint8_t*)writeval, sizeof(ads129x_regs_t)); ads129x_read_multiregs(ADS129X_REG_ID, (uint8_t*)&rdbak, sizeof(ads129x_regs_t)); @@ -163,10 +146,10 @@ bool ads129x_write_regs(ads129x_regs_t* writeval) { return true; } -void ads129x_read_data(ads129x_capture_data_t* capture_data) { +static void ads129x_read_data(ads129x_capture_data_t* capture_data) { uint8_t rddata[9]; - ADS129X_CS_RESET(); /* 选中设备 */ + nrf_gpio_pin_clear(ADS1291_SPI_CS0_PIN); /* 选中设备 */ nrf_delay_us(10); port_spi_transmit_receive(ADS129X_COMMAND_RDATA); @@ -174,7 +157,7 @@ void ads129x_read_data(ads129x_capture_data_t* capture_data) { for (int i = 0; i < 9; i++) { rddata[i] = port_spi_transmit_receive(0); } - ADS129X_CS_SET(); + nrf_gpio_pin_set(ADS1291_SPI_CS0_PIN); /** * @brief @@ -195,21 +178,32 @@ void ads129x_read_data(ads129x_capture_data_t* capture_data) { capture_data->ch2data = i24toi32(&rddata[6]); } +static bool ads129x_ping() { + uint8_t data; + ads129x_read_multiregs(ADS129X_REG_ID, (uint8_t*)&data, sizeof(uint8_t)); + if (data == 0x052) { + return true; + } + return false; +} /*********************************************************************************************************************** * PUBLIC_FUNC * ***********************************************************************************************************************/ -void ads1291_ready_pin_irq(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { - if (ADS129X_DRDY_GET()) { - static ads129x_capture_data_t capture_data; - ads129x_read_data(&capture_data); - ecg_algo_process_data(capture_data.ch1data); +static void ads1291_ready_pin_irq(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { + static ads129x_capture_data_t capture_data; + // 读 + ads129x_read_data(&capture_data); - one_frame_t frame; - frame.data = ecg_algo_get_report_data(); - frame.leadoff = capture_data.loffstate; - ecg_data_mgr_push_one_frame(frame); - } + // 算法处理 + // ecg_algo_process_data(capture_data.ch1data); + + // 上报 + one_frame_t frame; + // frame.data = ecg_algo_get_report_data(); + frame.data = capture_data.ch1data; + frame.leadoff = capture_data.loffstate; + ecg_data_mgr_push_one_frame(frame); } void ecg_service_init() { // @@ -217,17 +211,28 @@ void ecg_service_init() { // * @brief * 在这里初始化一些硬件无关的内存组件 */ - ecg_data_mgr_init(); ecg_algo_init(); + + // 初始化部分硬件 + znrf_gpio_cfg_output(ADS1291_PWDN_PIN, NRF_GPIO_PIN_NOPULL); + nrf_gpio_pin_clear(ADS1291_PWDN_PIN); } void ecg_service_load() { /** * @brief 硬件接口初始化 */ - nrfx_gpiote_init(); + // GPIO初始化 + znrf_gpio_cfg_output(ADS1291_SPI_CS0_PIN, NRF_GPIO_PIN_NOPULL); + znrf_gpio_cfg_output(ADS1291_PWDN_PIN, NRF_GPIO_PIN_NOPULL); + znrf_gpio_cfg_output(ADS1291_START_PIN, NRF_GPIO_PIN_NOPULL); + nrf_gpio_pin_set(ADS1291_SPI_CS0_PIN); + nrf_gpio_pin_clear(ADS1291_PWDN_PIN); + nrf_gpio_pin_clear(ADS1291_START_PIN); + + // SPI初始化 ads129x_spi_config.sck_pin = ADS1291_SPI_SCK_PIN; ads129x_spi_config.mosi_pin = ADS1291_SPI_MOSI_PIN; ads129x_spi_config.miso_pin = ADS1291_SPI_MISO_PIN; @@ -238,11 +243,9 @@ void ecg_service_load() { ads129x_spi_config.mode = NRF_DRV_SPI_MODE_1; ads129x_spi_config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST; nrf_drv_spi_init(&ads129x_spi, &ads129x_spi_config, NULL, NULL); - znrf_gpio_cfg_output(ADS1291_SPI_CS0_PIN, NRF_GPIO_PIN_NOPULL); - znrf_gpio_cfg_output(ADS1291_PWDN_PIN, NRF_GPIO_PIN_NOPULL); - znrf_gpio_cfg_output(ADS1291_START_PIN, NRF_GPIO_PIN_NOPULL); - ZASSERT(nrfx_gpiote_is_init()); + // 中断初始化 + nrfx_gpiote_init(); nrf_gpio_cfg_input(ADS1291_READY_PIN, NRF_GPIO_PIN_PULLUP); nrf_drv_gpiote_in_config_t inConfig = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false); // inConfig.pull = NRF_GPIO_PIN_PULLUP; // 默认上拉 @@ -250,40 +253,39 @@ void ecg_service_load() { nrfx_gpiote_in_init(ADS1291_READY_PIN, &inConfig, ads1291_ready_pin_irq); nrfx_gpiote_in_event_enable(ADS1291_READY_PIN, true); - /** - * @brief ads129x 芯片初始化 - */ - - ADS129X_CS_SET(); - - ADS129X_REST_RESET(); - ADS129X_START_RESET(); - nrf_delay_ms(1000); - ADS129X_REST_SET(); + nrf_gpio_pin_set(ADS1291_PWDN_PIN); nrf_delay_ms(30); /* 硬件复位 */ - + ads129x_send_cmd(ADS129X_COMMAND_WAKEUP); ads129x_send_cmd(ADS129X_COMMAND_SDATAC); /* 软件复位,并停止连续读状态 */ - nrf_delay_ms(30); + + for (size_t i = 0; i < 100; i++) { + if (ads129x_ping()) { + break; + } + nrf_delay_ms(1); + } + + ZASSERT(ads129x_ping()); static ads129x_regs_t regcache; ads129x_readback_regs(®cache); ads129x_dump_regs(®cache); regcache.cfg1 = 0x02; regcache.cfg2 = 0xE0; - regcache.loff = 0xF0; + regcache.loff = 0xF1; regcache.ch1set = 0x00; - regcache.ch2set = 0x00; + regcache.ch2set = 0x81; regcache.rld_sens = 0x20; regcache.loff_sens = 0x03; + ads129x_write_regs(®cache); - ads129x_send_cmd(ADS129X_COMMAND_WAKEUP); /* 软件复位,并停止连续读状态 */ } void ecg_service_unload() { /** * @brief */ ads129x_send_cmd(ADS129X_COMMAND_STANDBY); /* 软件复位,并停止连续读状态 */ - ADS129X_REST_RESET(); + nrf_gpio_pin_clear(ADS1291_PWDN_PIN); nrfx_gpiote_in_event_disable(ADS1291_READY_PIN); @@ -308,6 +310,19 @@ static uint32_t ecg_service_captured_time = 0; void ecg_service_start_capture() { // ecg_data_mgr_clear_buffer(); + + if (m_testmode_flag) { + static ads129x_regs_t regcache; + ads129x_readback_regs(®cache); + ads129x_dump_regs(®cache); + + regcache.cfg2 = ADS129X_SET_BITS(regcache.cfg2, ADS129X_INT_TEST, ADS129X_INT_TEST_ON); + regcache.cfg2 = ADS129X_SET_BITS(regcache.cfg2, ADS129X_INT_FREQ, ADS129X_INT_FREQ_AC); + regcache.ch1set = ADS129X_SET_BITS(regcache.ch1set, ADS129X_MUXx, ADS129X_CHx_INPUT_TEST); + + ads129x_write_regs(®cache); + } + ads129x_send_cmd(ADS129X_COMMAND_START); /* 发送开始数据转换(等效于拉高START引脚) */ ecg_service_captured_time = znordic_getpower_on_ms(); } @@ -315,10 +330,21 @@ void ecg_service_stop_capture() { // ads129x_send_cmd(ADS129X_COMMAND_STOP); /* 发送停止数据转换(等效于拉低START引脚) */ } uint32_t ecg_service_has_captured_time() { return znordic_haspassed_ms(ecg_service_captured_time); } - -void ecg_service_subic_write_reg(uint8_t addr, uint8_t val) { ads129x_rw_reg(ADS129X_COMMAND_WREG | addr, val); } +void ecg_service_subic_write_reg(uint8_t addr, uint8_t val) { + if (addr > sizeof(ads129x_regs_t)) { + return; + } + static ads129x_regs_t regcache; + ads129x_readback_regs(®cache); + uint8_t* p = (uint8_t*)®cache; + p[addr] = val; + ads129x_write_regs(®cache); +} uint8_t ecg_service_subic_read_reg(uint8_t addr) { return ads129x_rw_reg(ADS129X_COMMAND_RREG | addr, 0); } - int32_t ecg_service_get_display_val() { return ecg_algo_get_display_data(); } - int32_t ecg_service_get_heart_rate() { return ecg_algo_get_heart_rate(); } + +void ecg_service_set_in_test_mode(bool testmode) { + ZLOGI("ecg_service_set_in_test_mode %d", testmode); + m_testmode_flag = testmode; +} diff --git a/app/src/app_service/ecg_service/ecg_service.h b/app/src/app_service/ecg_service/ecg_service.h index d890698..ca6484c 100644 --- a/app/src/app_service/ecg_service/ecg_service.h +++ b/app/src/app_service/ecg_service/ecg_service.h @@ -26,12 +26,13 @@ void ecg_service_init(); void ecg_service_load(); void ecg_service_unload(); -void ecg_service_start_capture(); -void ecg_service_stop_capture(); +void ecg_service_start_capture(); +void ecg_service_stop_capture(); uint32_t ecg_service_has_captured_time(); -int32_t ecg_service_get_display_val(); -int32_t ecg_service_get_heart_rate(); +int32_t ecg_service_get_display_val(); +int32_t ecg_service_get_heart_rate(); void ecg_service_subic_write_reg(uint8_t addr, uint8_t val); uint8_t ecg_service_subic_read_reg(uint8_t addr); +void ecg_service_set_in_test_mode(bool testmode); diff --git a/app/src/main.c b/app/src/main.c index 3396a1e..9af7164 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -64,7 +64,7 @@ void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) { int main() { zapp_early_init(); - znordic_init_without_wd(); + znordic_init(); zapp_init(); /******************************************************************************* diff --git a/app/src/one_conduction_main.c b/app/src/one_conduction_main.c index 1ac1f9f..e96d44f 100644 --- a/app/src/one_conduction_main.c +++ b/app/src/one_conduction_main.c @@ -184,6 +184,12 @@ void one_conduction_process_rx_packet(uint8_t* rx, int len) { send_success_receipt(rxheader, 0); } + else if (cmd == ify_hrs_cmd_set_ecg_in_test_mode) { + int32_t testmode = *(int32_t*)rxheader->data; + ecg_service_set_in_test_mode(testmode); + send_success_receipt(rxheader, 0); + } + else { send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); } @@ -261,6 +267,11 @@ void on_state_change(device_state_t from, device_state_t to) { void on_zapp_ebus_event(void* p_event_data, uint16_t event_size) { if (!p_event_data) return; app_event_t* p_event = (app_event_t*)p_event_data; + + if(p_event->eventType == kappevent_tmr_scheduler_event){ + ZLOGI("tmr event."); + } + if (zapp_state_machine_now_state() == kstate_standby) { /** * @brief diff --git a/ify_hrs_protocol b/ify_hrs_protocol index 08b14b4..a1fda58 160000 --- a/ify_hrs_protocol +++ b/ify_hrs_protocol @@ -1 +1 @@ -Subproject commit 08b14b499e98175014068f19fdfaddded14718b3 +Subproject commit a1fda58c30f6bb892c9f503280b3896c67e00dda