• STM32F103 USART1 IDLE FLAG


    STM32F103 USART1 IDLE 旗标进中断ISR后, 会自动清除
    目前在接收不定长度的 Modbus Frame上, 还是以 RXNE为基础
    想改用STM32 DMA + USART IDLE试试, 看能不能降低中断次数/CPU使用率.
    数据发送频率低, 长度<16
    USART1 RX 以 DMA Normal mode 驱动 ( Buffer & CNDTR = 80)
    接收 不定个字符后, 等USART1触发 IDLE 中断 (其他 RXNEIE, TXEIE, TCIE关闭),
    网上 + CSDN 搜了 STM32 DMA + USART IDLE的文章, 概念上都建议在中断 ISR中判断 IDLEF

    开始实作
    (a) DMA1 -> RX Buffer 数据接收正确
    (b) USART1 触发 IDLE中断, 程序进入ISR正常

    void USART1_IRQHandler(void)
    {
    	int  iRXLen =0;  
        if( RESET != USART_GetITStatus( USART1, USART_IT_IDLE )) 
         {
            iRXLen = USART_BUFFER_SIZE - (uint16_t)(DMA1_Channel5->CNDTR);
            if( iRXLen > 3)  
              {
    			    // DMA_Cmd( DMA1_Channel4, DISABLE );    
    			    DMA1_Channel4->CCR &= ~DMA_CCR4_EN;     
    	            flagMessgaeIn=1; ; 
             }
         }  
         USART1->SR=0; 
    }     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    问题发生了:
    当我判断 USART_FLAG_IDLE 时, IDLE旗标, 它自己清除了!
    实验发现, 似乎进了中断USART1_IRQHandler后就会清除.
    断点 设在进入后第一个点, SR=0x000000D0
    执行第一个指令时, 就变成 SR=0x000000C0
    嗯! USART_FLAG_IDLE = 0x00000010 ( SR bit4 )

    <答案>
    ST RM0008文件上, 说的是IDLEF要软件清除.它漏说了: IDLEF 进ISR会被自动清除!
    意思是, 开了 IDLEIE, 你是摸不到IDLEF的!
    使用上: 不开中断的状况下, 可以轮询 IDLEF, 再软件清除!
    我就想知道那些说 STM32F103可以在 ISR里面判断 IDLEF的,
    你们真的试过吗, 还是搬来搬去忽悠呢? 这属实是开了眼界.
    想不到数字世界 0 , 1 之外, 竟然出现了薛定谔的猫!

    那我家猫也出出镜好了
    Cat Name = Pearl

    void DMA1_Init(void)
    {
    	    DMA_InitTypeDef  DMA_InitStruct;
    	    // Enable DMA1 Clock    
    	    RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE);  
    	    
    	    // TX Config    
    	    DMA_DeInit( DMA1_Channel4 );
    	    DMA_InitStruct.DMA_BufferSize       = 0;
    	    DMA_InitStruct.DMA_DIR              = DMA_DIR_PeripheralDST;
    	    DMA_InitStruct.DMA_M2M              = DMA_M2M_Disable;
    	    DMA_InitStruct.DMA_MemoryBaseAddr   = (uint32_t)USART_TX_Buffer;
    	    DMA_InitStruct.DMA_MemoryDataSize   = DMA_MemoryDataSize_Byte;
    	    DMA_InitStruct.DMA_MemoryInc        = DMA_MemoryInc_Enable;
    	    DMA_InitStruct.DMA_Mode             = DMA_Mode_Normal;
    	    DMA_InitStruct.DMA_PeripheralBaseAddr = USART1_BASE +0x0004;
    	    DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
    	    DMA_InitStruct.DMA_PeripheralInc    = DMA_PeripheralInc_Disable;
    	    DMA_InitStruct.DMA_Priority         = DMA_Priority_High;  
    	    DMA_Init( DMA1_Channel4, &DMA_InitStruct);
    	    DMA_Cmd( DMA1_Channel4, DISABLE );
    	    
    	   
    	    // RX Config
    	    DMA_DeInit( DMA1_Channel5);
    	    DMA_InitStruct.DMA_BufferSize       = USART_BUFFER_SIZE;
    	    DMA_InitStruct.DMA_DIR              = DMA_DIR_PeripheralSRC;
    	    DMA_InitStruct.DMA_M2M              = DMA_M2M_Disable;
    	    DMA_InitStruct.DMA_MemoryBaseAddr   = (uint32_t)USART_RX_Buffer;
    	    DMA_InitStruct.DMA_MemoryDataSize   = DMA_MemoryDataSize_Byte;
    	    DMA_InitStruct.DMA_MemoryInc        = DMA_MemoryInc_Enable;
    	    DMA_InitStruct.DMA_Mode             = DMA_Mode_Normal;
    	    DMA_InitStruct.DMA_PeripheralBaseAddr= USART1_BASE +0x0004;
    	    DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
    	    DMA_InitStruct.DMA_PeripheralInc    = DMA_PeripheralInc_Disable;
    	    DMA_InitStruct.DMA_Priority         = DMA_Priority_High;      
    	    DMA_Init( DMA1_Channel5, &DMA_InitStruct);
    	    DMA_Cmd( DMA1_Channel5, ENABLE);
        }
    
    void USART1_Init(uint32_t baud)
    {
    	    USART_InitTypeDef USART_InitStructure;
    	    GPIO_InitTypeDef GPIO_InitStructure;
    	    NVIC_InitTypeDef NVIC_InitStrue;    
    		
    	    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    		  
    		  // Set GPIO PA9 as USART1 TX 
    	    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; 
    	    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//USART1_TX PA.9
    	    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
    	    GPIO_Init(GPIOA, &GPIO_InitStructure);  
    	
    		  // Set GPIO PA10 as USART1 RX 
    	    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; 
    	    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//USART1_RX PA.10
    	    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
    	    GPIO_Init(GPIOA, &GPIO_InitStructure);  	
    		
    		  // Init USART1	
    	    USART_DeInit(USART1); 
    	    USART_InitStructure.USART_BaudRate = baud; 
    	    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_Rx | USART_Mode_Tx;  
    	    USART_Init(USART1, &USART_InitStructure);  
    	
    	    // Enable USART1 Interrupt
    	    USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); 
    	    USART_ITConfig(USART1, USART_IT_TC, DISABLE);
    		USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
    	    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); 
    	    
    	    // Set NVIC Interrupt
    	    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_0 ); 
    	    NVIC_InitStrue.NVIC_IRQChannel = USART1_IRQn;
    	    NVIC_InitStrue.NVIC_IRQChannelCmd = ENABLE; 
    	    NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority = 0; 
    	    NVIC_InitStrue.NVIC_IRQChannelSubPriority = 13; 
    	    NVIC_Init(&NVIC_InitStrue); 
    	    
    	    DMA1_Init(); 
    	    // USART1 TX Channle4
    	    USART_DMACmd( USART1, USART_DMAReq_Tx, ENABLE);
    	    // USART1 RX Channel5   
    	    USART_DMACmd( USART1, USART_DMAReq_Rx, ENABLE);    
    	    USART_Cmd(USART1,ENABLE); 
    	    DelayXms(2);        
    	    (void)USART1->SR;        
    	    (void)USART1->DR;   
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95

    STM32F10x USART Status register
    Status register除了 IDLEIE外, 关闭其余所有 USART1 Interrupt Sources

    void USART1_IRQHandler(void)
    {
    	int  iRXLen =0;  
         if( RESET ==  ( USART1->SR & 0x000F )) 	// No Error
         {
            iRXLen = USART_BUFFER_SIZE - (uint16_t)(DMA1_Channel5->CNDTR);
            if( iRXLen > 3)  
              {	// DMA_Cmd( DMA1_Channel5, DISABLE );    
    			    DMA1_Channel5->CCR &= ~DMA_CCR5_EN;     
    	            flagMessgaeIn=1; ; 
             }
         } 
         else
         { 		    // Restart RX DMA when Error: PE , NE, FE, ORE
    			    DMA1_Channel5->CCR &= ~DMA_CCR5_EN;          
    			    DMA1_Channel5->CNDTR  = USART_BUFFER_SIZE;          
    			    DMA1_Channel5->CCR  |= DMA_CCR5_EN;          			    
         }
         // Clear All Pending Flags -> Expected to clear all error flags
         (void)USART1->SR; 
         (void)USART1->DR; 
    }   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    [附源码]Python计算机毕业设计SSM建筑材料采购管理系统(程序+LW)
    SpringBoot_整合Mybatis-plus
    Mybaitis入门基础(一)MyBatis的概念引入及工作原理
    DocArray Updates 0.38+0.39
    使用el-tree实现懒加载、请求接口的检索依次展开
    MySQL学习笔记8——游标
    微信小程序开发学习—Day1
    本地化部署对比选型推荐——百数低代码平台
    Groovy安装开发环境
    Go语言:使用简单的 for 迭代语句进行 TDD 驱动测试开发与 benchmark 基准测试
  • 原文地址:https://blog.csdn.net/weixin_44679008/article/details/133612908