【FR801xH】富芮坤FR801xH之软件I2C读写OCH1973

00. 目录

01. FR801xH概述

在这里插入图片描述

FR801xH 系列芯片是面向SOC(片上系统),易于快速开发的低功耗蓝牙芯片。基于 Freqchip 的蓝牙智能固件和协议栈的支持,完全兼容蓝牙 V5.3(LE 模式)协议。同时用户可以基于芯片内置的 ARM CorteM3 嵌入式 32 位高性能单片机开发各种应用程序。

蓝牙智能固件包括 L2CAP 服务层协议、安全管理器 (SM)、属性协议(ATT)、通用属性配置文件 (GATT)和通用访问配置文件(GAP)。此外,还 支持应用程序配置文件,例如接近度、健康温度计、 心率、血压、血糖、人机界面设备(HID)和 SDK (包括驱动程序、OS-API 等)。SDK 还集成了用于网络应用程序的 SIG Mesh 协议。

采用 Freqchip 的创新技术,将 PMU(锂电池充电 器+LDO)、带 XIP 模式的 QSPI FLASH ROM、 I2C、UART、GPIO、ADC、PWM 集成在一块芯片中,为客户提供:

  • 竞争力的功耗
  • 稳定的蓝牙连接
  • 极低的 BOM 成本

02. FR801xH功能框图

在这里插入图片描述

03. I2C相关类型

位于 components\driver\include\driver_iic.h

3.1 iic_channel_t

enum iic_channel_t
{
    IIC_CHANNEL_0,
    IIC_CHANNEL_1,
    IIC_CHANNEL_MAX,
};

3.2 enum_iic_int_indx_t

typedef enum
{
	 INT_TRANS_DONE                   = 0x00000001,
	 INT_ARB_FAIL                     = 0x00000002,
	 INT_NO_ACK                       = 0x00000004,
	 INT_MS_DATA_REQ                  = 0x00000008,
	 INT_SLV_DATA_REQ                 = 0x00000010,
	 INT_RX_FFF                       = 0x00000020,
	 INT_RX_FFNE                      = 0x00000040,
	 INT_MS_TX_FFNF                   = 0x00000080,
	 INT_SW_RST                       = 0x00000100,
	 INT_ADD_TYPE_SEL                 = 0x00000200,
	 INT_SLV_TX_FFNF                  = 0x00000400,
}enum_iic_int_indx_t;

04. I2C相关API

4.1 iic_init

/*********************************************************************
 * @fn      iic_init
 *
 * @brief   Initialize iic instance.
 *
 * @param   channel     - IIC_CHANNEL_0 or IIC_CHANNEL_1.
 *          speed       - SCL speed when working as master, N * 1000
 *          slave_addr  - local address when working as slave
 *
 * @return  None.
 */
void iic_init(enum iic_channel_t channel, uint16_t speed, uint16_t slave_addr);
功能:
	初始化 IIC 模块,默认配置为为 7 位地址模式
参数:
	channel 初始化对象,可选 IIC_CHANNEL_0、IIC_CHANNEL_1
	speed 配置总线时钟速率为 speed*1000
	slave_addr 当本机工作在从机模式时的从机地址
返回值:
	None

4.2 iic_write_byte

/*********************************************************************
 * @fn      iic_write_byte
 *
 * @brief   write one byte to slave.
 *
 * @param   channel     - IIC_CHANNEL_0 or IIC_CHANNEL_1.
 *          slave_addr  - slave address
 *          reg_addr    - which register to be writen
 *          data        - data to be writen
 *
 * @return  None.
 */
uint8_t iic_write_byte(enum iic_channel_t channel, uint8_t slave_addr, uint8_t reg_addr, uint8_t data);
功能:
	将一个字节数据发送给从机的特定地址
参数:
	channel  -  操作对象
	slave_addr  -  从机地址
	reg_addr  -  操作的从机寄存器地址
	data  -  待写入的数据
返回值:
	None

4.3 iic_write_bytes

/*********************************************************************
 * @fn      iic_write_bytes
 *
 * @brief   write multi-bytes to slave.
 *
 * @param   channel     - IIC_CHANNEL_0 or IIC_CHANNEL_1.
 *          slave_addr  - slave address
 *          reg_addr    - which register to be writen
 *          buffer      - pointer to data buffer
 *          length      - how many bytes to be written
 *
 * @return  None.
 */
uint8_t iic_write_bytes(enum iic_channel_t channel, uint8_t slave_addr, uint8_t reg_addr, uint8_t *buffer, uint16_t length);
功能:
	将多个字节数据发送给从机的特定地址
参数:
	channel  -  操作对象
	slave_addr  -  从机地址
	reg_addr  -  操作的从机寄存器起始地址
	buffer  -  待写入的数据
	length  -  待写入的数据长度
返回值:
	true:写入成功;false:写入失败

4.4 iic_read_byte

/*********************************************************************
 * @fn      iic_read_byte
 *
 * @brief   read one byte frome slave.
 *
 * @param   channel     - IIC_CHANNEL_0 or IIC_CHANNEL_1.
 *          slave_addr  - slave address
 *          reg_addr    - which register to be written
 *          buffer      - store data to buffer
 *
 * @return  None.
 */
uint8_t iic_read_byte(enum iic_channel_t channel, uint8_t slave_addr, uint8_t reg_addr, uint8_t *buffer);
功能:
	从从机的特定地址读取一个字节数据
参数:
	channel  -  操作对象
	slave_addr  -  从机地址
	reg_addr  -  操作的从机寄存器地址
	buffer  -  读取数据的保存地址
返回值:
	true:读取成功;false:读取失败

4.5 iic_read_bytes

/*********************************************************************
 * @fn      iic_read_bytes
 *
 * @brief   read multi-bytes frome slave.
 *
 * @param   channel     - IIC_CHANNEL_0 or IIC_CHANNEL_1.
 *          slave_addr  - slave address
 *          reg_addr    - which register to be written
 *          buffer      - buffer pointer to be written
 *          length      - how many bytes to be read
 *
 * @return  None.
 */
uint8_t iic_read_bytes(enum iic_channel_t channel, uint8_t slave_addr, uint8_t reg_addr, uint8_t *buffer, uint16_t length);
功能:
	从从机的特定地址读取多个字节数据
参数:
	channel  -  操作对象
	slave_addr  -  从机地址
	reg_addr  -  操作的从机寄存器起始地址
	buffer  -  读取数据的保存地址
	length  -  待读取的数据长度
返回值:
	true:读取成功;false:读取失败


05. 软件I2C程序示例

myi2c.h

void och1973_i2c_init(void);
void och_i2c_read(uint8_t reg, uint8_t length, uint8_t *i2cdata);
void och_i2c_write(uint8_t reg, uint8_t length, uint8_t *i2cdata);
void och_delay(uint8_t delayms);

void I2C_Configuration(void);

myi2c.c

#define SUCCESS 1 // 响应正常
#define ERROR 0   // 响应错误

#define ACK_OK 1                         // 响应正常
#define ACK_ERR 0                        // 响应错误
#define IIC_DEVICE_RADDR (0x0C << 1) + 1 // IIC 初始化地址
#define IIC_DEVICE_WADDR 0x0C << 1
// IIC 通信延时,User_IIC_Delay()函数使用,
// 数值越小,则通信速度越快
#define IIC_DelayVaule 3
#define User_IIC_SCL(a) (a ? gpio_porta_write(gpio_porta_read() | (1 << 6)) : gpio_porta_write(gpio_porta_read() & ~(1 << 6)))
#define User_IIC_SDA(a) (a ? gpio_porta_write(gpio_porta_read() | (1 << 7)) : gpio_porta_write(gpio_porta_read() & ~(1 << 7)))
#define User_IIC_READ_SDA() (gpio_porta_read() & (1 << 7) ? 1 : 0)
#define User_IIC_SET_SDA_INPUT() (gpio_porta_set_dir(gpio_porta_get_dir() | (1 << 7)))
#define User_IIC_SET_SDA_OUPUT() (gpio_porta_set_dir(gpio_porta_get_dir() & ~(1 << 7)))

/*******************************************************************************
 * Function Name : I2C_Configuration
 * Description : EEPROM 管脚配置
 * Input : None
 * Output : None
 * Return : None
 * Attention : None
 *******************************************************************************/
void I2C_Configuration(void)
{
    system_set_port_mux(GPIO_PORT_A, GPIO_BIT_6, PORTA6_FUNC_A6);
    system_set_port_mux(GPIO_PORT_A, GPIO_BIT_7, PORTA7_FUNC_A7);
    gpio_set_dir(GPIO_PORT_A, GPIO_BIT_6, GPIO_DIR_OUT);
    gpio_set_dir(GPIO_PORT_A, GPIO_BIT_7, GPIO_DIR_OUT);
    gpio_set_pin_value(GPIO_PORT_A, GPIO_BIT_6, 1);
    gpio_set_pin_value(GPIO_PORT_A, GPIO_BIT_7, 1);
}

/*****************************************************************************************
 * 函 数 名: User_IIC_Delay
 * 入口参数: a - 延时时间
 * 返 回 值: 无
 * 函数功能: 简单延时函数
 * 说 明: 为了移植的简便性且对延时精度要求不高,所以不需要使用定时器做延时
 ******************************************************************************************/
void User_IIC_Delay(uint32_t a)
{
    volatile uint16_t i;

    while (a--)
    {
        for (i = 0; i < 2; i++)
            ;
    }
}

/*****************************************************************************************
 * 函 数 名: User_IIC_Start * 入口参数: 无
 * 返 回 值: 无
 * 函数功能: IIC 起始信号
 * 说 明: 在 SCL 处于高电平期间,SDA 由高到低跳变为起始信号
 ******************************************************************************************/
void User_IIC_Start(void)
{
    User_IIC_SDA(1);
    User_IIC_SCL(1);
    User_IIC_Delay(IIC_DelayVaule);
    User_IIC_SDA(0);
    User_IIC_Delay(IIC_DelayVaule);
    User_IIC_SCL(0);
    User_IIC_Delay(IIC_DelayVaule);
}
/*****************************************************************************************
 * 函 数 名: User_IIC_Stop
 * 入口参数: 无
 * 返 回 值: 无
 * 函数功能: IIC 停止信号
 * 说 明: 在 SCL 处于高电平期间,SDA 由低到高跳变为起始信号
 ******************************************************************************************/
void User_IIC_Stop(void)
{
    User_IIC_SCL(0);
    User_IIC_Delay(IIC_DelayVaule);
    User_IIC_SDA(0);
    User_IIC_Delay(IIC_DelayVaule);
    User_IIC_SCL(1);
    User_IIC_Delay(IIC_DelayVaule);
    User_IIC_SDA(1);
    User_IIC_Delay(IIC_DelayVaule);
}

/*****************************************************************************************
 * 函 数 名: User_IIC_ACK
 * 入口参数: 无
 * 返 回 值: 无
 * 函数功能: IIC 应答信号
 * 说 明: 在 SCL 为高电平期间,SDA 引脚输出为低电平,产生应答信号
 ******************************************************************************************/
void User_IIC_ACK(void)
{
    User_IIC_SCL(0);
    User_IIC_Delay(IIC_DelayVaule);
    User_IIC_SDA(0);
    User_IIC_Delay(IIC_DelayVaule);
    User_IIC_SCL(1);
    User_IIC_Delay(IIC_DelayVaule);
    User_IIC_SCL(0); // SCL 输出低时,SDA 应立即拉高,释放总线
    User_IIC_SDA(1);
    User_IIC_Delay(IIC_DelayVaule);
}

/*****************************************************************************************
 * 函 数 名: User_IIC_NoACK
 * 入口参数: 无
 * 返 回 值: 无
 * 函数功能: IIC 非应答信号
 * 说 明: 在 SCL 为高电平期间,若 SDA 引脚为高电平,产生非应答信号
 ******************************************************************************************/
void User_IIC_NoACK(void)
{
    User_IIC_SCL(0);
    User_IIC_Delay(IIC_DelayVaule);
    User_IIC_SDA(1);
    User_IIC_Delay(IIC_DelayVaule);
    User_IIC_SCL(1);
    User_IIC_Delay(IIC_DelayVaule);
    User_IIC_SCL(0);
    User_IIC_Delay(IIC_DelayVaule);
}

/*****************************************************************************************
 * 函 数 名: User_IIC_WaitACK
 * 入口参数: 无
 * 返 回 值: 无
 * 函数功能: 等待接收设备发出应答信号
 * 说 明: 在 SCL 为高电平期间,若检测到 SDA 引脚为低电平,则接收设备响应正常
 ******************************************************************************************/
uint8_t User_IIC_WaitACK(void)
{
    uint8_t ret;
    User_IIC_SDA(1);
    User_IIC_Delay(IIC_DelayVaule);
    User_IIC_SCL(1);
    User_IIC_SET_SDA_INPUT(); // 设置 SDA 为输入模式
    User_IIC_Delay(IIC_DelayVaule);
    if (User_IIC_READ_SDA() != 0) // 判断设备是否有做出响应
    {
        User_IIC_SCL(0);
        User_IIC_Delay(IIC_DelayVaule);
        ret = ACK_ERR; // 无应答
    }
    else
    {
        User_IIC_SCL(0);
        User_IIC_Delay(IIC_DelayVaule);
        ret = ACK_OK; // 应答正常
    }

    User_IIC_SET_SDA_OUPUT(); // 设置 SDA 为输出模式
    return ret;
}
/*****************************************************************************************
 * 函 数 名: User_IIC_WriteByte
 * 入口参数: IIC_Data - 要写入的 8 位数据
 * 返 回 值: ACK_OK - 设备响应正常
 * ACK_ERR - 设备响应错误
 * 函数功能: 写一字节数据
 * 说 明:高位在前
 ******************************************************************************************/
uint8_t User_IIC_WriteByte(uint8_t IIC_Data)
{
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
        User_IIC_SDA(IIC_Data & 0x80);
        User_IIC_Delay(IIC_DelayVaule);
        User_IIC_SCL(1);
        User_IIC_Delay(IIC_DelayVaule);
        User_IIC_SCL(0);
        if (i == 7)
        {
            User_IIC_SDA(1);
        }
        IIC_Data <<= 1;
    }
    return User_IIC_WaitACK(); // 等待设备响应
}
/*****************************************************************************************
 * 函 数 名: User_IIC_ReadByte
 * 入口参数: ACK_Mode - 响应模式,输入 1 则发出应答信号,输入 0 发出非应答信号
 * 返 回 值: ACK_OK - 设备响应正常
 * ACK_ERR - 设备响应错误
 * 函数功能:读一字节数据
 * 说 明:1.高位在前
 * 2.应在主机接收最后一字节数据时发送非应答信号
 ******************************************************************************************/
uint8_t User_IIC_ReadByte(uint8_t ACK_Mode)
{
    uint8_t IIC_Data = 0;
    uint8_t i = 0;

    User_IIC_SET_SDA_INPUT();
    for (i = 0; i < 8; i++)
    {
        IIC_Data <<= 1;
        User_IIC_SCL(1);
        User_IIC_Delay(IIC_DelayVaule);
        IIC_Data |= (User_IIC_READ_SDA() & 0x01);
        User_IIC_SCL(0);
        User_IIC_Delay(IIC_DelayVaule);
    }
    User_IIC_SET_SDA_OUPUT();
    if (ACK_Mode == 1) // 应答信号
        User_IIC_ACK();
    else
        User_IIC_NoACK(); // 非应答信号
    return IIC_Data;
}
/*****************************************************************************************
 * 函 数 名: IIC_WriteHandle
 * 入口参数: 寄存器地址
 * 返 回 值: 操作结果
 *
 * 函数功能:写设备地址和寄存器地址
 ******************************************************************************************/
uint8_t IIC_WriteHandle(uint8_t addr)
{
    uint8_t status; // 状态标志位
    // User_IIC_Start(); // 启动 IIC 通信
    if (User_IIC_WriteByte(IIC_DEVICE_WADDR) == ACK_OK) // 写数据指令
    {
        if (User_IIC_WriteByte(addr) == ACK_OK) // 写入 8 位地址
            status = SUCCESS;                   // 操作成功
    }
    else
    {
        status = ERROR;
    }
    return status;
}

/*****************************************************************************************
 * 函 数 名: IIC_WriteData
 * 入口参数: 寄存器地址 参数
 * 返 回 值: 操作结果
 *
 * 函数功能:向寄存器地址写入参数
 ******************************************************************************************/
uint8_t IIC_WriteData(uint8_t addr, uint8_t value)
{
    uint8_t status;
    User_IIC_Start();                     // 启动 IIC 通讯
    if (IIC_WriteHandle(addr) == SUCCESS) // 写入要操作的寄存器
    {
        if (User_IIC_WriteByte(value) != ACK_OK) // 写数据
        {
            status = ERROR;
        }
    }
    User_IIC_Stop();  // 停止通讯
    status = SUCCESS; // 写入成功
    return status;
}
/*****************************************************************************************
 * 函 数 名: IIC_WriteReg
 * 入口参数: 寄存器地址 参数
 * 返 回 值: 操作结果
 *
 * 函数功能:向寄存器地址写入多个参数
 ******************************************************************************************/
uint8_t IIC_WriteReg(uint8_t addr, uint8_t cnt, uint8_t *value)
{
    uint8_t status;
    uint8_t i;
    User_IIC_Start();
    if (IIC_WriteHandle(addr) == SUCCESS) // 写入要操作的寄存器
    {
        for (i = 0; i < cnt; i++) // 计数
        {
            User_IIC_WriteByte(value[i]); // 写入数据
        }
        User_IIC_Stop();  // 停止 IIC 通信
        status = SUCCESS; // 写入成功
    }
    else
    {
        User_IIC_Stop(); // 停止 IIC 通信
        status = ERROR;  // 写入失败
    }
    return status;
}
/*****************************************************************************************
 * 函 数 名: IIC_ReadReg
 * 入口参数: 寄存器地址 夺取个数 缓存
 * 返 回 值: 操作结果
 *
 * 函数功能:从寄存器地址读取多个参数
 ******************************************************************************************/
uint8_t IIC_ReadReg(uint8_t addr, uint8_t cnt, uint8_t *value)
{
    uint8_t status;
    uint8_t i;

    status = ERROR;
    User_IIC_Start(); // 启动 IIC 通信

    if (IIC_WriteHandle(addr) == SUCCESS) // 写入要操作的寄存器
    {
        User_IIC_Start();                                   // 重新启动 IIC 通讯
        if (User_IIC_WriteByte(IIC_DEVICE_RADDR) == ACK_OK) // 发送读命令
        {
            for (i = 0; i < cnt; i++) // 计数
            {
                if (i == (cnt - 1))
                {
                    value[i] = User_IIC_ReadByte(0); // 读到最后一个数据时发送 非应答信号
                }
                else
                {
                    value[i] = User_IIC_ReadByte(1); // 发送应答信号
                }
            }
            User_IIC_Stop(); // 停止 IIC 通信
            status = SUCCESS;
        }
    }
    User_IIC_Stop(); // 停止 IIC 通信
    return (status);
}

void och_i2c_read(uint8_t reg, uint8_t length, uint8_t *i2cdata)
{
    IIC_ReadReg(reg, length, i2cdata);
}

void och_i2c_write(uint8_t reg, uint8_t length, uint8_t *i2cdata)
{
    IIC_WriteReg(reg, length, i2cdata);
}

void och_delay(uint8_t delayms)
{
    co_delay_100us(delayms * 10);
}

demo.c

void och1973_demo(void)
{

    uint8_t data[2] = {0};

    uint8_t data_array[6]; // create an array to store data output from sensors
    int16_t result[3];
    char str[16];


    I2C_Configuration();
    OCH1973_CheckWIA(data);
    co_printf("ID: 0x%2X 0x%2X\r\n", data[0], data[1]);

    value = 0x0c;
    och_i2c_write(OCH1973_REG_CNTL2, 1, &value);
    co_delay_100us(1);

    // 默认0x03
    value = 0;
    och_i2c_read(OCH1973_REG_CNTL2, 1, &value);
    co_printf("OCH1973_REG_CNTL2: 0x%02x\r\n", value);


    // 0: Magnetic output mode  1: Angle output mode
    //  OCH1973_OP_CONTINUOUS_MODE_6_500Hz   OCH1973_Rising OCH1973_Falling
    OCH1973_Init(OCH1973_VALUE_CONTINUOUS_MODE_1_5Hz, OCH1973_LOW_NOISE_MODE, OCH1973_HIGH_RANGE_MODE, OCH1973_Falling, OCH1973_XYplane, OCH_DISABLE);
    // continuous measurement mode,measurement frequency is 100Hz,low noise mode,high range mode,OD-INT Interrupt edge Falling,XYplane,Enable Angle


    while (1)
    {
        //===========Polling mode==================
        if (OCH1973_CheckDRDY() == 1) // data is ready
        {
            OCH1973_GetXYZ_HLdata(data_array); // read datas
            // OCH1973_Get_ANGLE(angle_array);

            OCH1973_MergeHighLowData(data_array, result, 6);

            och_i2c_read(OCH1973_REG_CNTL2, 1, &value);
            co_printf("--->value: %d  x: %d   y: %d   z: %d \r\n", value, result[2], result[1], result[0]);
        }

        co_delay_100us(10000);
    }
}

程序运行结果

******Connected******

******Start Auto Burn******
****************************************************
******CRC Success******

******Burn Success******
?ID: 0x48 0xC0
OCH1973_REG_CNTL2: 0x0c


06. 附录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沧海一笑-dj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值