在线时间1944 小时
UID3338155
注册时间2017-7-26
NXP金币3170
TA的每日心情 | 奋斗 前天 10:11 |
---|
签到天数: 868 天 连续签到: 2 天 [LV.10]以坛为家III
金牌会员
 
- 积分
- 10400
- 最后登录
- 2025-8-22
|
本帖最后由 andeyqi 于 2024-1-5 22:49 编辑
概述: 以下链接是官方对I2C设备驱动的介绍,可以从中了解下I2C驱动模型的结构。
RT-Thread I2C 驱动框架提供了一个结构化的方式来支持 I2C 总线通信,方便统一的接口方式访问 I2C 设备。RT-Thread I2C 驱动框架主要包括两个层次的抽象: I2C 驱动的核心文件是i2c_core.c,对应的核心结构体为rt_i2c_bus_device, 该结构体是 RT-Thread 中定义的用于表示 I2C 总线设备的结构体。它包含了一些关键的字段,用于描述和管理具体的 I2C 总线。以下是 rt_i2c_bus_device 结构体的主要字段和功能
- /*for i2c bus driver*/
- struct rt_i2c_bus_device
- {
- struct rt_device parent;/* 设备基类 device */
- const struct rt_i2c_bus_device_ops *ops;/* I2C 下操作方法 */
- rt_uint16_t flags;/* I2C 支持的读写标志等 */
- struct rt_mutex lock;/* 互斥锁,保证多线程范访问安全 */
- rt_uint32_t timeout; /* 超时时间 */
- rt_uint32_t retries; /* retry 次数 */
- void *priv;/* 私有数据 */
- };
复制代码
对于适配I2C总线驱动,我们只需关注struct rt_i2c_bus_device_ops *ops成员即可,ops 成员定义了I2C 总线的访问方法定义如下:
- struct rt_i2c_bus_device_ops
- {
- rt_ssize_t (*master_xfer)(struct rt_i2c_bus_device *bus,
- struct rt_i2c_msg msgs[],
- rt_uint32_t num);
- rt_ssize_t (*slave_xfer)(struct rt_i2c_bus_device *bus,
- struct rt_i2c_msg msgs[],
- rt_uint32_t num);
- rt_err_t (*i2c_bus_control)(struct rt_i2c_bus_device *bus,
- int cmd,
- void *args);
- };
复制代码 本地使用的S32K开发板是master 须实现master_xfer函数,slave_xfer/i2c_bus_control 没有实现不过不影响我们使用I2C总线访问通过RT-thread i2c 驱动框架本地实现代码如下:
- /*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include "drv_i2c.h"
- #include "board.h"
- struct s32k_i2c
- {
- struct rt_i2c_bus_device bus;
- char *device_name;
- rt_uint32_t instance;
- rt_uint32_t timeout;
- lpi2c_master_state_t state;
- };
- static rt_ssize_t master_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num)
- {
- rt_ssize_t ret = (0);
- rt_uint32_t index = 0;
- struct s32k_i2c *i2c = RT_NULL;
- struct rt_i2c_msg *msg = RT_NULL;
- status_t result = STATUS_SUCCESS;
- bool stop = false;
-
- i2c = (struct s32k_i2c *)bus;
-
- LPI2C_DRV_MasterSetSlaveAddr(i2c->instance,msgs[0].addr,false);
-
- for(index = 0; index < num; index++)
- {
- if(index == (num-1))
- stop = true;
-
- msg = &msgs[index];
-
- if(RT_I2C_RD & msg->flags)
- {
- result = LPI2C_DRV_MasterReceiveDataBlocking(i2c->instance, msg->buf,msg->len, stop , i2c->timeout);
- }
- else
- {
- result = LPI2C_DRV_MasterSendDataBlocking(i2c->instance, (const uint8_t * )msg->buf,msg->len, stop , i2c->timeout);
- }
-
- if(result != STATUS_SUCCESS)
- break;
- }
-
- if (result == STATUS_SUCCESS)
- {
- ret = index;
- }
- return ret;
- }
- static rt_ssize_t slave_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num)
- {
- return -RT_ENOSYS;
- }
- static rt_err_t i2c_bus_control(struct rt_i2c_bus_device *bus, int cmd, void *args)
- {
- return -RT_EINVAL;
- }
- static const struct rt_i2c_bus_device_ops ops =
- {
- master_xfer,
- slave_xfer,
- i2c_bus_control,
- };
- extern void LPI2C0_Master_IRQHandler(void);
- void S32K14X_LPI2C0_Master_Slave_IRQHandler(void)
- {
- /* enter interrupt */
- rt_interrupt_enter();
- LPI2C0_Master_IRQHandler();
- /* leave interrupt */
- rt_interrupt_leave();
- }
- static struct s32k_i2c i2c0 = {0};
- int rt_hw_i2c_init(void)
- {
-
- i2c0.device_name = "i2c0";
- i2c0.bus.ops = &ops;
- i2c0.instance = INST_LPI2C0;
- i2c0.timeout = 500;
-
- INT_SYS_InstallHandler(LPI2C0_Master_IRQn,S32K14X_LPI2C0_Master_Slave_IRQHandler,NULL);
-
- /* init i2c0 bus */
- LPI2C_DRV_MasterInit(i2c0.instance, &lpi2c0_MasterConfig0, &i2c0.state);
-
- rt_i2c_bus_device_register(&i2c0.bus, i2c0.device_name);
- return RT_EOK;
- }
- INIT_APP_EXPORT(rt_hw_i2c_init);
复制代码
上面的代码里我们使用了S32 SDK 的LPI2C_DRV_MasterReceiveDataBlocking/LPI2C_DRV_MasterSendDataBlocking 的API函数,但是S32的SDK 的这些接口时跟OS 相耦合的,在 S32K Software Development Kit (SDK) 中存在一个OSIF层,OSIF (Operating System Interface) 层是一个抽象层,用于提供操作系统相关的接口,使得 S32K SDK 可以在不同的操作系统上运行。OSIF 层包含了对于操作系统的适配接口,互斥锁、信号量等。这种设计使得 S32K SDK 能够灵活地在不同的实时操作系统 (RTOS) 上运行。以下图片可以看出OS 和 接口之间夹杂了osif 我们需要实现基于RT-thread 实现osif 相关的接口。
OSIF 依赖OS 相关的接口如下。
按照上面的要是求SDK OS相关的依赖。osif_rtthread.c
- /*
- * Copyright (c) 2016, Freescale Semiconductor, Inc.
- * Copyright 2016-2020 NXP
- * All rights reserved.
- *
- * NXP Confidential. This software is owned or controlled by NXP and may only be
- * used strictly in accordance with the applicable license terms. By expressly
- * accepting such terms or by downloading, installing, activating and/or otherwise
- * using the software, you are agreeing that you have read, and that you agree to
- * comply with and are bound by, such license terms. If you do not agree to be
- * bound by the applicable license terms, then you may not retain, install,
- * activate or otherwise use the software. The production use license in
- * Section 2.3 is expressly granted for this software.
- */
- /*!
- * @file osif_freertos.c
- *
- * @page misra_violations MISRA-C:2012 violations
- *
- * @section [global]
- * Violates MISRA 2012 Required Rule 1.3, Taking address of near auto variable
- * The code is not dynamically linked. An absolute stack address is obtained when
- * taking the address of the near auto variable. A source of error in writing
- * dynamic code is that the stack segment may be different from the data segment.
- *
- * @section [global]
- * Violates MISRA 2012 Advisory Directive 4.9, Function-like macro defined.
- * The macros are used to validate input parameters to driver functions.
- *
- * @section [global]
- * Violates MISRA 2012 Required Rule 7.2, Unsigned integer literal without a 'U' suffix
- * Register address defined by FreeRTOS header files.
- *
- * @section [global]
- * Violates MISRA 2012 Advisory Rule 8.7, External could be made static.
- * Function is defined for usage by application code.
- *
- * @section [global]
- * Violates MISRA 2012 Advisory Rule 8.13, Pointer variable could be declared as pointing to const
- * Type definition is done in FreeRTOS header files.
- *
- * @section [global]
- * Violates MISRA 2012 Advisory Rule 11.4, Conversion between a pointer and integer type.
- * The cast is required to initialize a pointer with an unsigned long define, representing an address.
- *
- * @section [global]
- * Violates MISRA 2012 Required Rule 11.6, Cast from unsigned int to pointer.
- * This is required for initializing pointers to the module's memory map, which is located at a
- * fixed address.
- *
- */
- #include <stdbool.h>
- #include "device_registers.h"
- #include "osif.h"
- #include "devassert.h"
- #if !defined (USING_OS_RTTHREAD)
- #error "Wrong OSIF selected. Please define symbol USING_OS_RTTHREAD in project settings or change the OSIF variant"
- #endif
- /*******************************************************************************
- * Variables
- ******************************************************************************/
- static rt_atomic_t osifid = 0;
- /*******************************************************************************
- * Private Functions
- ******************************************************************************/
- /*******************************************************************************
- * Code
- ******************************************************************************/
- /*FUNCTION**********************************************************************
- *
- * Function Name : OSIF_TimeDelay
- * Description : This function blocks (sleep) the current thread for a number
- * of milliseconds.
- *
- * Implements : OSIF_TimeDelay_freertos_Activity
- *END**************************************************************************/
- void OSIF_TimeDelay(uint32_t delay)
- {
- /* One dependency for FreeRTOS config file */
- /* INCLUDE_vTaskDelay */
- rt_thread_mdelay(delay);
- }
- /*FUNCTION**********************************************************************
- *
- * Function Name : OSIF_GetMilliseconds
- * Description : This function returns the number of miliseconds elapsed since
- * starting the internal timer (since scheduler was started).
- *
- * Implements : OSIF_GetMilliseconds_freertos_Activity
- *END**************************************************************************/
- uint32_t OSIF_GetMilliseconds(void)
- {
- /*
- * Return the tick count in miliseconds
- * Note: if configTICK_RATE_HZ is less than 1000, the return value will be truncated
- * to 32-bit wide for large values of the tick count.
- */
- return (uint32_t)(rt_tick_get_millisecond());
- }
- /*FUNCTION**********************************************************************
- *
- * Function Name : OSIF_MutexLock
- * Description : This function obtains the mutex lock or returns error if timeout.
- *
- * Implements : OSIF_MutexLock_freertos_Activity
- *END**************************************************************************/
- status_t OSIF_MutexLock(const mutex_t * const pMutex,
- const uint32_t timeout)
- {
- /* The (pMutex == NULL) case is a valid option, signaling that the mutex does
- * not need to be locked - do not use DEV_ASSERT in this case */
- status_t osif_ret_code = STATUS_SUCCESS;
-
- if (pMutex != NULL)
- {
- rt_err_t ret = rt_mutex_take(pMutex->handle,timeout);
- osif_ret_code = (ret == RT_EOK) ? STATUS_SUCCESS : STATUS_ERROR;
- }
- return osif_ret_code;
- }
- /*FUNCTION**********************************************************************
- *
- * Function Name : OSIF_MutexUnlock
- * Description : This function unlocks the mutex, fails if the current thread
- * is not the mutex holder.
- *
- * Implements : OSIF_MutexUnlock_freertos_Activity
- *END**************************************************************************/
- status_t OSIF_MutexUnlock(const mutex_t * const pMutex)
- {
- /* The (pMutex == NULL) case is a valid option, signaling that the mutex does
- * not need to be unlocked - do not use DEV_ASSERT in this case */
- status_t osif_ret_code = STATUS_SUCCESS;
- if (pMutex != NULL)
- {
- rt_err_t ret = rt_mutex_release(pMutex->handle);
- osif_ret_code = (ret == RT_EOK) ? STATUS_SUCCESS : STATUS_ERROR;
- }
-
- return osif_ret_code;
- }
- /*FUNCTION**********************************************************************
- *
- * Function Name : OSIF_MutexCreate
- * Description : This function creates (registers) a mutex object to the OS.
- *
- * Implements : OSIF_MutexCreate_freertos_Activity
- *END**************************************************************************/
- status_t OSIF_MutexCreate(mutex_t * const pMutex)
- {
- /* The (pMutex == NULL) case is a valid option, signaling that the mutex does
- * not need to be created - do not use DEV_ASSERT in this case */
- char name[RT_NAME_MAX] = {'\0'};
- rt_atomic_add(&(osifid), 1);
-
- rt_sprintf(name,"oi%d",osifid);
-
- pMutex->handle = rt_mutex_create(name, RT_IPC_FLAG_PRIO);
- return pMutex->handle ? STATUS_SUCCESS: STATUS_ERROR;
- }
- /*FUNCTION**********************************************************************
- *
- * Function Name : OSIF_MutexDestroy
- * Description : This function removes the mutex from the OS (and frees memory).
- *
- * Implements : OSIF_MutexDestroy_freertos_Activity
- *END**************************************************************************/
- status_t OSIF_MutexDestroy(const mutex_t * const pMutex)
- {
- /* The (pMutex == NULL) case is a valid option, signaling that the mutex does
- * not need to be destroyed - do not use DEV_ASSERT in this case */
- rt_mutex_delete(pMutex->handle);
-
- return STATUS_SUCCESS;
- }
- /*FUNCTION**********************************************************************
- *
- * Function Name : OSIF_SemaWait
- * Description : This function performs the 'wait' (decrement) operation on a semaphore,
- * returns error if operation times out.
- *
- * Implements : OSIF_SemaWait_freertos_Activity
- *END**************************************************************************/
- status_t OSIF_SemaWait(semaphore_t * const pSem,
- const uint32_t timeout)
- {
- DEV_ASSERT(pSem);
- rt_err_t ret;
-
- if(OSIF_WAIT_FOREVER == timeout)
- {
- ret = rt_sem_take(pSem->handle,RT_WAITING_FOREVER);
- }
- else
- {
- ret = rt_sem_take(pSem->handle,timeout);
- }
- return ret == RT_EOK ? STATUS_SUCCESS : STATUS_ERROR;
- }
- /*FUNCTION**********************************************************************
- *
- * Function Name : OSIF_SemaPost
- * Description : This function performs the 'post' (increment) operation on a semaphore.
- *
- * Implements : OSIF_SemaPost_freertos_Activity
- *END**************************************************************************/
- status_t OSIF_SemaPost(semaphore_t * const pSem)
- {
- DEV_ASSERT(pSem);
- //status_t osif_ret_code;
- rt_sem_release(pSem->handle);
-
- return STATUS_SUCCESS;
- }
- /*FUNCTION**********************************************************************
- *
- * Function Name : OSIF_SemaCreate
- * Description : This function creates (registers) a semaphore object to the OS.
- *
- * Implements : OSIF_SemaCreate_freertos_Activity
- *END**************************************************************************/
- status_t OSIF_SemaCreate(semaphore_t * const pSem,
- const uint8_t initValue)
- {
- DEV_ASSERT(pSem);
- char name[RT_NAME_MAX] = {'\0'};
-
- rt_atomic_add(&(osifid), 1);
-
- rt_sprintf(name,"oi%d",osifid);
-
- pSem->handle = rt_sem_create((const char *)name, initValue, RT_IPC_FLAG_PRIO);
- return pSem->handle ? STATUS_SUCCESS: STATUS_ERROR;
- }
- /*FUNCTION**********************************************************************
- *
- * Function Name : OSIF_SemaDestroy
- * Description : This function removes a semaphore object from the OS (frees memory).
- *
- * Implements : OSIF_SemaDestroy_freertos_Activity
- *END**************************************************************************/
- status_t OSIF_SemaDestroy(const semaphore_t * const pSem)
- {
- DEV_ASSERT(pSem);
- rt_sem_delete(pSem->handle);
-
- return STATUS_SUCCESS;
- }
- /*******************************************************************************
- * EOF
- ******************************************************************************/
复制代码 osif.h更新
- /*
- * Copyright (c) 2016, Freescale Semiconductor, Inc.
- * Copyright 2016-2020 NXP
- * All rights reserved.
- *
- * NXP Confidential. This software is owned or controlled by NXP and may only be
- * used strictly in accordance with the applicable license terms. By expressly
- * accepting such terms or by downloading, installing, activating and/or otherwise
- * using the software, you are agreeing that you have read, and that you agree to
- * comply with and are bound by, such license terms. If you do not agree to be
- * bound by the applicable license terms, then you may not retain, install,
- * activate or otherwise use the software. The production use license in
- * Section 2.3 is expressly granted for this software.
- */
- #ifndef OSIF_H
- #define OSIF_H
- #include <stdint.h>
- /**
- * @page misra_violations MISRA-C:2012 violations
- *
- * @section [global]
- * Violates MISRA 2012 Advisory Rule 2.5, Global macro not referenced.
- * The macro defines a value that will be interpreted as an infinite timeout.
- *
- */
- /*! @file */
- /*!
- * @addtogroup osif
- * @{
- */
- /*******************************************************************************
- * Definitions
- ******************************************************************************/
- /*! @cond DRIVER_INTERNAL_USE_ONLY */
- #ifdef USING_OS_FREERTOS
- /* FreeRTOS implementation */
- #include "FreeRTOS.h"
- #include "semphr.h"
- #if configSUPPORT_STATIC_ALLOCATION == 1
- typedef struct {
- SemaphoreHandle_t handle;
- StaticSemaphore_t buffer;
- } semaphore_t;
- typedef semaphore_t mutex_t;
- #else /* configSUPPORT_STATIC_ALLOCATION == 0, it's dynamic allocation */
- /*! @brief Type for a mutex. */
- typedef SemaphoreHandle_t mutex_t;
- /*! @brief Type for a semaphore. */
- typedef SemaphoreHandle_t semaphore_t;
- #endif /* configSUPPORT_STATIC_ALLOCATION == 1 */
-
- #elif defined(USING_OS_RTTHREAD)
- #include <rtthread.h>
- typedef struct {
- rt_sem_t handle;
- } semaphore_t;
-
- typedef struct{
- rt_mutex_t handle;
- }mutex_t;
- #else
- /* Bare-metal implementation */
- /*! @brief Type for a mutex. */
- typedef uint8_t mutex_t;
- /*! @brief Type for a semaphore. */
- typedef volatile uint8_t semaphore_t;
- #endif /* ifdef USING_OS_FREERTOS */
- /*! @endcond */
- #define OSIF_WAIT_FOREVER 0xFFFFFFFFu
- #include "status.h"
- /*******************************************************************************
- * API
- ******************************************************************************/
- #if defined (__cplusplus)
- extern "C" {
- #endif
- /*!
- * @brief Delays execution for a number of milliseconds.
- *
- * @param[in] delay Time delay in milliseconds.
- */
- void OSIF_TimeDelay(const uint32_t delay);
- /*!
- * @brief Returns the number of miliseconds elapsed since starting the internal timer
- * or starting the scheduler.
- *
- * @return the number of miliseconds elapsed
- */
- uint32_t OSIF_GetMilliseconds(void);
- /*!
- * @brief Waits for a mutex and locks it.
- *
- * @param[in] pMutex reference to the mutex object
- * @param[in] timeout time-out value in milliseconds
- * @return One of the possible status codes:
- * - STATUS_SUCCESS: mutex lock operation success
- * - STATUS_ERROR: mutex already owned by current thread
- * - STATUS_TIMEOUT: mutex lock operation timed out
- *
- */
- status_t OSIF_MutexLock(const mutex_t * const pMutex,
- const uint32_t timeout);
- /*!
- * @brief Unlocks a previously locked mutex.
- *
- * @param[in] pMutex reference to the mutex object
- * @return One of the possible status codes:
- * - STATUS_SUCCESS: mutex unlock operation success
- * - STATUS_ERROR: mutex unlock failed
- */
- status_t OSIF_MutexUnlock(const mutex_t * const pMutex);
- /*!
- * @brief Create an unlocked mutex.
- *
- * @param[in] pMutex reference to the mutex object
- * @return One of the possible status codes:
- * - STATUS_SUCCESS: mutex created
- * - STATUS_ERROR: mutex could not be created
- */
- status_t OSIF_MutexCreate(mutex_t * const pMutex);
- /*!
- * @brief Destroys a previously created mutex.
- *
- * @param[in] pMutex reference to the mutex object
- * @return One of the possible status codes:
- * - STATUS_SUCCESS: mutex destroyed
- */
- status_t OSIF_MutexDestroy(const mutex_t * const pMutex);
- /*!
- * @brief Decrement a semaphore with timeout.
- *
- * @param[in] pSem reference to the semaphore object
- * @param[in] timeout time-out value in milliseconds
- * @return One of the possible status codes:
- * - STATUS_SUCCESS: semaphore wait operation success
- * - STATUS_TIMEOUT: semaphore wait timed out
- */
- status_t OSIF_SemaWait(semaphore_t * const pSem,
- const uint32_t timeout);
- /*!
- * @brief Increment a semaphore
- *
- * @param[in] pSem reference to the semaphore object
- * @return One of the possible status codes:
- * - STATUS_SUCCESS: semaphore post operation success
- * - STATUS_ERROR: semaphore could not be incremented
- */
- status_t OSIF_SemaPost(semaphore_t * const pSem);
- /*!
- * @brief Creates a semaphore with a given value.
- *
- * @param[in] pSem reference to the semaphore object
- * @param[in] initValue initial value of the semaphore
- * @return One of the possible status codes:
- * - STATUS_SUCCESS: semaphore created
- * - STATUS_ERROR: semaphore could not be created
- */
- status_t OSIF_SemaCreate(semaphore_t * const pSem,
- const uint8_t initValue);
- /*!
- * @brief Destroys a previously created semaphore.
- *
- * @param[in] pSem reference to the semaphore object
- * @return One of the possible status codes:
- * - STATUS_SUCCESS: semaphore destroyed
- */
- status_t OSIF_SemaDestroy(const semaphore_t * const pSem);
- /*! @}*/
- #if defined (__cplusplus)
- }
- #endif
- /*! @}*/
- #endif /* OSIF_H */
- /*******************************************************************************
- * EOF
- ******************************************************************************/
复制代码
至此I2C 驱动程序已经适配完成,后续使用RT-thread 的I2C-tool 软件包来验证I2C总线通信状况详见(https://www.nxpic.org.cn/module/forum/thread-802558-1-1.html)
|
|