查看: 9065|回复: 16

[分享] 【跟我学OSKinetis】第9课-进击的PDB!!!

[复制链接]

该用户从未签到

17

主题

113

帖子

0

注册会员

Rank: 2

积分
130
最后登录
1970-1-1
发表于 2013-11-25 15:05:14 | 显示全部楼层 |阅读模式
 PDB是什么意思,英文全称是Programmable Delay Block,即可编程延时模块。从中文字面意思上看,每个字都那么熟悉,但是就是无法理解是什意思,很正常,但是再仔细看下技术文档中对该模块的简要介绍,应该就略知一二了吧。下面是文档中英文介绍的翻译:
可编程延时模块(PDBADC输入的硬件触发DAC生成的间隔触发提供可控制的内部或外部触发可编程的间隔时间以便能使ADC的转换或者DAC的更新达到精准定时
上面的介绍是一整句话,但是已经阐释了PDB的整个功能。别看它这么长,说白了就是为ADC或DAC提供硬件触发的,再具体点就是提供什么触发呢,可以提供来自单片机内部模块的触发、外部的触发或者软件可编程的触发。来自单片机内部的模块的触发可以是CMP、PIT、FTM等等。也就是说PDB可以理解为一个桥梁,它接受不同来源的触发,转而再去触发ADC或DAC模块,相当于ADC、或DAC的管家一样


PDB工作原理

之前的废话
要讲清楚PDB的工作原理,真的不是一件简单的事情,如果按照技术文档的流程来看,你会越看越晕。技术文档的流程是先介绍特点、再介绍具体的寄存器最后进行功能描述。虽然符合书写原则,但是对于新手来讲确实如同天书一般。我是如何看的呢,如果我对这个模块不了解,那么我会先看一些关于该模块的简要介绍、特点,再去看章节最后一部分的功能描述(Functional Description)。这些功能描述往往会捎带上寄存器的初始化流程、模块的运行流程等信息,这样我就对这个模块有了大体上的了解,最后再去逐一攻破细节。

看懂PDB模块图
说了这么多看技术文档的心得,其实是为我接下来的描述找后路,因为很可能你会看不懂我的描述,呵呵。如果真是这样,那就赶紧去啃技术文档吧。我接下来也只是说说PDB的重点需要描述的地方,告诉大家我对于PDB工作方式的理解。首先看下PDB的模块图解,改图描述了整个模块内部的关系机理。
 
OSKinetis-9-1.png

 

图中两个关键的部分分别是绿框和红框部分,没有这两部分,PDB的工作无从谈起。
绿框部分是PDB的计数器部分,和大部分涉及到时间的外设模块一样,PDB也有计数器、MOD模寄存器等等。有了计数器,就有了基本的定时功能,也就可以控制触发的时间了。由“PDB Counter”框出来的引线,分别引向了橙色框“控制逻辑”部分、蓝色框“中断延时”部分和黄色框“ADC通道触发”部分。也就是说,PDB计数器分别会向这几部分提供计数支持。
蓝框部分是PDB的中断延时功能,当PDB计数器“PDB Counter”的值等于蓝框中“PDBIDLY”寄存器的值时,PDB会根据TOEx位来判断是否产生PDB中断。有了这个功能,PDB就可以被当做一个普通的周期中断定时器来使用了。
橙色框部分是控制逻辑模块,该模块可以理解为是用来控制PDB寄存器复位的。那么那些事件可以引起“PDB Counter”的复位呢?首先看绿框,当“PDBCNT”寄存器的值等于“PDBMOD”模寄存器的值时就会告诉“Control Logic”模块计数器到达预设上限了。如果“CONT”位为1表示PDB为连续工作模式,则“Control Logic”通知“PDB Counter”复位重新计数,如果果“CONT”位为0表示PDB为单次转换模式,则“Control Logic”等待触发事件的到来,这个触发事件就是红框表示出来的部分。当触发事件发生,则“Control Logic”通知“PDB Counter”复位重新计数。
红框部分就是上面说的触发模块了,触发源由“TRIGSEL”位进行选择,触发源可以是Trigger-In 0~14或“SWTRIG”软件触发中的任意一个。从图中还可以看出,触发源出来的引向不止用来控制PDB的复位,还引向了“DAC interval trigger x”DAC间隔触发器,也就是说,触发源可以触发DAC间隔触发器产生DAC触发,当“DAC Interval Counter x”间隔计数器的值等于“DACINTx”的值的时候,就会输出DAC触发事件。另外触发源还引向了黄框的部分,即ADC。
黄色框是通道n的预触发m模块,什么n呀m啊估计你已经荤菜了。简单理解就是n代表ADC的0或1模块,m为ADCx的A或B组通道。也就是说“Ch0 pre-trigger 0”用来触发ADC0的A组通道,同理“Ch0 pre-trigger 1”用来触发ADC0的B组通道。名字理解了,但是这个黄框内的复杂关系估计还是会让你晕菜,没关系,我们从已知的部分开始看。当触发源控制计数器复位开始计时后,“PDB Counter”的值就一直和“PDBCHnDLYm”的值进行对比,当相等后就会最终输出“Pre-trigger m”事件,这个就是ADC的硬件触发信号。图中的什么Ack、BB等等信号,是Back to Back模式中需要用到的,这个我们会在以后讲到,今天大家能消化这些就不错了。


什么是预触发
可能有朋友会问了,触发就触发呗,怎么还搞个预触发,太复杂了。其实仔细想想就不难理解,从上图的模块图中不难看出,触发源只能选择一个,而相对来说ADC0模块有两组通道A和B,如果PDB在收到触发后就就立即触发A和B组是不可能的,因为ADCx的每组通道是不可能同时进行转换的,必定有一个先后顺序,有了先后顺序就必定需要有延时等待,因此就需要了上面讲到的“PDBCHnDLYm”通道延时寄存器,而这个延时计数的过程就是预触发过程,当“PDBCHnDLYm”的值等于“PDB Counter”的值时所导致的触发就是预触发。我们还可以从下面的示例图中看出这个过程:
 
OSKinetis-9-2.png

 

当PDB接收到了触发源的输入事件后(红色线开始),“PDB Counter”就会开始计数,持续“PDBCHnDLY0”的时间后,也就是黄色线的长度,会产生“Ch n pre-trigger 0”预触发信号,与此同时,对应产生“Ch n trigger”通道n的触发事件。以此类推,当等待“PDBCHnDLYm”的时间后,产生“Ch n pre-trigger m”预触发信号和对应的触发信号。
 
PDB编程实践

PDB周期定时中断

说了这么多天书,还是来实践一下才是正道。首先我们做点简单的事情,让PDB先运行起来,不触发任何东西,就自己生成定时中断好了。打开例程“LPLD_PdbPeriodicInt”,这个例程实现的功能和PIT的功能类似,我们将在周期产生的中断函数中输出信息。具体先看初始化函数pdb_init()的代码:

            
1

            
            
  pdb_init_struct.PDB_CounterPeriodMs = 1000;   //计数器溢出周期1000毫秒

            
            
2

            
            
  pdb_init_struct.PDB_TriggerInputSourceSel = TRIGGER_SOFTWARE; //触发源为软件触发

            
            
3

            
            
  pdb_init_struct.PDB_ContinuousModeEnable = TRUE;      //连续工作模式

            
            
4

            
            
  pdb_init_struct.PDB_DelayMs = 200;    //中断延时时间200毫秒

            
            
5

            
            
  pdb_init_struct.PDB_IntEnable = TRUE; //使能延时中断

            
            
6

            
            
  pdb_init_struct.PDB_Isr = pdb_isr;    //中断函数设置

            
            
7

            
            
  LPLD_PDB_Init(pdb_init_struct);

            
            
8

            
            
  LPLD_PDB_EnableIrq();

            
            
9

            
            
  LPLD_PDB_SoftwareTrigger();

            

Line 1:配置PDB计数器的溢出周期为1000毫秒,库函数会根据我们设置的时间,自动计算出MOD寄存器、MULT因子、PRESCALER分频的值。
Line 2:利用成员变量PDB_TriggerInputSourceSel配置PDB的触发源为软件触发,TRIGGER_SOFTWARE。
Line 3:配置PDB的工作模式为连续工作,即图中CONT位的值为1,PDB计数器会在等于MOD的值后立即复位并继续计数。
Line 4:配置中断延时时间为200毫秒,库函数会根据这个时间自动计算出“PDBIDLY”寄存器的值。
Line 5~6:使能PDB中断,配置中断函数。
Line 7:初始化PDB。
Line 8:使能中断请求。
Line 9:软件触发PDB开始工作。这个函数的作用就是让图中红框部分产生一个软件触发信号给“Control Logic”。
配置完PDB后,PDB的延时中断功能就会立即开始工作,不过程序会运行以下这句代码:

            
1

            
            
printf("Waiting for 200ms, and then:\r\n");

            

等待200ms后,第一次中断会发生,再等待1000ms后,第二次中断会发生。以后每个1000ms会发送一次中断。也就是说,初始化完成后,程序首先会延时200ms,才会触发第一次中断。这就是初始化时设置PDB_DelayMs为200ms的效果了。如果你不明白为什么,可以回头去看看第一幅PDB模块图。

PDB触发ADC采集
与前面几个例程不同,这是一个综合例程,我们要配合使用ADC+PDB+PIT这个3个模块来实现自动定时采集功能。打开例程“LPLD_PdbAnalogSample”,看main()函数中的初始化代码,首先初始化ADC的相关设置:

            
1

            
            
  adc0_init_struct.ADC_Adcx = ADC0;     //选择ADC0

            
            
2

            
            
  adc0_init_struct.ADC_BitMode = SE_12BIT;      //配置转换精度

            
            
3

            
            
  adc0_init_struct.ADC_CalEnable = TRUE;        //使能初始化自动校准

            
            
4

            
            
  adc0_init_struct.ADC_HwTrgCfg = HW_TRGA;      //配置为硬件触发转换

            
            
5

            
            
  adc0_init_struct.ADC_Isr = adc0_isr;  //设置ADC中断函数

            
            
6

            
            
  LPLD_ADC_Init(adc0_init_struct);   

            
            
7

            
            
  LPLD_ADC_Chn_Enable(ADC0, DAD1);

            
            
8

            
            
  LPLD_ADC_EnableConversion(ADC0, DAD1, 0, TRUE);

            
            
9

            
            
  LPLD_ADC_EnableIrq(adc0_init_struct);

            

Line 4:前面几行没有要说的,主要是这里配置成员变量ADC_HwTrgCfg使ADC0为硬件触发转换模式。
Line 5:配置ADC中断函数,由于我们没有使用DMA功能,因此需要在中断里来获取转换结果。
Line 8:调用LPLD_ADC_EnableConversion()函数使能转换,该函数的前两个参数分别设置模块号和通道号,第3个参数设置转换通道为A组,第4个参数为使能转换结束中断。
Line 9:使能中断请求。

接下来初始化PDB的相关设置:

            
1

            
            
  pdb_init_struct.PDB_CounterPeriodMs = 1000;   //PDB计数器周期设置

            
            
2

            
            
  pdb_init_struct.PDB_LoadModeSel = LOADMODE_0; //加载模式设置

            
            
3

            
            
  pdb_init_struct.PDB_ContinuousModeEnable = FALSE;     //禁用连续工作模式

            
            
4

            
            
  pdb_init_struct.PDB_TriggerInputSourceSel = TRIGGER_PIT0;     //配置触发源为PIT0

            
            
5

            
            
  LPLD_PDB_Init(pdb_init_struct);

            
            
6

            
            
  LPLD_PDB_AdcTriggerCfg(ADC0, PRETRIG_EN_A, 0);

            

Line 2:这是第1个例程没有配置过的参数,配置PDB_LoadModeSel加载模式,这里选择模式LOADMODE_0。加载模式指的是PDB寄存器中如CNT、MOD、DLY寄存器的加载模式,具体描述请参见PDB模块在线函数手册。
Line 3:禁用连续工作模式。
Line 4:配置PDB输入触发源为TRIGGER_PIT0,即PIT0模块。
Line 6:PDB对ADC的触发配置,调用函数LPLD_PDB_AdcTriggerCfg(),配置预触发ADC0模块,预触发A通道使能,预触发延时为0。
最后配置PDB的触发源,PIT模块:

            
1

            
            
  pit0_init_struct.PIT_Pitx = PIT0;     //选择PIT0

            
            
2

            
            
  pit0_init_struct.PIT_PeriodMs = 500;  //PIT0计数周期500ms

            
            
3

            
            
  LPLD_PIT_Init(pit0_init_struct);  

            

Line 2:配置PIT0技术周期为500毫秒,即每过500毫秒触发一次PDB。那么它和PDB的1000ms计数周期什么关系呢,这里的意思是没500ms触发一次PDB开始工作,这是PDB开始计数,其实PDB根本计不到1000ms就会被下一次PIT0触发。
Line 3:直接初始化PIT0,不用设置中断函数,也不用使能中断请求,因为PIT只需要产生触发信号,不用产生中断。

全部初始化完毕,整个工程才真正开始运作,首先PIT会触发PDB开始工作,PDB收到触发输入后经过0秒延迟预触发ADC0模块的A组转换通道,A组通道被触发后开始AD转换工作,转换完成后触发中断运行函数adc0_isr(),看其代码:

            
1

            
            
void adc0_isr()

            
            
2

            
            
{

            
            
3

            
            
  int16 result;

            
            
4

            
            
  uint8 ab = LPLD_ADC_GetSC1nCOCO(ADC0);

            
            
5

            
            
  result = LPLD_ADC_GetResult(ADC0, ab);

            
            
6

            
            
  printf("ADC0_R[%d]=%d\r\n", ab, result);

            
            
7

            
            
}

            

Line 4:首先调用LPLD_ADC_GetSC1nCOCO()函数查看到底是ADC0的A组还是B组产生的中断,因为ADCx的A、B组通道都进入同一个中断,因此必须用此函数判断是哪组产生的中断。
Line 5:调用LPLD_ADC_GetResult()函数获取ADC0模块A组通道的转换结果,该函数和ADC的LPLD_ADC_Get()函数都是获取转换结果,但是前者不会等待转换结束,且必须指定A、B组通道,后者会等待转换结束,且只获取A组结果(因为只有A组能软件触发转换

未交待的后话
本节课只介绍了PDB的定时中断和ADC触发例程,其实PDB还可以触发DAC模块,大家可以在了解OSKinetis V3库函数的基础上自行学习使用。
而且关于触发ADC的转换,更加效率的方式是配合DMA的使用。这样的话,就不需要ADC产生中断来获取转换结果了,可以直接通过DMA的ADC请求源来不依靠CPU获取转换结果。具体例程可以参考“LPLD_DmaPdbAnalogSample”。
更加牛叉的方法是利用ADC的乒乓模式配合PDB的back to back功能,来完成4个ADC通道的自动连续采集,实际案例请参考“LPLD_DmaPdbADCx4”。
 
       
  • 有什么需求和疑问欢迎联系 support[AT]lpld.cn   
  • OSKinetis固件库专业讨论群,有机会和固件库开发者一对一交流。QQ群:184156168(入群请输入“LPLD固件库”)   
  • OSKinetis V3固件库及例程获取:https://www.eefocus.com/bbs/article_891_527991.html
 
回复

使用道具 举报

该用户从未签到

0

主题

18

帖子

0

新手上路

Rank: 1

积分
9
最后登录
1970-1-1
发表于 2013-12-21 11:45:51 | 显示全部楼层

回复:【跟我学OSKinetis】第9课-进击的PDB!!!

各种元器件datasheet上搜IC数据手册看中文版吧,不仅datasheet是中文的,还可以用中文关键字搜索datasheet内容。芯片功能、封装、参数都能找到。
回复 支持 反对

使用道具 举报

该用户从未签到

0

主题

10

帖子

0

新手上路

Rank: 1

积分
10
最后登录
1970-1-1
发表于 2014-2-26 10:28:58 | 显示全部楼层

回复:【跟我学OSKinetis】第9课-进击的PDB!!!

楼主,我想问下PDB的trigger-in对应的是哪些PIT?
回复 支持 反对

使用道具 举报

该用户从未签到

14

主题

164

帖子

0

高级会员

Rank: 4

积分
722
最后登录
2016-10-20
发表于 2015-9-29 22:11:39 | 显示全部楼层
PDB很有用,K,V,才有,L,E,EA及其他系列没看见有,要好好学习一下。
回复 支持 反对

使用道具 举报

该用户从未签到

11

主题

101

帖子

0

中级会员

Rank: 3Rank: 3

积分
303
最后登录
2021-11-15
发表于 2015-9-30 09:02:41 | 显示全部楼层
多谢分享,讲得很详细很到位
回复 支持 反对

使用道具 举报

  • TA的每日心情
    奋斗
    2017-5-3 11:19
  • 签到天数: 10 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    50

    主题

    1万

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    14090
    最后登录
    2024-4-19
    发表于 2015-9-30 09:20:47 | 显示全部楼层
    看看。。。。 blank.png blank1.png blank2.png blank3.png blank4.png blank5.png blank6.png blank7.png blank8.png blank9.png
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2025-5-7 09:07
  • 签到天数: 353 天

    连续签到: 1 天

    [LV.8]以坛为家I

    141

    主题

    8056

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    5786
    最后登录
    2025-5-7
    发表于 2015-10-1 08:33:53 | 显示全部楼层
    学习
        154120hhw0q0e0hpw374yw.png
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2019-11-18 12:16
  • 签到天数: 560 天

    连续签到: 1 天

    [LV.9]以坛为家II

    23

    主题

    913

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    2305
    最后登录
    2019-11-18
    发表于 2015-10-1 22:08:24 | 显示全部楼层
    感谢分享………………
    1.png
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2018-9-20 20:56
  • 签到天数: 20 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    12

    主题

    449

    帖子

    0

    高级会员

    Rank: 4

    积分
    984
    最后登录
    2018-9-20
    发表于 2015-10-1 22:14:21 | 显示全部楼层
    好好学习
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2019-11-18 12:16
  • 签到天数: 560 天

    连续签到: 1 天

    [LV.9]以坛为家II

    23

    主题

    913

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    2305
    最后登录
    2019-11-18
    发表于 2015-10-1 22:19:31 | 显示全部楼层
    感谢分享………………
    1.png
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-8-5 14:45 , Processed in 0.107543 second(s), 29 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表