rt-thread-official/bsp/essemi/es32f0271/drivers/drv_i2c.c

276 lines
7.3 KiB
C

/*
* Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-10-23 yuzrain the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <rtdbg.h>
#include "board.h"
#include "drv_i2c.h"
#include "md_i2c.h"
#include "md_gpio.h"
#ifdef RT_USING_I2C
#define TIMEOUT 0xF
/* Define I2C hardware SCL timeout */
#define I2C_TIMING_48MHZ_CLK100KHZ ((0xBU<<28)|(4<<20)|(2<<16)|(0xF<<8)|(0x13))
/**
* @brief: I2C receive.
* @param: i2cx, pointer to the I2Cx
* @param: addr, address
* @param: buf, send data buffer
* @param: len, the length of buf
* @param: timout, timeout
* @retval: rt_err_t
*/
static rt_err_t __i2c_master_recv(I2C_TypeDef *i2cx, rt_uint16_t addr,
rt_uint8_t *buf, rt_uint16_t len, rt_uint32_t timout)
{
rt_uint32_t rt_timout;
//
// Config I2C transfer mode
//
md_i2c_set_con2_add10(i2cx, MD_I2C_ADDRESSINGMODE_7BIT);
/* Config slaver address */
md_i2c_set_con2_sadd(i2cx, addr);
/* Config data size */
md_i2c_set_con2_nbytes(i2cx, len);
/* Reset TX FIFO */
md_i2c_set_fcon_txfrst(i2cx, MD_I2C_TXFIFO_RESET);
/* Config mode */
md_i2c_set_con2_rd_wrn(i2cx, MD_I2C_MASTER_READ);
/* Config auto-reload */
md_i2c_set_con2_reload(i2cx, MD_I2C_NORELOAD_MODE);
/* When NBYTES is matched, the communication will be automatically stop */
md_i2c_set_con2_autoend(i2cx, MD_I2C_AUTOEND_MODE);
/* Start the I2C communication */
md_i2c_set_con2_start(i2cx, MD_I2C_START_GENERATION);
while (len > 0)
{
/* Wait Rx FIFO non-empty */
rt_timout = timout;
while (md_i2c_is_active_stat_rxe(i2cx) && (--rt_timout));
if (rt_timout == 0)
return RT_ETIMEOUT;
*buf++ = md_i2c_recv(i2cx);
len--;
}
return RT_EOK;
}
/**
* @brief: I2C send.
* @param: i2cx, pointer to the I2Cx
* @param: addr, address
* @param: buf, send data buffer
* @param: len, the length of buf
* @param: timout, timeout
* @retval: rt_err_t
*/
static rt_err_t __i2c_master_send(I2C_TypeDef *i2cx, rt_uint16_t addr,
rt_uint8_t *buf, rt_uint16_t len, rt_uint32_t timout)
{
rt_uint32_t rt_timout;
rt_uint8_t index;
//
// Config I2C transfer mode
//
md_i2c_set_con2_add10(i2cx, MD_I2C_ADDRESSINGMODE_7BIT);
/* Config slaver address */
md_i2c_set_con2_sadd(i2cx, addr);
/* Config data size */
md_i2c_set_con2_nbytes(i2cx, len);
/* Reset TX FIFO */
md_i2c_set_fcon_txfrst(i2cx, MD_I2C_TXFIFO_RESET);
/* Config mode */
md_i2c_set_con2_rd_wrn(i2cx, MD_I2C_MASTER_WRITE);
/* Enable auto-end */
md_i2c_set_con2_autoend(i2cx, MD_I2C_AUTOEND_MODE);
//
// Check if the bus is busy
//
/* Wait bus to be ready */
rt_timout = timout;
while ((READ_BIT(i2cx->STAT, I2C_STAT_BUSY_MSK) == I2C_STAT_BUSY_MSK) && (--rt_timout));
if (rt_timout == 0)
return RT_EBUSY;
//
// Start to send
//
if (len <= 8)
{
for (index = 0; index < len; index++)
md_i2c_send(i2cx, *buf++);
len = 0;
}
else
{
for (index = 0; index < 8; index++)
md_i2c_send(i2cx, *buf++);
len -= 8;
}
/* Start the I2C communication */
md_i2c_set_con2_start(i2cx, MD_I2C_START_GENERATION);
while (len > 0)
{
rt_timout = timout;
while (md_i2c_is_active_stat_txf(i2cx) && (--rt_timout));
if (rt_timout == 0)
return RT_ETIMEOUT;
md_i2c_send(i2cx, *buf++);
len--;
}
return RT_EOK;
}
static rt_size_t es32f0_master_xfer(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num)
{
struct rt_i2c_msg *msg;
rt_uint32_t i;
rt_err_t ret = RT_ERROR;
for (i = 0; i < num; i++)
{
msg = &msgs[i];
if (msg->flags & RT_I2C_RD)
{
if (__i2c_master_recv(bus->priv, msg->addr << 1, msg->buf, msg->len, TIMEOUT) != 0)
{
LOG_E("i2c bus write failed,i2c bus stop!\n");
goto out;
}
}
else
{
if (__i2c_master_send(bus->priv, msg->addr << 1, msg->buf, msg->len, TIMEOUT) != 0)
{
LOG_E("i2c bus write failed,i2c bus stop!\n");
goto out;
}
}
}
ret = i;
out:
LOG_E("send stop condition\n");
return ret;
}
const struct rt_i2c_bus_device_ops es32f0_i2c_ops =
{
es32f0_master_xfer,
RT_NULL,
RT_NULL,
};
static void _i2c_init(void)
{
md_i2c_inittypedef I2C_Init =
{
.Timing = CLK100kHz48M,
.Address1 = 0x55 << 1,
.AddrSize = MD_I2C_ADDRESSINGMODE_7BIT,
.DualAddressMode = MD_I2C_DUALADDRESS_DISABLE,
.Address2 = 0xAA,
.Address2Masks = MD_I2C_ADDR2_NOMASK
};
#ifdef BSP_USING_I2C1
/* Open I2C clock */
SET_BIT(RCU->APB1EN, RCU_APB1EN_I2C1EN_MSK);
/* GPIO configuration */
md_gpio_set_pull (GPIOC, MD_GPIO_PIN_12, MD_GPIO_PULL_UP);
md_gpio_set_pull (GPIOD, MD_GPIO_PIN_2, MD_GPIO_PULL_UP);
md_gpio_set_output_type (GPIOC, MD_GPIO_PIN_12, MD_GPIO_OUTPUT_OPENDRAIN);
md_gpio_set_output_type (GPIOD, MD_GPIO_PIN_2, MD_GPIO_OUTPUT_OPENDRAIN);
md_gpio_set_mode (GPIOC, MD_GPIO_PIN_12, MD_GPIO_MODE_FUNCTION);
md_gpio_set_mode (GPIOD, MD_GPIO_PIN_2, MD_GPIO_MODE_FUNCTION);
md_gpio_set_function8_15(GPIOC, MD_GPIO_PIN_12, MD_GPIO_AF1);
md_gpio_set_function0_7 (GPIOD, MD_GPIO_PIN_2, MD_GPIO_AF1);
//
// Config I2C
//
md_i2c_init(I2C1, &I2C_Init);
#endif
#ifdef BSP_USING_I2C2
/* Open I2C clock */
SET_BIT(RCU->APB1EN, RCU_APB1EN_I2C2EN_MSK);
/* GPIO configuration */
md_gpio_set_pull (GPIOB, MD_GPIO_PIN_10, MD_GPIO_PULL_UP);
md_gpio_set_pull (GPIOB, MD_GPIO_PIN_11, MD_GPIO_PULL_UP);
md_gpio_set_output_type (GPIOB, MD_GPIO_PIN_10, MD_GPIO_OUTPUT_OPENDRAIN);
md_gpio_set_output_type (GPIOB, MD_GPIO_PIN_11, MD_GPIO_OUTPUT_OPENDRAIN);
md_gpio_set_mode (GPIOB, MD_GPIO_PIN_10, MD_GPIO_MODE_FUNCTION);
md_gpio_set_mode (GPIOB, MD_GPIO_PIN_11, MD_GPIO_MODE_FUNCTION);
md_gpio_set_function8_15(GPIOB, MD_GPIO_PIN_10, MD_GPIO_AF1);
md_gpio_set_function8_15(GPIOB, MD_GPIO_PIN_11, MD_GPIO_AF1);
//
// Config I2C
//
md_i2c_init(I2C2, &I2C_Init);
#endif
}
#ifdef BSP_USING_I2C2
static struct rt_i2c_bus_device i2c_device2;
#endif
#ifdef BSP_USING_I2C1
static struct rt_i2c_bus_device i2c_device1;
#endif
int rt_hw_i2c_init(void)
{
_i2c_init();
#ifdef BSP_USING_I2C2
/* define i2c Instance */
rt_memset((void *)&i2c_device2, 0, sizeof(struct rt_i2c_bus_device));
i2c_device2.ops = &es32f0_i2c_ops;
i2c_device2.priv = I2C2;
rt_i2c_bus_device_register(&i2c_device2, "i2c2");
#endif
#ifdef BSP_USING_I2C1
/* define i2c Instance */
rt_memset((void *)&i2c_device1, 0, sizeof(struct rt_i2c_bus_device));
i2c_device1.ops = &es32f0_i2c_ops;
i2c_device1.priv = I2C1;
rt_i2c_bus_device_register(&i2c_device1, "i2c1");
#endif
return RT_EOK;
}
INIT_DEVICE_EXPORT(rt_hw_i2c_init);
#endif