想请教一个问题,我使用的是STM32H7B0 的板子做一个提升采样率的功能。配置情况如下:ADC 时钟配置为 32 MHz,ADC 配置为 4 通道使用 DMA 传输并开启 DMA 中断,如果我把 ADC 的采样周期 sConfig.SamplingTime 从 ADC_SAMPLETIME_16CYCLES_5 设置到 ADC_SAMPLETIME_8CYCLES_5时,程序运行就会出现卡死,不知道问题出现在哪里?(猜测是中断频率太高出现的)如果设置在ADC_SAMPLETIME_16CYCLES_5 程序是正常运行的,采样也是正常的;如果设置为ADC_SAMPLETIME_8CYCLES_5 程序就会卡死,想请教是什么原因? 我的 ADC 和 DMA 配置如下: RCC_PeriphCLKInitTypeDefPeriphClkInitStruct = {0}; ADC_MultiModeTypeDefmultimode = {0}; ADC_ChannelConfTypeDefsConfig = {0}; /* 使能 ADC 时钟 */ __HAL_RCC_ADC12_CLK_ENABLE(); /** ADC 配置 */ ADC1_Handle.Instance= ADC1; // 选择 ADC1 ADC1_Handle.Init.ClockPrescaler= ADC_CLOCK_ASYNC_DIV1; // ADC1 进行 1 分频 ADC1_Handle.Init.Resolution= ADC_RESOLUTION_16B; // 分辨率 16bit ADC1_Handle.Init.ScanConvMode= ADC_SCAN_ENABLE; // 扫描模式开启 ADC1_Handle.Init.EOCSelection= ADC_EOC_SINGLE_CONV; // ADC1_Handle.Init.LowPowerAutoWait= DISABLE; // 关闭低功耗自动等待 ADC1_Handle.Init.ContinuousConvMode= ENABLE; // 连续转换模式开启 ADC1_Handle.Init.NbrOfConversion= 4; // 转换 4 个通道 ADC1_Handle.Init.DiscontinuousConvMode= DISABLE; // 不连续转换 ADC1_Handle.Init.ExternalTrigConv= ADC_SOFTWARE_START; // ADC 软件触发 ADC1_Handle.Init.ExternalTrigConvEdge= ADC_EXTERNALTRIGCONVEDGE_NONE; // 不进行外部触发 ADC1_Handle.Init.ConversionDataManagement= ADC_CONVERSIONDATA_DMA_CIRCULAR; // ADC-DMA 循环传输 ADC1_Handle.Init.Overrun= ADC_OVR_DATA_PRESERVED; // 数据溢出时,覆盖写入 ADC1_Handle.Init.LeftBitShift= ADC_LEFTBITSHIFT_NONE; // 对齐方式 ADC1_Handle.Init.OversamplingMode= DISABLE; // 不进行过采样 if(HAL_ADC_Init(&ADC1_Handle) != HAL_OK) { } /** 初始化外设时钟 */ PeriphClkInitStruct.PeriphClockSelection= RCC_PERIPHCLK_ADC; PeriphClkInitStruct.PLL2.PLL2M= 4; PeriphClkInitStruct.PLL2.PLL2N= 8; PeriphClkInitStruct.PLL2.PLL2P= 4; PeriphClkInitStruct.PLL2.PLL2Q= 1; PeriphClkInitStruct.PLL2.PLL2R= 2; PeriphClkInitStruct.PLL2.PLL2RGE= RCC_PLL2VCIRANGE_3; PeriphClkInitStruct.PLL2.PLL2VCOSEL= RCC_PLL2VCOWIDE; PeriphClkInitStruct.PLL2.PLL2FRACN= 0.0; PeriphClkInitStruct.AdcClockSelection= RCC_ADCCLKSOURCE_PLL2; if(HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { } /* ADC1 DMA 初始化 */ DMA_ADC1_Handle.Instance= DMA1_Stream0; DMA_ADC1_Handle.Init.Request= DMA_REQUEST_ADC1; DMA_ADC1_Handle.Init.Direction= DMA_PERIPH_TO_MEMORY; DMA_ADC1_Handle.Init.PeriphInc= DMA_PINC_DISABLE; DMA_ADC1_Handle.Init.MemInc= DMA_MINC_ENABLE; DMA_ADC1_Handle.Init.PeriphDataAlignment= DMA_PDATAALIGN_HALFWORD; DMA_ADC1_Handle.Init.MemDataAlignment= DMA_MDATAALIGN_HALFWORD; DMA_ADC1_Handle.Init.Mode= DMA_CIRCULAR; DMA_ADC1_Handle.Init.Priority= DMA_PRIORITY_MEDIUM; DMA_ADC1_Handle.Init.FIFOMode= DMA_FIFOMODE_DISABLE; if(HAL_DMA_Init(&DMA_ADC1_Handle) != HAL_OK) { } __HAL_LINKDMA(&ADC1_Handle,DMA_Handle,DMA_ADC1_Handle); /** 配置多通道模式 */ multimode.Mode= ADC_MODE_INDEPENDENT; if(HAL_ADCEx_MultiModeConfigChannel(&ADC1_Handle, &multimode) != HAL_OK) { } /** 配置规则转换通道 4 */ sConfig.Channel= ADC_CHANNEL_4; sConfig.Rank =ADC_REGULAR_RANK_1; sConfig.SamplingTime= ADC_SAMPLETIME_16CYCLES_5; sConfig.SingleDiff= ADC_SINGLE_ENDED; sConfig.OffsetNumber= ADC_OFFSET_NONE; sConfig.Offset= 0; sConfig.OffsetSignedSaturation= DISABLE; if(HAL_ADC_ConfigChannel(&ADC1_Handle, &sConfig) != HAL_OK) { } /** 配置规则转换通道 7 */ sConfig.Channel= ADC_CHANNEL_7; sConfig.Rank =ADC_REGULAR_RANK_2; if(HAL_ADC_ConfigChannel(&ADC1_Handle, &sConfig) != HAL_OK) { } /** 配置规则转换通道 8 */ sConfig.Channel= ADC_CHANNEL_8; sConfig.Rank =ADC_REGULAR_RANK_3; if(HAL_ADC_ConfigChannel(&ADC1_Handle, &sConfig) != HAL_OK) { } /** C配置规则转换通道 18 */ sConfig.Channel= ADC_CHANNEL_18; sConfig.Rank =ADC_REGULAR_RANK_4; if(HAL_ADC_ConfigChannel(&ADC1_Handle, &sConfig) != HAL_OK) { } HAL_ADCEx_Calibration_Start(&ADC1_Handle,ADC_CALIB_OFFSET, ADC_SINGLE_ENDED); HAL_ADC_Start_DMA(&ADC1_Handle,(uint32_t*)&ADC_ConvertedValue, 4); 开启 DMA 中断配置如下: /* DMA 控制器时钟使能 */ __HAL_RCC_DMA1_CLK_ENABLE(); /* DMA 中断初始化 */ /*DMA1_Stream0_IRQn 中断配置 */ HAL_NVIC_SetPriority(DMA1_Stream0_IRQn,0, 0); HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn); DMA 中断程序如下: /** *@brief This function handles DMA1 stream0 global interrupt. */ voidDMA1_Stream0_IRQHandler(void) { uint16_t size = 4; uint16_t temp_buff1[4]; // uint16_t temp_buff2[4]; if(__HAL_DMA_GET_FLAG(&DMA_ADC1_Handle,DMA_FLAG_TCIF0_4)) { // 把数据写入环形缓冲区 for(uint16_t i = 0; i < size; i++) { temp_buff1 =ADC_ConvertedValue; // temp_buff2 = 0; } Write_RingBuff(temp_buff1, size); __HAL_DMA_CLEAR_FLAG(&DMA_ADC1_Handle,DMA_FLAG_TCIF0_4); } HAL_DMA_IRQHandler(&DMA_ADC1_Handle); } 其中 Write_RingBuff 这个是一个写入循环缓冲区,为了能够通过串口打印观察到采样的点,所以用缓冲区临时存储,这个函数测试是没有 bug 的,屏蔽以后也是运行不了。
主函数是这样的: MPU_Config(); // 分配内存存储单元 HAL_Init(); // HAL 层初始化 SystemClock_Config(); // 配置系统时钟 LED_Init(); // 初始化 LED 引脚 KEY_Init(); // 初始化按键引脚 USART1_Init(); // USART1 初始化 ADC_Init(); // 初始化 ADC RingBuff_Init();
uint16_t size = 4; // uint8_t temp_buff1[128] = {0}; uint16_t temp_buff2[4]; // 初始化 for(uint16_t i = 0; i < size; i++) { temp_buff2 = i + 2; }
while(1) { if(RINGBUFF_LEN > Get_RingBuff_Ridx()) // + 4) { Read_RingBuff(temp_buff2, size);
// sprintf((char*)temp_buff1, "%d,%d,%d,%d\n",temp_buff2[0], temp_buff2[1], temp_buff2[2], temp_buff2[3]); // Usart_SendString(temp_buff1); // HAL_Delay(1); printf("%d,%d,%d,%d\n",temp_buff2[0], temp_buff2[1], temp_buff2[2], temp_buff2[3]);
// printf("%d,%d,%d,%d,",temp_buff2[0], temp_buff2[1], temp_buff2[2], temp_buff2[3]); }
}
主函数用于读出缓冲区数据,用串口打印出来。
ADC 配置的是快通道,计算卡死时候的中断频率应该是有 (32MHz) / (7.5 + 8.5) / 4 = 0.5MHz 左右(DMA 转换完成后开始中断,有 4 个通道)。
所以综上,麻烦看一下配置情况是否正确,中断卡死的具体原因是什么,如果我想调试了可以正常运行我需要怎么配置或者使用什么方法来处理。(任务期望尽量多获取采样点数)还麻烦大佬帮忙看看,感谢!!
|