S3C2440-IIS放音
时间:03-28
来源:互联网
点击:
S3C2440A的Inter-IC Sound(IIS)总线接口作为一个编解码接口连接外部8/16位立体声音频解码IC用于迷你碟机和可携式应用。IIS总线接口支持IIS总线数据格式和MSB-justified数据格式。该接口对FIFO的访问采用了DMA模式取代了中断。它可以在同一时间接受和发送数据。S3C2440一共有5个引脚用于IIS:IISDO,IISDI,IISSCLK,IISLRCK和CDCLK。前两个信号用于数字音频信号的输入输出,另外3个引脚都与音频信号的频率有关,可见要用好IIS,就要把信号频率设置正确。IISSCLK为串行时钟,每一个时钟信号传送一位音频信号,因此IISSCLK的频率=声道数*采样频率*采样位数,如采样频率为44.1kHz,采样的位数为16位,声道数2个(左,右两个声道),则IISSCLK的频率=32fs=1411.2kHz。IISLRCK为帧时钟,用于切换左右声道,如IISLRCK为高电平表示正在传输的是左声道数据,为低表示传输的是右声道数据。因此IISLRCK的频率应该正好等于采样频率。由于IIS只负责数字音频信号的传输,而要真正实现音频信号的放录还需要额外的处理芯片(在这里我们使用UDA1341),CDCLK为该芯片提供系统同步时钟,即编解码时钟,主要用于音频的A/D,D/A采样时的采样时钟,一般CDCLK为256fs或384fs。UDA1341使用L3接口,通过L3接口可以实现UDA1341和S3C2440控制信息的传递。L3指3根线,L3DATA(数据线,用于传输数据),L3MODE(模式线,用于选择模式),L3CLOCK(时钟线,用于传输时钟)。先传输地址模式数据,再传输数据模式数据。L3MODE为低时是地址模式,L3MODE为高时是数据传输模式。L3DATA和L3CLOCK相互作用,完成8位数据的传输,传输的顺序是先低位数据,再高位数据。地址模式用于选择设备和定义目标寄存器,在这种模式下,8位数据的含义是:高6位是设备地址(UDA1341的地址为000101),低两位是后面数据模式的类型(00:DATA0,01:DATA1,10:STATUS)。
下面这个程序完成从WAV音频文件中提取出数组。
#include <stdio.h>
#include<stdlib.h>
#include <string.h>
#include <memory.h>
int main(){
FILE *stream, *fp;
unsigned char *music;
char ch[5];
int start, end, num, t, i, j, r;
if(((stream = fopen("D:\\music.wav","rb")) == NULL) || ((fp = fopen("D:\\music.h","wb+")) == NULL)){
printf("%s","cannot open output file.\n");
return 1;
}
fseek(stream,0,SEEK_SET);
start = ftell(stream); //获得文件的起始地址
fseek(stream,0,SEEK_END);
end = ftell(stream); //获得文件的结束地址
fseek(stream,0,SEEK_SET);
music = (unsigned char *)malloc(end-start); //动态分配一个buffer
fwrite("unsigned char music[",1,20,fp);
fwrite("]={",1,3,fp);
fwrite("\n", 2, 1, fp);
num = (end - start - 0x2c) / 16; //m每行16个
t = (end - start - 0x2c) % 16;
fread(music, 1, end - start, stream);
for(i = 0; i < num; i++){
for(j = 0; j < 16; j++){
memset(ch,0,5);
r = (int)music[i*16+j+0x2c]; //从0x2c开始是音频数据
r &= 0xff;
sprintf(ch,"0x%02x",r); //先转化成一定格式
fwrite(ch,sizeof(ch),1,fp);
fwrite(",",1,1,fp);
}
fwrite("\n",1,2,fp);
}
for(i = 0; i < t; i++){
memset(ch,0,5);
r = (int)music[i*16+j+0x2c];
r &= 0xff;
sprintf(ch,"0x%02x",r);
fwrite(ch,sizeof(ch),1,fp);
if(i != t-1)
fwrite(",",1,1,fp);
}
fwrite("};",1,2,fp);
fclose(stream);
fclose(fp);
system("pause");
return 0;
}
完成音频文件的播放。IISFIFO为16位宽,深度为32。将音频数组中的数据装入IISFIFO,装满后IIS读取IISFIFO中的数据,即放音,然后再将音频数组中的数据读入IISFIFO,周而复始,完成放音。
#include "2440addr.h"
#include "music.h"
#define L3MODE 1<<2
#define L3DATA 1<<3
#define L3CLOCK 1<<4
void WriteL3(unsigned char data, unsigned int mode){
//mode = 0,地址模式;mode = 1,数据传输模式
int i, k;
if(mode == 0){
rGPBDAT = rGPBDAT & "(L3MODE|L3DATA|L3CLOCK )|L3CLOCK;
}
else{
rGPBDAT = rGPBDAT & "(L3MODE|L3DATA|L3CLOCK)|(L3CLOCK|L3MODE);
}
for(k = 0; k < 5; k++)
;
for(i = 0; i < 8; i++){
if(data & 0x1){
rGPBDAT &= "L3CLOCK;
rGPBDAT |= L3DATA;
for(k = 0; k < 5; k++)
;
rGPBDAT |= L3CLOCK;
rGPBDAT |= L3DATA;
for(k = 0; k < 5; k++)
;
}
else{
rGPBDAT &= "L3CLOCK;
rGPBDAT &= "L3DATA;
for(k = 0; k < 5; k++)
;
rGPBDAT |= L3CLOCK;
rGPBDAT &= "L3DATA;
for(k = 0; k < 5; k++)
;
}
data >>= 1;
}
rGPBDAT = rGPBDAT & "(L3MODE|L3DATA|L3CLOCK)|(L3CLOCK|L3MODE);
}
void PlayMusic(unsigned char buffer[], unsigned int length){
int i, fifo;
//UDA1341
//STATUS模式
rGPBDAT = rGPBDAT & "(L3MODE|L3DATA|L3CLOCK)|(L3CLOCK|L3MODE);
WriteL3(0x14+2,0);
//复位
WriteL3(0x60,1);
WriteL3(0x14+2,0);
//00010000 系统时钟频率384fs
WriteL3(0x10,1);
WriteL3(0x14+2,0);
//11000001 输出增益,ADC关,DAC开
WriteL3(0xc1,1);
//IIS
//DMA禁止,在接受空闲状态,不产生IISLRCK信号,IIS预分频使能
rIISCON = (0<<5)|(0<<4)|(0<<3)|(1<<2)|(1<<1);
//主设备时钟PCLK,主设备模式,发送模式,串行数据16位,主时钟是384fs,串行位时钟32fs
rIISMOD = (0<<9)|(0<<8)|(2<<6)|(0<<5)|(0<<4)|(1<<3)|(1<<2)|(1<<0);
//预分频都是N=3
rIISPSR = (3<<5)|3;
//发送FIFO正常,发送FIFO使能
rIISFCON = (0<<15)|(1<<13);
//IIS start
rIISCON |= 0x1;
for(fifo = 0; fifo <= length; fifo += 64){
while(rIISCON &(1<<7));
for(i = 0; i < 32; i++)
rIISFIFO = (buffer[i*2+fifo]) + (buffer[i*2+1+fifo]<<8);
}
//IIS close
rIISCON = 0x0;
}
int Main(){
rGPBUP = rGPBUP & "(0x7<<2) | (0x7<<2); //The pull up function is disabled GPB[4:2] 1 1100
rGPBCON = rGPBCON & "(0x3f<<4) | (0x15<<4); //GPB[4:2]=Output(L3CLOCK):Output(L3DATA):Output(L3MODE)
rGPBDAT = 0x1ec;
rGPEUP = rGPEUP & "(0x1f) | 0x1f; //The pull up function is disabled GPE[4:0] 1 1111
rGPECON = rGPECON & "(0x3ff) | 0x2aa; //GPE[4:0]=I2SSDO:I2SSDI:CDCLK:I2SSCLK:I2SLRCK
rMPLLCON = (150<<12)|(5<<4)|(0<<0);
PlayMusic(music, sizeof(music));
while(1);
return 0;
}
作者:李万鹏
下面这个程序完成从WAV音频文件中提取出数组。
#include <stdio.h>
#include<stdlib.h>
#include <string.h>
#include <memory.h>
int main(){
FILE *stream, *fp;
unsigned char *music;
char ch[5];
int start, end, num, t, i, j, r;
if(((stream = fopen("D:\\music.wav","rb")) == NULL) || ((fp = fopen("D:\\music.h","wb+")) == NULL)){
printf("%s","cannot open output file.\n");
return 1;
}
fseek(stream,0,SEEK_SET);
start = ftell(stream); //获得文件的起始地址
fseek(stream,0,SEEK_END);
end = ftell(stream); //获得文件的结束地址
fseek(stream,0,SEEK_SET);
music = (unsigned char *)malloc(end-start); //动态分配一个buffer
fwrite("unsigned char music[",1,20,fp);
fwrite("]={",1,3,fp);
fwrite("\n", 2, 1, fp);
num = (end - start - 0x2c) / 16; //m每行16个
t = (end - start - 0x2c) % 16;
fread(music, 1, end - start, stream);
for(i = 0; i < num; i++){
for(j = 0; j < 16; j++){
memset(ch,0,5);
r = (int)music[i*16+j+0x2c]; //从0x2c开始是音频数据
r &= 0xff;
sprintf(ch,"0x%02x",r); //先转化成一定格式
fwrite(ch,sizeof(ch),1,fp);
fwrite(",",1,1,fp);
}
fwrite("\n",1,2,fp);
}
for(i = 0; i < t; i++){
memset(ch,0,5);
r = (int)music[i*16+j+0x2c];
r &= 0xff;
sprintf(ch,"0x%02x",r);
fwrite(ch,sizeof(ch),1,fp);
if(i != t-1)
fwrite(",",1,1,fp);
}
fwrite("};",1,2,fp);
fclose(stream);
fclose(fp);
system("pause");
return 0;
}
完成音频文件的播放。IISFIFO为16位宽,深度为32。将音频数组中的数据装入IISFIFO,装满后IIS读取IISFIFO中的数据,即放音,然后再将音频数组中的数据读入IISFIFO,周而复始,完成放音。
#include "2440addr.h"
#include "music.h"
#define L3MODE 1<<2
#define L3DATA 1<<3
#define L3CLOCK 1<<4
void WriteL3(unsigned char data, unsigned int mode){
//mode = 0,地址模式;mode = 1,数据传输模式
int i, k;
if(mode == 0){
rGPBDAT = rGPBDAT & "(L3MODE|L3DATA|L3CLOCK )|L3CLOCK;
}
else{
rGPBDAT = rGPBDAT & "(L3MODE|L3DATA|L3CLOCK)|(L3CLOCK|L3MODE);
}
for(k = 0; k < 5; k++)
;
for(i = 0; i < 8; i++){
if(data & 0x1){
rGPBDAT &= "L3CLOCK;
rGPBDAT |= L3DATA;
for(k = 0; k < 5; k++)
;
rGPBDAT |= L3CLOCK;
rGPBDAT |= L3DATA;
for(k = 0; k < 5; k++)
;
}
else{
rGPBDAT &= "L3CLOCK;
rGPBDAT &= "L3DATA;
for(k = 0; k < 5; k++)
;
rGPBDAT |= L3CLOCK;
rGPBDAT &= "L3DATA;
for(k = 0; k < 5; k++)
;
}
data >>= 1;
}
rGPBDAT = rGPBDAT & "(L3MODE|L3DATA|L3CLOCK)|(L3CLOCK|L3MODE);
}
void PlayMusic(unsigned char buffer[], unsigned int length){
int i, fifo;
//UDA1341
//STATUS模式
rGPBDAT = rGPBDAT & "(L3MODE|L3DATA|L3CLOCK)|(L3CLOCK|L3MODE);
WriteL3(0x14+2,0);
//复位
WriteL3(0x60,1);
WriteL3(0x14+2,0);
//00010000 系统时钟频率384fs
WriteL3(0x10,1);
WriteL3(0x14+2,0);
//11000001 输出增益,ADC关,DAC开
WriteL3(0xc1,1);
//IIS
//DMA禁止,在接受空闲状态,不产生IISLRCK信号,IIS预分频使能
rIISCON = (0<<5)|(0<<4)|(0<<3)|(1<<2)|(1<<1);
//主设备时钟PCLK,主设备模式,发送模式,串行数据16位,主时钟是384fs,串行位时钟32fs
rIISMOD = (0<<9)|(0<<8)|(2<<6)|(0<<5)|(0<<4)|(1<<3)|(1<<2)|(1<<0);
//预分频都是N=3
rIISPSR = (3<<5)|3;
//发送FIFO正常,发送FIFO使能
rIISFCON = (0<<15)|(1<<13);
//IIS start
rIISCON |= 0x1;
for(fifo = 0; fifo <= length; fifo += 64){
while(rIISCON &(1<<7));
for(i = 0; i < 32; i++)
rIISFIFO = (buffer[i*2+fifo]) + (buffer[i*2+1+fifo]<<8);
}
//IIS close
rIISCON = 0x0;
}
int Main(){
rGPBUP = rGPBUP & "(0x7<<2) | (0x7<<2); //The pull up function is disabled GPB[4:2] 1 1100
rGPBCON = rGPBCON & "(0x3f<<4) | (0x15<<4); //GPB[4:2]=Output(L3CLOCK):Output(L3DATA):Output(L3MODE)
rGPBDAT = 0x1ec;
rGPEUP = rGPEUP & "(0x1f) | 0x1f; //The pull up function is disabled GPE[4:0] 1 1111
rGPECON = rGPECON & "(0x3ff) | 0x2aa; //GPE[4:0]=I2SSDO:I2SSDI:CDCLK:I2SSCLK:I2SLRCK
rMPLLCON = (150<<12)|(5<<4)|(0<<0);
PlayMusic(music, sizeof(music));
while(1);
return 0;
}
作者:李万鹏
- 基于MSP430系列单片机的CAN总线接口转换卡设计(01-17)
- 各种通讯总线介绍(01-18)
- I2C总线原理及应用实例 (01-18)
- I2C总线在多机通信中的应用(01-17)
- 基于SPI总线的电能计量芯片ATT7022及其在配电监测终端的应用(01-18)
- CAN总线—PROFIBUS-DP总线网关的实现方法(01-17)