同步STM32的SAI外设传输普通数据

乐活   2024-11-03 22:30   江苏  

FreeEEG32-32通道同步ADC生物电采集系统

关于32通道同步ADC采集系统答疑

一般同步ADC都是使用的FPGA,但是单片机也可以采集!虽然I2S和SAI都是传音频数据的,但其实可以传普通数据,本质都是二进制数据流嘛!(全网都没有相关的文章)

就是一个中断来了,然后通过SD线进来,DMA外设从SD搬到了内存,就是这么简单。

可以串行的从这里进去,4个SD口,4个ADC,数据太多还可以通过FIFO来缓冲,然后把FIFO的数据传到DMA里面。

我给了三个demo段:

  1. 实现了一个双通道SAI(串行音频接口)的DMA数据采集功能。也就是说,它会同时从两个SAI通道(Block B2和Block A1)采集数据,并将采集到的数据分别存储到两个不同的缓冲区中。

  2. 当ADC的引脚就绪,启动SAI模块读取数据,并通过UART7以二进制形式输出。

  3. 实现了一个多通道SAI(串行音频接口)的DMA数据采集功能,并且使用了中断来处理DMA完成事件。它可以同时从四个SAI通道(Block B2, Block A1, Block B1, Block A2)采集数据,并将采集到的数据分别存储到不同的缓冲区中。

    1. 多通道同时采集: 通过同时启动四个SAI通道的DMA传输,实现了多通道的数据同时采集。

    2. DMA高效传输: 使用DMA方式进行数据传输,可以减轻CPU的负担,提高数据传输效率。

    3. 中断处理: 通过DMA中断,可以在DMA传输完成后立即进行后续处理,提高系统响应速度。

    4. 灵活配置: 可以根据需要选择是否启用DMA中断。

    5. 缓冲区存储: 将采集到的数据分别存储到不同的缓冲区中,方便后续的处理。


采集使用的ADC是AD777x,他们不是单纯的SPI输出,而是并行的输出接口,在官方给出的代码里面有着不同数据输出的方式:

这里使用了SAI的外设,就使用这个模式

串行的输出

一帧数据

三个宏

三个宏,用于配置AD7779模数转换器(ADC)的寄存器。这些宏可以用来设置数据的输出格式、数据头格式和时钟分频系数。

  1. AD7779_DOUT_FORMAT(x)

  • (x) & 0x3: 取出输入值x的低两位。

  • ((x) & 0x3) << 6: 将提取的两位左移6位,放到寄存器中的指定位置。

  • 最终的结果用来配置AD7779寄存器中的数据输出格式。

  • 作用: 定义数据输出格式,决定每个采样点的位数。

  • AD7779_DOUT_HEADER_FORMAT

    • (1 << 5): 将值的第5位设置为1,其他位为0。

    • 这个值用来在AD7779寄存器中启用数据头格式。

    • 作用: 定义数据头格式,包括同步和帧同步等信息。


    这么多数据要加CRC的,也就是要加个头


    AD7779、AD7771都是这样的为了快速的移动数据使用了大量的DMA外设

    SAI外设使用中断来启动

    SD数据线

    模式是非同步的从设备,就是等着数据来

    这个就是一些设置,数据深度开到了最大

    两个FIFO全开

    FIFO在APB的下面

    这个是中断的地址

    这个函数就是就是接收DMA的数据

    使用这样的结构直接获取来自SAI外设上面的数据

    实现了一个双通道SAI(串行音频接口)的DMA数据采集功能。也就是说,它会同时从两个SAI通道(Block B2和Block A1)采集数据,并将采集到的数据分别存储到两个不同的缓冲区中。

    1. 条件判断:

    • if (FREESMARTEEG_ADC & FREESMARTEEG_ADC_SAI_READ_DMAMUX): 这一行代码首先检查了两个宏定义:FREESMARTEEG_ADCFREESMARTEEG_ADC_SAI_READ_DMAMUX

    • 只有当这两个宏定义都为真时,才会执行后续的代码。这意味着,只有当ADC功能和SAI读取DMA复用功能都开启时,才会进行数据采集。

  • 启动DMA传输:

    • 这行代码启动了SAI Block B2的DMA接收。它会将从SAI Block B2接收到的32位数据存储到datas[0]这个缓冲区中。

      HAL_SAI_Receive_DMA(&hsai_BlockB2, datas[0], SAI_DATASIZE_32):

    同样,这行代码启动了SAI Block A1的DMA接收,并将数据存储到datas[1]缓冲区中。

      HAL_SAI_Receive_DMA(&hsai_BlockA1, datas[1], SAI_DATASIZE_32)
  • 等待DMA传输完成:

    • 这行代码会一直等待,直到SAI Block B2的DMA传输完成。

      while (HAL_SAI_GetState(&hsai_BlockB2) != HAL_SAI_STATE_READY)
    • 这行代码会一直等待,直到SAI Block A1的DMA传输完成。

      while (HAL_SAI_GetState(&hsai_BlockA1) != HAL_SAI_STATE_READY)
  • 检查条件: 确保ADC和DMA复用功能开启。

  • 启动DMA: 同时启动两个SAI通道的DMA接收。

  • 等待完成: 等待两个DMA传输都完成。


    • 双通道同时采集: 通过同时启动两个SAI通道的DMA传输,实现了双通道的数据同时采集。

    • 缓冲区存储: 将采集到的数据分别存储到不同的缓冲区中,方便后续的处理。

    • 等待机制: 通过循环等待DMA传输完成,确保数据采集的完整性。


    在ADC的数据传输的时候是有个信号的

    1. 条件判断:

    • 检查是否开启了ADC和SAI读取功能。

      FREESMARTEEG_ADC & FREESMARTEEG_ADC_SAI_READ
  • 数据读取循环:

    • 循环等待DMA传输完成。

      HAL_SAI_GetState(&hsai_BlockB1) != HAL_SAI_STATE_READY:
    • 启动DMA方式接收32位的数据,并将数据存储到datasBuffer[0]中。

      HAL_SAI_Receive_DMA(&hsai_BlockB1, datasBuffer[0], SAI_DATASIZE_32):
    • 读取DRDY引脚的状态。

      HAL_GPIO_ReadPin(AD_DRDY_GPIO_Port, AD_DRDY_Pin):
    • 循环等待DRDY引脚变为高电平,表示数据准备就绪。

    • 等待数据就绪:

    • 启动SAI接收:

    • 等待DMA传输完成:

  • 数据打印:

    • 遍历接收到的数据,逐字节打印成二进制形式。

    • print7_binary函数:用于打印一个字节的二进制表示。

    • print7_symbol(';'): 用于打印分隔符';'。

    • print7_line(): 用于打印换行符。

    • 检查是否开启了UART7文本输出。

      FREESMARTEEG_OUT & FREESMARTEEG_SAI_TEXT_UART7:
    • 检查输出模式:

    • 循环打印数据:

    • SAI (Serial Audio Interface): 一种高速串行音频接口,用于音频数据的传输。

    • DMA (Direct Memory Access): 一种数据传输方式,可以高效地直接将数据从外设传输到内存,减轻CPU的负担。

    • DRDY (Data Ready): 数据就绪信号,表示新的数据已经准备好可以读取。

    • 二进制输出: 将数据以二进制的形式打印出来。


    1. 条件判断:

    • 这一行代码首先检查了两个宏定义:FREESMARTEEG_ADCFREESMARTEEG_ADC_SAI_READ_INT。只有当这两个宏定义都为真时,才会执行后续的代码。这意味着,只有当ADC功能和SAI读取中断功能都开启时,才会进行数据采集。

      if (FREESMARTEEG_ADC & FREESMARTEEG_ADC_SAI_READ_INT):
  • 启动数据采集:

    • 如果启用了DMA中断:

    • 如果没有启用DMA中断:

    • HAL_SAI_Receive_DMA: 启动四个SAI通道的DMA接收,并将数据分别存储到datas[0]datas[1]datas[2]datas[3]这四个缓冲区中。

    • 程序会等待每个DMA传输完成,然后设置SAI_RxCplt标志位,表示数据采集周期结束。

    • 程序直接等待每个DMA传输完成,然后设置SAI_RxCplt标志位。

    • if (SAI_RxStart): 这行代码检查了一个标志位SAI_RxStart,用于判断是否需要开始新的数据采集周期。

    • SAI_DMA_INT_SHIFT: 这个标志位表示是否启用了DMA中断。

  • 等待DMA传输完成:

    • 无论是否启用了DMA中断,程序都会通过HAL_SAI_GetState函数来等待每个DMA传输完成。


    1. 检查条件: 确保ADC和SAI读取中断功能开启,并且需要开始新的数据采集周期。

    2. 启动DMA: 启动四个SAI通道的DMA接收。

    3. 等待完成: 等待所有DMA传输完成。

    4. 设置标志位: 设置SAI_RxCplt标志位,表示数据采集周期结束。

    第一个的连接是这样的,全连接

    第二个也是

    然后时钟线就两个,外设4个,然后可以把时钟给到别人

    音频子模块既可作为接收器,又可作为发送器;既可与另一模块同步,又可以不同步。SAI 可与其它 SAI 相连接来同步运行。

    音频数据的量化位数可能不同,控制器支持16bit、24bit和32bit三种数据长度, 因为数据寄存器是16bit的,所以对于24bit和32bit数据长度需要发送两个。为此,可以产生四种数据和帧格式组合:
    • 将16位数据封装在16位帧中
    • 将16位数据封装在32位帧中
    • 将24位数据封装在32位帧中
    • 将32位数据封装在32位帧中
    当使用32位数据包中的16位数据时,前16位(MSB)为有效位,16位LSB被强制清零,无需任何软件操作或DMA请求(只需一个读/写操作)。如果程序使用DMA传输(一般都会用),则24位和32位数据帧需要对数据寄存器执行两次DMA操作。24位的数据帧,硬件会将8位非有效位扩展到带有0位的32位。对于所有数据格式和通信标准而言,始终会先发送最高有效位(MSB优先)。

    另外的外设,就没有时钟线了

    是使用的第一个的时钟线

    同理

    这个是时钟树上面的位置

    这个就是IO的输入的口

    云深之无迹
    纵是相见,亦如不见,潇湘泪雨,执念何苦。
     最新文章