这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【分享开发笔记,赚取电动螺丝刀】左对齐模式下I2S通讯的实践

共9条 1/1 1 跳转至

【分享开发笔记,赚取电动螺丝刀】左对齐模式下I2S通讯的实践

专家
2025-04-27 12:25:11   被打赏 22 分(兑奖)     打赏

作为学习I2S通讯的第一个例子,使用STC的Ai8051U单片机,在生成三角波形例程的基础上进行改造,程序代码如下:



/*************  功能说明    **************
本例程基于AI8051U为主控芯片的实验箱进行编写测试.
使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。
edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。
测试工作频率为 45.1584MHz
******************************************/
#include "../../comm/AI8051U.h"
#include "stdio.h"
#include "intrins.h"
typedef unsigned charu8;
typedef unsigned intu16;
typedef unsigned longu32;
#define     FOSC            45158400UL      // 定义主时钟
#define     SampleRate      44100           // 定义采样率
#define     MCKOE           1               // I2S 主时钟输出控制 , 0:禁止 I2S 主时钟输出, 1:允许 I2S 主时钟输出
#define     I2SEN           0x04            // I2S 模块使能    0x00:禁止, 0x04:允许
//0:从机发送模式
//1:从机接收模式
//2:主机发送模式
//3:主机接收模式,
#define     I2S_MODE        2               // I2S 模式
//0:短帧同步
//1:长帧同步
#define PCMSYNC 0 //PCM 帧同步
//0: I2S 飞利浦标准
//1: MSB 左对齐标准
//2:LSB 右对齐标准
//3:PCM 标准
#define STD_MODE 1 //I2S 标准选择
//0:时钟稳定状态为低电平
//1:时钟稳定状态为高电平
#define CKPOL 0 //I2S 稳态时钟极性
//0:16 位
//1:24 位
//2:32 位
//3:保留
#define DATLEN 0 //数据长度
//0:16 位
//1: 32 位
#define CHLEN 0 //通道长度(每个音频通道的位数)
#if (MCKOE == 1) //允许主时钟输出
    #define I2SDIV FOSC/(16*2*8*SampleRate) //对于双声道允许主时钟输出 16bit 256fs
    //则 2*DIV + ODD = I2S 时钟 / 256fs
    //必要需要 DIV >= 2, 即分频系数 >=4.
#endif
#if (MCKOE == 0) //禁止主时钟输出
    #define I2SDIV FOSC/(16*2*SampleRate) //对于双声道禁止主时钟输出 16bit
    //则 2*DIV + ODD = I2S 时钟 / 32fs
    //必要需要 DIV >= 2, 即分频系数 >=4.
#endif
u8 dac_index; //输出计数索引
// 延时处理,LED闪烁用
void  delay_ms(u16 ms) {
     u16 i;
     do {
          i = FOSC / 6000;
          while(--i);
     }while(--ms);
}
void main(void) {
    EAXFR = 1; //允许访问扩展的特殊寄存器,XFR
    //(32 位模式请使用这句,注释下一句)
    // P_SW2 |= 0x80; //允许访问扩展的特殊寄存器,XFR
    //(8 位模式请使用这句,注释上一句)
    
    WTST = 0; // 设置取程序代码等待时间, 赋值为 0 表示不等待,程序以最快速度运行
    
    CKCON = 0; // 设置访问片内的 xdata 速度,赋值为 0 表示用最快速度访问,不增加额外的等待时间
    
    // 配置端口模式,全都设置为准双向口模式
    P0M0 = 0x00; P0M1 = 0x00;
    P1M0 = 0x00; P1M1 = 0x00;
    P2M0 = 0x00; P2M1 = 0x00;
    P3M0 = 0x00; P3M1 = 0x00;
    P4M0 = 0x00; P4M1 = 0x00;
    P5M0 = 0x00; P5M1 = 0x00;
    
    I2SMD = 0xff;   //内部保留字节,需设置为 FFH
    I2SCR = 0x80;   //使能发送缓冲区空中断(0x80)
    
    // 设置 I2S 主时钟输出(I2SMCK), 设置 ODD
    I2SPRH = (MCKOE << 1) + (I2SDIV & 1); 
    
    I2SPRL = I2SDIV/2; //设置 I2S 时钟分频
    I2SCFGH = I2S_MODE; //设置 I2S 模式为主机发送模式
    I2SCFGL = (PCMSYNC << 7) + (STD_MODE << 4) + (CKPOL << 3) + (DATLEN << 1) + CHLEN;
    
    //0: P3.2(BCLK) P3.4(SD) P5.4(MCLK) P3.5(WS)
    P_SW3 = (P_SW3 & 0x3f) | (0<<6); //I2S 端口切换
    
    I2SCFGH |= I2SEN; // 使能 I2S 模块
    
    // 开中断
    EA = 1;
    
    dac_index = 0;
    
    while (1) {
        // 闪烁P00所在LED,仅仅是为了证明程序已经工作 
        P00 = 0;//LED On
        delay_ms(500);
        P00 = 1;//LED Off
        delay_ms(500);
    }
}
// I2S发送完成中断
void I2S_ISR(void) interrupt 62  {
    u8 i;
    
    // 发送缓冲区空
    if (I2SSR & 0x02) {
        
        // 哪个通道的发送通道的数据为空
        if (I2SSR & 0x04)  {
            // 右声道发送完成,准备左通道的
            i = dac_index;
            I2SDRL = i; //发送下一帧音频数据
            I2SDRH = 0;
            
        } else {
            // 左声道发送完成,准备右通道的
            i = dac_index;
            I2SDRL = i^255; //发送下一帧音频数据
            I2SDRH = 0;
            
            dac_index++;
        }
}
}

代码说明:

1、设置I2SCR

图片1.png

I2SCR = 0x80;   //使能发送缓冲区空中断(0x80)


TXEIE : B7 = 1,表示当发送缓冲区数据被发送完成后,会产生中断。在本例中,I2S外设是被当做主设备使用的,向外发送数据。


2、设置I2SPRH 和 I2SPRL 

图片2.png


#define     FOSC            45158400UL      // 定义主时钟
#define     SampleRate      44100           // 定义采样率44.1KHz
#define     MCKOE           1               // I2S 主时钟输出控制 , 0:禁止 I2S 主时钟输出, 1:允许 I2S 主时钟输出
#if (MCKOE == 1) //允许主时钟输出
    #define I2SDIV FOSC/(16*2*8*SampleRate) //对于双声道允许主时钟输出 16bit 256fs
//则 2*DIV + ODD = I2S 时钟 / 256fs , 需要 DIV >= 2, 即分频系数 >=4.
// 根据计算 I2SDIV=45158400/(16*2*8*44100)=4
#endif
// 设置 I2S 主时钟输出(I2SMCK), 设置 ODD=0,MCKOE=1
I2SPRH = (MCKOE << 1) + (I2SDIV & 1);    //                  =2
I2SPRL = I2SDIV/2;                    // 设置 I2S 时钟分频 =2 
当 I2S 主时钟输出使能时(MCKOE 设置为 1)、当信道帧宽度为 16 位时,音频采样频率 FS=I2S 时钟÷[(16×2)×(2×DIV+ODD)×8)]


3、设置I2SCFGH 和 I2SCFGL

 

图片3.png


#define     I2SEN           0x04            // I2S 模块使能    0x00:禁止, 0x04:允许
//0:从机发送模式
//1:从机接收模式
//2:主机发送模式
//3:主机接收模式,
#define     I2S_MODE        2               // I2S 模式
//0:短帧同步
//1:长帧同步
#define PCMSYNC    0              //PCM 帧同步
//0: I2S 飞利浦标准
//1: MSB 左对齐标准
//2:LSB 右对齐标准
//3:PCM 标准
#define STD_MODE    1             // I2S 标准选择
//0:时钟稳定状态为低电平
//1:时钟稳定状态为高电平
#define CKPOL      0               //I2S 稳态时钟极性
//0:16 位
//1:24 位
//2:32 位
//3:保留
#define DATLEN      0             //数据长度
//0:16 位
//1: 32 位
#define CHLEN       0        //通道长度(每个音频通道的位数)
I2SCFGH = I2S_MODE;          //设置 I2S 模式为主机发送模式
I2SCFGL = (PCMSYNC << 7) + (STD_MODE << 4) + (CKPOL << 3) + (DATLEN << 1) + CHLEN;  // 
//0: P3.2(BCLK) P3.4(SD) P5.4(MCLK) P3.5(WS)
P_SW3 = (P_SW3 & 0x3f) | (0<<6); //I2S 端口切换
I2SCFGH |= I2SEN; // 使能 I2S 模块


4、数据发送过程中,通道的判断处理

图片4.png

TXE :发送完成标志

CHSID : 0:左通道正在发送或接收数据;1:右通道正在发送或接收数据


程序中为了明显区别左右声道数据的不同,特意做了取反处理,运行起来后用逻辑分析仪测量到的波形:


从波形上看,左声道数据在前,右声道数据在后,数据为16位长度,高位在前,低位在后。

图片8.png

与左对齐模式 Left Justified Standard是一致的。

标准左对齐格式的数据的MSB没有相对于BCLK延迟一个时钟。左对齐格式的左右声道数据的MSB在LRCK边沿变化后BCLK的第一个上升沿有效。左对齐格式的优点在于,由于在LRCK变化后的第一个SCK上升沿就开始采样,它不需要关心左右声道数据的字长。

图片9.png

BLCK的时钟频率:

图片10.png

从波形上看,为5.56MHz的样子,根据公式《SCLK的频率=2×采样频率×采样位数》的计算结果看,出入比较大啊。


工程文件:

main.zip




高工
2025-04-27 12:42:55     打赏
2楼

你这时钟抖动太大了,是不是代码写的有漏洞?


专家
2025-04-27 19:08:10     打赏
3楼

感谢分享


专家
2025-04-27 19:09:31     打赏
4楼

感谢分享


工程师
2025-05-09 16:21:49     打赏
5楼

注意一下文章排版非常乱


院士
2025-05-10 23:47:26     打赏
6楼

王哥 那时钟不匹配有啥解决思路吗?


专家
2025-05-11 15:32:29     打赏
7楼

时钟匹配的问题还没有解决,打算以后再用别家的单片机试试和时钟有关的处理,作对比学习。

现在在学习在STC的实验盒上使用“TLV320AIC23”芯片输出波形。刚好也可以测试时钟能否配合TLV320AIC23的设置输出正常波形。


高工
2025-05-11 17:48:10     打赏
8楼

这个 I2S的时钟最大是多少呢?时钟频率可以稳定在5.56MHZ,实际使用的时候会不会太快?


专家
2025-05-13 15:32:15     打赏
9楼

思路很清晰,感谢分享。


共9条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]