前两天看了下一个名为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保持它原来的状态,不要去动它。把能改的都改好了,基本上就能出声了。刚开始配置这些寄存器有点摸着石头过河的感觉,还好有浦工、林工、还有晓峰的支持,基本上还算顺利的就搞出声来了。当然出声只是初级阶段,它还能做很多事。过了这条河就是阳关道了,大胆往前走吧。
调试这两个芯片总觉得不太顺,有点点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
}