RT-Thread源码解读-------ADC设备

本文深入解析了RT-Thread操作系统中ADC设备的源码,从应用层API到框架实现再到底层半导体驱动。介绍了rt_adc_enable、rt_adc_read等关键函数的实现,并探讨了应用层接口与底层硬件操作的关系,以及对RT-Thread ADC框架设计的两点思考。
摘要由CSDN通过智能技术生成

一、ADC简介
ADC指的是模拟量转换成数字量,一般是将模拟的电压或者电流信号转换成数字量。这里要说明一下,在RT-Thread源码中所说的ADC设备指的一般是MCU内部的ADC模块(大家可以理解为能够直接操作ADC工作参数的模块)。笔者在项目开发过程中使用过一些检测身体特征的传感器(心率传感器),这些传感器本质上就是一个ADC转换成器,将采集的模拟类型的身体信号转换成数字量,然后经过像I2C或者SPI等通信协议传送给MCU。那么这些传感器,在RT-Thread内核中并不会将它们视为ADC设备,而是将它们视为I2C或者SPI设备(这具体根据传感器与MCU采用的通信方式来界定的)。
我还是采用从应用层一步一步向底层代码探究的方式剖析ADC设备源码。首先讲解应用层API接口的使用;接着讲解ADC框架的源码;最后讲解半导体厂商的底层实现。
ADC设备介绍
二、ADC设备源码剖析
应用程序通过 RT-Thread 提供的 ADC 设备管理接口来访问 ADC 硬件,相关接口如下所示:
在这里插入图片描述1、rt_device_find
对于发现ADC设备和发现UART设备内部实现是一样的,只需要将ADC设备名称作为该函数的参数就可以了。具体的代码解析,可以看我写的关于UART设备的文章。
2、rt_adc_enable
a、应用层API接口
在读取 ADC 设备数据前需要先使能设备,通过如下函数使能设备:
在这里插入图片描述b、框架实现
rt_adc_enable函数在RT-Thread内部框架实现代码如下:

rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_uint32_t channel)
{
   
    rt_err_t result = RT_EOK;

    RT_ASSERT(dev);
    if (dev->ops->enabled != RT_NULL)
    {
   
        result = dev->ops->enabled(dev, channel, RT_TRUE);//调用底层的ADC开启函数
    }
    else
    {
   
        result = -RT_ENOSYS;
    }

    return result;
}

该函数其实就是做一件事,当应用层调用该函数打开ADC设备时,该函数会执行最关键的一步:result = dev->ops->enabled(dev, channel, RT_TRUE); 。该函数会执行底层操作硬件的代码,打开ADC设备。比如说,如果我们使用的是STM32,那么该函数就会打开ADC片内外设。
c、底层实现(半导体或者硬件驱动需要做的事)
如果我们使用的是STM32芯片,那么当应用层调用函数rt_adc_enable打开ADC设备时,最终会执行的底层函数为stm32_adc_enabled。函数stm32_adc_enabled最终会操作硬件相关的代码打开ADC设备。挖坑你可能会产生疑问,我是怎么知道的会调用该函数。请不要着急,我会在本文章的后面进行讲解,我们先看一下该函数的具体实现,上代码:

static rt_err_t stm32_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled)
{
   
    ADC_HandleTypeDef *stm32_adc_handler;
    RT_ASSERT(device != RT_NULL);
    stm32_adc_handler = device->parent.user_data;

    if (enabled)
    {
   
#if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0)
        ADC_Enable(stm32_adc_handler);
#else
        __HAL_ADC_ENABLE(stm32_adc_handler);//调用HAL库代码实现打开片内ADC模块
#endif
    }
    else
    {
   
#if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0)
        ADC_Disable(stm32_adc_handler);
#else
        __HAL_ADC_DISABLE(stm32_adc_handler);//调用HAL代码实现关闭片内ADC模块
#endif
    }

    return RT_EOK;
}

大家可以看到在函数stm32_adc_enabled有很多宏,这里会根据我们使用的具体的STM32平台执行不同的函数。我们假设使用的是STM32F4X系列的MCU,则需要执行的代码是__HAL_ADC_ENABLE(stm32_adc_handler); 。继续贴代码(代码所在文件:Stm32f4xx_hal_adc.h (bsp\stm32\libraries\stm32f4xx_hal\stm32f4xx_hal_driver\inc)):

/**
  * @brief  Enable the ADC peripheral.
  * @param  __HANDLE__ ADC handle
  * @retval None
  */
#define __HAL_ADC_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->CR2 |=  ADC_CR2_ADON)

是不是感觉很简单,就一行代码。我们继续贴代码:

#define ADC_CR2_ADON_Pos          (0U)                                         
#define ADC_CR2_ADON_Msk          (0x1UL << ADC_CR2_ADON_Pos)                   /*!< 0x00000001 */
#define ADC_CR2_ADON              ADC_CR2_ADON_Msk                             /*!<A/D Converter ON / OFF *///从这里可以看出是开启ADC转换器
/** 
  * @brief  ADC handle Structure definition
  */ 
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
typedef struct __ADC_HandleTypeDef
#else
typedef struct
#endif
{
   
  ADC_TypeDef                   *Instance;                   /*!< Register base address */

  ADC_InitTypeDef               Init;                        /*!< ADC required parameters */

  __IO uint32_t                 NbrOfCurrentConversionRank;  /*!< ADC number of current conversion rank */

  DMA_HandleTypeDef             *DMA_Handle;                 /*!< Pointer DMA Handler */

  HAL_LockTypeDef               Lock;                        /*!< ADC locking object */

  __IO uint32_t                 State;                       /*!< ADC communication state */

  __IO uint32_t                 ErrorCode;                   /*!< ADC Error code */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
  void (* ConvCpltCallback)(struct __ADC_HandleTypeDef *ha
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值