本文档以STM32F767平台为例,详细介绍SylixOS上GPIO模仿I2C总线的驱动开发流程。
2.初始化
GPIO模仿的I2C总线的初始化,实际上是I2C总线的SDA和SCL的GPIO管脚初始化。初始化流程如图 2.1所示。
图 2.1 I2C初始化流程图
代码实现,如程序清单 2.1所示。I2C总线的SDA和SCL两个GPIO管脚的GPIO速度要设置成快速模式,输出模式需要设置成推挽输出模式。
程序清单 2.1 I2C初始化代码
/*
* 申请 I2C 1 通道的 SCL 的 GPIO
*/
if (ERROR_NONE != API_GpioRequest(I2C1_CHANNEL_SCL, I2C1_SCL_GPIO_NAME)) {
return (PX_ERROR);
}
/*
* 设置上拉
*/
if (ERROR_NONE != API_GpioSetPull(I2C1_CHANNEL_SCL, GPIO_PUPD_PU)) {
return (PX_ERROR);
}
/*
* 设置为推挽输出模式,且 GPIO 速度为快速
*/
if (ERROR_NONE != API_GpioDirectionOutput(I2C1_CHANNEL_SCL,
(GPIO_SPEED_SET |
GPIO_OTYPE_SET |
LW_GPIOF_INIT_HIGH))) {
return (PX_ERROR);
}
/*
* 申请 I2C 1 通道的 SDA 的 GPIO
*/
if (ERROR_NONE != API_GpioRequest(I2C1_CHANNEL_SDA, I2C1_SDA_GPIO_NAME)) {
return (PX_ERROR);
}
if (ERROR_NONE != API_GpioSetPull(I2C1_CHANNEL_SDA, GPIO_PUPD_PU)) {
return (PX_ERROR);
}
if (ERROR_NONE != API_GpioDirectionOutput(I2C1_CHANNEL_SDA,
(GPIO_SPEED_SET |
GPIO_OTYPE_SET |
LW_GPIOF_INIT_HIGH))) {
return (PX_ERROR);
}
3.传输流程
GPIO模拟I2C总线驱动和普通的I2C总线驱动的最大区别是普通的I2C总线驱动的数据传输只要将要传输的数据写入寄存器即可,而GPIO模拟I2C总线驱动的数据传输是直接通过GPIO管脚将电平拉高拉低(拉高是1,拉低是0)传输数据。
3.1写数据流程
如程序清单 3.1所示,I2C的写数据流程如下:
主设备发送开始信号;
主设备发送7位从设备地址和1位写操作位;
从设备发送应答信号;
主设备发送要写的8位从设备内部地址;
从设备发送应答信号;
主设备开始对从设备写操作;
主设备发送结束信号。
程序清单 3.1 I2C的写数据流程
static INT __i2cXferWrite (UINT uiChannel,
PLW_I2C_MESSAGE pI2cMsg,
INT iLength)
{
INT iIndex;
__i2cStart(uiChannel); /* 发送开始信号 */
/*
* 发送 7 位器件地址和 1 位写操作位
*/
__i2cSendByte((pI2cMsg->I2CMSG_usAddr & I2C_ADDR_MASK), uiChannel);
if (__i2cWaitAck(uiChannel)) { /* 等待设备的 ACK 信号 */
return (PX_ERROR);
}
/*
* 发送要写的设备的内部地址
*/
__i2cSendByte(((pI2cMsg->I2CMSG_usAddr) & I2C_INTER_ADDR_MASK), uiChannel);
if (__i2cWaitAck(uiChannel)) { /* 等待设备的 ACK 信号 */
return (PX_ERROR);
}
for (iIndex = 0; iIndex < iLength; iIndex++) {
__i2cSendByte(*(pI2cMsg->I2CMSG_pucBuffer)++, uiChannel);
/* 发送字节 */
if (__i2cWaitAck(uiChannel)) { /* 等待设备的 ACK 信号 */
return (PX_ERROR);
}
}
__i2cStop(uiChannel); /* 产生一个停止信号 */
udelay(I2C_WRITE_BYTE_DELAY);
return (ERROR_NONE);
}
3.2读数据流程
如程序清单 3.2所示,I2C的读数据流程如下:
写模式,主设备发送开始信号;
主设备发送7位从设备地址和1位写操作位;
从设备发送应答信号;
主设备发送要写的8位从设备内部地址;
从设备发送应答信号;
进入读取模式,设备再次发送开始信号;
主设备发送7位从设备地址和1位读操作位;
从设备发送应答信号;
主设备开始对从设备读操作;
主设备发送结束信号。
程序清单 3.2 I2C读数据流程
static INT __i2cXferRead (UINT uiChannel,
PLW_I2C_MESSAGE pI2cMsg,
INT iLength)
{
INT iIndex;
__i2cStart(uiChannel); /* 发送开始信号 */
/*
* 发送 7 位器件地址和 1 位写操作位,(I2CMSG_usAddr 中的 9-15 位为器件地址)
*/
__i2cSendByte(((pI2cMsg->I2CMSG_usAddr >> 8) & I2C_ADDR_MASK), uiChannel);
if (__i2cWaitAck(uiChannel)) { /* 等待设备的 ACK 信号 */
return (PX_ERROR);
}
/*
* 发送要读的设备的内部地址
*/
__i2cSendByte(((pI2cMsg->I2CMSG_usAddr) & I2C_INTER_ADDR_MASK), uiChannel);
if (__i2cWaitAck(uiChannel)) { /* 等待设备的 ACK 信号 */
return (PX_ERROR);
}
/*
* 进入读取模式
*/
__i2cStart(uiChannel); /* 发送开始信号 */
/*
* 发送 7 位器件地址和 1 位读操作位,(I2CMSG_usAddr 中的 8-15 位为器件地址和读写位)
*/
__i2cSendByte(((pI2cMsg->I2CMSG_usAddr >> 8) &
I2C_ADDR_MASK) |
LW_I2C_M_RD, uiChannel);
if (__i2cWaitAck(uiChannel)) { /* 等待设备的 ACK 信号 */
return (PX_ERROR);
}
for (iIndex = 0; iIndex < iLength - 1; iIndex++) {
/*
* 读取设备发来的 1 个字节数据
*/
*(pI2cMsg->I2CMSG_pucBuffer)++ = __i2cReadByte(I2C_ACK_SEND, uiChannel);
}
*(pI2cMsg->I2CMSG_pucBuffer) = __i2cReadByte(I2C_NACK_SEND, uiChannel);
__i2cStop(uiChannel); /* 产生停止信号 */
return (ERROR_NONE);
}
SylixOS 基于STM32平台的GPIO模仿I2C总线的驱动开发流程
原文地址:http://blog.51cto.com/12558316/2073503