1

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

目标很简单:

  • 从 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 只返回零)。只是对正确方向的提示会有所帮助,无论如何我正在编写自己的代码。中断?事件?计时器?轮询完整缓冲区?只有你可能知道。

有一个好的,thx

4

1 回答 1

0

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

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, 0, NULL);

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

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

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

于 2021-02-04T11:31:30.227 回答