总线学习5--I2S

一 环境

这次使用的MAX98357A芯片来做实验,接收的I2S数据,连接模拟喇叭进行播放。

这个芯片的数据手册:MAX98357A Datasheet(PDF) - Maxim Integrated Products

然后主控也升级了,这次没用之前的老朋友raspberry pico。主要是因为pico没有I2S口,这次换了一个ESP32 S3,也是现在比较强的终端板,后面可能还会用这个做一些视频类的试验。

首先还是在ESP32 S3烧写Micropython的环境,这个遇到不少问题,搞了两三个小时。

安装烧写工具倒是简单,就是

pip install esptool

之后去micropython网站下载bin。后面烧写的时候是两个U口要换着用,也还好。不过烧完遇到不少麻烦。不管是GPT还是国内技术网,说烧写清一色是这样。

esptool.py --chip esp32s3 --port COM3 --baud 460800 write_flash -z 0x1000 firmware.bin

但是这样烧进去就会

之前没遇到过这样的问题,一下就懵圈了,百度了无数篇贴文,都说把解释器换成ESP8266就行了,然后又说版本不能下最新,要随机找之前的版本试。。。但是我试了N次,都不行。。。

无奈只有换成谷歌,发现这个帖子:

Espressif ESP32-S3-WROOM-1 + Micropython --- invalid header: 0xffffffff - Stack Overflow

 原来是烧写地址要改成-z 0,也就是从0起始位置开始烧。。。

esptool.py --chip esp32s3 --port COM3 --baud 460800 write_flash -z 0 firmware.bin

之后立马就OK了。然后搭建环境。环境如下。ESP32用I2S连MAX98357小板,然后MAX98357小板连喇叭。

  • 3.3V -> Vin
  • GND -> GND
  • GPIO18 -> BCLK
  • GPIO17 -> LRCLK
  • GPIO5 -> DIN

喇叭是在PDD上买的一个5块钱。参数书4欧3W,查到的MAX98357最大可以推动4欧8W。所以应该是没问题。

算下来数字功放芯片MAX98357差不多11块,还有这个小喇叭5块,另外线还要自己出,有一些排线还要自己焊,整体下来这个试验成本就要20块。。。所以说搞硬件确实花钱啊,不过反过来说这样也才有一些门槛。。像软件没有门槛,一台电脑就能下场,现在行情已经彻底乱了。。。

二 代码

这次做了两个试验,一个简单的正弦波,一个是播放wav。

1 正弦波
from machine import I2S, Pin

# 设置I2S配置,使用替代引脚
i2s = I2S(0,
          sck=Pin(18),     # BCLK
          ws=Pin(17),      # LRCLK
          sd=Pin(5),       # DIN
          mode=I2S.TX,     # 发送模式
          bits=16,         # 每个样本的位数
          format=I2S.MONO, # 单声道
          rate=44100,      # 采样率
          ibuf=20000)      # 缓冲区大小


import math
import array

# 生成一个简单的正弦波音频数据
def generate_sine_wave(frequency, sample_rate, amplitude, duration):
    samples = sample_rate * duration
    sine_wave = array.array("h", (0 for _ in range(samples)))

    for i in range(samples):
        sine_wave[i] = int(amplitude * math.sin(2 * math.pi * frequency * i / sample_rate))

    return sine_wave

# 生成1kHz的正弦波
sine_wave = generate_sine_wave(1000, 44100, 32767, 1)  # 2秒的1kHz正弦波

print("Test I2S.")
# 播放音频数据
while True:
    i2s.write(sine_wave)
wav_file.close()

    

其实这个代码很典型了,          bits=16,         # 每个样本的位数  rate=44100,      # 采样率ibuf=20000)      # 缓冲区大

这里也解释了为什么之前在上层要配置这些。尤其是bit和采样率。

在这里,我也做了试验,主要是修改generate_sine_wave(1000, 44100, 32767, 1)。确实不同的频率发出来的声音不一样。

2 播放wav
from machine import I2S, Pin
import ustruct

# 打开WAV文件
wav_file = open('house_lo.wav', 'rb')

# 读取WAV文件头
wav_header = wav_file.read(44)

# 正确解析WAV文件头
header = ustruct.unpack('<4sI4s4sIHHIIHH4sI', wav_header)
chunk_id, chunk_size, format, subchunk1_id, subchunk1_size, audio_format, channels, sample_rate, byte_rate, block_align, bits_per_sample, subchunk2_id, subchunk2_size = header

print(f'Channels: {channels}, Sample Rate: {sample_rate}, Bits Per Sample: {bits_per_sample}')

def convert_8bit_to_16bit(data):
    # 将8位音频数据转换为16位
    converted = bytearray()
    for byte in data:
        # 扩展到16位: 中心点为128,扩展至32768
        converted.extend(ustruct.pack('<h', (byte - 128) << 8))
    return converted

# 更新I2S的采样率
#i2s.sample_rate(sample_rate)
i2s = I2S(0, sck=Pin(18), ws=Pin(17), sd=Pin(5), mode=I2S.TX, bits=16, format=I2S.MONO, rate=11025, ibuf=20000)
#i2s = I2S(0, sck=Pin(18), ws=Pin(17), sd=Pin(5), mode=I2S.TX, bits=bits_per_sample, format=I2S.MONO if channels == 1 else I2S.STEREO, rate=sample_rate, ibuf=20000)

# 播放WAV文件数据
while True:
    audio_data = wav_file.read(1024)
    if not audio_data:
        break
    audio_data_16bit = convert_8bit_to_16bit(audio_data)
    i2s.write(audio_data_16bit)

# 关闭WAV文件
wav_file.close()

在这里有几个值得注意的。

首先是找wav文件,不能大的,而且采样率波特率都要合格,最后是Windows系统里面的house_lo.wav,这个文件76K,节奏明快,播放的时候还可以随着起舞。很是有趣。

然后也是wav文件,不同的文件,对应的采样率位数这些都不同,首先都要在wav文件文件头里面解析这部分,然后这些都要在启动I2S的时候设置进去,这些都是动态的。

最后是位数,ESP32的I2S不支持16位,所以这里用了个函数转换成16位。

三 I2S协议

1 I2S协议

整体抓包的图

从图上可以看到BCLK,也就是最下面那个是时钟。LRCLK也就是中间那个是左右声道选择,有点类似SPI片选那根线,DIN也就是最上面那个,就是数据线。

看协议介绍,SCK的时钟频率 = 声道数 * 采样频率 * 采样位数。

我这边是BCLK=11025×16×1=176400Hz。不过这里有点稍微奇怪,我在代码中设置的其实是单声道I2S.MONO,但是从波形上看还是双声道,ESP32是把第一个声道给复制了一遍,所以最后的BCLK=11025×16×2=352800Hz。

下面看看每一个Data

看一下DIN的图,看起来是时钟线上升沿作为有效位,这个和I2C一样,一次有16个bit,2个byte。这里的数据是1100 0101 0000 0000,也就是上面解析出来的0xC500。这里也就是对应着上面的16位采样。

2 音频采样

下面是科普:

什么是音频采样?

音频信号在原始状态下是模拟信号,表现为随时间连续变化的电压波形。为了将这些模拟信号存储或处理为数字形式,需要将其转换为一系列离散的数字值。这一过程称为采样

  • 采样率:每秒钟对模拟信号进行采样的次数。采样率越高,音频的时间分辨率越高,能够更精确地捕捉声音的细节。常见的采样率有44.1 kHz(CD质量)、48 kHz、96 kHz等。

  • 位深度(Bit Depth):每个采样点使用的位数。位深度决定了每个采样值的精度,即信号的动态范围(能够表达的最小和最大振幅之间的差异)。16位采样表示每个采样点使用16位二进制数来表示。

16位采样意味着每个音频样本点可以有 2162^{16}216(即65,536)个不同的可能值。这些值用于表示音频信号在该时间点的振幅(音量)。

  • 更高的位深度意味着更大的动态范围。16位音频的动态范围大约是96 dB,这意味着它可以表示从非常安静到非常响亮的声音细节。
  • 音频质量:16位采样被广泛用于CD音质的音频格式。在这种设置下,音频能够很好地平衡文件大小和音质。

从这里来看,声音就是一个波形。采样率就是采样次数,越多这个波形越准确。然后采样就是这个点的精度。越多就是越准。

3 PCM编码

里面用的实际就是PCM。解析Header头的动作,在上面2.2可以看到。

PCM(Pulse Code Modulation,脉冲编码调制)是一种用于表示模拟信号的数字编码方法。它是数字音频的基础编码方式,广泛应用于各种音频格式和传输标准中。以下是对PCM格式的详细介绍:

PCM的基本原理

PCM的基本原理包括三个主要步骤:采样、量化和编码。

  1. 采样(Sampling)

    • 将连续的模拟信号在固定的时间间隔内进行采样,得到一系列离散的样本。
    • 采样频率(Sampling Rate)决定了每秒钟采样的次数,常见的采样频率有44.1kHz(CD音质)、48kHz、96kHz等。
  2. 量化(Quantization)

    • 将每个采样值转换为最接近的离散数字值。
    • 量化级数(Quantization Levels)决定了每个样本的精度,通常用位深度(Bit Depth)表示,如16位、24位等。
  3. 编码(Encoding)

    • 将量化后的数字值编码为二进制数据,便于存储和传输。

PCM格式的特性

  • 无损编码:PCM是一种无损编码方法,能够精确地表示原始模拟信号。
  • 高保真度:由于PCM能够精确地表示原始信号,因此它具有很高的音频保真度。
  • 通用性:PCM广泛应用于CD、DVD、数字电话、音频流媒体等领域。

PCM数据的表示

PCM数据通常以二进制形式存储和传输。以下是一个简单的PCM数据表示示例:

 
 

采样频率:44.1kHz

位深度:16位

声道数:2(立体声)

在这种情况下,每秒钟有44,100个样本,每个样本由16位表示,每个样本包含两个声道的数据(左声道和右声道)。

PCM数据的存储格式

PCM数据可以存储在多种文件格式中,最常见的是WAV文件格式。以下是一个WAV文件的PCM数据结构示例:

 
 

RIFF Header

ChunkID: "RIFF"

ChunkSize: 36 + SubChunk2Size

Format: "WAVE"

fmt Subchunk

Subchunk1ID: "fmt "

Subchunk1Size: 16

AudioFormat: 1 (PCM)

NumChannels: 2 (立体声)

SampleRate: 44100

ByteRate: 176400 (SampleRate * NumChannels * BitsPerSample/8)

BlockAlign: 4 (NumChannels * BitsPerSample/8)

BitsPerSample: 16

data Subchunk

Subchunk2ID: "data"

Subchunk2Size: NumSamples * NumChannels * BitsPerSample/8

Data: PCM音频数据

PCM的应用

  • CD音频:CD音频使用44.1kHz的采样频率和16位的位深度。
  • 专业音频:专业音频录制和制作通常使用更高的采样频率(如96kHz)和更高的位深度(如24位)。
  • 电话通信:数字电话系统通常使用8kHz的采样频率和8位的位深度。

PCM的优缺点

优点:

  • 高保真度:能够精确地表示原始模拟信号。
  • 无损编码:没有数据压缩,保留了所有原始信息。
  • 通用性:广泛应用于各种音频设备和系统。

缺点:

  • 数据量大:由于没有压缩,PCM数据量较大,存储和传输成本较高。
  • 不适合低带宽传输:在带宽受限的情况下,PCM可能不适合直接传输。

总结

PCM是一种基础的数字音频编码方法,通过采样、量化和编码将模拟信号转换为数字数据。它具有高保真度和无损编码的优点,广泛应用于各种音频系统和设备中。尽管数据量较大,但其高保真度使其成为高质量音频应用的首选。

四 小结和参考

好吧,I2S协议实际上本身也没有太多的内容,我觉得比较独特的还是时钟要根据参数来计算。其它还是声音本身的内容,后面有时间再看看吧。。。

声音基础概览 - 官方 Apple 支持 (中国)

音频基础学习一——声音的本质、术语与特性_音频的特性-CSDN博客

音频基础学习二——声音的波形-CSDN博客

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值