ads131m02 调试与学习笔记
- 时序
- SPI
参考链接:
ADS131M02_TI官网资料参考
ADS131M02—英文使用手册
ADS131M0x—参考代码 Example C Code
ADS131M02 是一款 two 通道、同步采样、24 位、ΔΣ 模数转换器 (ADC),具有宽动态范围、低功耗和电能测量特定功能,因此非常适合电能计量、功率计量和断路器应用。
ADS131M02 同属于ADS131M0x系列,x代表通道位数,M02为2通道,M08为8通道。
DSP使用的也是TI的 TMS320F280049C,通讯方式为SPI
时序
SPI
简单介绍一下SPI,如果需要详细了解可以参考这篇文章:SPI通信详解
SPI 是英语 Serial Peripheral interface 的缩写,即串行外围设备接口。SPI 接口主要应用在 EEPROM,FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,STM32 也有 SPI 接口。
ADS131M02使用SPI兼容接口来配置器件并检索转换数据。该器件始终充当 SPI 从机; SCLK 和 CS 是接口的输入。该接口在SPI模式1下运行,其中CPOL = 0,CPHA = 1。在SPI模式1中,SCLK空闲为低电平,数据仅在SCLK上升沿启动或更改;数据由主机和从机在SCLK下降沿上锁存或读取。该接口是全双工的,这意味着接口可以同时发送和接收数据。
该器件包括典型的 SPI 信号:SCLK、CS、DIN (MOSI) 和 DOUT (MISO)。此外,还有另外两个数字引脚提供额外的功能。DRDY 引脚用作主机的标志,用于指示新的转换数据可用。SYNC/RESET引脚是一个双功能引脚,允许将转换同步到外部事件,并允许硬件设备复位。
疑问1:但在实际程序中,我初始化SPI为模式1时发现通讯数据接收回来刚好会便宜一位,如发送复位指令应该回复0xFF22,但是实际回复0x7F91,其正好是FF22右移一位,初始化为SPI的0模式,CPOL = 0,CPHA = 0时又收发都正常,但与手册中说明的却不符…求大佬指点
- 片选 Chip Select (CS)
CS 引脚是一个低电平有效输入信号,用于选择用于通信的器件。该器件忽略任何通信,当 CS 保持高电平时,DOUT 为高阻抗。在通信帧期间将 CS 保持低电平,以确保正确通信。每次 CS 为高电平时,接口都会重置。 - 串行数据时钟 Serial Data Clock (SCLK)
SCLK 引脚是一个输入,用作接口的串行时钟。SCLK上升沿的DOUT引脚转换的输出数据和DIN的输入数据均锁存于SCLK的下降沿。 - 串行数据输入 Serial Data Input (DIN)
DIN引脚是器件的串行数据输入引脚。当 CS 引脚为低电平时,串行命令由器件通过 DIN 引脚移入,每个 SCLK 下降沿。 - 串行数据输出 Serial Data Output (DOUT)
DOUT 引脚是该器件的串行数据输出引脚。当 CS 引脚为低电平时,该器件通过每个上升的 SCLK 边沿串行移出命令响应和 ADC 转换数据。当 CS 为高电平时,该引脚处于高阻抗状态。 - 数据就绪 Data Ready (DRDY)
DRDY引脚是一个低电平有效输出,用于指示转换模式下新的转换数据何时准备就绪,或者在电流检测模式下是否满足电流检测要求。将DRDY引脚连接到主机上的数字输入,以在转换模式下触发定期数据检索。(转换模式:连续转换;全局斩波)。
DRDY引脚与ADS131M02上给定通道的采样时间之间的关系取决于该通道的相位校准设置以及MODE寄存器中DRDY_SEL[1:0]位的状态。DRDY_SEL[1:0]位的设置决定了DRDY引脚何时被激活(即,变为低电平):
当DRDY_SEL[1:0]被设置为00b时,DRDY会在具有最大正相位校准设置(即,最滞后的)的通道有新转换结果时激活。
当DRDY_SEL[1:0]被设置为01b时,设备会在任何通道数据准备就绪时激活DRDY。
当DRDY_SEL[1:0]被设置为10b或11b时,DRDY会在具有最负相位校准设置(即,最领先的)的通道有新转换数据时激活。
在全局斩波模式下,改变DRDY_SEL[1:0]位对DRDY行为没有影响,因为在该模式下相位校准自动禁用。
在MODE寄存器中,DRDY_HIZ位配置了DRDY引脚在非断言(即高电平)时的状态。默认情况下,该位是0b,意味着引脚使用推挽输出级主动驱动为高电平。当该位被设置为1b时,DRDY表现为一个开漏数字输出。如果DRDY未断言,可以使用一个100kΩ的上拉电阻将引脚拉高。
MODE寄存器中的DRDY_FMT位决定了DRDY信号的格式。
当该位为0b时,新数据通过DRDY从高电平变为低电平来指示,并保持低电平,直到所有转换数据从设备中移出,或者在下次DRDY过渡到低电平之前短暂地保持低电平然后变为高电平。当DRDY_FMT位为1b时,新数据通过DRDY引脚上的一个短暂负脉冲来指示。
如果当DRDY_FMT为1b时,主机在DRDY脉冲后不读取转换数据,则设备会跳过一个转换结果,并且在数据因生成脉冲的方式而再次就绪的第二次实例之前,不会提供另一个DRDY脉冲。
重要的是要注意,当新转换完成而正在读取转换数据时,DRDY脉冲会被阻塞。因此,为了避免DRDY行为的不一致性,应避免在新转换完成的时间段内读取ADC数据。这样可以确保DRDY信号能够准确地反映数据就绪的状态。
在我的程序中参考TI工程例子,使用DRDY中断在中断函数中获取采样转换数据并保存。
__interrupt void GPIO_DRDY_IRQHandler(void)
{int32 ch0 = 0xFF, ch1 = 0xFF;ReadData(&adcdata_channel);if(queueIndex >= WINDOW_LEN){queueIndex = 0;}ch0queue[queueIndex] = adcdata_channel.channel0; // 通道0ch1queue[queueIndex++] = adcdata_channel.channel1; // 通道1Interrupt_clearACKGroup(PIEACK_GROUP1); //清理中断标志(必须)
}
- 转换同步或系统复位 Conversion Synchronization or System Reset (SYNC/RESET)
SYNC/RESET引脚是一个多功能数字输入引脚,主要用于允许主机将转换同步到外部进程或复位器件。
SPI通信帧
ADS131M02上的 SPI 通信以帧形式执行。每个 SPI 通信帧都由几个字组成。
通过在MODE寄存器中对WLENGTH[1:0]位进行编程,字长可配置为16位、24位或32位。ADS131M02实现了 SPI 通信的超时功能。使用 MODE 寄存器中的 TIMEOUT 位启用或禁用超时。启用后,整个 SPI 帧(第一个 SCLK 到最后一个 SCLK)必须在 215 个 CLKIN 周期内完成,否则 SPI 将复位。此功能是为了在 CS 绑定低的情况下恢复 SPI 同步而提供的方法。该接口是全双工的,这意味着该接口能够在DOUT上传输数据,同时在DIN上接收数据。主机在 DIN 上发送的输入帧始终以命令开头。设备在 DOUT 上传输的输出帧上的第一个字始终以对在前一个输入帧上写入的命令的响应开始。命令中的字数取决于提供的命令。对于大多数命令,框架中有四个单词。在 DIN 上,主机提供命令,如果启用了输入 CRC,则提供命令 CRC,如果禁用了输入 CRC,则提供一个零字,以及另外两个零字。同时在DOUT上,该器件输出来自前一帧命令的响应、代表两个ADC通道的ADC数据字和一个CRC字。图 8-18 展示了一个典型的命令框架结构。
SPI通信字
带有ADS131M02的SPI通信帧由单词组成。DIN上的字可以包含命令、寄存器写入期间的寄存器设置或输入数据的CRC。DOUT上的字可以包含命令响应、寄存器读取期间的寄存器设置、ADC转换数据或输出数据的CRC。字可以是 16、24 或 32 位。字长由MODE寄存器中的WLENGTH[1:0]位配置。设备默认为 24 位字长。命令、响应、CRC 和寄存器始终包含 16 位实际数据。这些字始终是最高有效位 (MSB) 对齐的,因此最低有效位 (LSB) 是零填充的,以适应 24 位或 32 位字的大小。ADC转换数据标称值为24位。当器件配置为 16 位通信时,ADC 会截断其 8 个 LSB。对于由MODE寄存器中的WLENGTH[1:0]位配置的ADC数据,有两种32位通信选项。ADC数据可以是用零填充的LSB,也可以是MSB符号扩展的数据。
疑问2:在调试中发现无论发送什么数据都回复0xFF22
论坛相关问题:ADS131M04: 任何指令的回复第一个字节都是FF24
ADS131M02: 周期DRDY_n低脉冲,之后立即受到0xFF22数据输出
后续经过仔细对时序并修改,再用示波器测量发送数据的波形发现24bits,3字节的数据原本是一次发送的,但分了两次,先发送16bits,再发送8bits,很奇怪官方库的接口就是有问题,后续将底层读写寄存器的代码直接拷过来操作,并在发送结束拉高片选前多延时一点确保在一个完整24bits发送完毕再拉高片选信号,最终解决。
其底层无非即是读写,spib_addr + 0x8 位置的寄存器完成发送,粗略封的调试接口如下:
uint16_t Send24bits(uint16 spi_data1, uint16 spi_data2, uint16 spi_data3)
{uint8 dataRx[4] = { 0 }; while(((*((volatile uint16_t *)(spib_addr + 0x2)))& 0x20) != 0U){}(*((volatile uint16_t *)(spib_addr + 0x8)))= spi_data1; // Send the first 8 bits of the datawhile(((*((volatile uint16_t *)(spib_addr + 0x2)))& 0x40) == 0U) {}dataRx[0] = (*((volatile uint8_t *)(spib_addr + SPI_O_RXBUF))); // Check for data to read.while(((*((volatile uint16_t *)(spib_addr + 0x2)))& 0x20) != 0U){}(*((volatile uint16_t *)(spib_addr + 0x8)))= spi_data2;while(((*((volatile uint16_t *)(spib_addr + 0x2)))& 0x40) == 0U) {}dataRx[1] = (*((volatile uint8_t *)(spib_addr + SPI_O_RXBUF)));while(((*((volatile uint16_t *)(spib_addr + 0x2)))& 0x20) != 0U){ }(*((volatile uint16_t *)(spib_addr + 0x8)))= spi_data3;while(((*((volatile uint16_t *)(spib_addr + 0x2)))& 0x40) == 0U) {}dataRx[2] = (*((volatile uint8_t *)(spib_addr + SPI_O_RXBUF)));while(((*((volatile uint16_t *)(spib_addr + 0x2)))& 0x20) != 0U){}uint16_t adcResponse = combineBytes(dataRx[0], dataRx[1]);return adcResponse;
}
通信协议:指令与回复
其余不多解释,参照途中格式即可,着重说明一下读写寄存器的命令:
读寄存器: RREG (101a aaaa annn nnnn)
RREG 用于读取器件寄存器。命令字的二进制格式为 101a aaaa annn nnnn,其中a aaaa a 是开始读取的寄存器的二进制地址,nnn nnnn 是要读取的连续寄存器的无符号二进制数减 1。在ADS131M02上读取寄存器有两种情况。当读取单个寄存器(nnn nnnn = 000 0000b)时,设备在下一帧的命令响应字中输出寄存器内容。如果使用单个命令 (nnn nnnn > 000 0000b) 读取多个寄存器,则设备将按地址顺序顺序输出请求的寄存器数据。
举例:如果要读取地址为0x2,即MODE寄存器(默认值0x0510)时,地址a aaaa a 部分应该为0 0001 0,读取寄存器个数为1,nnn nnnn 即为 1-1=0,所以发送的命令就是 1010 0001 0000 0000 , 然后回复的是读寄存器指令的回复,接着下一个再发送NULL(即全0),这是读回来的就是,0x2地址寄存器的值,为0x0510。
读取多个寄存器时,当 nnn nnnn 在 RREG 命令字中被指定为大于零的数字时,将从器件中读取多个寄存器。与ADS131M02上的所有 SPI 命令一样,响应发生在命令后面帧的输出上。响应不是单个确认词,而是跨越多个词,以便移出所有请求的寄存器。继续切换 SCLK 以适应整个数据流的输出。ADC转换数据不会在RREG命令之后在帧中输出,以读取多个寄存器。图 显示了读取多个寄存器的示例
// 读取地址为 0x3的CLOCK寄存器,默认值为 0x030ESend24bits(0xA1FF, 0x80FF, 0x00FF); // 1010 0001 1000 0000 0000 0000Send24bits(0x00FF, 0x00FF, 0x00FF); // 应返回0x030E
写寄存器 WREG (011a aaaa annn nnnn)
与读寄存器指令同理,WREG 命令允许写入任意数量的连续设备寄存器。命令字的二进制格式是 011a aaaa annn nnnn,其中 aaaa a 是要开始写入的寄存器的二进制地址,nnn nnnn 是要写入的连续寄存器的无符号二进制数减 1。在命令字之后立即发送要写入的数据。将每个寄存器的预期内容写入单独的单词,MSB 对齐。如果使能了输入CRC,则在寄存器数据之后写入此CRC。当寄存器被转换为 DIN 时,它们被写入器件。因此,CRC错误并不能阻止将错误值写入寄存器。WREG 命令期间的输入 CRC 错误会在 STATUS 寄存器中设置CRC_ERR位。设备会忽略对只读寄存器或越界地址的写入。寄存器映射地址空间中的间隙仍包含在参数 nnn nnnn 中,但不可写入,因此不会对它们进行任何更改。在以下帧中出现的对 WREG 命令的响应显示为 010a、aaaa、ammm mmmm,其中 mmm mmmm 是实际写入的寄存器数减去 1。主机可以根据 nnn nnnn 检查此数字,以确保写入预期的寄存器数。
显示了典型的 WREG 序列。在本例中,要写入的寄存器数量大于ADC通道的数量,因此,帧延伸到ADC通道和输出CRC字之外。确保在每次有新数据可用的事务处理期间,所有ADC数据和输出CRC都被移出。因此,在某些情况下,帧必须扩展到发送寄存器数据所需的字数之外。
举例:
// 给地址为 0x3的CLOCK寄存器,写为 0x0302Send24bits(0x61FF, 0x80FF, 0x00FF); // 0110 0001 1000 0000 0000 0000Send24bits(0x03FF, 0x02FF, 0x00FF);
未完待续。。。。