VxWorks开发板驱动程序学习之IIC
来源:互联网 发布:cpu温度检测软件知乎 编辑:程序博客网 时间:2024/04/30 12:25
手上的一块S3C2410的开发板搭载VxWorks 5.5操作系统,今天开始继续学习BSP源码和驱动程序,争取在硕士毕业前能自己实现BSP的配置。
- IIC接口
- IIC总线的状态及信号
- IIC总线数据传输格式
- S3C2410 IIC接口
- S3C2410 IIC串行总线编程
- S3C2410 IIC 驱动程序
- 验证结果
IIC接口
这里简单复习一下IIC接口的相关知识。
IIC/I2C(Inter-Integrated Circuit)总线由Philips公司针对MCU需要研制的二线式串行总线,用于MCU及外围设备通信。
IIC总线主要特点:
- IIC总线长度可高达7.6m,并能够以100kb/s的最大传输速率支持40个组件。
- IIC总线支持多主控。主控能控制信息传输和时钟频率。任一时刻只有一个主控。
IIC总线要求:
- 各个设备必须共地
- 两根信号线必须接上拉电阻
多IIC设备接口示意图:
IIC总线的状态及信号
由于上拉电阻的存在,SCL和SDA在总线处于空闲状态均为高电平。
主控器想使用总线就应当先拉低SCL,控制总线,传送完成后应当释放总线。
启动信号:SCL为高,SDA上产生下降沿
结束信号:SCL为高,SDA上产生上升沿
应答/响应信号(A/NA) — 数据接收者接收到1字节后,应当主动向数据发出者发送一个应答信号。对应SCL的第9个应答时钟脉冲,SDA为低表示应答,继续发送;SDA为高表示非应答,结束发送。
地址信号(寻址字节) —
其中,(DA3-DA0)为器件的固有地址编码,由器件生产厂家给定;(A2、A1、A0)为器件地址引脚电平,高为1,接地为0;读写控制位(R/nW),为1表示主机读,为0表示主机写。
等待状态: 从机接收完一个数据字节后,可以拉低SCL使总线系统进入等待状态;当从机完成数据处理后,再释放SCL线,主机方可继续发送数据。
IIC总线数据传输格式
- 一般格式
- 主控制器写操作格式
- 主控制器读操作格式
- 主控制器读/写操作格式
好了,IIC总线接口相关知识就复习到此,现在来看看S3C2410的IIC接口
S3C2410 IIC接口
先来看看S3C2410下的IIC串行总线控制器框图:
S3C2410的端口E的GPE15用作数据线SDA,GPE14用作连续时钟线SCL。使用时要记得外部加上拉电阻。
发送数据写入到 IICDS
接收数据从IICDS读取
S3C2410的4个IIC专用寄存器:
IICSTAT的常用控制字:
- 启动主设备发送的控制字为 0xF0 (Tx)
- 结束主设备发送的控制字为 0xD0 (Tx)
- 启动主设备接收的控制字为 0xB0 (Rx)
- 结束主设备接收的控制字为 0x90 (Rx)
IICADD 地址寄存器仅对从设备有意义。
S3C2410 IIC串行总线编程
直接看图吧:
IIC主发送模式流程
IIC主接收模式流程
S3C2410 IIC 驱动程序
/* 文件模块说明: * 2410Iic.c S3C2410内部驱动,初始化驱动器,外部EERPROM采用 * ATMEL AT24C128-128kbit * 文件版本: * 开发人员: * 创建时间: * Copyright(c) t0 - t1 CompanyName Limited Co. */
#include "intLib.h" #include "2410addr.h" // 寄存器地址宏头文件 // 24C128IIC总线定义 #define CN_IIC_VOLUME (0x4000) // IIC容量,16KB #define AT24128256_w (0xa0 ) // 写地址:原理图中 A2A1A0 均接地 #define AT24128256_r (0xa1 ) // 读地址 #define IIC_mode_mask (0x3f ) #define IIC_mtx (0xc0 ) // 主机发送模式 #define IIC_mrx (0x80 ) // 主机接收模式 #define pagelength ( 64 )
//------------------------------------------------------------------------------ // 初始化IIC程序 void IIC_init(void) { UINT32 dwValReg; // GPE14 ~ GPE15为IIC接口 // GPECON[31:28] = 0b 1010 = 配置GPE14为IICSCL, GPE15为IICSDA SNGS3C_REG_READ( rGPECON, dwValReg ); dwValReg = (dwValReg & 0xAFFFFFFF); dwValReg = (dwValReg | 0xA0000000); SNGS3C_REG_WRITE( rGPECON, dwValReg ); // IICCON[7] ENABLE // IICCON[6] Tx Clock Source, 0 = IICCLK = fPCLK / 16; 1 = IICCLK = fPCLK / 512 // IICCON[5] Interrupt Enable // 50Mhz/16/(9+1) = 312.5Khz // AT24C128 在 3.3V 时的最大工作频率为 400KHz *(volatile UINT32 *)rIICCON=(1<<7)|(0<<6)|(1<<5)|9; // = 0xa9 *(volatile UINT32 *)rIICSTAT=0xd0; // 状态控制字:0xd0 结束主设备发送 *(volatile UINT32 *)rIICADD=0x00; // 器件地址 0x00 }
// 函数名称:IIC_WaitBus // 函数功能:等待IIC总线操作结束 // 返回值: 若操作等待超时返回 false; 正确则返回 true char IIC_WaitBus(void) { UINT i=0; // IICCON[4] - Interrupt is depending while( !( (*(volatile UINT32*)rIICCON) & 0x10 ) ) // no interruption { i++; if(i > 1000) // 超时 return (FALSE); } return (TRUE); // 还未超时就有中断产生 }
// 函数名称:IIC_WaitAck // 函数功能:等待IIC总线应答信号 // 返回值: 若操作等待超时或得不到应答信号,返回 false; 正确则返回 true // 说明: 先等待操作结束信号,然后判断是否有应答信号 char IIC_WaitAck(void) { UINT i=0; while( !( (*(volatile UINT32*)rIICCON) & 0x10) ) // 查询中断信号 { i++; if(i>1000) return (FALSE); } if( (*(volatile UINT32*)rIICSTAT) & 0x1 ) // ACK was not received return (FALSE); return (TRUE); }
// 函数名称:IIC_WaitEnd // 函数功能:等待写操作结束 // 返回值: char IIC_WaitEnd(void) { int i, k; // 尝试100次写地址并等待应答,只要收到一次即认为写操作成功,否则写操作失败 for(i=0; i<100; i++) { *(volatile UINT32*) rIICDS = AT24128256_w; // IIC器件AT24C128写地址 for(k=0; k<100; k++) ; // 延时 *(volatile UINT32*) rIICCON = (1<<7)|(0<<6)|(1<<5)|9; *(volatile UINT32*) rIICSTAT = 0xf0; // 0XF0 启动发送状态字 k = 0; if(TRUE == IIC_WaitAck()) return (TRUE); } return (FALSE); }
// 函数名称:IIC_Read // 函数功能:读芯片 // 返回值: 0 读成功; 1 读失败 // 读24C128 UINT32 IIC_Read(UINT32 start, char * buf, UINT length) { int i, iicbusy, k; // 读出起始地址+数据长度大于芯片容量(字节)则退出 if( (start+length) > CN_IIC_VOLUME ) return; iicbusy = IIC_WaitEnd(); // 等待写操作结束 for(k=0; k<100; k++) ; *(volatile UINT32*) rIICDS = (UINT8) (start/256); // 地址高字节 for(k=0; k<100; k++) ; *(volatile UINT32*) rIICCON = (1<<7)|(0<<6)|(1<<5)|9; if(FALSE == IIC_WaitAck()) return 1; *(volatile UINT32*) rIICDS = (UINT8) (start%256); // 地址低字节 for(k=0; k<100; k++) ; *(volatile UINT32*) rIICCON = (1<<7)|(0<<6)|(1<<5)|9; if(FALSE == IIC_WaitAck()) return 1; *(volatile UINT32*) rIICSTAT = 0xb0; // 状态控制字: 0XB0 启动主设备接收 *(volatile UINT32*) rIICDS = AT24128256_r; // IIC器件AT24C128读地址 *(volatile UINT32*) rIICCON = (1<<7)|(0<<6)|(1<<5)|9; // = 0xa9 if(FALSE == IIC_WaitAck()) return 1; for(i=0; i<length; i++) { if(i == length - 1) { *(volatile UINT32*) rIICCON = 0xa9; // (1<<7)|(0<<6)|(1<<5)|9 *(volatile UINT32*) rIICCON = 0x29; // 禁止应答 } else { *(volatile UINT32) rIICCON = 0xa9; } if(FALSE == IIC_WaitBus()) // 等待总线操作结束 return ; buf[i] = *(volatile UINT32*) rIICDS; } *(volatile UINT32*) rIICSTAT = 0x90; // 状态控制字: 0x90 停止主设备接收 for(k=0; k<100; k++) ; *(volatile UINT32*) rIICCON = 0xa9; // (1<<7)|(0<<6)|(1<<5)|9 return 0; }
// 函数名称:IIC_Write // 函数功能:写芯片 // 返回值: 0 读成功; 1 读失败 // 写24C128 UINT32 IIC_Write(UINT32 start, char * buf, UINT length) { int i, j, iicbusy, k, addr = start; // 写入地址大于芯片容量(字节)则退出 if( (addr+length) > CN_IIC_VOLUME ) return; iicbusy = IIC_WaitEnd(); // 等待写操作结束 *(volatile UINT32*) rIICDS = (UINT8) (addr/256); // 地址高字节 for(k=0; k<100; k++) ; *(volatile UINT32*) rIICCON = (1<<7)|(0<<6)|(1<<5)|9; if(FALSE == IIC_WaitAck()) return 1; *(volatile UINT32*) rIICDS = (UINT8) (addr%256); // 地址低字节 for(k=0; k<100; k++) ; *(volatile UINT32*) rIICCON = (1<<7)|(0<<6)|(1<<5)|9; if(FALSE == IIC_WaitAck()) return 1; j = FALSE; for(i=0; i<length; i++) { if(j) { j = FALSE; iicbusy = IIC_WaitEnd(); // 等待写操作结束 for(k=0; k<100; k++) ; *(volatile UINT32*) rIICDS = (UINT8) ((addr+i)/256); // 地址高字节 for(k=0; k<100; k++) ; *(volatile UINT32*) rIICCON = (1<<7)|(0<<6)|(1<<5)|9; if(FALSE == IIC_WaitAck()) return 1; *(volatile UINT32*) rIICDS = (UINT8) (addr+i); // 地址低字节 for(k=0; k<100; k++) ; *(volatile UINT32*) rIICCON = (1<<7)|(0<<6)|(1<<5)|9; if(FALSE == IIC_WaitAck()) return 1; } *(volatile UINT32*) rIICDS = buf[i]; // 发送字节数据 for(k=0; k<100; k++) ; *(volatile UINT32*) rIICCON = (1<<7)|(0<<6)|(1<<5)|9; if(FALSE == IIC_WaitAck()) return 1; // 没有写完全部length字节长度的数据 并且还没有写满一整页,则继续写入 if( (i<length) && (0 == ((addr+i+1) % pagelength)) ) { *(volatile UINT32*) rIICSTAT = 0xd0; // 状态控制字:0xd0 主设备发送结束, 产生停止信号 *(volatile UINT32*) rIICCON = (1<<7)|(0<<6)|(1<<5)|9; taskDelay(1); j = TRUE; } } if(!j) { *(volatile UINT32*) rIICSTAT = 0xd0; // 状态控制字:0xd0 主设备发送结束, 产生停止信号 *(volatile UINT32*) rIICCON = (1<<7)|(0<<6)|(1<<5)|9; } taskDelay(1); return 0; }
// 函数功能:向定值区写入数据,先读,再擦除,最后写 // 输入参数:wAddress 写入区地址 0-0x10 0000 // pbyBuff 为待写入字节流指针 // dwLen 为字节流长度 // 返回值: 0 成功; 1 失败 STATUS Iic_Write_Data(UINT32 wAddress, UINT8* pbyBuf, UINT32 dwLen) { UINT32 ret; ret = IIC_Write(wAddress, pbyBuf, dwLen); return ret; }
// 函数功能:从定值区读取数据 // 输入参数:wAddress 为读取区地址 // pbyBuf 为待读取字节流指针 // dwLen 为字节流长度 // 返回值: 0 成功; 1 失败 STATUS Iic_Read_Data(UINT32 wAddress, UINT8 *pbyBuf, UINT32 dwLen) { UINT32 ret; ret = IIC_Read(wAddress, pbyBuf, dwLen); return ret; }
// 函数功能:向定值区写入半字(16位) // 输入参数:wAddress 为写入区地址, wBuf 为待写入数据 // 返回值: 0 成功; 1 失败 STATUS Iic_Write_Word(UINT32 wAddress, UINT16 wData) { UINT32 ret; UINT8 buf[2]; buf[0] = wData & 0x00ff; buf[1] = (wData >> 8) & 0x00ff; ret = Iic_Write_Data(wAddress, &buf[0], 2); return ret; }
// 函数功能:从定值区读取半字(16位) // 输入参数:wAddress 为读取区地址 // 返回值: 待读取数据,低16位有效 UINT16 Iic_Read_Word(UINT32 wAddress) { UINT8 buf[2]; UINT16 wData, wData1, wData2; Iic_Read_Data(wAddress, &buf[0], 2); wData1 = buf[0]; wData2 = buf[1]; wData = (wData1 & 0x00ff | (wData2&0x00ff) << 8); return (wData); }
今晚就把IIC驱动代码分享到这里,明天到系统上实际运行试试,看看能否成功写入并读取数据。
验证结果
2016/09/28
在这里做了一个简单的测试,申请一个长度为50的字符数组并清空,向IIC器件写入字符串 “I love China!”,短暂延时后,从IIC器件里面读回来存到 字符数组中,并打印出来。可以看到,结果正确。
证明以上驱动程序,完全正确。
- VxWorks开发板驱动程序学习之IIC
- VxWorks开发板驱动程序学习之LED
- VxWorks开发板驱动程序学习之KEY
- VxWorks开发板驱动程序学习之SPI
- VxWorks开发板驱动程序学习之普通ADC驱动
- VxWorks开发板驱动程序学习之LCD(2.2寸)
- VxWorks开发板驱动程序学习之内部UART0
- VxWorks开发板驱动程序学习之SD卡
- VxWorks开发板驱动程序学习之文件系统(一)
- IIC驱动程序之完善篇
- IIC驱动程序之完善篇
- 【DSP开发】【Linux开发】IIC设备驱动程序
- 51单片机之IIC&EEPROM的驱动程序
- VxWorks下数据采集卡驱动程序开发
- VxWorks设备驱动程序开发指南(三)---驱动程序的分类
- VxWorks驱动程序开发指南(四)--驱动程序的组织结构
- VxWorks驱动程序开发指南--驱动程序的组织结构
- VxWorks设备驱动程序开发指南---驱动程序的分类
- 使用命名空间和类中原本有的函数同时出现时的调用次序
- 微信小程序开发环境搭建
- 渲染世界的OPENGL<13>纹理进阶-矩形及立方体贴图
- Xamarin.iOS项目编译提示Could not AOT the assembly
- poj 2965 The Pilots Brothers' refrigerator
- VxWorks开发板驱动程序学习之IIC
- Visual Studio Online 创建项目
- 进程关系
- <opencv for android>HOG描述子计算的参数
- CVE-2012-1889漏洞利用
- 如何用树莓派3+Python+wiringpi生成PWM
- vim撤销undo与反撤销redo
- js面试题
- #define REGISTER(NAME)