IMX6ULL裸机篇之I2C实验主控代码说明一

一.  I2C 实验简介

 I2C实验: 学习如何使用 I.MX6U 的 I2C 接口来驱动 AP3216C,读取 AP3216C 的传感器数据。

AP3216C:是一个三合一的环境光传感器ALS+PS+IRLED,ALS是环境光,PS是接近传感器,IR是红外LED,与主控芯片通信使用的是 I2C接口。

I.MX6U 4 I2C 接口,可 以通过这 4 I2C 接口来连接一些 I2C 外设。

本文只介绍I2C主控制器的几个函数:

(1)  I2C初始化接口

(2)  几个信号产生函数:start信号,stop信号,restart信号;

(3)  错误检查函数

二.  I2C主控代码

1.  I2C主控说明

(1)   I2C初始化函数:i2c_init() 接口。

首先,需要关闭 I2C;

其次,设置 I2C的时钟频率;

设置频率根据 《IMX6ULL参考手册》“Table 31-3. I2C_IFDR Register Field Values”表,如果需要100kbit的速率,则 66000000/100000=660。经过查找IC位设置位0X38或0X15的时候,为640分频,66000000/640=103.125Kbit;

(2) 几个信号产生函数:start信号,stop信号,restart信号;

i2c_master_start() 接口:start 信号产生函数。

i2c_master_stop()接口:stop信号产生函数。

i2c_master_retart()接口: restart 信号产生函数。

(3)   错误检查函数:i2c_check_and_clear_error()接口

检查如下:

是否存在仲裁丢失错误

是否存在没有收到 ACK信号

2. I2C主控制器代码

本实验 在 RTC实时时钟实验的工程上进行编写。

RTC实验工程拷贝一份,重新命名为 17_i2c工程。

/bsp 目录下创建一个 i2c文件,用来存放 i2c主控的代码。在 /bsp/i2c目录下创建 两个文件: bsp_i2c.h bsp_i2c.c 文件。

bsp_i2c.h代码如下:

#ifndef     _BSP_I2C_H_
#define     _BSP_I2C_H_

#include "imx6ull.h"

//定义相关宏
#define   I2C_STATUS_OK              (0)
#define   I2C_STATUS_BUSY            (1)
#define   I2C_STATUS_IDLE            (2)
#define   I2C_STATUS_NAK             (3)
#define   I2C_STATUS_ARBITRATIONLOST (4)  //仲裁丢失
#define   I2C_STATUS_TIMEOUT         (5)
#define   I2C_STATUS_ADDRNAK         (6)

//传输方向结构体
enum i2c_direction {
    kI2C_Write = 0x00,   //主机向从机写数据
    kI2C_Read = 0x01,
};


void i2c_init(I2C_Type* base);
unsigned char i2c_master_start(I2C_Type* base, unsigned char slave_addr, enum i2c_direction data_direction);
unsigned char i2c_master_stop(I2C_Type* base);
unsigned char i2c_master_repeated_start(I2C_Type* base, unsigned char slave_addr, enum i2c_direction data_direct);
unsigned char i2c_check_and_clear_error(I2C_Type* base, unsigned int isr_status);
#endif

bsp_i2c.c文件中的部分代码如下:

#include "bsp_i2c.h"

/*I2C初始化*/
void i2c_init(I2C_Type* base)
{
    //关闭I2C 
    base->I2CR &= ~(1 << 7);
    //设置I2C的时钟
    //66000KHz/640 = 103kHz/s
    base->IFDR = 0X15;
    
    //打开I2C
    base->I2CR |= (1 << 7);
}

/*start信号产生以及从机地址发送函数*/
unsigned char i2c_master_start(I2C_Type* base, unsigned char slave_addr, enum i2c_direction direct)
{
    //判断 I2C忙
    if(base->I2SR & (1 << 5))
        return I2C_STATUS_BUSY;

    //设置为主机+发送模式 
    base->I2CR |= (1 << 5) | (1 << 4);
    //产生start信号(即发送从机地址)
    base->I2DR = (slave_addr << 1) | ((direct == kI2C_Write)? 0:1); //高7位为从机地址,最后1位为读写位
    return I2C_STATUS_OK;
}

/*stop信号产生函数*/
unsigned char i2c_master_stop(I2C_Type* base)
{
    unsigned short timeout = 0xFFFF;
    //清除I2CR的 bit5~bit3
    base->I2CR &= ~((1 << 5)|(1 << 4)|(1 << 3));
    //等待I2C忙结束+超时检测
    while(base->I2SR & (1 << 5))
    {
        timeout--;
        if(timeout == 0) //超时跳出
        {
            return I2C_STATUS_TIMEOUT;
        }
    }
    return I2C_STATUS_OK;
}

/*repeated start信号产生函数*/
unsigned char i2c_master_repeated_start(I2C_Type* base, unsigned char slave_addr, enum i2c_direction data_direct)
{
    //检查I2C忙且工作在从机模式
    if((base->I2SR & (1 << 5)) && ((base->I2CR & (1 << 5)) == 0))
    {
        return I2C_STATUS_BUSY;
    }

    //设置为发送模式+发送repeat-start信号
    base->I2CR |= (1 << 4) | (1 << 2);
    //发送从机地址
    base->I2DR = (slave_addr << 1) | ((data_direct == kI2C_Write)? 0:1);
    return I2C_STATUS_OK;
}

/*error检查函数*/
unsigned char i2c_check_and_clear_error(I2C_Type* base, unsigned int isr_status)
{
    //检查是否是仲裁丢失错误  
    if(isr_status & (1 << 4))
    {
        base->I2SR &= ~(1 << 4); //清除标志位
        base->I2CR &= ~(1 << 7);
        base->I2CR |= (1 << 7);
        return I2C_STATUS_ARBITRATIONLOST;
    }
    else if(isr_status & (1 << 0)) //未收到 ACK信号
    {
        return I2C_STATUS_NAK;
    }
    return I2C_STATUS_OK;
}

本文介绍了I2C的部分接口的实现,下一篇学习  I2C的总线读时序实现与写时序的实现。

你可能感兴趣的:(嵌入式C开发,裸机开发,arm开发,linux,c语言)