#include "ads129x.h" #include "ads129x_type.h" #include "nrf_drv_gpiote.h" #include "znordic.h" /** * @brief ads129x 使用注意事项 * * ads129x SPI 通信格式 * * [cmd 8bit] [data nbit] * * * ads129x 支持的指令如下 * 唤醒 (0x02) * 待机 (0x04) * 复位 (0x06) * 开始转换 (0x08) * 停止 (0x0A) * 通道偏移校准 (0x1A) * 使能数据连续读模式 (0x10) * 停止数据连续读模式 (0x11) * 读数据 (0x12) * 读寄存器 (0x2x) * 写寄存器 (0x4x) * * * 注意事项: * 1. 当ads129x处于连续读模式下,寄存器读写指令失效 * 2. 不进入连续模式下,可以通过[读数据]指令,读取数据,此时寄存器操作指令是有效的 * */ static ads129x_cfg_t* ads129x_cfg; #define ADS129X_CS_SET() nrf_gpio_pin_set(ads129x_cfg->cspin); #define ADS129X_CS_RESET() nrf_gpio_pin_clear(ads129x_cfg->cspin); #define ADS129X_START_SET() nrf_gpio_pin_set(ads129x_cfg->startpin); #define ADS129X_START_RESET() nrf_gpio_pin_clear(ads129x_cfg->startpin); #define ADS129X_REST_SET() nrf_gpio_pin_set(ads129x_cfg->pwdnpin); #define ADS129X_REST_RESET() nrf_gpio_pin_clear(ads129x_cfg->pwdnpin); #define ADS129X_DRDY_GET() nrf_gpio_pin_read(ads129x_cfg->drdypin) static void port_ads129x_delay_us(uint32_t us) { nrf_delay_us(us); } static void port_ads129x_delay_ms(uint32_t ms) { nrf_delay_ms(ms); } #define port_delay_ms port_ads129x_delay_ms /*********************************************************************************************************************** * BASE_FUNCTION_IMPL * ***********************************************************************************************************************/ uint8_t port_spi_transmit_receive(uint8_t tx) { uint8_t data; nrf_drv_spi_transfer(ads129x_cfg->spi, &tx, 1, &data, 1); return data; } /* ads129X发送指令 */ uint8_t ads129x_send_cmd(uint8_t cmd) { uint8_t rx = 0; ADS129X_CS_RESET(); /* 选中设备 */ port_ads129x_delay_us(100); rx = port_spi_transmit_receive(cmd); port_ads129x_delay_us(100); ADS129X_CS_SET(); /* 释放设备 */ return rx; } /* ads129X读写寄存器,自动根据指令类型区分读和写操作 */ uint8_t ads129x_rw_reg(uint8_t cmd, uint8_t data) { uint8_t rx = 0; ADS129X_CS_RESET(); /* 选中设备 */ port_ads129x_delay_us(1); port_spi_transmit_receive(cmd); /* 发送读写指令 */ port_spi_transmit_receive(0X00); /* 只写一个数据 */ if ((cmd & ADS129X_COMMAND_RREG) == ADS129X_COMMAND_RREG) /* 判断指令类型 */ rx = port_spi_transmit_receive(0X00); /* 返回寄存器值 */ else rx = port_spi_transmit_receive(data); /* 写入数值 */ port_ads129x_delay_us(1); ADS129X_CS_SET(); /* 释放设备 */ return rx; } /* 从指定寄存器开始读写一定数量的寄存器 */ void ads129X_write_multiregs(uint8_t reg, uint8_t* ch, uint8_t size) { uint8_t i; ADS129X_CS_RESET(); /* 选中设备 */ port_ads129x_delay_us(100); port_spi_transmit_receive(ADS129X_COMMAND_WREG | reg); port_ads129x_delay_us(100); port_spi_transmit_receive(size - 1); for (i = 0; i < size; i++) { port_ads129x_delay_us(100); port_spi_transmit_receive(*ch); ch++; } port_ads129x_delay_us(100); ADS129X_CS_SET(); } /* 从指定寄存器开始读写一定数量的寄存器 */ void ads129X_read_multiregs(uint8_t reg, uint8_t* ch, uint8_t size) { uint8_t i; ADS129X_CS_RESET(); /* 选中设备 */ port_ads129x_delay_us(100); port_spi_transmit_receive(ADS129X_COMMAND_RREG | reg); port_ads129x_delay_us(100); port_spi_transmit_receive(size - 1); for (i = 0; i < size; i++) { port_ads129x_delay_us(100); *ch = port_spi_transmit_receive(0); ch++; } port_ads129x_delay_us(100); ADS129X_CS_SET(); } 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); ZLOGI("loff : %x", regcache->loff); ZLOGI("ch1set : %x", regcache->ch1set); ZLOGI("ch2set : %x", regcache->ch2set); ZLOGI("rld_sens : %x", regcache->rld_sens); ZLOGI("loff_sens : %x", regcache->loff_sens); ZLOGI("loff_stat : %x", regcache->loff_stat); ZLOGI("resp1 : %x", regcache->resp1); ZLOGI("resp2 : %x", regcache->resp2); ZLOGI("gpio : %x", regcache->gpio); } 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)); writeval->id = 0; writeval->loff_stat = writeval->loff_stat & (0x01 << 6); rdbak.id = 0; rdbak.loff_stat = rdbak.loff_stat & (0x01 << 6); if (memcmp(writeval, &rdbak, sizeof(ads129x_regs_t)) != 0) { ZLOGE("ads129x_write_reg reg fail"); return false; } ZLOGI("ads129x_write_reg reg success"); return true; } /*********************************************************************************************************************** * EXTERN * ***********************************************************************************************************************/ void ads129x_read_data_loop() { // app_timer_pause(); // ads129x_capture_data_t capture_data; // while (true) { // ads129x_read_data(&capture_data); // ZLOGI("%d {%d} %x", ADS129X_DRDY_GET(), capture_data.ch1data, capture_data.loffstate); // znordic_force_flush_log(); // } } uint8_t ads129x_init(ads129x_cfg_t* cfg) { /** * @brief */ ads129x_cfg = cfg; ZASSERT(nrfx_gpiote_is_init()); ADS129X_CS_SET(); ADS129X_REST_RESET(); ADS129X_START_RESET(); port_ads129x_delay_ms(1000); ADS129X_REST_SET(); port_ads129x_delay_ms(100); /* 硬件复位 */ ads129x_send_cmd(ADS129X_COMMAND_SDATAC); /* 软件复位,并停止连续读状态 */ port_ads129x_delay_ms(100); ads129x_send_cmd(ADS129X_COMMAND_RESET); port_ads129x_delay_ms(1000); ads129x_send_cmd(ADS129X_COMMAND_SDATAC); port_ads129x_delay_ms(100); static ads129x_regs_t regcache; ads129x_readback_regs(®cache); ads129x_dump_regs(®cache); regcache.cfg1 = 0x02; regcache.cfg2 = 0xE0; regcache.loff = 0xF0; regcache.ch1set = 0x00; regcache.ch2set = 0x00; regcache.rld_sens = 0x20; regcache.loff_sens = 0x03; ads129x_write_regs(®cache); nrf_gpio_pin_set(ads129x_cfg->pwdnpin); return 0; } #if 0 uint8_t ads129x_start_capture(bool test) { ads129x_send_cmd(ADS129X_COMMAND_SDATAC); /* 进入停止连续读模式 */ port_delay_ms(10); static ads129x_regs_t regcache; ads129x_readback_regs(®cache); ads129x_dump_regs(®cache); regcache.cfg1 = 0x02; regcache.cfg2 = 0xE0; regcache.loff = 0xF0; regcache.ch1set = 0x00; regcache.ch2set = 0x00; regcache.rld_sens = 0x20; regcache.loff_sens = 0x03; /* 导联脱落比较器开,内部2.42v参考电压 */ regcache.cfg2 = ADS129X_SET_BITS(regcache.cfg2, ADS129X_PDB_LOFF_COMP, ADS129X_PDB_LOFF_COMP_ON); regcache.cfg2 = ADS129X_SET_BITS(regcache.cfg2, ADS129X_PDB_REFBUF, ADS129X_PDB_REFBUF_ON); regcache.cfg2 = ADS129X_SET_BITS(regcache.cfg2, ADS129X_VREF_4V, ADS129X_VREF_2420MV); /* 通道二导联脱落检测功能开 */ regcache.loff_sens = ADS129X_SET_BITS(regcache.loff_sens, ADS129X_LOFF2N, ADS129X_LOFF2N_ON); regcache.loff_sens = ADS129X_SET_BITS(regcache.loff_sens, ADS129X_LOFF2P, ADS129X_LOFF2P_ON); if (test) { 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); regcache.ch2set = ADS129X_SET_BITS(regcache.ch2set, ADS129X_MUXx, ADS129X_CHx_INPUT_TEST); } ads129x_write_regs(®cache); port_delay_ms(10); ads129x_send_cmd(ADS129X_COMMAND_START); /* 发送开始数据转换(等效于拉高START引脚) */ port_delay_ms(10); return 0; } #endif uint8_t ads129x_read_reg(uint8_t add) { return ads129x_rw_reg(ADS129X_COMMAND_RREG | add, 0); } void ads129x_write_reg(uint8_t add, uint8_t data) { ZLOGI("ads129x_write_reg %x %x", add, data); static ads129x_regs_t regcache; ads129x_readback_regs(®cache); uint8_t* reg = (uint8_t*)®cache; reg[add] = data; ads129x_write_regs(®cache); } uint8_t ads129x_start_capture() { ads129x_send_cmd(ADS129X_COMMAND_START); /* 发送开始数据转换(等效于拉高START引脚) */ return 0; } uint8_t ads129x_stop_capture() { ads129x_send_cmd(ADS129X_COMMAND_STOP); /* 发送停止数据转换(等效于拉低START引脚) */ return 0; } 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) { rev |= 0xFF000000; } return rev; } void ads129x_read_data(ads129x_capture_data_t* capture_data) { uint8_t rddata[9]; ADS129X_CS_RESET(); /* 选中设备 */ port_ads129x_delay_us(10); port_spi_transmit_receive(ADS129X_COMMAND_RDATA); port_ads129x_delay_us(1); for (int i = 0; i < 9; i++) { rddata[i] = port_spi_transmit_receive(0); } ADS129X_CS_SET(); /** * @brief * * 回读数据格式(datasheet page 42) * 24bit status (1100 + LOFF_STAT[4:0] + GPIO[1:0] + 13`b0) * 24bit ch0 MSB * 24bit ch1 MSB * */ uint32_t status = (((uint32_t)rddata[0]) << 16) | (((uint32_t)rddata[1]) << 8) | ((uint32_t)rddata[2]); capture_data->loffstate = (status >> (13 + 2)) & 0x1f; capture_data->gpio0 = status >> (14); capture_data->gpio1 = status >> (13); capture_data->ch1data = i24toi32(&rddata[3]); capture_data->ch2data = i24toi32(&rddata[6]); } uint8_t ads129x_get_lead_off_state() { // FLIP2,FLIP1,LOFF2N,LOFF2P,LOFF1N,LOFF1P uint8_t leadoffstate = ads129x_read_reg(ADS129X_REG_LOFFSTAT); return leadoffstate; } uint8_t ads129x_enter_low_power_mode() { return 0; } uint8_t ads129x_enter_lead_off_detect_mode() { return 0; }