中级会员
- 积分
- 214
- 金钱
- 214
- 注册时间
- 2014-4-30
- 在线时间
- 26 小时
|
drv_hard_i2c.c___________________________________________________________________________
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include "drv_hard_i2c.h"
#ifdef RT_USING_HARD_I2C
#define DBG_TAG "drv.i2c"
#ifdef DRV_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif /* DRV_DEBUG */
#include <rtdbg.h>
/** @defgroup Private Defines
* @{
*/
#define HAED_I2C_CONFIG(x) \
{ \
.bus_name = "i2c"#x, \
.scl_pin_name = BSP_I2C##x##_SCL_PIN, \
.sda_pin_name = BSP_I2C##x##_SDA_PIN, \
.speed = BSP_I2C##x##_CLOCK, \
.pInitFunc = MX_I2C##x##_Init, \
.pHi2c = &hi2c##x, \
.i2c_bus = { \
.ops = &i2c_bus_ops, \
}, \
}
/** @defgroup Private Variables
* @{
*/
#ifdef BSP_USING_I2C1
static I2C_HandleTypeDef hi2c1;
#endif /* BSP_USING_I2C1 */
#ifdef BSP_USING_I2C2
static I2C_HandleTypeDef hi2c2;
#endif /* BSP_USING_I2C2 */
#ifdef BSP_USING_I2C3
static I2C_HandleTypeDef hi2c3;
#endif /* BSP_USING_I2C3 */
/** @defgroup Private Functions
* @{
*/
static rt_size_t i2c_xfer( struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num);
#ifdef BSP_USING_I2C1
static void MX_I2C1_Init(rt_uint32_t speed);
#endif /* BSP_USING_I2C1 */
#ifdef BSP_USING_I2C2
static void MX_I2C2_Init(rt_uint32_t speed);
#endif /* BSP_USING_I2C2 */
#ifdef BSP_USING_I2C3
static void MX_I2C3_Init(rt_uint32_t speed)
#endif /* BSP_USING_I2C3 */
static struct rt_i2c_bus_device_ops i2c_bus_ops = {
.master_xfer = i2c_xfer,
.slave_xfer = RT_NULL,
.i2c_bus_control = RT_NULL,
};
static struct stm32_hard_i2c_config hard_i2c_config[] = {
#ifdef BSP_USING_I2C1
HAED_I2C_CONFIG(1)
#endif /* BSP_USING_I2C1 */
#ifdef BSP_USING_I2C2
HAED_I2C_CONFIG(2)
#endif /* BSP_USING_I2C2 */
#ifdef BSP_USING_I2C3
HAED_I2C_CONFIG(3)
#endif /* BSP_USING_I2C3 */
};
enum {
#ifdef BSP_USING_I2C1
I2C1_INDEX,
#endif /* BSP_USING_I2C1 */
#ifdef BSP_USING_I2C2
I2C2_INDEX,
#endif /* BSP_USING_I2C2 */
#ifdef BSP_USING_I2C3
I2C3_INDEX,
#endif /* BSP_USING_I2C3 */
};
/* To parse I2C port and pin define */
static int up_char(char * c)
{
if ((*c >= 'a') && (*c <= 'z'))
{
*c = *c - 32;
}
return 0;
}
static void get_pin_by_name(const char* pin_name, GPIO_TypeDef **port, uint16_t *pin)
{
int pin_num = atoi((char*) &pin_name[2]);
char port_name = pin_name[1];
up_char(&port_name);
up_char(&port_name);
*port = ((GPIO_TypeDef *) ((uint32_t) GPIOA
+ (uint32_t) (port_name - 'A') * ((uint32_t) GPIOB - (uint32_t) GPIOA)));
*pin = (GPIO_PIN_0 << pin_num);
}
static rt_err_t hard_i2c_gpio_clk_enable(GPIO_TypeDef *gpiox)
{
/* check the parameters */
RT_ASSERT(IS_GPIO_ALL_INSTANCE(gpiox));
/* gpio ports clock enable */
switch ((uint32_t)gpiox)
{
#if defined(__HAL_RCC_GPIOA_CLK_ENABLE)
case (uint32_t)GPIOA:
__HAL_RCC_GPIOA_CLK_ENABLE();
break;
#endif
#if defined(__HAL_RCC_GPIOB_CLK_ENABLE)
case (uint32_t)GPIOB:
__HAL_RCC_GPIOB_CLK_ENABLE();
break;
#endif
#if defined(__HAL_RCC_GPIOC_CLK_ENABLE)
case (uint32_t)GPIOC:
__HAL_RCC_GPIOC_CLK_ENABLE();
break;
#endif
#if defined(__HAL_RCC_GPIOD_CLK_ENABLE)
case (uint32_t)GPIOD:
__HAL_RCC_GPIOD_CLK_ENABLE();
break;
#endif
#if defined(__HAL_RCC_GPIOE_CLK_ENABLE)
case (uint32_t)GPIOE:
__HAL_RCC_GPIOE_CLK_ENABLE();
break;
#endif
#if defined(__HAL_RCC_GPIOF_CLK_ENABLE)
case (uint32_t)GPIOF:
__HAL_RCC_GPIOF_CLK_ENABLE();
break;
#endif
#if defined(__HAL_RCC_GPIOG_CLK_ENABLE)
case (uint32_t)GPIOG:
__HAL_RCC_GPIOG_CLK_ENABLE();
break;
#endif
#if defined(__HAL_RCC_GPIOH_CLK_ENABLE)
case (uint32_t)GPIOH:
__HAL_RCC_GPIOH_CLK_ENABLE();
break;
#endif
#if defined(__HAL_RCC_GPIOI_CLK_ENABLE)
case (uint32_t)GPIOI:
__HAL_RCC_GPIOI_CLK_ENABLE();
break;
#endif
#if defined(__HAL_RCC_GPIOJ_CLK_ENABLE)
case (uint32_t)GPIOJ:
__HAL_RCC_GPIOJ_CLK_ENABLE();
break;
#endif
#if defined(__HAL_RCC_GPIOK_CLK_ENABLE)
case (uint32_t)GPIOK:
__HAL_RCC_GPIOK_CLK_ENABLE();
break;
#endif
default:
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t hard_i2c_clk_enable(uint8_t busnum)
{
/* uart clock enable */
switch (busnum)
{
#ifdef BSP_USING_I2C1
case 1:
__HAL_RCC_I2C1_CLK_ENABLE();
break;
#endif /* BSP_USING_I2C1 */
#ifdef BSP_USING_I2C2
case 2:
__HAL_RCC_I2C2_CLK_ENABLE();
break;
#endif /* BSP_USING_I2C2 */
#ifdef BSP_USING_I2C3
case 3:
__HAL_RCC_I2C3_CLK_ENABLE();
break;
#endif /* BSP_USING_I2C3 */
default:
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t hard_i2c_gpio_configure(struct stm32_hard_i2c_config *config)
{
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
GPIO_TypeDef *scl_port;
GPIO_TypeDef *sda_port;
uint16_t scl_pin;
uint16_t sda_pin;
uint8_t i2c_num = config->bus_name[3] - '0';
/* get gpio port and pin address */
get_pin_by_name(config->scl_pin_name, &scl_port, &scl_pin);
get_pin_by_name(config->sda_pin_name, &sda_port, &sda_pin);
/* gpio ports clock enable */
hard_i2c_gpio_clk_enable(scl_port);
if (scl_port != sda_port) {
hard_i2c_gpio_clk_enable(sda_port);
}
/* scl pin initialize */
GPIO_InitStruct.Pin = scl_pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
HAL_GPIO_Init(scl_port, &GPIO_InitStruct);
HAL_GPIO_WritePin(scl_port, scl_pin, GPIO_PIN_SET);
/* sda pin initialize */
GPIO_InitStruct.Pin = sda_pin;
HAL_GPIO_Init(sda_port, &GPIO_InitStruct);
HAL_GPIO_WritePin(sda_port, sda_pin, GPIO_PIN_SET);
/* i2c periphal clock enable */
hard_i2c_clk_enable(i2c_num);
return RT_EOK;
}
/**
* I2C bus common interrupt process. This need add to I2C ISR.
*
* @param config hard i2c bus instance pointor
*/
static inline void i2cx_event_isr(struct stm32_hard_i2c_config *config)
{
HAL_I2C_EV_IRQHandler(config->pHi2c);
}
static inline void i2cx_error_isr(struct stm32_hard_i2c_config *config)
{
HAL_I2C_ER_IRQHandler(config->pHi2c);
}
/**
* if i2c is locked, this function will unlock it
*
* @param stm32 config class
*
* @return RT_EOK indicates successful unlock.
*/
static rt_err_t hard_i2c_bus_unlock(struct stm32_hard_i2c_config *config)
{
rt_int32_t i = 0;
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_TypeDef *scl_port;
GPIO_TypeDef *sda_port;
uint16_t scl_pin;
uint16_t sda_pin;
/* get gpio port and pin address */
get_pin_by_name(config->scl_pin_name, &scl_port, &scl_pin);
get_pin_by_name(config->sda_pin_name, &sda_port, &sda_pin);
if (PIN_LOW == HAL_GPIO_ReadPin(sda_port, sda_pin)) {
while (i++ < 9)
{
HAL_GPIO_WritePin(scl_port, scl_pin, PIN_HIGH);
rt_hw_us_delay(100);
HAL_GPIO_WritePin(scl_port, scl_pin, PIN_LOW);
rt_hw_us_delay(100);
}
}
if (PIN_LOW == HAL_GPIO_ReadPin(sda_port, sda_pin)) {
return -RT_ERROR;
}
return RT_EOK;
}
#ifdef BSP_USING_I2C1
static void MX_I2C1_Init(rt_uint32_t speed)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = speed;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_16_9;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/*## Configure the NVIC for I2C1 ########################################*/
/* NVIC for I2Cx */
HAL_NVIC_SetPriority(I2C1_EV_IRQn, 10, 0);
HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
HAL_NVIC_SetPriority(I2C1_ER_IRQn, 11, 0);
HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
}
void I2C1_EV_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
i2cx_event_isr(&hard_i2c_config[I2C1_INDEX]);
/* leave interrupt */
rt_interrupt_leave();
}
void I2C1_ER_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
i2cx_error_isr(&hard_i2c_config[I2C1_INDEX]);
/* leave interrupt */
rt_interrupt_leave();
}
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
/* release sem to notice function */
rt_sem_release(hard_i2c_config[I2C1_INDEX].tx_notice);
}
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
/* release sem to notice function */
rt_sem_release(hard_i2c_config[I2C1_INDEX].rx_notice);
}
#endif
/**
* @brief i2c bus data xfer for transmit and receive.
* @param bus pointer to hard i2c configurate instance.
* msgs info data to xfer by i2c bus.
* num the total data length to xfer.
* @retval function execute result if success is xfer count.
*/
static rt_size_t i2c_xfer( struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num)
{
HAL_StatusTypeDef status;
rt_err_t ret = 0;
rt_size_t xfer_len = 0;
struct rt_i2c_msg *msg;
struct stm32_hard_i2c_config *pCfg = rt_container_of(bus, struct stm32_hard_i2c_config, i2c_bus);
for (int i = 0; i < num; i++)
{
msg = &msgs;
if (msg->flags & RT_I2C_RD)
{
/***** I2C master to receive *****/
rt_mutex_take(pCfg->lock, RT_WAITING_FOREVER);
/* master receive data by interrupt */
status = HAL_I2C_Master_Receive_IT(pCfg->pHi2c, msg->addr << 1, msg->buf, msg->len);
if (status != HAL_OK) {
HAL_I2C_Master_Abort_IT(pCfg->pHi2c, msg->addr << 1);
rt_mutex_release(pCfg->lock);
ret = RT_ERROR;
goto __exit;
}
/* wait receive complete */
ret = rt_sem_take(pCfg->rx_notice, (10 * msg->len));
if (ret != RT_EOK)
{
HAL_I2C_Master_Abort_IT(pCfg->pHi2c, msg->addr << 1);
rt_mutex_release(pCfg->lock);
goto __exit;
}
rt_mutex_release(pCfg->lock);
xfer_len++;
}
else
{
/***** I2C master to transmit *****/
rt_mutex_take(pCfg->lock, RT_WAITING_FOREVER);
/* master transmit data by interrupt */
status = HAL_I2C_Master_Transmit_IT(pCfg->pHi2c, msg->addr << 1, msg->buf, msg->len);
if (status != HAL_OK)
{
HAL_I2C_Master_Abort_IT(pCfg->pHi2c, msg->addr << 1);
rt_mutex_release(pCfg->lock);
ret = RT_ERROR;
goto __exit;
}
/* wait transmit complete */
ret = rt_sem_take(pCfg->tx_notice, (10 * msg->len));
if (ret != RT_EOK)
{
HAL_I2C_Master_Abort_IT(pCfg->pHi2c, msg->addr << 1);
rt_mutex_release(pCfg->lock);
goto __exit;
}
rt_mutex_release(pCfg->lock);
xfer_len++;
}
}
__exit:
if (xfer_len == num) {
ret = xfer_len;
}
return ret;
}
/* Hard I2C initialization function */
int rt_hw_hardi2c_init(void)
{
int result = RT_ERROR;
char name[RT_NAME_MAX];
rt_size_t obj_num = sizeof(hard_i2c_config) / sizeof(struct stm32_hard_i2c_config);
for (int i = 0; i < obj_num; i++)
{
/* Step 1: start to init i2c bus GPIO to OD mode */
hard_i2c_gpio_configure(&hard_i2c_config);
/* Step 2: To check SDA is or not pull-down, when is pull-down to send 9-clocks unlock bus */
hard_i2c_bus_unlock(&hard_i2c_config);
/* Step 3: To configurate hard I2C bus by speed */
hard_i2c_config.pInitFunc(hard_i2c_config.speed);
/* Step 4: register bus to kernel */
result = rt_i2c_bus_device_register(&(hard_i2c_config.i2c_bus), hard_i2c_config.bus_name);
if (result != RT_EOK)
{
LOG_E("%s bus init failed!", hard_i2c_config.bus_name);
result |= RT_ERROR;
}
else
{
LOG_I("%s bus init success!", hard_i2c_config.bus_name);
result |= RT_EOK;
}
/* Step 5: create mutex and notice semaphore */
if (result == RT_EOK)
{
/* mutex lock create */
rt_memset(name, 0, RT_NAME_MAX);
rt_snprintf(name, RT_NAME_MAX, "%s_l", hard_i2c_config.bus_name);
hard_i2c_config.lock = rt_mutex_create(name, RT_IPC_FLAG_FIFO);
/* tx sem notice create */
rt_memset(name, 0, RT_NAME_MAX);
rt_snprintf(name, RT_NAME_MAX, "%s_st", hard_i2c_config.bus_name);
hard_i2c_config.tx_notice = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO);
/* rx sem notice create */
rt_memset(name, 0, RT_NAME_MAX);
rt_snprintf(name, RT_NAME_MAX, "%s_sr", hard_i2c_config.bus_name);
hard_i2c_config.rx_notice = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO);
}
if ((hard_i2c_config.lock != RT_NULL) && \
(hard_i2c_config.tx_notice != RT_NULL) && (hard_i2c_config.rx_notice != RT_NULL))
{
LOG_E("%s bus variables init failed!", hard_i2c_config.bus_name);
result |= RT_ERROR;
}
}
return result;
}
INIT_BOARD_EXPORT(rt_hw_hardi2c_init);
#endif
drv_hard_i2c.h___________________________________________________________________________
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-20 cheung first version
*/
#ifndef __DRV_I2C__
#define __DRV_I2C__
#include <rtthread.h>
#include <rthw.h>
#include <rtdevice.h>
#include <board.h>
#ifdef RT_USING_HARD_I2C
/* stm32 config class */
typedef void (*pI2CInit)(rt_uint32_t speed);
struct stm32_hard_i2c_config
{
const char *bus_name;
const char *scl_pin_name;
const char *sda_pin_name;
rt_uint32_t speed;
pI2CInit pInitFunc;
I2C_HandleTypeDef *pHi2c;
struct rt_i2c_bus_device i2c_bus;
/* notice and lock define */
rt_sem_t tx_notice;
rt_sem_t rx_notice;
rt_mutex_t lock;
};
int rt_hw_hardi2c_init(void);
#endif
#endif /* RT_USING_I2C */
还需要在RT-Thread Setting 中关闭 “使用GPIO模拟I2C”
|
|