背景:采用RT5350开发板做做主控器,配合声音采集模块实现声音采集,混声,组网传输等功能的系统。已有了声音采集模I2C配置程序(stm32),I2S配置程序(有问题)。
RT5350##
rt5350其实就是一个路由器,上面加在的是一个Linux内核的小系统,外置的接口有UART、SPI、I2C、I2S等可用于Linux开发,本次系统需要用到的只是I2C、I2S两部分,另外下载调试还需要用到ttyS1串口与LAN或WAN接口。具体信息请参考文档YG -WIFI-132开发版说明
首先要阅读文档资料,其中重要的是前三部分SDK开发指南,应仔细阅读,会了解到Uboot的编译、内核配置/编译、以及下载文件到自己的板子上等具体操作。
- 使用到的开发环境是厂商提供好的虚拟机镜像Fedora6+4.12,里面有配置好的开发环境;
- tftp下载文件到开发板
- 超级终端打印log和发送控制命令
然后按照文档中的方法编译烧写内核,原封不动的编译烧写后发现上电后搜索不到路由器的无线网信号,后来我先选取Save Configuration to an Alternate File然后再按照文档中的配置,编译烧写上电后找到了信号。缺省的AP为RT5350_AP。
I2C##
配置GPIO为I2C模式###
在文档资料中的第九部分提到GPIO的配置说明,但是里面只是提到GPIO7~GPIO14。根据 datasheet中 1.3 PinSharing Scheme中提到I2C是GPIO1和GPIO2,所以如何配置还需从Datasheet中找。在内核配置->Devices Driver->Character devices下我们看到有一个Ralink RT2880 I2C Support很显然这是一个厂商提供的I2C设备例程,当然这也是我们最终参考的程序。
在主函数i2cdrv_init中有一行代码,就是将GPIO配制成I2C模式
/* configure i2c to normal mode */
RT2880_RGE (RALINK_SYSCTL_BASE + 0x60) &= ~1;
在Datasheet中3.4 System Control中找到GPIO Purpose Select中提到该寄存器b[1]=1为I2C模式,b[1]=0则为GPIO模式。
开发板I2C控制器初始化###
这部分代码在i2c_drv.c
void i2c_master_init (void)
Ps:这部分代码主要是参考Datasheet中的 3.10 I2C Controller,通过寄存器的配置实现基本的参数设置和收发数据得实现,而非调用Linux系统的i2c控制器驱动,应该仔细阅读!!!
只修改设备地址i2cdrv_addr即可
unsigned long i2cdrv_addr = FM34_ADDR;
#define FM34_ADDR (0xC0>>1)
i2c_write###
根据俊哥的程序,需要这个函数完成一个连续8byte的连续写入,结合Datesheet和i2c_drv.c的写函数修改如下
int i2c_write(u8* data,u8 len)
{
int i,j;
RT2880_REG(RT2880_I2C_BYTECNT_REG) = len-1;
RT2880_REG(RT2880_I2C_DATAOUT_REG) = data[0];
RT2880_REG(RT2880_I2C_STARTXFR_REG) = WRITE_CMD;
for(i=1;i<len;i++)
{
// printk("%d ",i);
udelay(170);
j = 0;
do{
if(IS_SDOEMPTY){
RT2880_REG(RT2880_I2C_DATAOUT_REG) = data[i];
}
break;
}while (++j<max_ee_busy_loop);
}
i = 0;
while(IS_BUSY && i<i2c_busy_loop){
i++;
}
return true;
}
在调试过程中有很多问题需要注意:
- 调试工具可以使用建议逻辑分析仪看I2C输出。可以看到是否有数据写出,根据协议首先写出的是设备地址,查看是否有应答信号,有应答信号再继续。工具为SALEAE
- 在调试过程中要注意延时,谨慎使用
printk
函数 因为该函数会造成延时,导致输出结果不可预测。开始没有正确数据出来,加上printk ("%d",i);
后可以看到数据正常传出但是从第二个开始就有一小段延时,没法解释,后来才是知道就是打印字符的时间。 - 结合逻辑分析仪软件读出一个字节数据传出需要150ms的时间,于是加入延时
udelay (170);
后数据连续传出很漂亮。
写设备控制命令串###
unsigned char fm_WriteMem(unsigned char AdrHi,unsigned char AdrLo,unsigned char DataHi,unsigned char DataLo)
{
unsigned char wBuf[7];
wBuf[0] = 0xfc;
wBuf[1] = 0xf3;
wBuf[2] = 0x3b;
wBuf[3] = AdrHi;
wBuf[4] = AdrLo;
wBuf[5] = DataHi;
wBuf[6] = DataLo;
return i2c_write(wBuf,7);
}
设备命令字符串的结构在FM34-500B Datasheet V1.4的2.6 SHI (Serial Host Interface)中有详细的解释与说明。
读设备控制命令###
unsigned int fm_ReadMem(unsigned char AdrHi,unsigned char AdrLo,int* data)
{
unsigned char hi_byte,low_byte;
unsigned char write_buf[5];
write_buf[0] = 0xfc;
write_buf[1] = 0xf3;
write_buf[2] = 0x37;
write_buf[3] = AdrHi;
write_buf[4] = AdrLo;
if(!i2c_write(write_buf,5))
{
return false;
}
if(i2c_write(read_buf1,4))
{
i2c_read(&hi_byte,1);
}
if(i2c_write(read_buf2,4))
{
i2c_read(&low_byte,1);
}
*data = ((unsigned int)hi_byte<<8)+(unsigned int)low_byte;
return true;
}
实现流程在FM34-500B Datasheet V1.4中由详尽说明。
测试函数###
static int test(void)
{
int data = 0xffff;
printk("i2c_master_init\n");
i2c_master_init();
fm_WriteMem(0x23,0x6f,0xab,0xcd);
fm_ReadMem(0x23,0x6f,&data);
printk("the 0x236f result is :%d \r\n",data);
fm_WriteMem(0x23,0x6f,0x0b,0x05);
fm_ReadMem(0x23,0x6f,&data);
printk("result is :%d\r\n",data);
}
测试写函数与读函数是否可行。
设备初始化函数###
int fm_int(void)
{
int i;
int data = 0xffff;
printk("init fm34\r\n");
mdelay(1000);
printk("i2c_master_init\n");
i2c_master_init();
for(i = 0; i<37;i++)
{
while(!fm_WriteMem(*(*(init_farameter2+i)+0),*(*(init_farameter2+i)+1),*(*(init_farameter2+i)+2),*(*(init_farameter2+i)+3)));
}
mdelay(10);
for(i = 37; i<75;i++)
{
while(!fm_WriteMem(*(*(init_farameter2+i)+0),*(*(init_farameter2+i)+1),*(*(init_farameter2+i)+2),*(*(init_farameter2+i)+3)));
}
mdelay(10);
while(!fm_WriteMem(0x22,0xfb,0x00,0x00));
mdelay(10);
while(data != 0x5a5a)
{
while(!fm_ReadMem(0x22, 0xfb , &data))//(0x8000: before parameter configure, 0x0 means finish configure, 0x5A5A means DSP running)
{
mdelay(20);
}
printk("the 0x22fb result is : %d \r\n",data);
}
}
这个过程是初始化I2C设备的全过程,所有的命令串写在数组unsigned char init_farameter2
中,一次完成所有寄存器配置后,发送开始配置命令并等待设备响应,会返回0x5a5a
注意:
- 由于控制命令串有75条在发送过程中会出错,所以我试着将它分为两次发送;
- 即便是这样还是总是不能通过,于是在每一次读写操作前加上了一个小延时
mdelay(10);
得以解决; - 函数设计缺陷,在没有得到正确应答的情况下会无限响应下去,只能重启。
后记###
到此FM34配置工作的已结束,下一步要看I2S的驱动。
调试方法还是编译模块fm_drv.ko,通过insmod命令加载测试。
网友评论