使用 ESP32、I2S MEMS 麦克风和 SD 卡FreeRTOS、PlatformIO、ESP-PROG同步缓冲区传输

问题描述

我知道这个论坛不喜欢这样的“开放式”问题,不过我还是希望有人能帮我解开这个结,非常感谢。

目标很简单:

  • 从 2 个 adafruit sph0645 麦克风读取立体声 32 位 44100 S/s I2S 信号
  • 创建一个 wav-header 并将数据存储到 SD 卡上

我已经研究了几天,我知道这会比我原先想象的要复杂得多。主要原因:信号质量。像关于这个主题的大多数教程一样,这些麦克风最简单的“hello world”是对 I2S 样本的循环轮询。轮询、填充缓冲区、通过串行输出或写入 SD 卡。这将返回一个断断续续、嘈杂、加速的 RL 音频版本。内部 DMA 缓冲区的填充可以看作是恒定的,但其余的大多是混乱的,所以

如何将这些 DMA 缓冲区与我的其余代码同步?

根据 STM32 HAL 的经验,我可以想象一些寄存器可以设置为在缓冲区已满时抛出中断,或者可以通过队列在任务之间发送事件。关于这个主题的例子要么在主循环中轮询一个糟糕的采样率和位深度,要么使用页面过大的代码并且从不解决它的作用,“只是复制和它工作”,不好。 ESP32-Arduino 框架是否提供了一些正确的方法? espressif 文档并不值得期待,因为他们的一些 I2S 接口函数甚至不起作用(如果你也在研究这个主题,你也可能已经注意到 i2s_read 只返回零)。只是一个正确方向的提示会有所帮助,无论如何我正在编写自己的代码。中断?活动?计时器?轮询完整缓冲区?可能只有你知道。

祝你好运,谢谢

解决方法

多亏了 https://github.com/atomic14/,我现在有了一个非常有效的同步方法的答案。这种方法已经被 https://esp32.com/viewtopic.php?t=12546 尝试过,他也没有完全理解发生了什么:espressif i2s-interface 提供了一个存储在事件中的标志,每次 一个指定的 dma-buffers 已接收到完整的数据集,因此,已满。它看起来像这样:

while(<your condition>){

i2s_event_t evt;
if (xQueueReceive(<your queue>,&evt,portMAX_DELAY) == pdPASS){
  if (evt.type == I2S_EVENT_RX_DONE){
    size_t bytesRead = 0;
    do{

      //read data via i2s_read or i2s_read_bytes


    } while (bytesRead > 0);

没有数据存储在这个队列中,而是一个标志,然后可用于同步 dma 填充和进一步缓冲/计算/发送读取数据。

但是这仅在您在特定设置中安装 i2s 驱动程序时才有效。而不是使用

i2s_driver_install(I2S_NUM_0,&i2s_config,NULL);

在您的设置中,您可以通过传递队列句柄和长度来激活事件的“关联性”:

i2s_driver_install(I2S_NUM_0,4,&<your queue>);

希望这有助于入门,它确实帮助了我。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...