Skip to content

Latest commit

 

History

History
462 lines (318 loc) · 26 KB

ADC驱动模块详细设计说明书.rst

File metadata and controls

462 lines (318 loc) · 26 KB

引言

本文档对ADC驱动设计思路,使用方法以及相关术语进行说明。

编写目的

本文档是微内核项目中ADC驱动模块的详细设计说明书,可以作为开发人员熟悉理解ADC驱动工作流程和ADC驱动维护的参考资料,可作为应用开发者使用ADC的参考资料。

项目概述

μLinx 操作系统是凝思软件自主研制的具有微内核特征的实时操作系统,μLinx 操作系统支持M400单片机,M400 是智芯微电子的一款以 ARMV8-M 为基础的 MCU 芯片。智芯 MCU_dev V1.0是基于 M400 芯片开发的一块外设功能齐全的开发板。μLinx操作系统中ADC驱动实现了μLinx通过简单的IO操作函数操作ADC外设的功能。

适用范围

本文档用于软件设计和开发阶段,它的上游(依据的基线)是产品需求说明书,它的下游是测试计划,并为测试报告提供测试依据。

术语定义

表格 1.1: 术语定义

序号 术语 描述
  ADC 模数转换

参考资料

[1] DEMO_M400_LQFP144.pdf

[2] M400 用户手册 1.1.pdf

总体设计

在本驱动中,ADC外设驱动分为上下两部分,上半部分驱动是通用驱动程序,功能是为应用层代码提供通用接口,将ADC设备在μLinx系统中注册为字符设备,应用可以通过标准的IO操作来实现对底层ADC外设的控制。下半部分驱动是特定平台的驱动程序,功能是进行M400单片机ADC底层相关的寄存器的设置,ADC驱动根据输入参数对硬件进行初始化。

硬件特性

介绍

16 位 ADC 模块的工作时钟最高为 56MHz 支持多达 8 个单端输入和 4 个差分输入的 ADC 信号的采集,一路采样保持电路,这些通道的 ADC 转换可在单次采样,多次采样取平均值, 简单连续采样(不切换通道),复杂连续采样(切换通道)模式下进行, ADC 的结果存储 在一个 16 位数据寄存器中,两个单端输入可以组成一个差分输入。差分输入和单端输入是 互斥的。

主要支持的特性如下:

时钟

ADC时钟来源于PCLK,PCLK由SYSCLK分频得到,而SYSCLK来自HCLK的分频,HCLK来自SYSCLK或SYSCLK的特殊分频,SYSCLK可选PLL、HOSC、LOSC三者之一。下图为M400单片机中与ADC相关的时钟结构图。

图示 1: ADC时钟来源

备注:M400的典型SYSCLK为200M。XHOSC为外部晶振,M400开发板MCU_dev V1.0使用的XHOSC为30MHz。

输入输出引脚

外部输出引脚

ADC模块不涉及输出引脚。

外部输入引脚

ADC最多支持8路单端或 4路差分输入信号的采集,每个单端采集对应一个外部输入引脚(也即每组差分输入对应两个输入引脚例如在原理图上面第0组差分输入的两个输入引脚分别为ADC_IN<0>和ADC_IP<0>),除此之外还有两个参考电压的输入引脚分别为正参考电压VREFP和负参考电压VREFN

表格 2.1: ADC 输入引脚功能IO复用表

Pin编号(144封装) 第几功能 输入源
27 OPTION 0 ADC_IN< 3>
28 OPTION 0 ADC_IP< 3>
29 OPTION 0 ADC_IN< 2>
30 OPTION 0 ADC_IP< 2>
31 OPTION 0 ADC_IN< 1>
32 OPTION 0 ADC_IP< 1>
33 OPTION 0 ADC_IN< 0>
34 OPTION 0 ADC_IP< 0>
35 OPTION 0 VREFP
36 OPTION 0 VREFN (VSS)

ADC采样模式

单数值采样模式

ADC_CON1_REG1的Bit5:4设置为0时,ADC只进行单个数值采样,采样之后会自动结束采样。这里单数值模式有两种情况,一种是ADC只采样一次,或者采样多次取平均值,平均值计算一共有2次采样平均,4次采样平均,8次采样平均三种情况,具体的由ADC_CON1_REG1的Bit7:6决定(要注意的是单值和单次,单值模式下不论ADC连续采样几次最终读取到的数据只有一个)。单值采样模式下面的多次采样过程不受trig_en控制,trig_en可以理解为ADC采用触发信号的使能开关。在ADC其它采样模式时具体介绍。

简单连续采样模式

ADC_CON1_REG1的Bit5:4设置为1时,进行简单连续采样(不切换采样通道),该采样模式下面不支持自动求平均值,采样时会产生多次中断和多个有效数据。产生中断和有效数据之后如果trig_en==0(ADC_CON1_REG1的bit0为0), 则由DMA或者CPU搬移数据。然后ADC立马进行下一次采样,要停止采样只有手动编程设置ADC_CON4_REG寄存器的bit0为0。如果trig_en==1(ADC_CON1_REG1的bit0为1),则需要等待下一次采样的触发信号(adc_trig)来临之后,才进行下一次采样。触发信号可以配置为timerb_tc1,timerc_tc1,timerd_tc1具体使用哪一种触发信号由ADC_CON1_REG1的Bit3:1决定。timerb_tc1,timerc_tc1,timerd_tc1分别是由定时器B,C,D的计数器1产生的,具体定时器怎么配置需要结合芯片手册上面定时器章节的说明。但是在手册上面没有看见具体的的说明,定时器是如何触发ADC采样的,只看见了触发源是上面提到的三个定时器的计数器。

复杂连续采样模式1

ADC_CON1_REG1的Bit5:4设置为2时,进行复杂连续采样(切换采样通道,但不重载通道),其中切换采样通道是指,多个通道同时有信号输入时,adc处理完一个通道的数据,按照事先指定的采样通道编号顺序,处理下一个通道的数据,例如8个采样通道如果都有信号输入,但是实际采样的顺序是设置为 3 4 7 1 5 采样时就先采集3通道的信号,然后4通道,再7通道,实际的通道采样顺序由ADC_CON3_REG寄存器的Bit11:0 决定,重载通道在后续采样模式中进行介绍。该采样模式下面不支持自动求平均值,采样时会产生多次中断和多个有效数据。产生中断和有效数据之后如果trig_en==0(ADC_CON1_REG1的bit0为0), 则由DMA或者CPU搬移数据。采样的过程成是按照ADC_CON3_REG寄存器的Bit11:0 指定的通道编号,从小到大依次扫描对应的通道采样,完成一轮通道扫描之后就自动进行下一轮通道扫描进行下一次采样,要停止采样只有手动编程设置ADC_CON4_REG寄存器的bit0为0。如果trig_en==1(ADC_CON1_REG1的bit0为1),则需要等待下一轮通道扫描的触发信号(adc_trig)来临之后,才进行下一论采样。触发信号可以配置为timerb_tc1,timerc_tc1,timerd_tc1具体使用哪一种触发信号由ADC_CON1_REG1的Bit3:1决定。timerb_tc1,timerc_tc1,timerd_tc1分别是由定时器B,C,D的计数器1产生的,具体定时器怎么配置需要结合芯片手册上面定时器章节的说明。但是在手册上面没有看见具体的的说明,定时器是如何触发ADC采样的,只看见了触发源是上面提到的三个定时器的计数器。需要注意的是差分采样和单端采样存在互斥的关系,在设置通道编号时需要注意,具体的参考芯片手册上的通道设置互斥表。

复杂连续采样模式2

ADC_CON1_REG1的Bit5:4设置为3时,进行复杂连续采样(切换采样通道,并且重载通道),其中切换采样通道是指,多个通道同时有信号输入时,adc处理完一个通道的数据,按照事先指定的采样通道编号顺序,处理下一个通道的数据,例如8个采样通道如果都有信号输入,但是实际采样的顺序是设置为 3 4 7 1 5 采样时就先采集3通道的信号,然后4通道,再7通道,实际的通道采样顺序由ADC_CON3_REG寄存器的Bit11:0 决定,重载通道是指在采样过程中可以重新设置寄存器ADC_CON3_REG寄存器的Bit11:0的值,来改变通道采样的顺序,比如上面的顺序最开始为3 4 7 1 5,可以根据实际需要改为2 6 8 1 6 4。该采样模式下面不支持自动求平均值,采样时会产生多次中断和多个有效数据。产生中断和有效数据之后如果trig_en==0(ADC_CON1_REG1的bit0为0), 则由DMA或者CPU搬移数据。采样的过程成是按照ADC_CON3_REG寄存器的Bit11:0 指定的通道编号,从小到大依次扫描对应的通道采样,完成一轮通道扫描之后就自动进行下一轮通道扫描进行下一次采样,(重载通道模式下需要先再次设置好下一次采样的通道编号,才可进行下一轮采样)。要停止采样只有手动编程设置ADC_CON4_REG寄存器的bit0为0。如果trig_en==1(ADC_CON1_REG1的bit0为1),则需要等待下一轮通道扫描的触发信号(adc_trig)来临之后,才进行下一论采样。(重载通道模式下要先等待adc_chn_int 中断产生,然后重新设置通道采样顺序。才可进行下一轮采样) 触发信号可以配置为timerb_tc1,timerc_tc1,timerd_tc1具体使用哪一种触发信号由ADC_CON1_REG1的Bit3:1决定。timerb_tc1,timerc_tc1,timerd_tc1分别是由定时器B,C,D的计数器1产生的,具体定时器怎么配置需要结合芯片手册上面定时器章节的说明。但是在手册上面没有看见具体的的说明,定时器是如何触发ADC采样的,只看见了触发源是上面提到的三个定时器的计数器。需要注意的是差分采样和单端采样存在互斥的关系,在设置通道编号时需要注意,具体的参考芯片手册上的通道设置互斥表。

驱动功能

参考ADC的硬件特性,ADC驱动拟支持以下功能,驱动相关的参数可以通过IOCTL的方式进行设置或读取。

1.数值采样模式:单通道单次采样,或者采样多次最终获取到一个平均值。

2.简单连续采样模式:单通道多次连续采样,不计算平均值。

3.复杂连续采样模式1:多通道同时采样,而且采样过程中会切换采样通道,采样通道不能进行重排。

4.复杂连续采样模式2:多通道同时采样,采样过程中会切换采样通道,而且通道可以进行重排。

5.可配置DMA数据存储

6.所有通道都能够进行采样,单端采样或者差分采样。

7.支持定时采样。

总体框架

ADC的总体设计是沿用ulinx系统中的ADC驱动框架,通过在伪文件系统注册生成字符设备的方式供用户层使用,支持IOCTL接口,支持设置各类采样模式。

设备注册

ADC设备注册流程如图,通过boardctl()接口调用板级初始化程序完成ADC的硬件初始化,设备注册流程,设备注册成功后会在ulinx系统伪文件系统中生成字符设备,设备地址一般是形如/dev/adcX的形式,支持通过标准IO操作读写设备。

图示 2: ADC驱动注册流程

设备使用

上层应用使用open函数开启ADC设备时 底层驱动会完成硬件的初始化,然后把ADC设备绑定到文件IO操作的标准函数中,之后就可以向访问文件一样操作ADC设备。ADC设备open流程如下:

详细设计

IOCTL

在ulinx中应用程序可以通过IOCTL的方式对ADC进行设置、参数读取。其中ADC相关ioctl支持的命令主要有三个

表格 3.1: ADC通用IOCTL命令

CMD Description Return
ANIOC_TRIGGER 开启ADC转换 没有返回值
ANIOC_GET_NCHANNELS 获取已经设置的ADC通道数 返回底层驱动stop函数执行结果
ANIOC_RUN_ADCTEST 运行ADC测试函数  

软件框架

操作函数集

在ADC驱动中,构建了一个ADC的操作函数集,对接上层ADC驱动框架的驱动函数集:

static const struct adc_ops_s g_adcops =

{

.ao_bind = adc_bind,

.ao_reset = adc_reset,

.ao_setup = adc_setup,

.ao_shutdown = adc_shutdown,

.ao_rxint = adc_rxint,

.ao_ioctl = adc_ioctl,

};

以上操作函数集是几乎所有平台的ADC驱动均应支持的操作函数。

ADC驱动中还实现了一个私有结构体,用于M400的ADC的各种初始化设置。

static struct taishan400_dev_s g_adcpriv1 =

{

.irq = TAISHAN400_IRQ_ADC,

.isr = adc123_interrupt,

.intf = 1,

.base = TAISHAN400_ANACTRL_BASE,

.adcpara.avgTime = ADC_CON1_AVGTIMES_1,

.adcpara.chCombined = ADC_CON3_CHNCOMBINED_0,

.adcpara.smpWidth = ADC_CON1_SMP_WIDTH_(8),

#ifdef ADC_HAVE_TIMER

.adcpara.waitFetch = ADC_CON1_NOTWAITFETCH,

.adcpara.trigSrc = ADC_CON1_TRIG_SEL_TIMERD1,

.adcpara.trigEn = ADC_CON1_TRIG_EN,

#else

.adcpara.trigEn = ADC_CON1_TRIG_DIS,

#endif

#ifdef ADC1_HAVE_TIMER

.timirq = ADC1_TIMER_IRQ,

.tbase = ADC1_TIMER_BASE,

.freq = ADC_SAMPLE_FREQUENCY,

.cfreq = ADC_COUNT_FREQUENCY,

.timpara.matchCtl = TC_MCR_CLEARTC,

.timpara.outMode = 0,

.timpara.outPulseW= 0,

#ifdef ADC_TIRGGER_CAPTURE

.timpara.prescale = ADC_TIRGGER_COUNTER_DIV;

#endif

#endif

#ifdef ADC1_HAVE_DMA

.dmachan = {DMAMAP_DMA0S0,DMAMAP_DMA1S0},

.hasdma = true,

.s_base = TAISHAN400_ANACTRL_BASE_S,

.blocks = 1,

.trcnt = 1,

.dmabuffer = {0},

#endif

#ifdef CONFIG_PM

.pm_callback =

{

.prepare = adc_pm_prepare,

}

#endif

};

中断处理

ADC驱动函数中比较重要的是ADC中断的产生与处理,由于ADC完成转换之后的数据需要及时的传输出去,为了提高数据传输的效率使用DMA来进行数据传输。所以最终的中断发生在DMA传输完数据之后,因此中断处理函数的重点是DMA中断函数的处理,为了方便和ADC进行联动,ADC驱动上面设计了一个会从DMA 数据缓冲区里面读取数据的回调函数,当ADC数据转换完成,并且数据由DMA传输完成之后会产生一个DMA数据传输完成的中断,然后DMA中断函数调用该回调函数。回调函数间接调用驱动上半部分的adc_receive,把来自DMA的数据和完成数据转化的ADC通道打包成一条adc_msg_s消息,然后交由缓冲队列来管理数据。加入缓冲队列的目的主要是为了防止驱动层数据转换太快,应用层可能来不及处理每条数据,所以用缓冲队列起到数据暂存的效果。

驱动功能实现

单数值采样模式

ADC_CON1_REG1的Bit5:4设置为0时,ADC只进行单个数值采样,采样之后会自动结束采样。这里单数值模式有两种情况,一种是ADC只采样一次,或者采样多次取平均值,平均值计算一共有2次采样平均,4次采样平均,8次采样平均三种情况,具体的由ADC_CON1_REG1的Bit7:6决定(要注意的是单值和单次,单值模式下不论ADC连续采样几次最终读取到的数据只有一个)。单值采样模式下面的多次采样过程不受trig_en控制,trig_en可以理解为ADC采用触发信号的使能开关。单数值采样模式主要涉及的寄存器汇总如下表

表格 3.2: 单数值采样模式设置

寄存器 功能
ADC_CON1_REG[15:8] 根据实际情况设置 设置采样周期数
ADC_CON1_REG[7:6] 根据实际情况设置 单值采样设置的取平均数系数
ADC_CON1_REG[5:4] 0 设置ADC采样模式
ADC_CON1_REG[0] 0 设置是否需要采样触发信号

简单连续采样模式

ADC_CON1_REG1的Bit5:4设置为1时,进行简单连续采样(不切换采样通道),该采样模式下面不支持自动求平均值,采样时会产生多次中断和多个有效数据。产生中断和有效数据之后如果trig_en==0(ADC_CON1_REG1的bit0为0), 则由DMA或者CPU搬移数据。然后ADC立马进行下一次采样,要停止采样只有手动编程设置ADC_CON4_REG寄存器的bit0为0。如果trig_en==1(ADC_CON1_REG1的bit0为1),则需要等待下一次采样的触发信号(adc_trig)来临之后,才进行下一次采样。触发信号可以配置为timerb_tc1,timerc_tc1,timerd_tc1具体使用哪一种触发信号由ADC_CON1_REG1的Bit3:1决定。timerb_tc1,timerc_tc1,timerd_tc1分别是由定时器B,C,D的计数器1产生的。

表格 3.3: 简单连续采样模式设置

寄存器 功能
ADC_CON1_REG[15:8] 根据实际情况设置 设置采样周期数
ADC_CON1_REG[7:6] 必须设置为0 单值采样设置的取平均数系数
ADC_CON1_REG[5:4] 1 设置ADC采样模式
ADC_CON1_REG[3:1] 根据实际情况设置 设置ADC采样出发信号
ADC_CON1_REG[0] 1 设置是否需要采样触发信号
ADC_CON4_REG[0]   是否开启ADC采样

复杂连续采样模式1

ADC_CON1_REG1的Bit5:4设置为2时,进行复杂连续采样(切换采样通道,但不重载通道),其中切换采样通道是指,多个通道同时有信号输入时,adc处理完一个通道的数据,按照事先指定的采样通道编号顺序,处理下一个通道的数据,例如8个采样通道如果都有信号输入,但是实际采样的顺序是设置为 3 4 7 1 5 采样时就先采集3通道的信号,然后4通道,再7通道,实际的通道采样顺序由ADC_CON3_REG寄存器的Bit11:0 决定,重载通道在后续采样模式中进行介绍。该采样模式下面不支持自动求平均值,采样时会产生多次中断和多个有效数据。产生中断和有效数据之后如果trig_en==0(ADC_CON1_REG1的bit0为0), 则由DMA或者CPU搬移数据。采样的过程成是按照ADC_CON3_REG寄存器的Bit11:0 指定的通道编号,从小到大依次扫描对应的通道采样,完成一轮通道扫描之后就自动进行下一轮通道扫描进行下一次采样,要停止采样只有手动编程设置ADC_CON4_REG寄存器的bit0为0。如果trig_en==1(ADC_CON1_REG1的bit0为1),则需要等待下一轮通道扫描的触发信号(adc_trig)来临之后,才进行下一论采样。触发信号可以配置为timerb_tc1,timerc_tc1,timerd_tc1具体使用哪一种触发信号由ADC_CON1_REG1的Bit3:1决定。timerb_tc1,timerc_tc1,timerd_tc1分别是由定时器B,C,D的计数器1产生的

3.4: 复杂连续采样模式1设置
寄存器 功能
ADC_CON1_REG[15:8] 根据实际情况设置 设置采样周期数
ADC_CON1_REG[7:6] 必须设置为0 单值采样设置的取平均数系数
ADC_CON1_REG[5:4] 2 设置ADC采样模式
ADC_CON1_REG[3:1] 根据实际情况设置 设置ADC采样出发信号
ADC_CON1_REG[0] 1 设置是否需要采样触发信号
ADC_CON3_REG[11:0] 根据实际情况设置 设置连续采样模式时的采样通道切换顺序。
ADC_CON4_REG[0]   是否开启ADC采样

备注:需要注意的是差分采样和单端采样存在互斥的关系,在设置通道编号时需要注意,具体的参考芯片手册上的通道设置互斥表。

复杂连续采样模式2

ADC_CON1_REG1的Bit5:4设置为3时,进行复杂连续采样(切换采样通道,并且重载通道),其中切换采样通道是指,多个通道同时有信号输入时,adc处理完一个通道的数据,按照事先指定的采样通道编号顺序,处理下一个通道的数据,例如8个采样通道如果都有信号输入,但是实际采样的顺序是设置为 3 4 7 1 5 采样时就先采集3通道的信号,然后4通道,再7通道,实际的通道采样顺序由ADC_CON3_REG寄存器的Bit11:0 决定,重载通道是指在采样过程中可以重新设置寄存器ADC_CON3_REG寄存器的Bit11:0的值,来改变通道采样的顺序,比如上面的顺序最开始为3 4 7 1 5,可以根据实际需要改为2 6 8 1 6 4。该采样模式下面不支持自动求平均值,采样时会产生多次中断和多个有效数据。产生中断和有效数据之后如果trig_en==0(ADC_CON1_REG1的bit0为0), 则由DMA或者CPU搬移数据。采样的过程成是按照ADC_CON3_REG寄存器的Bit11:0 指定的通道编号,从小到大依次扫描对应的通道采样,完成一轮通道扫描之后就自动进行下一轮通道扫描进行下一次采样,(重载通道模式下需要先再次设置好下一次采样的通道编号,才可进行下一轮采样)。要停止采样只有手动编程设置ADC_CON4_REG寄存器的bit0为0。如果trig_en==1(ADC_CON1_REG1的bit0为1),则需要等待下一轮通道扫描的触发信号(adc_trig)来临之后,才进行下一论采样。(重载通道模式下要先等待adc_chn_int 中断产生,然后重新设置通道采样顺序。才可进行下一轮采样) 触发信号可以配置为timerb_tc1,timerc_tc1,timerd_tc1具体使用哪一种触发信号由ADC_CON1_REG1的Bit3:1决定。timerb_tc1,timerc_tc1,timerd_tc1分别是由定时器B,C,D的计数器1产生的,具体定时器怎么配置需要结合芯片手册上面定时器章节的说明阅读keil工程的范例代码。

3.5: 复杂连续采样模式1设置
寄存器 功能
ADC_CON1_REG[15:8] 根据实际情况设置 设置采样周期数
ADC_CON1_REG[7:6] 必须设置为0 单值采样设置的取平均数系数
ADC_CON1_REG[5:4] 3 设置ADC采样模式
ADC_CON1_REG[3:1] 根据实际情况设置 设置ADC采样触发信号
ADC_CON1_REG[0] 1 设置是否需要采样触发信号
ADC_CON3_REG[11:0] 根据实际情况设置 设置连续采样模式时的采样通道切换顺序。
ADC_CON4_REG[0]   是否开启ADC采样

备注:需要注意的是差分采样和单端采样存在互斥的关系,在设置通道编号时需要注意,具体的参考芯片手册上的通道设置互斥表。