Prima I2C 程序设置与读写 CS42L52 的寄存器
Issue 1
日期:2011/8/19
目录
1 I2C 简介
I2C 有两线――串行数据 SDA 和串行时钟 SCL。Prima 默认支持三路 I2C 端口,分别是两路硬件(I2C1 和 I2C2)和一路软件(I2C5),两个 I2C 分别对应 SDA_0、SCL_0 (I2C1)和 SDA_1、SCL_1(I2C2),在 Prima 的主控上是选择 SDA_1 和 SCL_1(I2C2)(详细见电路图文档 sirfatlasiv typical mini application system V1.1.pdf)。
2 硬件端口读写设置
2.1 驱动部分设置
在这里我们是通过 I2C 程序读写 CS42L52 的寄存器,该从设备驱动部分需要在 codec 中修改。
Codec.cpp(c:\wince600\platform\common\src\soc\prima_sirf_v2\common\src\drivers\wavedev\cs42l52)
1. 打开 I2C2 端口
DWORD Codec_InitI2C()
{
if (h_codec == NULL)
{
if ((h_codec = I2COpen(CS42L52_I2C_PORT_NUMB)) == NULL)
{
RETAILMSG(ZONE_ERROR, (TEXT("Codec: I2COpen faild !!!\r\n")));
return FALSE;
}
}
return ERROR_SUCCESS;
}
由于选择的是 I2C2 端口,因此参数 CS42L52_I2C_PORT_NUMB 在codec.h 定义:
#define CS42L52_I2C_PORT_NUMB TEXT("I2C2:")
static BOOL I2C_Write(HANDLE pI2CHandle, ULONG ulRegAddr, PBYTE pRegValBuf, UINT uiValBufLen)
{
I2CTRANS Trans;
Trans.bRead = FALSE;—————————————————————————-(1)
Trans.dwRegAddr = ulRegAddr;
Trans.pValueBuf = pRegValBuf;
Trans.uiValueLen = uiValBufLen;
Trans.dwClock = CS42L52_I2C_FREQ;————————————————————(2)
Trans.i2cdevinfo.pReadSeq = NULL;————————————————————(3)
Trans.i2cdevinfo.uiReadSeqLen = 0;
Trans.i2cdevinfo.pWriteSeq = NULL;———————————————————-(3)
Trans.i2cdevinfo.uiWriteSeqLen = 0;
Trans.i2cdevinfo.ulDevAddrW = CS42L52_ADDR_W;——————————————(4)
Trans.i2cdevinfo.ulDevAddrR = CS42L52_ADDR_R;——————————————(4)
if (!I2CTransact(pI2CHandle, &Trans))
{
ERRORMSG(1, (TEXT("codec:I2C write failed\r\n")));
return FALSE;
}
return TRUE;
}
对以上标注说明如下:
(1) 当 I2C 端口是写(发送)时,设置成 FLASE,读(接收)时为 TRUE;
(2) 这个频率,在 codec.h 中按如下设置:
#define CS42L52_I2C_FREQ 50000 //50Khz
(3) 这里是设置读写时序,设置成 NULL 即选择默认时序,默认时序可以在 I2C 的驱动中看到,在这里 I2C 的默认读写时序如下:
static const BYTE g_pI2CDefaultWriteSeq[] =
{ I2C_SEQ_SEG_DEVADDR_W | SEG_MASK_SEND_START | SEG_MASK_NEED_ACK,
I2C_SEQ_SEG_REGADDR | SEG_MASK_NEED_ACK,
I2C_SEQ_SEG_DATA | SEG_MASK_SEND_STOP | SEG_MASK_NEED_ACK
};
static const BYTE g_pI2CDefaultReadSeq[] =
{ I2C_SEQ_SEG_DEVADDR_W | SEG_MASK_SEND_START | SEG_MASK_NEED_ACK,
I2C_SEQ_SEG_REGADDR | SEG_MASK_NEED_ACK,
I2C_SEQ_SEG_DEVADDR_R | SEG_MASK_SEND_START | SEG_MASK_NEED_ACK,
I2C_SEQ_SEG_DATA | SEG_MASK_NEED_NACK | SEG_MASK_SEND_STOP
};
(4) 在 codec.h 中,进行如下定义:
#define CS42L52_ADDR_R 0x95
#define CS42L52_ADDR_W 0x94
这是 8 位寄存器二进制值,前七位是对从机的寻址,第八位是读写控制,0 是写,1 是读,下图为文档 CS42L52_DNZR.pdf 中的时序截图。
3. 读设置
static BOOL I2C_Read(HANDLE pI2CHandle, ULONG ulRegAddr, PBYTE pRegValBuf, UINT uiValBufLen)
{
I2CTRANS Trans;
Trans.bRead = TRUE;
Trans.dwRegAddr = ulRegAddr;
Trans.pValueBuf = pRegValBuf;
Trans.uiValueLen = uiValBufLen;
Trans.dwClock = CS42L52_I2C_FREQ;
Trans.i2cdevinfo.pReadSeq = NULL;
Trans.i2cdevinfo.uiReadSeqLen = 0;
Trans.i2cdevinfo.pWriteSeq = NULL;
Trans.i2cdevinfo.uiWriteSeqLen = 0;
Trans.i2cdevinfo.ulDevAddrW = CS42L52_ADDR_W;
Trans.i2cdevinfo.ulDevAddrR = CS42L52_ADDR_R;
if (!I2CTransact(pI2CHandle, &Trans))
{
ERRORMSG(1, (TEXT("codec:I2C read failed\r\n")));
return FALSE;
}
return TRUE;
}
可以看出,与写设置不同的只有 Trans.bRead 的值。
2.2 配置文件设置
1. 批处理
在批处理文件 SiRFprima_EVB.BAT (c:\wince600\platform\tt4x0bd) 中,对三路端口设置如下:
IF "%BSP_ATLAS_I2C%" == "1" (
SET BSP_ATLAS_I2C1=1
SET BSP_ATLAS_I2C2=1
SET BSP_ATLAS_I2C5=
)
需要打开的是 I2C2,因此 BSP_ATLAS_I2C2 必须设成1。
2. Platform.bib
在文件 Platform.bib(c:\wince600\platform\tt4x0bd\files)中设置如下:
IF BSP_ATLAS_I2C
i2c.dll $(_FLATRELEASEDIR)\i2c.dll NK SHK
ENDIF
3. 注册表
在注册表文件 Platform.reg(c:\wince600\platform\tt4x0bd\files)中对 I2C1 和 I2C2 设置如下:
IF BSP_ATLAS_I2C1
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\I2C1]
"Prefix"="I2C"
"Dll"="I2C.dll"
"Index"=dword:1
"Order"=dword:0
;"IClass"="{A32942B7-920C-486b-B0E6-92A702A99B35}"
IF BSP_USE_HIVE
; @CESYSGEN IF FILESYS_FSREGHIVE
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\I2C1]
"Flags"=dword:1000 ; Don't put this when there is no hive. It will cause the driver unable to load in hive.
; @CESYSGEN ENDIF FILESYS_FSREGHIVE
ENDIF
ENDIF
IF BSP_ATLAS_I2C2
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\I2C2]
"Prefix"="I2C"
"Dll"="I2C.dll"
"Index"=dword:2
"Order"=dword:0
;"IClass"="{A32942B7-920C-486b-B0E6-92A702A99B35}"
IF BSP_USE_HIVE
; @CESYSGEN IF FILESYS_FSREGHIVE
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\I2C2]
"Flags"=dword:1000 ; Don't put this when there is no hive. It will cause the driver unable to load in hive.
; @CESYSGEN ENDIF FILESYS_FSREGHIVE
ENDIF
ENDIF
3 IO 口模拟 I2C 读写设置
3.1 说明
软件端口设置在硬件端口设置的基础上做以下修改。
3.2 驱动部分设置
1. 打开端口
需要在 Codec 驱动中打开端口 I2C5,参数 CS42L52_I2C_PORT_NUMB 在codec.h 中的定义如下:
#define CS42L52_I2C_PORT_NUMB TEXT("I2C5:")
2. 修改 I2C 驱动
I2C 的驱动修改是在以下文件中完成
BspI2cLib.c (c:\wince600\platform\tt4x0bd\src\drivers\i2c\i2csoftlib)
#ifdef __SOFT__I2C__0__
#define I2C_GPIO_GROUP 3
#define I2C_GPIO_INDEX_SDA 18
#define I2C_GPIO_INDEX_SCL 19
#else
#define I2C_GPIO_GROUP 0
#define I2C_GPIO_INDEX_SDA 3
#define I2C_GPIO_INDEX_SCL 2
#endif
SDA_1 和 GPIO0_3 复用一个引脚,SCL_1 和 GPIO0_2 复用一个引脚,因此对 __SOFT__I2C__0__ 不予以设置(为空),选择第二种设置。
软件 I2C 端口设置是通过 GPIO 口的拉高拉低来模拟 I2C,具体设置如下:
void BspI2cLibInit()
{
GPIO_PAD_EN_SET(GPIO_GROUP(I2C_GPIO_GROUP), GPIO_MASK(I2C_GPIO_INDEX_SDA));
GPIO_PAD_EN_SET(GPIO_GROUP(I2C_GPIO_GROUP), GPIO_MASK(I2C_GPIO_INDEX_SCL));
PIO_SET_PULL(GPIO, GPIO_GROUP(I2C_GPIO_GROUP), GPIO_INDEX(I2C_GPIO_INDEX_SDA));
PIO_SET_PULL(GPIO, GPIO_GROUP(I2C_GPIO_GROUP), GPIO_INDEX(I2C_GPIO_INDEX_SCL));
}
void BspI2cLibDataHigh()
{
PIO_OUTPUT_ONE(GPIO, GPIO_GROUP(I2C_GPIO_GROUP), GPIO_INDEX(I2C_GPIO_INDEX_SDA));
PIO_OUTPUT_ENABLE(GPIO, GPIO_GROUP(I2C_GPIO_GROUP), GPIO_INDEX(I2C_GPIO_INDEX_SDA));
}
void BspI2cLibDataLow()
{
PIO_OUTPUT_ZERO(GPIO, GPIO_GROUP(I2C_GPIO_GROUP), GPIO_INDEX(I2C_GPIO_INDEX_SDA));
PIO_OUTPUT_ENABLE(GPIO, GPIO_GROUP(I2C_GPIO_GROUP), GPIO_INDEX(I2C_GPIO_INDEX_SDA));
}
void BspI2cLibClockHigh()
{
PIO_OUTPUT_ONE(GPIO, GPIO_GROUP(I2C_GPIO_GROUP), GPIO_INDEX(I2C_GPIO_INDEX_SCL));
PIO_OUTPUT_ENABLE(GPIO, GPIO_GROUP(I2C_GPIO_GROUP), GPIO_INDEX(I2C_GPIO_INDEX_SCL));
}
void BspI2cLibClockLow()
{
PIO_OUTPUT_ZERO(GPIO, GPIO_GROUP(I2C_GPIO_GROUP), GPIO_INDEX(I2C_GPIO_INDEX_SCL));
PIO_OUTPUT_ENABLE(GPIO, GPIO_GROUP(I2C_GPIO_GROUP), GPIO_INDEX(I2C_GPIO_INDEX_SCL));
}
BOOL BspI2cLibGetData()
{
PIO_OUTPUT_DISABLE(GPIO, GPIO_GROUP(I2C_GPIO_GROUP), GPIO_INDEX(I2C_GPIO_INDEX_SDA));
usWait(i2cDelay);
return PIO_READ_INPUT(GPIO, GPIO_GROUP(I2C_GPIO_GROUP), GPIO_INDEX(I2C_GPIO_INDEX_SDA));
}
3.3 配置文件设置
1. 批处理
在批处理文件 SiRFprima_EVB.BAT (c:\wince600\platform\tt4x0bd) 中,需要如下设置。
IF "%BSP_ATLAS_I2C%" == "1" (
SET BSP_ATLAS_I2C1=
SET BSP_ATLAS_I2C2=
SET BSP_ATLAS_I2C5=1
)
需要打开的是 I2C5,因此 BSP_ATLAS_I2C5 必须设置成1,至于 BSP_ATLAS_I2C1 和 BSP_ATLAS_I2C2 没有要求。
2. 注册表
在注册表文件 Platform.reg(c:\wince600\platform\tt4x0bd\files)中对 I2C5 的设置如下:
;Software I2C port number up from 5.And you can own 3 software i2c at most.
IF BSP_ATLAS_I2C5
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\I2C5]
"Prefix"="I2C"
"Dll"="I2C.dll"
"Index"=dword:5
"Order"=dword:0
;"IClass"="{A32942B7-920C-486b-B0E6-92A702A99B35}"
IF BSP_USE_HIVE
; @CESYSGEN IF FILESYS_FSREGHIVE
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\I2C5]
"Flags"=dword:1000 ; Don't put this when there is no hive. It will cause the driver unable to load in hive.
; @CESYSGEN ENDIF FILESYS_FSREGHIVE
ENDIF
ENDIF
4 测试
4.1 硬件端口读写设置测试
1)为了测试 I2C 的程序读写 CS42L52 的寄存器是否成功,在 Codec.cpp 的 Codec_init 函数中添加一个死循环:
blch1=0x57;
while(1){
Codec_I2C_WriteReg(FALSE, POWER_CTRL2, (PUCHAR)&blch1, 1);
msWait(1000); // 延时函数可自己设置
Codec_I2C_ReadReg(FALSE, POWER_CTRL2, (PUCHAR)&blch, 1);
RETAILMSG(1, (TEXT("KKKKKKK------POWER_CTRL2--------------%2x\r\n"),blch));
}
启动机器,在终端中可看到该循环打印的信息
———KKKKKKK------POWER_CTRL2--------------57(与写入寄存器的值相同)。
2)用示波器观察可得以下波形(在图上有简单注解):
4.2 IO 口模拟 I2C 读写设置测试
1)在终端同样可以看到死循环的打印信息。
2)示波器观察得到的波形如下: