从上层往下,依次将
a. RTT层: rt-thread/components/drivers/misc/adc.c
b. 中间层:libraries/drv_lpadc.c
c. 硬件层:libraries/MIMXRT1176/drivers/fsl_lpadc.c
添加构建,
其中中间层的 drv_lpadc.c编译时报错,参照SDK做了些修改(注释掉的是修改前的代码)
static rt_err_t imxrt_hp_adc_convert(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value)
{
//LPADC1 *base; //Modified by Hao 22/08/01
ADC_Type *base;
lpadc_conv_command_config_t mLpadcCommandConfigStruct;
lpadc_conv_trigger_config_t mLpadcTriggerConfigStruct;
lpadc_conv_result_t mLpadcResultConfigStruct;
//base = (LPADC1_BASE *)(device->parent.user_data); //Modified by Hao 22/08/01
base = (ADC_Type *)(device->parent.user_data);
RTT官方链接
RTT对ADC的操作流程如下,但一次只能读取单个通道的数据,效率不高,所以根据应用编写自己的代码
#include
#include
#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位 */
static int adc_vol_sample(int argc, char *argv[])
{
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);
return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(adc_vol_sample, adc voltage convert sample);
我的需求是,一次性读取11个电位器的数据,
RT176的ADC分成两部分,ADC1和ADC2,
特别的是ADC1 的 channel1,还分成了 sideA 和 sideB,
所以正常调用 RTT的接口,无法读取sideB的数据。
lpadc_conv_command_config_t mLpadcCommandConfigStruct1;
mLpadcCommandConfigStruct1.sampleChannelMode = kLPADC_SampleChannelSingleEndSideB;
mLpadcCommandConfigStruct1.enableAutoChannelIncrement = true;
mLpadcCommandConfigStruct1.loopCount = 4;
//假如读取的第一个通道是 channel0,那么loopCount=4,就会读取channel0-4,一共5个通道的数据
mLpadcCommandConfigStruct1.chainedNextCommandNumber = 2;
//比如读取sideA五个通道的指令为1号,读取sideB四个通道的指令是2号,这句话的意思是,执行完1号指令就会执行2号指令
以下是NXP RT1176的代码,可以看出每次只会返回一个32位的数据,
但我们有11个通道怎么办?
bool LPADC_GetConvResult(ADC_Type *base, lpadc_conv_result_t *result)
{
assert(result != NULL); /* Check if the input pointer is available. */
uint32_t tmp32;
tmp32 = base->RESFIFO;
if (0U == (ADC_RESFIFO_VALID_MASK & tmp32))
{
return false; /* FIFO is empty. Discard any read from RESFIFO. */
}
result->commandIdSource = (tmp32 & ADC_RESFIFO_CMDSRC_MASK) >> ADC_RESFIFO_CMDSRC_SHIFT;
result->loopCountIndex = (tmp32 & ADC_RESFIFO_LOOPCNT_MASK) >> ADC_RESFIFO_LOOPCNT_SHIFT;
result->triggerIdSource = (tmp32 & ADC_RESFIFO_TSRC_MASK) >> ADC_RESFIFO_TSRC_SHIFT;
result->convValue = (uint16_t)(tmp32 & ADC_RESFIFO_D_MASK);
return true;
}
NXP都帮我们想好了,每次都读回来的数据,
都会带着 commandIdSource 和 loopCountIndex
也就是前面说到的几号指令,和循环读取的次数。
这样我们就能知道是sideA或B,第几个通道的数据了
uint32_t = g_LpadcmyResultShift = 3
static rt_err_t my_adc_convert()
{
lpadc_conv_result_t mLpadcResultConfigStruct;
while(1)
{
LPADC_DoSoftwareTrigger(base, 1U);
for(uint8_t i=0;i<9;i++)
{
while (!LPADC_GetConvResult(base, &mLpadcResultConfigStruct))
{
//等待读取结束
}
ReadVal[i] = (mLpadcResultConfigStruct.convValue) >> g_LpadcmyResultShift;
rt_kprintf("Channel%d = %d\n",i,ReadVal[i] );
}
rt_thread_mdelay(2000);
}
1. 关于VREFH
读取AD值时发现,电位器的中间值不是 2048(12bit的最大值,4096的一半),而是3500左右
后来发现2V之后,读取的AD值就已经满4096了,原因在引脚 ADC_VREFH。
如果输入电压是 1.8V,那么量程就是 0 - 1.8V。
但是电位器接的是 3V3,是不是就没办法了呢??
RT1176还提供了缩放量程的功能,在ADC设置时打开就可以了
mLpadcCommandConfigStruct1.sampleScaleMode = kLPADC_SamplePartScale;
// kLPADC_SamplePartScale = 0U, /*!< Use divided input voltage signal. (Factor of 30/64). */
比如现在接入的是 1.8V, 选择这个模式之后,上限变成 1.8 * 64 / 30 = 3.84V,完全可以覆盖3.3V。
所以1.6V读取到的AD值约为 1650 左右,这样问题就解决了
lpadc_conv_result_t mLpadcResultConfigStruct;
LPADC_DoSoftwareTrigger(LPADC2, 1U);
for(uint8_t i=0;i<4;i++)
{
while (!LPADC_GetConvResult(LPADC2, &mLpadcResultConfigStruct))
{
}
ReadVal[i] = (mLpadcResultConfigStruct.convValue) >> g_LpadcResultShift;
}
LPADC_DoSoftwareTrigger(LPADC1, 2U);
while (!LPADC_GetConvResult(LPADC1, &mLpadcResultConfigStruct))
{
}
ReadVal[4] = (mLpadcResultConfigStruct.convValue) >> g_LpadcResultShift;