主频200MHz,配置为100kHz定时触发ADC采集5kHz信号,每个周期可以正常采集20个点,将定时器周期改为999,理论计算触发频率应该是200kHz,但是实际运行无法进入DMA中断了,这是什么问题?
[C] 纯文本查看 复制代码 static void TIM1_Config(u32 period)
{
TIM_HandleTypeDef htim ={0};
TIM_OC_InitTypeDef sConfig = {0};
__HAL_RCC_TIM1_CLK_ENABLE();
/*-----------------------------------------------------------------------
System Clock source = PLL (HSE)
SYSCLK(Hz) = 200000000 (CPU Clock)
HCLK(Hz) = 200000000 (AXI and AHBs Clock)
AHB Prescaler = 2
D2 APB1 Prescaler = 2 (APB1 Clock 100MHz)
D2 APB2 Prescaler = 2 (APB2 Clock 100MHz)
因为APB1 prescaler != 1, 所以 APB1上TIMxCLK = APB1 x 2 = 100MHz;
因为APB2 prescaler != 1, 所以 APB2上TIMxCLK = APB2 x 2 = 200MHz;
APB1 定时器有TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12
APB2 定时器有TIM1, TIM8 , TIM15
period = 20000
TIM1CLK = 200MHz/(Period + 1) / (Prescaler + 1) = 200MHz / 20000 / 1 = 10KHz
period = 2000
TIM1CLK = 200MHz/(Period + 1) / (Prescaler + 1) = 200MHz / 2000 / 1 = 100KHz
----------------------------------------------------------------------- */
HAL_TIM_Base_DeInit(&htim);
htim.Instance = TIM1;
htim.Init.Period = 1999;
htim.Init.Prescaler = 0;
htim.Init.ClockDivision = 0;
htim.Init.CounterMode = TIM_COUNTERMODE_UP;
htim.Init.RepetitionCounter = 0;
HAL_TIM_Base_Init(&htim);
sConfig.OCMode = TIM_OCMODE_PWM1;
sConfig.OCPolarity = TIM_OCPOLARITY_LOW;
/* 占空比50% */
sConfig.Pulse = 1000;
if(HAL_TIM_OC_ConfigChannel(&htim, &sConfig, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
/* 启动OC1 */
if(HAL_TIM_OC_Start(&htim, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
}
/*
*********************************************************************************************************
* 函 数 名: bsp_InitADC
* 功能说明: 初始化ADC
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitADC1(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
GPIO_InitTypeDef GPIO_InitStruct;
/* ## - 2 - 配置ADC采样使用的引脚 ####################################### */
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = ISEN_C_Pin|CLIP_C_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(OVP_V_GPIO_Port, &GPIO_InitStruct);
/* ## - 3 - 配置ADC采样使用的时钟 ####################################### */
__HAL_RCC_DMA2_CLK_ENABLE();
hdma_adc1.Instance = DMA2_Stream0; /* 使用的DMA2 Stream0 */
hdma_adc1.Init.Channel = DMA_CHANNEL_0; /* 请求类型采用DMA_REQUEST_ADC1 */
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY; /* 传输方向是从外设到存储器 */
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE; /* 外设地址自增禁止 */
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE; /* 存储器地址自增使能 */
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; /* 外设数据传输位宽选择半字,即16bit */
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; /* 存储器数据传输位宽选择半字,即16bit */
hdma_adc1.Init.Mode = DMA_CIRCULAR; /* 循环模式 */
hdma_adc1.Init.Priority = DMA_PRIORITY_LOW; /* 优先级低 */
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE; /* 禁止FIFO*/
hdma_adc1.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; /* 禁止FIFO此位不起作用,用于设置阀值 */
hdma_adc1.Init.MemBurst = DMA_MBURST_SINGLE; /* 禁止FIFO此位不起作用,用于存储器突发 */
hdma_adc1.Init.PeriphBurst = DMA_PBURST_SINGLE; /* 禁止FIFO此位不起作用,用于外设突发 */
/* 初始化DMA */
if(HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
Error_Handler();
}
/* 开启DMA1 Stream1的中断 */
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
/* 关联ADC句柄和DMA句柄 */
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
/* ## - 4 - 配置ADC ########################################################### */
__HAL_RCC_ADC1_CLK_ENABLE();
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; /* 采用AHB同步时钟,4分频,即200MHz/4 = 50MHz */
hadc1.Init.Resolution = ADC_RESOLUTION_12B; /* 16位分辨率 */
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE; /* 禁止扫描,因为仅开了一个通道 */
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; /* EOC转换结束标志 */
hadc1.Init.ContinuousConvMode = DISABLE; /* 禁止自动转换,采用的定时器触发转换 */
hadc1.Init.NbrOfConversion = 2; /* 使用了1个转换通道 */
hadc1.Init.DiscontinuousConvMode = DISABLE; /* 禁止不连续模式 */
hadc1.Init.NbrOfDiscConversion = 1; /* 禁止不连续模式后,此参数忽略,此位是用来配置不连续子组中通道数 */
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; /* 定时器1的CC1触发 */
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; /* 上升沿触发 */
hadc1.Init.DMAContinuousRequests = ENABLE;
/* 初始化ADC */
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/* 配置ADC通道 */
sConfig.Channel = ADC_CHANNEL_5; /* 配置使用的ADC通道 */
sConfig.Rank = ADC_REGULAR_RANK_1; /* 采样序列里的第1个 */
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; /* 采样周期 */
sConfig.Offset = 0; /* 无偏移的情况下,此参数忽略 */
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_3;
sConfig.Rank = ADC_REGULAR_RANK_2; /* 采样序列里的第2个 */
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* ## - 5 - 配置ADC的定时器触发 ####################################### */
TIM1_Config(ADC1_FS_100KHZ);
/* ## - 6 - 启动ADC的DMA方式传输 ####################################### */
//if (HAL_ADC_Start_DMA(&hadc1, (uint32_t *)ADC1Buf, ADC_SIZE*2) != HAL_OK)
//{
// Error_Handler();
//}
} [C] 纯文本查看 复制代码 /*
*********************************************************************************************************
* 函 数 名: DMA2_Stream0_IRQHandler
* 功能说明: DMA2 Stream0中断服务程序
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void DMA2_Stream0_IRQHandler(void)
{
/* 传输完成中断 */
if((DMA2->LISR & DMA_FLAG_TCIF0_4) != RESET)
{
/*
1、使用此函数要特别注意,第1个参数地址要32字节对齐,第2个参数要是32字节的整数倍。
2、进入传输完成中断,当前DMA正在使用缓冲区的前半部分,用户可以操作后半部分。
*/
SCB_InvalidateDCache_by_Addr((uint32_t *)(&ADC1Buf[512][0]), ADC_SIZE*2);
s_ADC1DmaAllFlag = 1;
/* 清除标志 */
DMA2->LIFCR = DMA_FLAG_TCIF0_4;
}
/* 半传输完成中断 */
if((DMA2->LISR & DMA_FLAG_HTIF0_4) != RESET)
{
/*
1、使用此函数要特别注意,第1个参数地址要32字节对齐,第2个参数要是32字节的整数倍。
2、进入半传输完成中断,当前DMA正在使用缓冲区的后半部分,用户可以操作前半部分。
*/
SCB_InvalidateDCache_by_Addr((uint32_t *)(&ADC1Buf[0][0]), ADC_SIZE*2);
s_ADC1DmaHarfFlag = 1;
/* 清除标志 */
DMA2->LIFCR = DMA_FLAG_HTIF0_4;
}
/* 传输错误中断 */
if((DMA2->LISR & DMA_FLAG_TEIF0_4) != RESET)
{
/* 清除标志 */
DMA2->LIFCR = DMA_FLAG_TEIF0_4;
}
/* 直接模式错误中断 */
if((DMA2->LISR & DMA_FLAG_DMEIF0_4) != RESET)
{
/* 清除标志 */
DMA2->LIFCR = DMA_FLAG_DMEIF0_4;
}
} |