1 概述
在rt-thread配置外设原本是妥妥的轻松,不过,这次在APM32E030R Micro-EVB却踩了一个坑。续前帖子,配置外设,从menuconfig就可以轻松搞定,但是,对于新的开发板,还是在移植上有不少的地方,还是需要微调才行。
2 配置ADC
还是启动menuconfig,进入到chip芯片的硬件配置,这个是配置外设,需要选中Enable ADC就是是能ADC的功能,这个开关就把rtthread的ADC驱动导入工程,
记住还要选择ADC1,这个是选择ADC的通道的,必选
然后点击存储,继续存在配置文件中,然后退出则可
3 踩坑并排查
编译工程,立刻就出现了状况,显示ADC1和ADC2没有定义,无法生成二进制文件
找到这个对应的文件所在,进行如下修改。原代码在这里并没有专门设置对应于芯片的配置,APM32E030R
Micro-EVB只有一个ADC通道,所以,在官方的驱动中,就不再分ADC1和ADC2等,所以,如果没有选择定义,就出现了这样的情况。看似解决问题很容易,但是需要逐条语句排查硬件pack代码中对应ADC部分的全部定义和参数配置,再对照rt-thread的定义阵列都正确定义,最后可以顺利编译通过。需要队底层驱动和rt-thread都比较了解才好,
static rt_err_t apm32_adc_channel_check(struct rt_adc_device *device, rt_uint32_t channel) { struct apm32_adc *adc_cfg = ((struct apm32_adc *)device->parent.user_data); #if defined(SOC_SERIES_APM32F0) || defined(SOC_SERIES_APM32E0) if ((adc_cfg->adc == ADC) ) { if (channel <= 18) { return RT_EOK; } } #endif #if defined(SOC_SERIES_APM32F1) || defined(SOC_SERIES_APM32E1) || defined(SOC_SERIES_APM32S1) if ((adc_cfg->adc == ADC1) || (adc_cfg->adc == ADC2)) { if (channel <= 15) { return RT_EOK; } } #endif #if defined(SOC_SERIES_APM32F1) || defined(SOC_SERIES_APM32E1) if (adc_cfg->adc == ADC3) { if (channel <= 8) { return RT_EOK; } } #endif #if defined(SOC_SERIES_APM32F4) if (adc_cfg->adc == ADC3) { if (channel <= 13) { return RT_EOK; } } #endif LOG_E("channel %d of %s is not supported.", channel, adc_cfg->name); return -RT_ERROR; }
这次编译顺利通过,但还有一些报警,直接无视
4 下载并运行
采用pyocd flash写入开发板,注意,对应于开发板的定义需要和pack中的定义一致,如APM32E030就不能通过,这里是APM32E030R8,才行
写入开发板,顺利读出ADC口的数据,
在代码中加入了main的命令,在msh中输入main的指令,就可以再次执行,实现会话式读取ADC的数据
5 补充,代码分析
#include <rtthread.h> #include <rtdevice.h> #include <board.h> #define ADC_DEV_NAME "adc1" /* ADC 设备名称 */ #define ADC_DEV_CHANNEL 5 /* ADC 通道 */ #define REFER_VOLTAGE 330 /* 参考电压 3.3V,数据精度乘以100保留2位小数*/ #define CONVERT_BITS (1 << 12) /* 转换位数为12位 */ /* defined the LED2 pin: PB6 */ #define LED2_PIN GET_PIN(B, 6) int main(void) { /* set LED2 pin mode to output */ rt_pin_mode(LED2_PIN, PIN_MODE_OUTPUT); rt_adc_device_t adc_dev; rt_uint32_t value, vol; rt_err_t ret = RT_EOK; /* 查找设备 */ adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME); if (adc_dev == RT_NULL) { rt_kprintf("adc sample run failed! can't find %s device!\n", ADC_DEV_NAME); return RT_ERROR; } /* 使能设备 */ ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL); /* 读取采样值 */ value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL); rt_kprintf("the value is :%d \n", value); /* 转换为对应电压值 */ vol = value * REFER_VOLTAGE / CONVERT_BITS; rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100); /* 关闭通道 */ ret = rt_adc_disable(adc_dev, ADC_DEV_CHANNEL); while (1) { rt_pin_write(LED2_PIN, PIN_HIGH); rt_thread_mdelay(500); rt_pin_write(LED2_PIN, PIN_LOW); rt_thread_mdelay(500); } return RT_EOK; } MSH_CMD_EXPORT(main, adc voltage convert sample);
在这些配置中,按照rt-thread的工作逻辑,都是需要先创建一个设备,这里是ADC设备,然后直接使能改设备
ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
随后就可以读取数据了,adc_dev是定义的adc外设设备,选择通道就可以。
本来,对应于APM32E030,在通道17,通道18分别有芯片温度读取和芯片电压读取,
但是这个rt-thread的驱动配置,为了整个APM32都适配,加了一个判断语句,最大的通道是16,在整个代码段里多次定义,所以,这里没有办法单独访问这两个
通道的adc数据。但是对应外部的参数,按照数据表格里面对应指定的引脚,是可以比较容易的实现的。
这里就是通道5对应的引脚
6 小结
配合这个小小的踩坑过程,可以比较完整的显示如何配置一个rtthread工程,并且在哪里进行驱动修改,如何进行修改。其他的外设,如PWM,RTC等都是完全一样的,实际发现,配置完还是都需要有所修改和调整的,整个过程可玩性不错。效果还是挺好的。