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正常

cpp 复制代码
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; 
}     

问题发生了:
当我判断 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的,

你们真的试过吗, 还是搬来搬去忽悠呢?

cpp 复制代码
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;   
}
相关推荐
电气_空空4 小时前
基于LabVIEW的数据采集系统设计与实现
单片机·嵌入式硬件·labview
caimouse4 小时前
ReactOS BootCD 光盘布局完整深度分析
单片机·reactos
zlinear数据采集卡5 小时前
从万用表的6步调零到硅片级微秒自校准:硬核拆解LHAMP188的宽压轨到轨与零漂移实战
arm开发·stm32·单片机·嵌入式硬件·fpga开发
三品吉他手会点灯6 小时前
嵌入式机器学习 - 学习笔记1.2.3 - 机器学习软件框架
人工智能·笔记·嵌入式硬件·学习·机器学习
国科安芯7 小时前
ASC8T245S 8通道电平转换设计实战:从系统架构到QFN24 Layout再到量产测试
网络·单片机·物联网·安全·fpga开发·系统架构
云栖梦泽8 小时前
将RAW打包成MIPI CSI2
linux·人工智能·嵌入式硬件
伟大的前程8 小时前
us级开定时器中断,单片机的开销大,改用轮询的方式
单片机·嵌入式硬件
ACP广源盛1392462567320 小时前
IX8024@ACP# 搭配此芯 AI 服务器 + 爱芯元智产品完整方案
大数据·运维·服务器·人工智能·分布式·嵌入式硬件
ShallWeL21 小时前
NVIDIA Jetson 早期系列演进
人工智能·嵌入式硬件·边缘计算·智能硬件
2501_914245931 天前
C语言与硬件交互:从GPIO到中断的嵌入式编程实践
c语言·单片机·交互