通过I2S播放PCM音频的方法是什么?

huangapple go评论92阅读模式
英文:

How to play pcm through I2S?

问题

I have ESP32-WROOM-32D板和MAX98357A I2S板,需要播放8KHz 8位PCM音频。 PCM音频缓冲区在头文件wavedata.h中声明为常量缓冲区,如下所示:

const uint8_t rawData[49428] = {0x52, 0x49, 0x46, 0x46,.......};

以下是用于通过I2S播放此缓冲区音频的测试代码:

#include "wavedata.h"
#include <Arduino.h>
#include <I2S.h>

#define LRC_PIN             26
#define BCLK_PIN            27
#define DOUT_PIN            25

void setup()
{
    I2S.begin(I2S_PHILIPS_MODE, 8000, 8);
    I2S.setSckPin(BCLK_PIN);
    I2S.setFsPin(LRC_PIN);
    I2S.setDataPin(DOUT_PIN);
}

void loop()
{
    I2S.write_blocking(rawData, 49428);
    delay(1000);
}

但是,我听不到扬声器发出声音。

我还尝试了以下方式:

#include "driver/i2s.h"
#include "wavedata.h"

#define I2S_SAMPLE_RATE     (8000)
#define I2S_SAMPLE_BITS     (I2S_BITS_PER_SAMPLE_8BIT)
#define I2S_CHANNEL_NUM     (1)
#define I2S_BUFFER_SIZE     (512)
#define PIN_LRC             25
#define PIN_BCLK            14
#define PIN_DIN             I2S_PIN_NO_CHANGE
#define PIN_DOUT            25
#define MCK                 I2S_PIN_NO_CHANGE

void setup()
{
    i2s_config_t i2s_config = {
        .mode = (i2s_mode_t)(I2S_MODE_MASTER),
        .sample_rate = I2S_SAMPLE_RATE,
        .bits_per_sample = I2S_SAMPLE_BITS,
        .channel_format = I2S_CHANNEL_FMT_ALL_LEFT,
        .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S),
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
        .dma_buf_count = 16,
        .dma_buf_len = I2S_BUFFER_SIZE,
        .use_apll = false,
        .tx_desc_auto_clear = true,
        .fixed_mclk = I2S_PIN_NO_CHANGE,
    };
    i2s_pin_config_t pin_config = {
        .bck_io_num = PIN_BCLK,
        .ws_io_num = PIN_LRC,
        .data_out_num = PIN_DOUT,
        .data_in_num = PIN_DIN,
    };

    i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
    i2s_set_pin(I2S_NUM_0, &pin_config);
    i2s_set_sample_rates(I2S_NUM_0, I2S_SAMPLE_RATE);

    size_t written_bytes = 0;
    while (written_bytes < sizeof(rawData)) {
        size_t bytes_to_write = sizeof(rawData) - written_bytes;
        if (bytes_to_write > I2S_BUFFER_SIZE) {
            bytes_to_write = I2S_BUFFER_SIZE;
        }
        i2s_write(I2S_NUM_0, &rawData[written_bytes], bytes_to_write, &written_bytes, portMAX_DELAY);
    }

    i2s_driver_uninstall(I2S_NUM_0);
}

void loop()
{
}

上述代码也没有工作。

英文:

I have ESP32-WROOM-32D board and MAX98357A I2S board which i need to play 8Khz 8bit PCM audio. The pcm audio buffer is declared as a constant buffer in header wavedata.h like below

const uint8_t rawData[49428] = {0x52, 0x49, 0x46, 0x46,.......};

Below is my test code for playing this buffer audio through I2S

#include &quot;wavedata.h&quot;
#include &lt;Arduino.h&gt;
#include &lt;I2S.h&gt;

#define LRC_PIN             26
#define BCLK_PIN            27
#define DOUT_PIN            25
void setup()
{
    I2S.begin(I2S_PHILIPS_MODE, 8000, 8);
    I2S.setSckPin(BCLK_PIN);
    I2S.setFsPin(LRC_PIN);
    I2S.setDataPin(DOUT_PIN);
    
}
void loop()
{
    I2S.write_blocking(rawData,49428);
    delay(1000);
}

But I am not hearing any sound from the speaker.

I tried like below also

#include &quot;driver/i2s.h&quot;
#include &quot;wavedata.h&quot;

#define I2S_SAMPLE_RATE     (8000)
#define I2S_SAMPLE_BITS     (I2S_BITS_PER_SAMPLE_8BIT)
#define I2S_CHANNEL_NUM     (1)
#define I2S_BUFFER_SIZE     (512)
#define PIN_LRC             25
#define PIN_BCLK            14
#define PIN_DIN             I2S_PIN_NO_CHANGE
#define PIN_DOUT            25
#define MCK                 I2S_PIN_NO_CHANGE

void setup()
{
    
    i2s_config_t i2s_config = {
        .mode = (i2s_mode_t)(I2S_MODE_MASTER),
        .sample_rate = I2S_SAMPLE_RATE,
        .bits_per_sample = I2S_SAMPLE_BITS,
        .channel_format = I2S_CHANNEL_FMT_ALL_LEFT,
        .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S),
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
        .dma_buf_count = 16,
        .dma_buf_len = I2S_BUFFER_SIZE,
        .use_apll = false,          // must be disabled in V2.0.1-RC1
        .tx_desc_auto_clear = true, // new in V1.0.1
        .fixed_mclk = I2S_PIN_NO_CHANGE,
    };
    i2s_pin_config_t pin_config = {
        .bck_io_num = PIN_BCLK,
        .ws_io_num = PIN_LRC,
        .data_out_num = PIN_DOUT,
        .data_in_num = PIN_DIN,
    };

    i2s_driver_install(I2S_NUM_0, &amp;i2s_config, 0, NULL);
    i2s_set_pin(I2S_NUM_0, &amp;pin_config);
    i2s_set_sample_rates(I2S_NUM_0, I2S_SAMPLE_RATE);

    size_t written_bytes = 0;
    while (written_bytes &lt; sizeof(rawData)) {
        size_t bytes_to_write = sizeof(rawData) - written_bytes;
        if (bytes_to_write &gt; I2S_BUFFER_SIZE) {
            bytes_to_write = I2S_BUFFER_SIZE;
        }
        i2s_write(I2S_NUM_0, &amp;rawData[written_bytes], bytes_to_write, &amp;written_bytes, portMAX_DELAY);
    }

    i2s_driver_uninstall(I2S_NUM_0);
}

void loop()
{
}

Above code also not working

答案1

得分: 0

以下是翻译好的代码部分:

看下面的工作代码。我注意到 MAX98357A 至少需要 16 位音频才能播放 pcm  

#include "driver/i2s.h"
#include "wavedata16.h"

#define I2S_SAMPLE_RATE     (8000)
#define I2S_SAMPLE_BITS     (I2S_BITS_PER_SAMPLE_16BIT)
#define I2S_CHANNEL_NUM     (1)
#define I2S_BUFFER_SIZE     (16)
#define PIN_LRC             12
#define PIN_BCLK            14
#define PIN_DIN             I2S_PIN_NO_CHANGE
#define PIN_DOUT            26

void setup()
{

    i2s_config_t i2s_config = {
        .mode = (i2s_mode_t)(I2S_MODE_MASTER| I2S_MODE_TX),
        .sample_rate = I2S_SAMPLE_RATE,
        .bits_per_sample = I2S_SAMPLE_BITS,
        .channel_format = I2S_CHANNEL_FMT_ALL_RIGHT,
        .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S | I2S_COMM_FORMAT_STAND_MSB),
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
        .dma_buf_count = 16,
        .dma_buf_len = I2S_BUFFER_SIZE,
    };
    i2s_pin_config_t pin_config = {
        .bck_io_num = PIN_BCLK,
        .ws_io_num = PIN_LRC,
        .data_out_num = PIN_DOUT,
        .data_in_num = PIN_DIN,
    };

    i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
    i2s_set_pin(I2S_NUM_0, &pin_config);
    i2s_set_clk((i2s_port_t)0, I2S_SAMPLE_RATE, I2S_SAMPLE_BITS, (i2s_channel_t)1);

}
size_t written_bytes = 0;
void loop()
{
  if (written_bytes >= ARRAY_LEN)
    written_bytes = 0;
  size_t bytes_to_write = sizeof(rawData) - written_bytes;
  i2s_write(I2S_NUM_0, &rawData[written_bytes], bytes_to_write, &written_bytes, portMAX_DELAY);
}

另一种方法是使用 I2S 库,请参考以下代码

#include <Arduino.h>
#include <I2S.h>
#include "wavedata16.h"
#define I2S_SAMPLE_RATE     8000
#define I2S_SAMPLE_BITS     16

#define PIN_LRC             12
#define PIN_BCLK            14
#define PIN_DOUT            26
int count = 0;

void setup() {


I2S.setSckPin(PIN_BCLK);
I2S.setFsPin(PIN_LRC);
  if (!I2S.begin(I2S_PHILIPS_MODE, I2S_SAMPLE_RATE, I2S_SAMPLE_BITS)) {

    Serial.println("初始化 I2S 失败!");

    while (1); // 什么也不做

  }
}

void loop() {

if(count>=ARRAY_LEN)
   count=0;
I2S.write(rawData[count]);
I2S.write(rawData[count]);
count++;

}

但如果要播放 8  PCM 缓冲区,有一种稍微棘手的方法,请参考以下代码

#include <Arduino.h>
#include <I2S.h>
#include "wavedata.h"
#define I2S_SAMPLE_RATE     8000
#define I2S_SAMPLE_BITS     16

#define PIN_LRC             12
#define PIN_BCLK            14
#define PIN_DOUT            33
int count = 0;

void setup() {


I2S.setSckPin(PIN_BCLK);
I2S.setFsPin(PIN_LRC);
I2S.setDataPin(PIN_DOUT);
  if (!I2S.begin(I2S_PHILIPS_MODE, I2S_SAMPLE_RATE, I2S_SAMPLE_BITS)) {

    Serial.println("初始化 I2S 失败!");

    while (1); // 什么也不做

  }
}

void loop() {

if(count>=ARRAY_LEN)
   count=0;
int16_t res = map(rawData[count],0,255,-32768,32767);
I2S.write(res);
I2S.write(res);
count++;

}
英文:

See the working code below. One point I noted is for MAX98357A at-least 16 bit audio is required to play pcm

#include &quot;driver/i2s.h&quot;
#include &quot;wavedata16.h&quot;
#define I2S_SAMPLE_RATE     (8000)
#define I2S_SAMPLE_BITS     (I2S_BITS_PER_SAMPLE_16BIT)
#define I2S_CHANNEL_NUM     (1)
#define I2S_BUFFER_SIZE     (16)
#define PIN_LRC             12
#define PIN_BCLK            14
#define PIN_DIN             I2S_PIN_NO_CHANGE
#define PIN_DOUT            26
void setup()
{
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER| I2S_MODE_TX),
.sample_rate = I2S_SAMPLE_RATE,
.bits_per_sample = I2S_SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_ALL_RIGHT,
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S | I2S_COMM_FORMAT_STAND_MSB),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 16,
.dma_buf_len = I2S_BUFFER_SIZE,
};
i2s_pin_config_t pin_config = {
.bck_io_num = PIN_BCLK,
.ws_io_num = PIN_LRC,
.data_out_num = PIN_DOUT,
.data_in_num = PIN_DIN,
};
i2s_driver_install(I2S_NUM_0, &amp;i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM_0, &amp;pin_config);
i2s_set_clk((i2s_port_t)0, I2S_SAMPLE_RATE, I2S_SAMPLE_BITS, (i2s_channel_t)1);
}
size_t written_bytes = 0;
void loop()
{
if (written_bytes &gt;= ARRAY_LEN)
written_bytes = 0;
size_t bytes_to_write = sizeof(rawData) - written_bytes;
i2s_write(I2S_NUM_0, &amp;rawData[written_bytes], bytes_to_write, &amp;written_bytes, portMAX_DELAY);
}

Another method is using I2S library see below code

#include &lt;Arduino.h&gt;
#include &lt;I2S.h&gt;
#include &quot;wavedata16.h&quot;
#define I2S_SAMPLE_RATE     8000
#define I2S_SAMPLE_BITS     16
#define PIN_LRC             12
#define PIN_BCLK            14
#define PIN_DOUT            26
int count = 0;
void setup() {
I2S.setSckPin(PIN_BCLK);
I2S.setFsPin(PIN_LRC);
if (!I2S.begin(I2S_PHILIPS_MODE, I2S_SAMPLE_RATE, I2S_SAMPLE_BITS)) {
Serial.println(&quot;Failed to initialize I2S!&quot;);
while (1); // do nothing
}
}
void loop() {
if(count&gt;=ARRAY_LEN)
count=0;
I2S.write(rawData[count]);
I2S.write(rawData[count]);
count++;
}

But if you want to play 8 bit PCM buffer a little tricky way is there see below code

#include &lt;Arduino.h&gt;
#include &lt;I2S.h&gt;
#include &quot;wavedata.h&quot;
#define I2S_SAMPLE_RATE     8000
#define I2S_SAMPLE_BITS     16
#define PIN_LRC             12
#define PIN_BCLK            14
#define PIN_DOUT            33
int count = 0;
void setup() {
I2S.setSckPin(PIN_BCLK);
I2S.setFsPin(PIN_LRC);
I2S.setDataPin(PIN_DOUT);
if (!I2S.begin(I2S_PHILIPS_MODE, I2S_SAMPLE_RATE, I2S_SAMPLE_BITS)) {
Serial.println(&quot;Failed to initialize I2S!&quot;);
while (1); // do nothing
}
}
void loop() {
if(count&gt;=ARRAY_LEN)
count=0;
int16_t res = map(rawData[count],0,255,-32768,32767);
I2S.write(res);
I2S.write(res);
count++;
}

huangapple
  • 本文由 发表于 2023年5月24日 18:53:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76322738.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定