返回列表 发新帖我要提问本帖赏金: 30.00元(功能说明)

[APM32F4] 基于APM32F411 DMA_ADC Handler模式分析及解决

[复制链接]
1334|7
 楼主| lzh12a3nf 发表于 2023-9-25 18:04 | 显示全部楼层 |阅读模式
本帖最后由 lzh12a3nf 于 2023-9-26 13:29 编辑

#申请原创#@21小跑堂
1、前言
    最近在编写DMA_ADC例程的过程中出现了一个中断配置的问题,在ADC采集过程中,结合手册进行ADC连续转换模式配置采集,手册上给出需要进行中断配置的信息,但是真实情况不需要进行中断配置也可以进行ADC连续转换采集,因此,我没过滤掉ADC采集中开启中断配置的信息,开启了ADC中断采集,因此这次以APM32F411官方例程中的DMA_ADC例程,复刻了此次出现的问题。

2、基于APM32F411 DMA_ADC例程问题复刻
  1. /*!
  2. * [url=home.php?mod=space&uid=247401]@brief[/url]     ADC Init
  3. *
  4. * @param     None
  5. *
  6. * @retval    None
  7. */
  8. void ADC_Init(void)
  9. {
  10.     GPIO_Config_T gpioConfig;
  11.     ADC_Config_T  adcConfig;

  12.     /* RCM Enable*/
  13.     RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);
  14.     /* GPIO Configuration */
  15.     GPIO_ConfigStructInit(&gpioConfig);
  16.     gpioConfig.pin = GPIO_PIN_0;
  17.     gpioConfig.mode = GPIO_MODE_AN;
  18.     gpioConfig.pupd = GPIO_PUPD_NOPULL;
  19.     GPIO_Config(GPIOA, &gpioConfig);

  20.     RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);

  21.     /* ADC Configuration */
  22.     ADC_Reset();
  23.     ADC_ConfigStructInit(&adcConfig);
  24.     /* Set resolution*/
  25.     adcConfig.resolution = ADC_RESOLUTION_12BIT;
  26.     /* Set dataAlign*/
  27.     adcConfig.dataAlign = ADC_DATA_ALIGN_RIGHT;
  28.     /* Set scanDir*/
  29.     adcConfig.scanConvMode = DISABLE;
  30.     /* Set convMode continous*/
  31.     adcConfig.continuousConvMode = ENABLE;
  32.     /* Set extTrigEdge*/
  33.     adcConfig.extTrigEdge = ADC_EXT_TRIG_EDGE_NONE;
  34.     /* Set nbrOfConversion*/

  35.     ADC_Config(ADC1, &adcConfig);
  36.     ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_112CYCLES);
  37.                
  38.     NVIC_EnableIRQRequest(ADC_IRQn,0x00,0x00);
  39.     ADC_EnableInterrupt(ADC1,ADC_INT_EOC);

  40.     ADC_EnableDMA(ADC1);
  41.     ADC_EnableDMARequest(ADC1);

  42.     /* Enable ADC*/
  43.     ADC_Enable(ADC1);
  44.     ADC_SoftwareStartConv(ADC1);
  45. }
   根据上述复刻代码,在ADC_Init()代码配置中,使用NVIC申请中断号,使能中断,但是在中断服务函数中,我并没有进行内容处理。
3、问题定位及疑惑
    当出现问题时,因为首先Debug进行单步调试,程序卡死时,出现以下的信息定位:
DMA_ADC1.png

    当程序出现问题时,我首先定位的信息便是Internal:Mode->Handler,Stack->MSP->0x20000400,同时Debug Faults中,SCB->DFSR寄存器的值为0x00000001。首先,模式有Thread变成Handler,这个变化可以说明当前程序由普通用户运行的代码变成了异常程序处理的代码。其次,看到SCB寄存器的内容,结合内核手册中的一些信息,如下:
DMA_ADC2.png
    DFSR->HALTED寄存器位置为1,从手册内容表示,CPU被调试器喊停,但被调停是因为什么原因呢?这个需要进一步分析,如下:
DMA_ADC3.png
    DFSR寄存器中HALTED寄存器被置位是因为在NVIC中进行了HALT的请求,然后我回顾了以下程序,在ADC初始化中进行了NVIC的请求,因为程序在ADC进行采集时,会一直跳进中断程序。记录到这里,我已经对问题进行了确认。因为在ADC配置中开启了中断,当中断开启后,请求了HALT,并且CPU响应了这次请求对ADC的中断服务函数进行处理,但我并没有对ADC的中断服务函数进行处理与ADC采集为连续配置模式,因此程序一直处在Handler模式与线程模式下的切换。并且结合.s启动文件可知,如下:
  1. Default_Handler PROC
  2. EXPORT  ADC_IRQHandler                      [WEAK]
   当我通过申请使能中断后,MCU会通过传入的中断号,并计算出偏移量,加载到中断向量表中(这个后面计划出一个启动文件分析,到时在细讲)。当MCU相应中断使能时,程序切换至Handler模式时,PC便将这个地址当做入口,跳入中断服务函数并执行。如下图形式(仅举例):
DMA_ADC4.png

    同时,因为我初始的程序并没有对ADC_Handler模式进行定义处理,同时导致MCU在响应中断后进不了中断服务函数,从而一致卡死在汇编语言B.处,类似C语言中的while(1);,从而产生死循环。


4、基于APM32F411 中断实现 DMA_ADC例程
APM32F411 DMA_ADC Demo.rar (7.63 MB, 下载次数: 6)

本次分享到这,如有问题,大家评论区一起讨论,谢谢!

打赏榜单

21小跑堂 打赏了 30.00 元 2023-09-27
理由:恭喜通过原创审核!期待您更多的原创作品~

评论

赞,来学习一下!  发表于 2023-10-12 11:47
问题的追踪和探究较为深入,问题的定位也相对准确,但是整体对问题点的阐述和过程分析及结果论述不够明确,文章显得比较散乱。但是这种严查到底的态度值得肯定。  发表于 2023-9-27 18:50
kenny01 发表于 2023-9-26 09:04 | 显示全部楼层
非常好的技术分享贴子,也经常遇到这个问题,点赞收藏
 楼主| lzh12a3nf 发表于 2023-9-26 10:13 | 显示全部楼层
kenny01 发表于 2023-9-26 09:04
非常好的技术分享贴子,也经常遇到这个问题,点赞收藏

 楼主| lzh12a3nf 发表于 2023-9-26 10:13 | 显示全部楼层
修改了部分文字表述
kai迪皮 发表于 2023-9-26 11:02 | 显示全部楼层
学习了,非常不错
 楼主| lzh12a3nf 发表于 2023-9-27 10:28 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

37

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部