STM32H5 SPI接口 访问非标准SPI ADC(AD7768)
参考:Manipulating MCU SPI Interface to Access a Nonstandard SPI ADC
目录
简介
标准SPI连接ADC芯片
AD7768 采用STM32微控制器 SPI 通过一条 DOUT 线读取代码
解决方案 1:MCU SPI 作为节点通过一条 DOUT 线与 SPI 主 ADC 连接
解决方案 2:MCU SPI 作为节点通过两条 DOUT 线与 SPI 主 ADC 连接
简介
当前许多的精密模数转换器(ADC)模块都有串行外设接口(SPI)或一些串行接口,用于控制器通信。而为了使ADC实现更快的吞吐速率,一些ADC采用了具有非标准三线或四线SPI作为节点。
本次使用的AD7768芯片具有多条SDO线路,它们用作SPI电源。在使用该类ADC芯片时需要使用非标准SPI读取数据。
图1.AD7768具有两个数据输出引脚。
标准SPI连接ADC芯片
SPI 是一个同步的、全双工的、基于主/节点的接口。来自 main 或 node 的数据在 rising 或 falling clock edge 上同步。main 和 node 都可以同时传输数据。图 2 显示了典型的 4 线 MCU SPI 接口连接。
图2.标准SPI连接ADC芯片
如果MCU的SPI和ADC串行接口具有标准的SPI时序模式,可使用MCU标准SPI读取ADC数据,须遵循SPI协议规范。但是有一些新的ADC具有非标准SPI时序行接口端口。MCU无法使用标准SPI读取ADC7768串行端口数据。
图3.AD7768 FORMATx = 1× 时序图输出仅在DOUT0上
表1. FORMATx真值表 – AD7768
如表1 所示,当 FORMATx = 11 或 10 时,通道 0 到通道 7 仅在 DOUT0 上输出数据。在标准模式下,AD7768/AD7768-4 作为主电源工作,并将数据流传输到 MCU、DSP 或 FPGA。AD7768/AD7768-4 为节点器件提供数据、数据时钟 (DCLK) 和下降沿成帧信号(DRDY)。
本文将介绍操作标准微控制器 SPI 以与具有非标准 SPI 端口的 ADC(AD7768) 连接的方法。
AD7768 采用STM32微控制器 SPI 通过一条 DOUT 线读取代码
STM32 微控制器广泛用于许多不同的应用。MCU 具有多个 SPI 端口,可以配置为具有典型 SPI 时序模式的 SPI 主端口或节点端口。以下会话中介绍的方法也可以应用于具有 8 位、16 位或 32 位帧的其他微控制器。
AD7768 的串行接口不是典型的 SPI 时序模式,AD7768 用作串行接口主接口。通常,用户必须使用 FPGA/CPLD 作为其控制器。
例如,使用 STM32 和 AD7768 评估板。解决方法 SPI 线的连接如图 4 所示。在此设置中,所有八个 AD7768 通道数据输出仅在 DOUT0 上。
图4.MCU SPI连接
需要解决的问题:
图5.AD7768 数据读入时序解决图解
解决方案 1:MCU SPI 作为节点通过一条 DOUT 线与 SPI 主 ADC 连接
这里我使用的芯片是STM32H563VGTx 使用CubeMX初始化了SPI2作为节点,读取AD7768的数据位。外部中断1判断数据是否准备就绪。
SPI2初始化代码:
//SPI寄存器基地址
hspi2.Instance = SPI2;
//指定工作模式为从机
hspi2.Init.Mode = SPI_MODE_SLAVE;
//双向工作状态
hspi2.Init.Direction = SPI_DIRECTION_2LINES_RXONLY;
//指定SPI数据大小
hspi2.Init.DataSize = SPI_DATASIZE_32BIT;
//指定串行时钟的稳定状态
hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
//指定串行时钟的采样状态
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
//指定NSS信号是硬件管理还是软件管理
hspi2.Init.NSS = SPI_NSS_SOFT;
//指定串行数据是高位开始还是低位开始
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
//指定是否使用TI模式
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
//指定是否启用CRC计算
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
//指定CRC计算的多项式
hspi2.Init.CRCPolynomial = 0x7;
//指定是否启用NSSP信号
hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
//指定NSS信号 哪个电平为活动电平
hspi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
//FIFO阈值级别
hspi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
//指定一个额外的延迟 以SPI时钟周期的数量表示 在主动边缘和第一个数据事务以主模式启动之间额外插入
hspi2.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
//指定在主模式下插入两个连续数据帧之间的最小时间延迟(以SPI时钟周期表示)。
hspi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
//控制SPI在主接收模式下的连续传输,并进行自动管理,避免出现超限情况。
hspi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
//备用功能GPIO状态控制
hspi2.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
//反转MOSI/MISO
hspi2.Init.IOSwap = SPI_IO_SWAP_DISABLE;
//指定RDY信号 是否在内部管理
hspi2.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
//指定RDY信号输入引脚 哪个电平为活动电平
hspi2.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;
使能外部中断1的中断服务函数代码(为了使MCU有足够的响应时间 将中断设置为上升沿触发): 略
中断服务函数:
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_1) //判断是否为外部中断1触发
{
//中断触发表示数据就绪(DRDY上升沿) 开启SPI2 接收数据
__HAL_SPI_ENABLE(&hspi2);
//清除中断标志位
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);
//主程序中的标志位
ad7768_flag = 1;
}
}
读取AD7768数据位主循环代码:
if(ad7768_flag == 1) //等待中断标志置1
{
ad7768_flag = 0; //清除中断标志
//抛出前一个ODR周期中 捕获的最后一个字节
Rx_temp = *(__IO uint8_t*)&hspi2.Instance->RXDR;
while(SPI2_ByteCount < SPI2_CNVByteNum) //读取SPI2_CNVByteNum通道数据
{
if(__HAL_SPI_GET_FLAG(&hspi2,SPI_FLAG_RXWNE)) //等待接收缓冲区非空
{
//将接收到的数据 从数据寄存器写入内存
SPI_RxBuffer[SPI2_ByteCount] = *(__IO uint8_t*)&hspi2.Instance->RXDR;
SPI2_ByteCount++; //接收数据自增
}
}
//每接收一组数据后(DRDY一个下降沿) 将SPI2关闭 防止读取额外的无效数据
__HAL_SPI_DISABLE(&hspi2);
SPI2_ByteCount = 0; //将计数变量清零
}
当软件处于中断模式时,DCLK 可以运行高达 4 MHz,并实现 ODR 8 kSPS。软件应进入中断处理程序,在一个半 DCLK 周期时间 (375 ns) 内启动 SPI。为了更轻松地使软件进入中断例程,MCU 可以在 DCLK 上升沿读取数据,这可以提供额外的半个 DCLK 周期时间。但是,由于 t5DCLK 上升到 DOUTx 无效最小值为 –3 ns(IOVDD = 1.8 V 时为 –4 ns),传播延迟 (>|t5|+ MCU 保持时间)应由 PCB 布线或缓冲器添加。
解决方案 2:MCU SPI 作为节点通过两条 DOUT 线与 SPI 主 ADC 连接
在第一种解决方案中,仅使用 DOUT0 输出所有 8 通道数据。因此,数据读取将 ADC 吞吐速率限制为 8 kSPS。如图 1 所示,DOUT0 上的通道 0 到通道 3 输出和 DOUT1 上的通道 4 到通道 7 输出可以减少数据传输时间。通过这样的改进,ODR 在 DCLK 4 MHz 时可以轻松达到 16 kSPS。
编辑
固件可以使用轮询模式而不是中断模式来减少 DRDY 上升沿触发器的时间延迟,使 SPI 能够接收数据。这可以在 DCLK 8 MHz 时实现 ODR 32 kSPS。
//等待产生中断 (中断方式 采用中断服务函数置标志位的方式 而轮询方式采用轮询查看是否产生中断)
while(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_4) != SET);
//检测到中断产生后 开启SPI读取数据
__HAL_SPI_ENABLE(&hspi3);
__HAL_SPI_ENABLE(&hspi2);
//清除中断标志
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);
//采集双线八通道数据 所以需要采集4轮
while(SPI2_ByteCount < 4)
{
//等待接收缓冲区非空
if(__HAL_SPI_GET_FLAG(&hspi3,SPI_FLAG_RXWNE))
{
//读取数据寄存器
SPI_RxBuffer[SPI2_ByteCount][SPI2_j] = *(__IO uint32_t*)&hspi2.Instance->RXDR;
SPI_RxBuffer[4+SPI2_ByteCount][SPI2_j] = *(__IO uint32_t*)&hspi3.Instance->RXDR;
SPI2_ByteCount++;
}
}
//关闭SPI
__HAL_SPI_DISABLE(&hspi2);
__HAL_SPI_DISABLE(&hspi3);
SPI2_ByteCount = 0;
作者:梦途笑匠