【Zephyr】02_从零教你开发芯片级ADC驱动(HAL层篇)
文章目录
- 前言
- 一、参考官方驱动API
- 1.1:基础API
- 1.2:参数结构体
- 二、功能函数操作逻辑梳理
- 2.1:系统初始化逻辑:
- 2.2:ADC配置初始化
- 2.3:ADC通道配置
- 2.4:原始数据获取
- 2.5:校准函数
- 三、HAL层函数定义
- 四、HAL层函数验证
- 4.1:验证方法论
- 4.2:验证过程
- 4.2.1:时钟使能(0x401800F0-bit0)
- 4.2.2:通道使能(0x4018C000)
- 4.2.2:时钟源分频(0x4018C000-bit30-28)
- 4.2.3:功能函数验证(0x4018C044)
- 总结
前言
本文详细记录了Zephyr下ADC驱动开发中硬件抽象层(HAL)的设计与实现过程。HAL层作为连接底层硬件与上层驱动的重要桥梁,其设计质量直接影响驱动的稳定性和可移植性。文档包含HAL层接口设计、功能函数实现、验证方法及结果分析等内容。
一、参考官方驱动API
1.1:基础API
typedef int (*adc_api_channel_setup)(const struct device *dev,const struct adc_channel_cfg *channel_cfg);typedef int (*adc_api_read)(const struct device *dev,const struct adc_sequence *sequence);
重要说明:ADC驱动API有两个功能函数,为保证与官方统一,传入的参数与我们在HAL层头文件定义的结构体相同
- 通道初始化:adc_api_channel_setup(),
需要传入的结构体adc_channel_cfg
- 数据读取:adc_api_read(),
需要传入的结构体adc_sequence
1.2:参数结构体
struct adc_channel_cfg {enum adc_gain gain; // 增益选择enum adc_reference reference; // 参考电压选择uint16_t acquisition_time; // 采样时间uint8_t channel_id : 5; // 通道ID (0-31)uint8_t differential : 1; // 差分模式标志// 可选字段(根据CONFIG_ADC_CONFIGURABLE_INPUTS)uint8_t input_positive; // 正输入uint8_t input_negative; // 负输入(差分模式)
};
struct adc_sequence {const struct adc_sequence_options *options; // 序列选项uint32_t channels; // 通道位掩码void *buffer; // 数据缓冲区size_t buffer_size; // 缓冲区大小uint8_t resolution; // 分辨率uint8_t oversampling; // 过采样bool calibrate; // 校准标志
};
说明:
- adc_channel_cfg:我们在HAL层需要定义的channel_cfg结构体,仅需考虑acquisition_time和channel_id即可,但需要额外定义结构体,来获取其他参数。
- adc_sequence:同理在HAL层需要定义的adc_sequence结构体,仅需考虑channels即可,但需要额外定义结构体,来获取其他参数。
二、功能函数操作逻辑梳理
2.1:系统初始化逻辑:
- 门控clock使能
- 门控clock复位
- ADC总线时钟使能
- Timer使能(中断,延时)
2.2:ADC配置初始化
- 配置对应GPIO引脚为ADC功能
- 时钟源选择
- 时钟分频
- 必须功能:clean,首次抓换延迟
- 校准函数
- 配置ACQ采样时间持续寄存器
2.3:ADC通道配置
- 根据通道名称,配置对应GPIO引脚
- 模式选择:暂提供nolmal,单次,连续三种
- 若为连续模式:配置第11:8位采样时间间隔
- 启动通道
2.4:原始数据获取
- 根据指定通道获取数据
2.5:校准函数
- 校准数据误差,可使用默认值
三、HAL层函数定义
根据针对性的功能函数梳理,我们可以裁剪出以下HAL层函数:
//结构体初始化,将寄存器结构体指针指向基地址
void hal_kadc_module_init(void);
//时钟源选择与分频
void hal_kadc_clk_div_config(enum adc_ch_clk inclk,uint16_t div_clk);
//校准
void kadc_hal_calibrate(uint32_t pre,bool use_data_en,bool use_mod,bool use_en,uint32_t cal_data);
//采样维持时间
void kadc_hal_acq_time_config(uint32_t acq_time);
//模式配置
void kadc_hal_mode_config(uint16_t channel_id,enum kadc_ch_mode mode,uint16_t continue_mod_time_n);
//通道使能
void kadc_hal_enable(uint16_t channel_id,enum kadc_ch_en en);
//数据获取
uint32_t kadc_hal_get_data(uint16_t channel_id);
四、HAL层函数验证
4.1:验证方法论
在完成HAL层函数的编写,我们不急于马上进行驱动开发,为保证减少驱动层BUG的出现,应先对HAL层进行验证,确认每条函数是否正确将寄存器置位。
常用的验证方法:
- 应用层:main.c验证函数,且打印函数调用前后的寄存器信息
- 驱动层:编写Shell指令进行函数验证,且打印函数调用前后的寄存器信息
4.2:验证过程
4.2.1:时钟使能(0x401800F0-bit0)
- 置位前:
- 置位后:(01)
说明:bit0为使能位,可以验证得时钟使能函数操作正确!
4.2.2:通道使能(0x4018C000)
- 通道1置位后:(02)
说明:bit1为通道1使能位,各通道对应各bit,可以验证得通道使能函数操作正确!
4.2.2:时钟源分频(0x4018C000-bit30-28)
- 分频系数:3(30)
说明:bit30:28为分频系数位,可以验证得分频函数操作正确!
4.2.3:功能函数验证(0x4018C044)
-
3.3V通电状态:
说明:根据寄存器信息,当前ADC捕获值为4084,即当前电压为4084*3.3/4096=3.29V,功能正常! -
浮空状态
说明:根据寄存器信息,当前ADC捕获值为1412,即当前电压为1412*3.3/4096=1.13V,功能不正常!待确认。
总结
硬件抽象层(HAL)作为连接底层硬件与上层应用的桥梁,需实现标准化接口与硬件无关性设计。针对ADC模块开发时,需封装设备初始化、通道配置、采样触发、数据读取等基础功能。本文介绍了ADC驱动开发下HAL层开发的思路与验证手段,为后续驱动层开发减少了BUG的出现和调试的困难。