IIC驱动写数据异常

duoduozb 2010-07-06 04:08:24
ARM9 2440.
裸机下的IIC驱动已经调试成功,现在需要以linux字符型驱动的形式实现,按照逻辑下调通的逻辑,只是用了一些内核读写寄存器的函数。
写数据时,用示波器观察波形,观察到会重复发送某个数据,或者是SDA线上的数据不是我往IICDS中写的数据。每一个IIC通信周期的第九时钟SD线都为低,处理器收到ACK。
为什么会出现这种情况呢?大家帮我看看我的写代码:

regIICCON =ioremap(0x54000000,4);
regIICSTAT=ioremap(0x54000004,4);
regIICADD =ioremap(0x54000008,4);
regIICDS =ioremap(0x5400000c,4);

//设置GPE15->IICSDA和GPE14->IICSCL
s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_IICSDA);
s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_IICSCL);

i2c_clock= clk_get(NULL, "i2c");
if (!i2c_clock)
{
printk(KERN_ERR "failed to get i2c clock source\n");
return -ENOENT;
}
clk_enable(i2c_clock);

//Enable ACK, Prescaler IICCLK=PCLK/16, Enable interrupt, Transmit clock value Tx clock=IICCLK/16
iowrite8(0xaf,regIICCON);//250kHz

//写slave设备地址
iowrite8(SAD_W,regIICDS);
iowrite8(0xf0,regIICSTAT);
while(!(ioread8(regIICCON)&S3C2410_IICCON_IRQPEND));

//写slave设备寄存器地址
iowrite8(0x80|addr,regIICDS);
iowrite8(ioread8(regIICCON)&(~S3C2410_IICCON_IRQPEND),regIICCON);
while(!(ioread8(regIICCON)&S3C2410_IICCON_IRQPEND));

//写数据
iowrite8(0x03,regIICDS);
iowrite8(ioread8(regIICCON)&(~S3C2410_IICCON_IRQPEND),regIICCON);
while(!(ioread8(regIICCON)&S3C2410_IICCON_IRQPEND));

//完成一次写操作,发stop信号
iowrite8(0xd0,regIICSTAT);
iowrite8(ioread8(regIICCON)&(~S3C2410_IICCON_IRQPEND),regIICCON);
udelay(10);


...全文
213 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
InsaneCode 2010-07-09
  • 打赏
  • 举报
回复
没弄过linux,wince页面上很多人没弄过。帮你顶顶
duoduozb 2010-07-09
  • 打赏
  • 举报
回复
每次写数据时,裸机下,while(!(ioread8(regIICCON)&S3C2410_IICCON_IRQPEND));等待中断位置位只需要us级的时间;
在linux 驱动下,从发送数据到第一次中断位置位居然花了几秒钟。
何解?
duoduozb 2010-07-09
  • 打赏
  • 举报
回复
搞定了。
自己感觉LINUX内核自带的IIC驱动太复杂,想着编写一个简单的IIC驱动。

之前用示波器观察,发现很多异常,例如:
1)写入IICDS的数据不正确;
2)写入IICDS的数据被重复发2次或者3次;
3)SDA线上的观察到的数据并非写入IICDS中要发送的数据;
4)无法重复执行发送;
5)把clk相关的函数屏蔽掉,仍然有IIC时钟信号。

IIC跟我之前调过的SPI不同,SPI分有查询、中断、DMA等模式,而IIC只能通过中断模式进行,当发送或接收到一个字节的数据会产生中断,IICSTAT的INTPENDING位会置1,通过这一状态位来判断发或收的动作是否完成。

因此,尝试着去向内核注册IRQ_IIC,request_irq函数返回-16(返回0为正常),意为这个中断号已经被其他驱动注册了。
查看内核启动的打印信息:
s3c2440-i2c s3c2440-i2c: slave address 0x10
s3c2440-i2c s3c2440-i2c: bus frequency set to 400k Hz
s3c2440-i2c s3c2440-i2c: i2c-0: S3C I2C adapter

这些打印信息可以在/drivers/i2c/buses/i2c-s3c2410.c中找到,分别在:
L702 s3c24xx_i2c_init: L721- slave address, L732- bus frequency
L732 s3c24xx_i2c_probe: L844- S3C I2C adapter

说明我用的内核已将自己的I2C驱动加载了。
配置内核时将I2C support选为“N”,不让内核加载自己的I2C驱动。
之前遇到的异常不再出现,可以按照自己的逻辑驱动IIC接口。
由于只是用到IICSTAT的中断pending位来判断发送或接收是否完成,可以不用申请IRQ_IIC中断号,可以不编写中断处理函数。
duoduozb 2010-07-07
  • 打赏
  • 举报
回复
并且数据总是被多传了一次
duoduozb 2010-07-07
  • 打赏
  • 举报
回复
数据能够正确写入IICDS中了。
原因是,第一次写时IICSTAT的[4]位没有使能。手册中写道,When serial output enable = 1 in the IICSTAT, IICDS is write-enabled.
但是现在用示波器观察还是发现SDA线上的数据异常,并非我写入IICDS要发送的数据。
wjcapple 2010-07-07
  • 打赏
  • 举报
回复
Mark,顶起
duoduozb 2010-07-06
  • 打赏
  • 举报
回复
试了一下,第一次写IICDS时,数据好像不能正确写入IICDS。
例如,
iowrite8(0x72,regIICDS);//写入0x72
val=ioread8(regIICDS);//读出的IICDS中的值为0x16

但是,如果
iowrite8(SAD_W,regIICDS);
iowrite8(0xf0,regIICSTAT);
while(!(ioread8(regIICCON)&S3C2410_IICCON_IRQPEND));//先进行一次数据发送

iowrite8(0x80|addr,regIICDS);
val=ioread8(regIICDS);//读出的IICDS中的值为0x80|addr的值
iowrite8(ioread8(regIICCON)&(~S3C2410_IICCON_IRQPEND),regIICCON);
while(!(ioread8(regIICCON)&S3C2410_IICCON_IRQPEND));

iowrite8(0x03,regIICDS);
val=ioread8(regIICDS);//读出的IICDS中的值为0x03
iowrite8(ioread8(regIICCON)&(~S3C2410_IICCON_IRQPEND),regIICCON);
while(!(ioread8(regIICCON)&S3C2410_IICCON_IRQPEND));

问什么会出现这种情况呢?
弄不明白了

21,597

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 驱动开发/核心开发
社区管理员
  • 驱动开发/核心开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧