OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 372|回复: 1

RT-Thread 硬件I2C驱动,结果验证,可以使用

[复制链接]

22

主题

49

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
214
金钱
214
注册时间
2014-4-30
在线时间
26 小时
发表于 2023-12-28 22:41:40 | 显示全部楼层 |阅读模式
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”

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

22

主题

49

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
214
金钱
214
注册时间
2014-4-30
在线时间
26 小时
 楼主| 发表于 2023-12-28 22:42:50 | 显示全部楼层
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 22:19

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表