sunrain_hjb的BLOG
Develop Helpful and Effective apps to make Jobs easier and Better!

  前两天看了下一个名为TDA7541的收音机芯片,这两天又在看一个名为TDA7415的音效芯片。把这两个芯片放在一起说,有点拗口,很容易弄混。但越是容易弄混的东西,又越得放在一起说,否则会越搞不清楚谁是谁。

  这两个看起来有点像双胞胎的片子都出自ST,或许不是双胞胎,没准还有一个TDA7451在哪里。它们弟兄两个都提供SPI或IIC接口,实际应用中可配置成使用SPI或者IIC。它们内部都有一堆寄存器,用于配置各种工作状态。需要小心的是,它们的这堆寄存器是只能写,不能读的。在调试7541时就想当然的以为可读可写。于是先写一把,再读出来看看,是否写进去了,结果读出来的值纹丝不动,又想当然的以为是IIC通讯有问题。IC有问题。结果仔细查看文档,发现它的读取似乎就只会返回一个值而已。误会了人家IIC那两根线。另外跟这个TDA7541配合使用的一个E2PROM也需要注意,是只能读不能写的,一写就坏事了。实践出真知,凡事可不能再想当然了。

  简单说一下TDA7541的使用流程,MCU读取与之配套使用的EEPROM,将读出的数据写到TDA7541里,算作初始化。接下来根据具体的情况修改7541内部几个寄存器实现相应的功能。csdn里有它的实例代码,可以参考一下。

  TDA7415内部的寄存器比较少,共32个,实际只会使用0~23和31这25个。其中0~23是功能寄存器,31寄存器是用于测试的。调试这个片子,建议先从测试寄存器入手,在其内部写入0x3E,这样就可以在相应的引脚上测得一个200KHz的信号。如果顺利到这一步,基本可以放心了,IIC通讯没有问题,写寄存器没有问题。千万记住,不要想当然的通过读取寄存器的方法来确定IIC通讯是否有问题。接下来就是按照它的文档配置那24个寄存器。

  这24个寄存器上电会被POR成0xFE,很多unused的bit保持它原来的状态,不要去动它。把能改的都改好了,基本上就能出声了。刚开始配置这些寄存器有点摸着石头过河的感觉,还好有浦工、林工、还有晓峰的支持,基本上还算顺利的就搞出声来了。当然出声只是初级阶段,它还能做很多事。过了这条河就是阳关道了,大胆往前走吧。

  为了调试方便,做了一个小工具,通过它可以快速配置内部各寄存器,也能假模假式的读取当前那些寄存器的值,截图如下。

                     image 

  截图中显示的那32个值,是成功初始化后的值。配置成如此这般,大概就能出声了。

  调试这两个芯片总觉得不太顺,有点点7451的意思。问题在哪里?首先是犯了经验主义的错误。经验有时的确能帮助解决问题,但迷信经验,反而会走弯路,比没有那些经验还要弯。其次是犯了投机主义的错误。偷懒惯了,总以为还能继续偷懒下去。总想着有别人现成的东西,拿来就用好了。事实上,没那么多投机取巧的好事。最后还犯了教条主义的错误。他们说是,其实未必就是,说不是,也未必真的不是。尽信书尚不如无书,何况是流言飞语,怎能奉为教条?凡事得实事求是才是。否则他一会儿说是,一会儿说不是,那到底是还是不是呢,自己只能晕头转向了。

  吃一堑,长一智。吸取教训,总结经验。过而能改,善莫大焉。

  最后贴上相关代码,仅供需要的同志参考。

 1 HANDLE ghTDAI2C = INVALID_HANDLE_VALUE;
 2 BOOL OpenTDAI2C();
 3 BOOL CloseTDAI2C();
 4 BOOL TDAInit();
 5 BOOL TDAI2CWrite(BYTE iOffset,BYTE iCount,BYTE *pBuffer);
 6 BOOL TDAPseudoReadAllReg(BYTE *pBuffer);
 7 
 8 static BYTE TDA_REG_BUF_RESET[32= {
 9     0xFF,0x00,0x0E,0x3F,
10     0xBF,0x5E,0xFF,0xFF,
11     0xFF,0x3E,0x7D,0xDD,
12     0x00,0x10,0x10,0x10,
13     0x10,0x1E,0x10,0x10,
14     0x80,0x38,0x0E,0xF0,
15     0xFE,0xFE,0xFE,0xFE,
16     0xFE,0xFE,0xFE,0xFE
17 };
18 
19 static BYTE TDA_REG_BUF[32= {
20     0xFF,0x00,0x0E,0x3F,
21     0xBF,0x5E,0xFF,0xFF,
22     0xFF,0x3E,0x7D,0xDD,
23     0x00,0x10,0x10,0x10,
24     0x10,0x1E,0x10,0x10,
25     0x80,0x38,0x0E,0xF0,
26     0xFE,0xFE,0xFE,0xFE,
27     0xFE,0xFE,0xFE,0xFE
28 };
29 
30 BOOL OpenTDAI2C()
31 {
32     ghTDAI2C = CreateFile(_T("I2C1:"),GENERIC_READ | GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);
33     return (ghTDAI2C != INVALID_HANDLE_VALUE);
34 }
35 
36 BOOL CloseTDAI2C()
37 {
38     if (ghTDAI2C != INVALID_HANDLE_VALUE)
39     {
40         return CloseHandle(ghTDAI2C);
41     }
42     return FALSE;
43 }
44 
45 BOOL TDAInit()
46 {
47     return TDAI2CWrite(0x0,32,TDA_REG_BUF_RESET);
48 }
49 
50 BOOL TDAI2CWrite(BYTE iOffset,BYTE iCount,BYTE *pBuffer)
51 {
52     BOOL nRet=0;
53     DWORD returned_bytes;
54     I2C_Param sendParam;
55     BYTE *pWriteBuf;
56 
57     pWriteBuf = new BYTE[iCount+1];
58     pWriteBuf[0= iOffset;
59 
60     if (iCount > 1)
61     {
62         pWriteBuf[0+= 0x20;//超过一个字节需配置为连续写
63     }
64     
65     memcpy(pWriteBuf+1,pBuffer,iCount);
66 
67     sendParam.DeviceAddr = 0x8C;
68     sendParam.nWriteByte = iCount+1;
69     sendParam.pWriteBuffer = pWriteBuf;
70     sendParam.nPort = 0;
71     sendParam.nMode = 0;
72     sendParam.nTimeout     = 100;
73     
74     nRet = DeviceIoControl(ghTDAI2C,IOCTL_I2C_WRITE,&sendParam,sizeof(I2C_Param),0,0,&returned_bytes,0);
75     delete[] pWriteBuf;
76     if (nRet)
77     {
78         iOffset = iOffset & 0x1F;//有效地址位
79         memcpy(TDA_REG_BUF+iOffset,pBuffer,iCount);
80         return TRUE;
81     }
82     return FALSE;
83 }
84 
85 BOOL TDAPseudoReadAllReg(BYTE *pBuffer)
86 {
87     if (pBuffer)
88     {
89         memcpy(pBuffer,TDA_REG_BUF,32);
90         return TRUE;
91     }
92     else
93     {
94         return FALSE;
95     }
96 }
posted on 2010-02-06 21:26  sunrain_hjb  阅读(4975)  评论(2编辑  收藏  举报

Map