Part Number:ADS1292ROther Parts Discussed in Thread: ADS1292
您好!本人在使用STM32H723系列进行HAL库开发时,发现单片机始终无法采集ADS1292R模块的信息,就连正常的读取ADS1292R的寄存器功能也无法实现,困扰了好几天。为了排除是模块的问题,我使用C8T6的例程在C8T6上测试了一遍,发现能够正常读取寄存器,说明模块是正常工作的,只能是软件方面的问题。我的软件配置如下:
我检查过原理图,SPI4的几个引脚并没有被其他SPI外设占用。ADS1292R的供电为3.3V,SCLK周期没有低于最小值50ns。以下是我的寄存器读取代码:
void ADS1292_Init(void) { // 屏蔽外部中断线10 HAL_NVIC_DisableIRQ(EXTI9_5_IRQn); ADS_CS_H; // 设置引脚状态为1 //__HAL_SPI_ENABLE(&hspi4);//使能SPI2 //SPI2_ReadWriteByte(0X00); ADS1292_PowerOnInit();//上电复位,进入待机模式 while(Set_ADS1292_Collect(0))//0 正常采集 //1 1mV1Hz内部侧试信号 //2 内部短接噪声测试 { printf("1292寄存器设置失败\r\n"); HAL_Delay(1000); } printf("寄存器设置成功\r\n"); HAL_Delay(1000); HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);//开DRDY中断 } void ADS1292_SET_REGBUFF(void) { ADS1292_REG[ID] = ADS1292_DEVICE;//ID只读 ADS1292_REG[CONFIG1] = 0x00; //0000 0aaa [7] 0连续转换模式 [6:3] 必须为0 ADS1292_REG[CONFIG1] |= Ads1292_Config1.Data_Rate;//[2:0] aaa 采样率设置采样率 ADS1292_REG[CONFIG2] = 0x00; //1abc d0e1 [7] 必须为1 [2] 必须为0 [0] 设置测试信号为1HZ、±1mV方波 ADS1292_REG[CONFIG2] |= Ads1292_Config2.Pdb_Loff_Comp<<6; //[6]a 导联脱落比较器是否掉电 ADS1292_REG[CONFIG2] |= Ads1292_Config2.Pdb_Refbuf<<5; //[5]b 内部参考缓冲器是否掉电 ADS1292_REG[CONFIG2] |= Ads1292_Config2.Vref<<4; //[4]c 内部参考电压设置,默认2.42V ADS1292_REG[CONFIG2] |= Ads1292_Config2.Clk_EN<<3; //[3]d CLK引脚输出时钟脉冲? ADS1292_REG[CONFIG2] |= Ads1292_Config2.Int_Test<<1; //[1]e 是否打开内部测试信号, ADS1292_REG[CONFIG2] |= 0x81;//设置默认位 ADS1292_REG[LOFF] = 0x10;//[7:5] 设置导联脱落比较器阈值 [4] 必须为1 [3:2] 导联脱落电流幅值 [1] 必须为0 [0] 导联脱落检测方式 0 DC 1 AC ADS1292_REG[CH1SET] = 0x00; //abbb cccc ADS1292_REG[CH1SET] |=Ads1292_Ch1set.PD<<7; //[7] a 通道1断电? ADS1292_REG[CH1SET] |=Ads1292_Ch1set.GAIN<<4; //[6:4]bbb 设置PGA增益 ADS1292_REG[CH1SET] |=Ads1292_Ch1set.MUX; //[3:0]cccc 设置通道1输入方式 ADS1292_REG[CH2SET] = 0x00; //abbb cccc ADS1292_REG[CH2SET] |=Ads1292_Ch2set.PD<<7; //[7] a 通道2断电? ADS1292_REG[CH2SET] |=Ads1292_Ch2set.GAIN<<4; //[6:4]bbb 设置PGA增益 ADS1292_REG[CH2SET] |=Ads1292_Ch2set.MUX; //[3:0]cccc 设置通道2输入方式 ADS1292_REG[RLD_SENS] = 0X00; //11ab cdef [7:6] 11 PGA斩波频率 fMOD/4 ADS1292_REG[RLD_SENS] |=Ads1292_Rld_Sens.Pdb_Rld<<5; //[5]a 该位决定RLD缓冲电源状态 ADS1292_REG[RLD_SENS] |=Ads1292_Rld_Sens.Rld_Loff_Sense<<4; //[4]b 该位使能RLD导联脱落检测功能 ADS1292_REG[RLD_SENS] |=Ads1292_Rld_Sens.Rld2N<<3; //[3]c 这个位控制通道2负输入 用于右腿驱动的输出 ADS1292_REG[RLD_SENS] |=Ads1292_Rld_Sens.Rld2P<<2; //[2]d 该位控制通道2正输入 用于右腿驱动的输出 ADS1292_REG[RLD_SENS] |=Ads1292_Rld_Sens.Rld1N<<1; //[1]e 这个位控制通道1负输入 用于右腿驱动的输出 ADS1292_REG[RLD_SENS] |=Ads1292_Rld_Sens.Rld1P; //[0]f 该位控制通道1正输入 用于右腿驱动的输出 ADS1292_REG[RLD_SENS] |= 0xc0;//设置默认位 ADS1292_REG[LOFF_SENS] = 0X00; //00ab cdef [7:6] 必须为0 ADS1292_REG[LOFF_SENS] |=Ads1292_Loff_Sens.Flip2<<5; //[5]a 这个位用于控制导联脱落检测通道2的电流的方向 ADS1292_REG[LOFF_SENS] |=Ads1292_Loff_Sens.Flip1<<4; //[4]b 这个位控制用于导联脱落检测通道1的电流的方向 ADS1292_REG[LOFF_SENS] |=Ads1292_Loff_Sens.Loff2N<<3; //[3]c 该位控制通道2负输入端的导联脱落检测 ADS1292_REG[LOFF_SENS] |=Ads1292_Loff_Sens.Loff2P<<2; //[2]d 该位控制通道2正输入端的导联脱落检测 ADS1292_REG[LOFF_SENS] |=Ads1292_Loff_Sens.Loff1N<<1; //[1]e 该位控制通道1负输入端的导联脱落检测 ADS1292_REG[LOFF_SENS] |=Ads1292_Loff_Sens.Loff1P; //[0]f 该位控制通道1正输入端的导联脱落检测 ADS1292_REG[LOFF_STAT] = 0x00; //[6]0 设置fCLK和fMOD之间的模分频比 fCLK=fMOD/4 [4:0]只读,导联脱落和电极连接状态 ADS1292_REG[RESP1] = 0X00;//abcc cc1d ADS1292_REG[RESP1] |=Ads1292_Resp1.RESP_DemodEN<<7;//[7]a 这个位启用和禁用通道1上的解调电路 ADS1292_REG[RESP1] |=Ads1292_Resp1.RESP_modEN<<6; //[6]b 这个位启用和禁用通道1上的调制电路 ADS1292_REG[RESP1] |=Ads1292_Resp1.RESP_ph<<2; //[5:2]c 这些位控制呼吸解调控制信号的相位 ADS1292_REG[RESP1] |=Ads1292_Resp1.RESP_Ctrl; //[0]d 这个位设置呼吸回路的模式 ADS1292_REG[RESP1] |= 0x02;//设置默认位 ADS1292_REG[RESP2] = 0x00; //a000 0bc1 [6:3]必须为0 [0]必须为1 ADS1292_REG[RESP2] |= Ads1292_Resp2.Calib<<7; //[7]a 启动通道偏移校正? ADS1292_REG[RESP2] |= Ads1292_Resp2.freq<<2; //[2]b 呼吸频率设置 ADS1292_REG[RESP2] |= Ads1292_Resp2.Rldref_Int<<1; //[1]c RLDREF信号源外部馈电? ADS1292_REG[RESP2] |= 0X01;//设置默认位 ADS1292_REG[GPIO] = 0x0C; //GPIO设为输入 [7:4]必须为0 [3:2]11 GPIO为输入 [1:0] 设置输入时,指示引脚电平,设置输出时控制引脚电平 } //通过SPI总线与ADS1292通信 u8 ADS1292_SPI(u8 com) { return SPI2_ReadWriteByte(com); } //写命令 void ADS1292_Send_CMD(u8 data) { ADS_CS_L; HAL_Delay(1); ADS1292_SPI(data); HAL_Delay(1); ADS_CS_H; } /*ADS1291、ADS1292和ADS1292R串行接口以字节形式解码命令,需要4个tCLK周期来解码和执行. 因此,在发送多字节命令时,4 tCLK周期必须将一个字节(或操作码)的结束与下一个字节(或操作码)分开。 假设CLK(时钟)为512 kHz,则tSDECODE (4 tCLK)为7.8125 us。 当SCLK(数据速率)为16mhz时,一个字节可以在500ns中传输,此字节传输时间不符合tSDECODE规范; 因此,必须插入一个延迟,以便第二个字节的末尾晚于7.3125us到达。 如果SCLK为1 MHz,则在8u秒内传输一个字节。由于此传输时间超过tSDECODE规范,处理器可以不延迟地发送后续字节。 在后面的场景中,可以对串行端口进行编程,使其从每个循环的单字节传输转移到多个字节*/ //读写多个寄存器 void ADS1292_WR_REGS(u8 reg,u8 len,u8 *data) { u8 i; ADS_CS_L; HAL_Delay(1); ADS1292_SPI(reg); HAL_Delay(1); ADS1292_SPI(len-1); if(reg&0x40) //写 { for(i=0;i<len;i++) { HAL_Delay(1); ADS1292_SPI(*data); data++; } } else //读 { for(i=0;i<len;i++) { HAL_Delay(1); *data = ADS1292_SPI(0); data++; } } HAL_Delay(1); ADS_CS_H; } //寄存器数组写入寄存器 u8 ADS1292_WRITE_REGBUFF(void) { u8 i,res=0; u8 REG_Cache[12]; //存储寄存器数据 ADS1292_SET_REGBUFF();//设置寄存器数组 ADS1292_WR_REGS(WREG|CONFIG1,11,ADS1292_REG+1);//数组变量写入寄存器 HAL_Delay(10); ADS1292_WR_REGS(RREG|ID,12,REG_Cache);//读寄存器 HAL_Delay(10); for(i=0;i<12;i++ ) //检查寄存器 { //printf("1111 device_id value: 0x%02X\r\n", REG_Cache[i]); //printf("Write: 0x%02X, Read: 0x%02X\r\n", ADS1292_REG[i], REG_Cache[i]); if(ADS1292_REG[i] != REG_Cache[i]) { if(i!= 0 && i!=8 && i != 11) //0 8 和11是ID 导联脱落和GPIO相关 res=1; else continue; } } return res; } void ADS1292_PowerOnInit(void) { //u8 i; //u8 REG_Cache[12]; ADS1292_Send_CMD(SDATAC);//发送停止连续读取数据命令 HAL_Delay(100); ADS1292_Send_CMD(RESET);//复位 HAL_Delay(1000); ADS1292_Send_CMD(SDATAC);//发送停止连续读取数据命令 HAL_Delay(100); } //设置通道1内部1mV测试信号 u8 ADS1292_Single_Test(void) //注意1292R开了呼吸解调,会对通道一的内部测试信号波形造成影响,这里只参考通道2即可,1292不受影响 { u8 res=0; Ads1292_Config2.Int_Test = INT_TEST_ON;//打开内部测试信号 Ads1292_Ch1set.MUX=MUX_Test_signal;//测试信号输入 Ads1292_Ch2set.MUX=MUX_Test_signal;//测试信号输入 if(ADS1292_WRITE_REGBUFF())//写入寄存器 res=1; HAL_Delay(10); return res; } //设置内部噪声测试 u8 ADS1292_Noise_Test(void) { u8 res=0; Ads1292_Config2.Int_Test = INT_TEST_OFF;//关内部测试信号 Ads1292_Ch1set.MUX = MUX_input_shorted;//输入短路 Ads1292_Ch2set.MUX = MUX_input_shorted;//输入短路 if(ADS1292_WRITE_REGBUFF())//写入寄存器 res=1; HAL_Delay(10); return res; } //正常信号采集模式 u8 ADS1292_Single_Read(void) { u8 res=0; Ads1292_Config2.Int_Test = INT_TEST_OFF;//关内部测试信号 Ads1292_Ch1set.MUX = MUX_Normal_input;//普通电极输入 Ads1292_Ch2set.MUX = MUX_Normal_input;//普通电极输入 if(ADS1292_WRITE_REGBUFF())//写入寄存器 res=1; HAL_Delay(10); return res; } //配置ads1292采集方式 u8 Set_ADS1292_Collect(u8 mode) { u8 res; HAL_Delay(10); switch(mode)//设置采集方式 { case 0: res =ADS1292_Single_Read(); break; case 1: res =ADS1292_Single_Test(); break; case 2: res =ADS1292_Noise_Test(); break; } if(res)return 1;//寄存器设置失败 ADS1292_Send_CMD(RDATAC); //启动连续模式 HAL_Delay(10); ADS1292_Send_CMD(START); //发送开始数据转换(等效于拉高START引脚) HAL_Delay(10); return 0; } uint8_t SPI2_ReadWriteByte(uint8_t TxData) { uint8_t retry=0; uint8_t RxData=0; while (__HAL_SPI_GET_FLAG(&hspi4, SPI_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位 { retry++; printf("1111 device_id value: 0x%02X\r\n", RxData); if(retry>200)return 0; } HAL_SPI_Transmit(&hspi4, &TxData, 1, HAL_MAX_DELAY); //通过外设SPIx发送一个数据 retry=0; while (__HAL_SPI_GET_FLAG(&hspi4, SPI_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位 { //printf("1111 device_id value: 0x%02X\r\n", RxData); printf("SPI State: %d\n", hspi4.State); retry++; if(retry>200)return 0; } HAL_SPI_Receive(&hspi4, &RxData, 1, HAL_MAX_DELAY); //printf("1111 device_id value: 0x%02X\r\n", RxData); return RxData; //返回通过SPIx最近接收的数据 }
经过调试,发现是卡在SPI2_ReadWriteByte(uint8_t TxData)函数的第二个循环里了,也就是说标志位__HAL_SPI_GET_FLAG(&hspi4, SPI_FLAG_RXNE) == RESET一直没有置位,说明接收缓存区始终为空。我自己xiel一个ADC采集,来采集SCLK的电压,发现SCLK一直没有波形,而在C8T6上SCLK是有波形的。这到底是为什么?求解答!
Amy Luo:
您好,
对于STM32H723 软件方面的问题建议你咨询ST 公司的技术支持。
对 ADS1292R 若有什么问题或疑问,你可以在此论坛发帖我们一起讨论。