|
本帖最后由 wtasbgg 于 2023-11-26 23:36 编辑
DMA双缓冲方式,启动转换时,DMA读到的数据前部分为0,这个一段时间感觉像是固定的,他采样率越高,启动开始的时候读到的数据为0 的时候越多,所有通道读出的数据都是0,感觉是FMC没有正常读到一样。后面读到的数据又正常。
10KHZ的采样率读到的数据,只取前4通道的数据,数据如下。
00 00 00 00 00 00 00 00 4E 1A 60 1A 74 1A 64 1A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 53 1A 65 1A 79 1A 69 1A 53 1A 65 1A 79 1A 69 1A 53 1A 65 1A 79 1A 69 1A 53 1A 65 1A 79 1A 69 1A 53 1A 65 1A 79 1A 69 1A 53 1A 65 1A 79 1A 69 1A 4D 1A 5F 1A 72 1A 63 1A 4D 1A 5F 1A 72 1A 63 1A 4D 1A 5F 1A 72 1A 63 1A 4D 1A 5F 1A 72 1A 63 1A 4D 1A 5F 1A 72 1A 63 1A 4D 1A 5F 1A 72 1A 63 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C 1A 5E 1A 72 1A 62 1A 4C
代码如下
/* DMA传输完成回调函数,弱定义 */
__weak void AD7606_DmaCplCb(DMA_HandleTypeDef *hdma)
{
// HAL_MDMA_Start_IT(&MDMA_Handle, (uint32_t)&g_sAd7606Buf[8], (uint32_t)&adc_buff[adc_num] , 8, 1);
memcpy(&adc_buff[adc_num],&g_sAd7606Buf[8],8);
adc_num+=4;
if(adc_num>max_num)
{
adc_over=1;
AD7606_StopRecord();
}
}
/* DMA半传输完成回调函数,弱定义 */
__weak void AD7606_DmaHalfCplCb(DMA_HandleTypeDef *hdma)
{
// HAL_MDMA_Start_IT(&MDMA_Handle, (uint32_t)&g_sAd7606Buf[0], (uint32_t)&adc_buff[adc_num] ,8, 1);
memcpy(&adc_buff[adc_num],&g_sAd7606Buf[0],8);
adc_num+=4;
}
/* DMA中断服务程序 */
void TIMx_UP_DMA_IRQHandler(void)
{
HAL_DMA_IRQHandler(&TIMDMA);
}
static void AD7606_SetTIMOutPWM(TIM_TypeDef* TIMx, uint32_t _ulFreq)
{
TIM_OC_InitTypeDef sConfig = {0};
GPIO_InitTypeDef GPIO_InitStruct;
uint16_t usPeriod;
uint16_t usPrescaler;
uint32_t uiTIMxCLK;
uint32_t pulse;
/* 配置时钟 */
CONVST_RCC_GPIO_CLK_ENABLE();
CONVST_TIM3_CLK_ENABLE();
TIMx_UP_DMA_STREAM_CLK_ENABLE();
/* 配置引脚 */
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = CONVST_AF;
GPIO_InitStruct.Pin = CONVST_PIN;
HAL_GPIO_Init(CONVST_GPIO, &GPIO_InitStruct);
/*-----------------------------------------------------------------------
bsp.c 文件中 void SystemClock_Config(void) 函数对时钟的配置如下:
System Clock source = PLL (HSE)
SYSCLK(Hz) = 400000000 (CPU Clock)
HCLK(Hz) = 200000000 (AXI and AHBs Clock)
AHB Prescaler = 2
D1 APB3 Prescaler = 2 (APB3 Clock 100MHz)
D2 APB1 Prescaler = 2 (APB1 Clock 100MHz)
D2 APB2 Prescaler = 2 (APB2 Clock 100MHz)
D3 APB4 Prescaler = 2 (APB4 Clock 100MHz)
因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = APB1 x 2 = 200MHz;
因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = APB2 x 2 = 200MHz;
APB4上面的TIMxCLK没有分频,所以就是100MHz;
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14,LPTIM1
APB2 定时器有 TIM1, TIM8 , TIM15, TIM16,TIM17
APB4 定时器有 LPTIM2,LPTIM3,LPTIM4,LPTIM5
----------------------------------------------------------------------- */
if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM15) || (TIMx == TIM16) || (TIMx == TIM17))
{
/* APB2 定时器时钟 = 200M */
uiTIMxCLK = SystemCoreClock / 2;
}
else
{
/* APB1 定时器 = 200M */
uiTIMxCLK = SystemCoreClock / 2;
}
if (_ulFreq < 100)
{
usPrescaler = 10000 - 1; /* 分频比 = 10000 */
usPeriod = (uiTIMxCLK / 10000) / _ulFreq - 1; /* 自动重装的值, usPeriod最小值200, 单位50us */
pulse = usPeriod; /* 设置低电平时间50us,注意usPeriod已经进行了减1操作 */
}
else if (_ulFreq < 3000)
{
usPrescaler = 100 - 1; /* 分频比 = 100 */
usPeriod = (uiTIMxCLK / 100) / _ulFreq - 1; /* 自动重装的值, usPeriod最小值666,单位500ns */
pulse = usPeriod-1; /* 设置低电平时间1us,注意usPeriod已经进行了减1操作 */
}
else /* 大于4K的频率,无需分频 */
{
usPrescaler = 0; /* 分频比 = 1 */
usPeriod = uiTIMxCLK / _ulFreq - 1; /* 自动重装的值, usPeriod最小值1000,单位5ns */
pulse = usPeriod - 199; /* 设置低电平时间1us,注意usPeriod已经进行了减1操作 */
}
/* PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
TimHandle.Instance = TIMx;
TimHandle.Init.Prescaler = usPrescaler; /* 用于设置定时器分频 */
TimHandle.Init.Period = usPeriod; /* 用于设置定时器周期 */
TimHandle.Init.ClockDivision = 0; /* 用于指示定时器时钟 (CK_INT) 频率与死区发生器以及数字滤波器(ETR、 TIx)
所使用的死区及采样时钟 (tDTS) 之间的分频比*/
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 用于设置计数模式,向上计数模式 */
TimHandle.Init.RepetitionCounter = 0; /* 用于设置重复计数器,仅 TIM1 和 TIM8 有,其它定时器没有 */
TimHandle.Init.AutoReloadPreload = 0; /* 用于设置定时器的 ARR 自动重装寄存器是更新事件产生时写入有效 */
if (HAL_TIM_PWM_DeInit(&TimHandle) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
/* 配置定时器PWM输出通道 */
sConfig.OCMode = TIM_OCMODE_PWM1; /* 配置输出比较模式 */
sConfig.OCPolarity = TIM_OCPOLARITY_HIGH; /* 设置输出高电平有效 */
sConfig.OCFastMode = TIM_OCFAST_DISABLE; /* 关闭快速输出模式 */
sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH; /* 配置互补输出高电平有效 */
sConfig.OCIdleState = TIM_OCIDLESTATE_SET; /* 空闲状态时,设置输出比较引脚为高电平 */
sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET; /* 空闲状态时,设置互补输出比较引脚为低电平 */
/* 占空比 */
sConfig.Pulse = pulse;
if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, CONVST_TIMCH) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
/* 使能定时器中断 */
__HAL_TIM_ENABLE_DMA(&TimHandle, TIM_DMA_UPDATE);
if (HAL_TIM_PWM_Start(&TimHandle, CONVST_TIMCH) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
/* 定时器UP更新触发DMA传输 */
TIMDMA.Instance = TIMx_UP_DMA_STREAM; /* 例化使用的DMA数据流 */
TIMDMA.Init.FIFOMode = DMA_FIFOMODE_ENABLE; /* 使能FIFO*/
TIMDMA.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; /* 用于设置阀值 */
TIMDMA.Init.MemBurst = DMA_MBURST_INC8; /* 用于存储器突发 */
TIMDMA.Init.PeriphBurst = DMA_PBURST_INC8; /* 用于外设突发 */
TIMDMA.Init.Request = TIMx_UP_DMA_REQUEST; /* 请求类型 */
TIMDMA.Init.Direction = DMA_PERIPH_TO_MEMORY; /* 传输方向是从外设到存储器 */
TIMDMA.Init.PeriphInc = DMA_PINC_DISABLE; /* 外设地址自增禁止 */
TIMDMA.Init.MemInc = DMA_MINC_ENABLE; /* 存储器地址自增使能 */
TIMDMA.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; /* 外设数据传输位宽选择半字,即16bit */
TIMDMA.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; /* 存储器数据传输位宽选择半字,即16bit */
TIMDMA.Init.Mode = DMA_CIRCULAR; /* 循环模式 */
TIMDMA.Init.Priority = DMA_PRIORITY_VERY_HIGH; /* 优先级低 */
/* 复位DMA */
if(HAL_DMA_DeInit(&TIMDMA) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
/* 初始化DMA */
if(HAL_DMA_Init(&TIMDMA) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
/* 关联DMA句柄到TIM */
//__HAL_LINKDMA(&TimHandle, hdma[TIM_DMA_ID_UPDATE], TIMDMA);
/* 配置DMA中断 */
HAL_NVIC_SetPriority(TIMx_UP_DMA_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(TIMx_UP_DMA_IRQn);
/* 注册半传输完成中断和传输完成中断 */
HAL_DMA_RegisterCallback(&TIMDMA, HAL_DMA_XFER_CPLT_CB_ID, AD7606_DmaCplCb);
HAL_DMA_RegisterCallback(&TIMDMA, HAL_DMA_XFER_HALFCPLT_CB_ID, AD7606_DmaHalfCplCb);
__HAL_DMA_CLEAR_FLAG(&TIMDMA,DMA_FLAG_TCIF1_5);
__HAL_DMA_CLEAR_FLAG(&TIMDMA,DMA_FLAG_HTIF1_5);
/* 启动DMA传输 */
HAL_DMA_Start_IT(&TIMDMA, (uint32_t)AD7606_BASE, (uint32_t)g_sAd7606Buf, AD7606_BUFSIZE);
}
|
|