|
如题,这几天在调试DMA方式通过TIM Capture实现 10KHz左右的PWM频率测量,参考 bsp_tim_capture.c 相关设置如下:
/** 32-bytes Alignment is needed for cache maintenance purpose */
ALIGN_32BYTES(__attribute__((section (".RAM_D3"))) uint32_t tim_capture[TIM_CAP_BUFF_SIZE]);
/* 注:SCT文件中与 RAM_D3 相关的定义:
RW_IRAM4 0x38000000 0x00010000 { ; RW data - 64KB SRAM4(0x38000000)
.ANY (+RW +ZI)
*(.RAM_D3)
}
*/
/* 相关MPU配置 */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x38000000;
MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER4; /* 其余MPU设置没有列出 */
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* 初始化 */
void bsp_Tim_Init(void)
{
/* 配置GPIO */
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 使能GPIO时钟 */
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
GPIO_InitStruct.Pin = GPIO_PIN_6;
HAL_GPIO_Init( GPIOA, &GPIO_InitStruct );
}
/* 配置DMA */
{
/* Enable DMA clock */
__HAL_RCC_DMA1_CLK_ENABLE();
dmaHandle.Instance = DMA1_Stream0;
dmaHandle.Init.Request = DMA_REQUEST_TIM3_CH1;
dmaHandle.Init.Direction = DMA_PERIPH_TO_MEMORY;
dmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;
dmaHandle.Init.MemInc = DMA_MINC_ENABLE;
dmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
dmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
dmaHandle.Init.Mode = DMA_CIRCULAR; // DMA_CIRCULAR; DMA_NORMAL
dmaHandle.Init.Priority = DMA_PRIORITY_VERY_HIGH;
dmaHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
/* Deinitialize & Initialize the DMA for new transfer */
HAL_DMA_DeInit(&dmaHandle);
if( HAL_DMA_Init( &dmaHandle ) != HAL_OK )
{
pErrorHandler( __FILE__, __LINE__ );
return ;
}
/* Associate the DMA handle */
__HAL_LINKDMA(&timHandle, hdma[TIM_DMA_ID_CC1], dmaHandle);
/* NVIC configuration for DMA Input data interrupt */
HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
}
/* 配置TIM */
{
TIM_IC_InitTypeDef sICConfig;
TIM_MasterConfigTypeDef sMasterConfig = {0};
__HAL_RCC_TIM3_CLK_ENABLE();
/* Set TIMx instance */
timHandle.Instance = TIM3;
timHandle.Init.Prescaler = 1; /* 2分频 */
timHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
timHandle.Init.Period = 0xFFFF; /* TIM3是16位 */
timHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
timHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_IC_Init(&timHandle) != HAL_OK)
{
pErrorHandler(__FILE__, __LINE__);
return ;
}
/* 从cubemx中摘抄过来的 */
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&timHandle, &sMasterConfig) != HAL_OK)
{
pErrorHandler(__FILE__, __LINE__);
}
/*##-2- Configure the Input Capture channel ################################*/
sICConfig.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;//TIM_ICPOLARITY_BOTHEDGE;
sICConfig.ICSelection = TIM_ICSELECTION_DIRECTTI;
sICConfig.ICPrescaler = TIM_ICPSC_DIV1;
sICConfig.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&timHandle, &sICConfig, TIM_CHANNEL_1) != HAL_OK)
{
pErrorHandler(__FILE__, __LINE__);
return ;
}
__HAL_TIM_DISABLE(&timHandle);
/* Enable the DMA Stream */
HAL_DMA_Start_IT(timHandle.hdma[TIM_DMA_ID_CC1], (uint32_t)&timHandle.Instance->CCR1, (uint32_t)tim_capture, TIM_CAP_BUFF_SIZE);
/* Enable the TIM Capture/Compare 1 DMA request */
__HAL_TIM_ENABLE_DMA(&timHandle, TIM_DMA_CC1);
/* Enable the Input Capture channel */
TIM_CCxChannelCmd(timHandle.Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
/* Enable the Peripheral */
__HAL_TIM_ENABLE(&timHandle);
}
}
/* 中断处理函数 */
void DMA1_Stream0_IRQHandler( void )
{
/* LISR: DMA low interrupt status register */
if( (DMA1->LISR & DMA_FLAG_TCIF0_4) != RESET )
{
/*
1、使用此函数要特别注意,第1个参数地址要32字节对齐,第2个参数要是32字节的整数倍。
2、进入传输完成中断,当前DMA正在使用缓冲区的前半部分,用户可以操作后半部分。
*/
SCB_InvalidateDCache_by_Addr((uint32_t *)tim_capture, TIM_CAP_BUFF_SIZE);
// SCB_InvalidateDCache();
/* 清除标志:
* 注意位的清除方式:This bit is set by hardware.
* It is cleared by software writing 1 to the corresponding bit in the DMA_LIFCR register
*/
DMA1->LIFCR |= DMA_FLAG_TCIF0_4;
}
/* 传输错误中断 */
if((DMA1->LISR & DMA_FLAG_TEIF0_4) != RESET)
{
/* 清除标志 */
DMA1->LIFCR |= DMA_FLAG_TEIF0_4;
}
/* 直接模式错误中断 */
if((DMA1->LISR & DMA_FLAG_DMEIF0_4) != RESET)
{
/* 清除标志 */
DMA1->LIFCR |= DMA_FLAG_DMEIF0_4;
}
}
故障现象:
在中断中打断点发现,无论采用 SCB_InvalidateDCache_by_Addr((uint32_t *)tim_capture, TIM_CAP_BUFF_SIZE) 还是 SCB_InvalidateDCache(),
tim_capture 中的数据不是每次都全部更新;
而且,有些相邻两个数据之间的差值明显偏离正确值。
请问硬汉,是MPU配置哪儿有问题吗?谢谢
|
|