雷羽舟 2022-11-11 16:03 采纳率: 0%
浏览 354
已结题

STM32无法进入DMA中断服务函数

我遇到了一个匪夷所思的问题,我开启了IDLE中断和DMA中断,其中IDLE中断是可以正常运行的,DMA中断却始终无法进入中断服务函数,哪怕在IDLE中断中用串口打印了出了dma相应的中断标志位是1,但仍然无法进入dma中断服务函数,不知道问题出在了哪里


//dma.c配置函数,其中设置dma缓冲为5,循环模式,开启DMA1_IT_TC5中断,dma抢占优先级为1,高于usart的中断优先级

void DMA_Config(DMA_Channel_TypeDef* DMA_CHx, u32 dir, u32 cpar, u32 cmar, u16 cndtr)   
{
       
//使能DMA时钟
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
       
//记录传输数据量       
        CNDTR = cndtr;
       
//配置DMA中断
        NVIC_InitStructure_DMA.NVIC_IRQChannel = DMA1_Channel5_IRQn; //开启DMA中断通道
        NVIC_InitStructure_DMA.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级2,优先于串口中断
        NVIC_InitStructure_DMA.NVIC_IRQChannelSubPriority = 3;                //子优先级3
        NVIC_InitStructure_DMA.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure_DMA);        //根据指定的参数初始化VIC寄存器
       
//去初始化DMA
        DMA_DeInit(DMA_CHx);
       
//为 DMA_InitTpyeDef 结构体成员赋值       
        DMA_InitStruct. DMA_PeripheralBaseAddr = cpar;
        DMA_InitStruct. DMA_MemoryBaseAddr = cmar;
        DMA_InitStruct. DMA_BufferSize = cndtr;
        DMA_InitStruct. DMA_Priority = DMA_Priority_Medium;
        DMA_InitStruct. DMA_DIR = dir;
        DMA_InitStruct. DMA_Mode = DMA_Mode_Circular;  //循环模式
        DMA_InitStruct. DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStruct. DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStruct. DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
        DMA_InitStruct. DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        DMA_InitStruct. DMA_M2M = DMA_M2M_Disable;
       
//DMA中断标志位初始化
  DMA_ClearITPendingBit(DMA1_IT_TC5);
       
//DMA1_CH5_TC中断使能
  DMA_ITConfig(DMA_CHx,DMA1_IT_TC5, ENABLE);  //开启DMA1_CH5_TC中断,DMA传输完成标志!
       
//DMA初始化
        DMA_Init(DMA_CHx, &DMA_InitStruct);
       
//使能DMA
  DMA_Cmd(DMA_CHx, ENABLE);
       
}



//dma开启函数,过程为关闭dma,重新赋值dma缓冲通道,开启dma

void DMA_EnableCmd(DMA_Channel_TypeDef* DMA_CHx)
{
//每次开启DMA之前必须先重装在CNDTR,开启CNDTR之前必须关闭DMA
    DMA_Cmd(DMA_CHx, DISABLE);
    
//重装在CNDTR
    DMA_SetCurrDataCounter(DMA_CHx, CNDTR);

//开启本次DMA传输
    DMA_Cmd(DMA_CHx, ENABLE);
}


//DMA1_IT_TC5中断服务函数,功能是每次dma传输完成后,将MyFlag全局变量置1,但是这个中断服务函数始终进不去!!

void DMA1_Channel5_IRQHandler()    //将超载标志置1
{
    if(DMA_GetITStatus(DMA1_IT_TC5) != RESET)
    {
        MyFlag = 1;
        DMA_ClearITPendingBit(DMA1_IT_GL5);
        DMA_ClearITPendingBit(DMA1_IT_TC5);    //清除DMA1_CH5_TC中断标志位,该函数作用原理和ClearFlag是一样的,都是对DMA_IFCR寄存器进行写操作!
    }
}


//usart.c配置函数,其中开启了usart1的dma功能

void uart_init(u32 bound){

    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
     
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);    //使能USART1,GPIOA时钟
  
    //USART1_TX   GPIOA.9
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
   
        //USART1_RX      GPIOA.10初始化
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

        //Usart1 NVIC 配置
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器
  
         //USART 初始化设置

        USART_InitStructure.USART_BaudRate = bound;//串口波特率
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
        USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
        USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //收发模式

        USART_Init(USART1, &USART_InitStructure); //初始化串口1
        USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); //开启串口空闲检测IDLE中断
        USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //开启串口DMA接收
        USART_Cmd(USART1, ENABLE);                    //使能串口1 

}


//IDLE中断服务函数,先打印dma对应的中断标志位,再打印MyFlag标志,其中MyFlag是一个全局变量,初始化为0,在dma中断服务函数中置1,也就是说如果打印得到DMA1_IT_TC5是1的话,MyFlag打印也应该得到1才对!但是实际情况是DMA1_IT_TC5打印值为1时,MyFlag依然打印值是0,说明根本没进入dma中断服务函数,要哭了.

if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
            {
                 DMA_FLAG = DMA_GetFlagStatus(DMA1_IT_TC5);                                 //获取DMA1_IT_TC5中断标志位
                 printf("The DMA1_TC5 status is %d\r\n",DMA_FLAG);                             //打印DMA1_IT_TC5中断标志位
                     printf("The MyFlag is %d\r\n",MyFlag);                                                  //打印MyFlag全局变量
                 printf("The IDLE status was SET!\r\n");
                 IDLE_ClearBit = USART_ReceiveData(USART1);                                      //清除IDLE标志位
                 if(USART_GetITStatus(USART1,USART_IT_IDLE) == RESET)
                 {
                      printf("The IDLE status is CLEAR!\r\n");
                        if(MyFlag == 0)   
                        {
                             Cmd = ServoCmd(USART_RX_BUF);
                             printf("The current Cmd is %d\r\n",Cmd);
                             if(Cmd >= 20 && Cmd <= 90)
                                {
                                     printf("占空比是%d%%\r\n",Cmd);
                               Duty_Count = Cmd * arr /100;
                             TIM_SetCompare1(TIM4,Duty_Count);                                    //IDLE中断控制TIM4_CH1的CCR寄存器,用于修改占空比
                                }    
                             else printf("非法指令!请重新输入:(输入范围:20至90)\r\n");
                        }
                        else 
                        {
                             MyFlag = 0;    //如果超载,重新刷新MyFlag,本次USART_RX_BUF中的数据无效,不做处理!
                             printf("数据超载!请重新输入o3o\r\n");
                        }
                        DMA_EnableCmd(DMA1_Channel5);                                       //重置DMA,使之从BUF[0]开始记录数据
                        printf("接收缓冲器内的数据是 %s\r\n",USART_RX_BUF);          //打印USART_RX_BUF的数据
                        memset(USART_RX_BUF,0,sizeof(USART_RX_BUF));               
                 }
            }

用串口打印结果如下:
输入“50\r\n”时,数据长度还没有达到dma缓冲长度,可以得到正确的结果:DMA1_IT_TC5 = 0,MyFlag = 0;
输入“123\r\n”时,数据长度达到了dma缓冲长度,dma完成一次传输,DMA1_IT_TC5 = 1,但是MyFlag依然是0,说明DMA1_IT_TC5中断服务函数没有运行!

img

现在遇到了一个新的问题,新建工程单独测试dma中断没有问题,在此基础上添加USART的IDLE中断,发现这个时候dma中断没问题,IDLE中断却又进不去了!如果把IDLE中断抢占优先级设置大于dma中断,串口打印就会出现类似于“干扰”一样的问题,所以我在想是不是串口中断和dma中断在stm32内部存在着冲突?

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "stdio.h"
 
 
/* Private define ------------------------------------------------------------*/
#define USART1_DR_Base  0x40013804
#define  SRC_USART1_DR (&(USART1->DR))
/* Private variables ---------------------------------------------------------*/
#define SENDBUFF_SIZE   5
vu8 SendBuff[SENDBUFF_SIZE];
 
 
 
void DMA_Configuration(void);
void USART1_Configuration(void);
//////////////////////////////////////////////////////////////////
//加入以下代码,支持printf函数,而不需要选择use MicroLIB      
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
    int handle; 
 
}; 
 
FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
_sys_exit(int x) 
{ 
    x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
    while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
    return ch;
}
#endif 
// 
// 
int main(void)
{
    
    SystemInit();
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
    USART1_Configuration(); 
    printf("USART1!\r\n");
    DMA_Configuration();                   
    while (1) 
    {         
    }
 
}
 
 
 
// Description    : NUSART1设置
void USART1_Configuration(void)
{
      NVIC_InitTypeDef NVIC_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1, ENABLE);
      //NVIC配置
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =  3; 
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    NVIC_Init(&NVIC_InitStructure); 
    //USART1_TX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    //USART1_RX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
 
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init(USART1, &USART_InitStructure);
        
        USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);         
    USART_Cmd(USART1, ENABLE);
}
 
 
void DMA_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);    //使能DMA传输
 
    DMA_DeInit(DMA1_Channel5);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(USART1->DR));
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                      //外设作源头//外设是作为数据传输的目的地还是来源
    DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;                                        //DMA缓存的大小 单位在下边设定
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;               //外设地址寄存器不递增
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                        //内存地址递增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;        //外设字节为单位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;            //内存字节为单位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                              //工作在循环缓存模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                            //4优先级之一的(高优先) VeryHigh/High/Medium/Low
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                               //非内存到内存
    DMA_Init(DMA1_Channel5, &DMA_InitStructure);                                    //根据DMA_InitStruct中指定的参数初始化DMA的通道1寄存器   
    DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);                               //DMA5传输完成中断
    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);                              //使能USART1的接收DMA请求
    DMA_Cmd(DMA1_Channel5, ENABLE);          
    DMA_ClearFlag(DMA1_FLAG_TC5); 
        //NVIC配置
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =  3; 
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    NVIC_Init(&NVIC_InitStructure); 
 
}
 

 
void USART1_IQRHandler(void)
{
     u16 IDLE_ClearBit;
    printf("Start IDLE Interrupt!\r\n");
     if(USART_GetITStatus(USART1,USART_IT_IDLE))
     {
          IDLE_ClearBit = USART_ReceiveData(USART1);
          while(USART_GetITStatus(USART1,USART_IT_IDLE));
          printf("%s\r\n", SendBuff); 
     }
}


void DMA1_Channel5_IRQHandler(void)
{
    u8 end;
    printf("Start DMA transmission!\r\n");
   if(DMA_GetITStatus(DMA1_IT_TC5))
    {        
        end = DMA_GetCurrDataCounter(DMA1_Channel5);
        DMA_ClearITPendingBit(DMA1_IT_GL5);///* 清中断源
        DMA_ClearFlag(DMA1_FLAG_TC5);         
        printf("%d\r\n", end);
    }
} 
 

运行结果:

img

如果USART的中断抢占优先级从3改为0,运行结果为:

img

img

每按一次发送就会打印几个字出来,太奇怪了!

  • 写回答

8条回答 默认 最新

  • Jackyin0720 2022-11-11 16:34
    关注

    你看看这篇实例【STM32 DMA无法进入中断】,对你是否有帮助:https://zhidao.baidu.com/question/609340263.html

    评论

报告相同问题?

问题事件

  • 系统已结题 11月19日
  • 修改了问题 11月11日
  • 创建了问题 11月11日

悬赏问题

  • ¥30 基于信创PC发布的QT应用如何跨用户启动后输入中文
  • ¥20 非root手机,如何精准控制手机流量消耗的大小,如20M
  • ¥15 远程安装一下vasp
  • ¥15 自己做的代码上传图片时,报错
  • ¥15 Lingo线性规划模型怎么搭建
  • ¥15 关于#python#的问题,请各位专家解答!区间型正向化
  • ¥15 unity从3D升级到urp管线,打包ab包后,材质全部变紫色
  • ¥50 comsol温度场仿真无法模拟微米级激光光斑
  • ¥15 上传图片时提交的存储类型
  • ¥15 VB.NET如何绘制倾斜的椭圆