|
最近有个项目,用Timer读取外部120Madc,方案是GPIO连接外部ADC模块的数据端口,用TIM1产生120MPWM作为ADC的采样同步时钟信号,同时触发TIM3产生4路移相,在TIM3的CH1~CH4的上升沿产生DMA请求去读取GPIO口。
#define FIFO_DBS_0 512
/* SRAM1 as the base */
#define FIFO_BBASE (0x30000000)
/* tpye define */
#define U8 unsigned char
/* Oscilloscope sampling buffer at block 0 */
static U8 * src_fifo0_0 = (U8 *)( FIFO_BBASE ); //定义绝对地址
static U8 * src_fifo0_1 = (U8 *)( FIFO_BBASE + FIFO_DBS_0 );
static U8 * src_fifo0_2 = (U8 *)( FIFO_BBASE + FIFO_DBS_0 * 2 );
static U8 * src_fifo0_3 = (U8 *)( FIFO_BBASE + FIFO_DBS_0 * 3 );
static TIM_HandleTypeDef TIM_Handle; /* USER CODE END PV */
TIM_HandleTypeDef htim;
//TIM_OC_InitTypeDef TIM_OC_Handle;
DMA_HandleTypeDef hdma_ch1;
DMA_HandleTypeDef hdma_ch2;
DMA_HandleTypeDef hdma_ch3;
DMA_HandleTypeDef hdma_ch4;
void MX_DMA_NVIC_Init(void) ;
/* USER CODE BEGIN PFP */
void MX_OSC_FIFO_DMA_CONFIG(void);
//TIM1即作为TIM4的主定时器,也作为TIM2的从定时器
//并根据主定时器TIM2同步触发产生150MHz的PWM
void MX_TIM1_Init(void)
{
/* enable the clk */
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIO时钟
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_TIM1_CLK_ENABLE(); //使能定时器时钟
/* define a struction */
GPIO_InitTypeDef GPIO_Handle = {0};
TIM_OC_InitTypeDef sConfigOC;
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* clear data */
memset(&sConfigOC,0,sizeof(sConfigOC));
memset(&sMasterConfig,0,sizeof(sMasterConfig));
/* define a struction */
//PWM管脚输出作为ADC工作的时钟读信号
GPIO_Handle.Pin = GPIO_PIN_9;
GPIO_Handle.Mode = GPIO_MODE_AF_PP;
GPIO_Handle.Pull = GPIO_NOPULL;
GPIO_Handle.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_Handle.Alternate = GPIO_AF1_TIM1;
HAL_GPIO_Init(GPIOE, &GPIO_Handle);
HAL_GPIO_Init(GPIOA, &GPIO_Handle);
/* time INIT */
TIM_Handle.Instance = TIM1;
TIM_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //时钟不分频
TIM_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; //向上计数
TIM_Handle.Init.Period = 2 - 1; //fpwm = 240/((2-1+1)*(1-1+1))=120MHz
TIM_Handle.Init.Prescaler = 1 - 1;
TIM_Handle.Init.RepetitionCounter = 0;
TIM_Handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_PWM_Init(&TIM_Handle);
/* msacter config */
sMasterConfig.MasterOutputTrigger = TIM_TRGO_ENABLE;//配置为TRGO模式,TIM1的EN信号触发
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET; //关闭TRGO2即ADC触发模式
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE; //配置为主模式
if (HAL_TIMEx_MasterConfigSynchronization(&TIM_Handle, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* PWM init */
sConfigOC.OCMode = TIM_OCMODE_PWM1; //PWM输出为PWM1
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; //输出极性为低
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; //禁止快速模式
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
sConfigOC.Pulse = 1; //占空比50%
/* CHANNEL init */
HAL_TIM_PWM_ConfigChannel(&TIM_Handle, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_ConfigChannel(&TIM_Handle, &sConfigOC, TIM_CHANNEL_2);
/* check */
/* start */
HAL_TIM_PWM_Start(&TIM_Handle, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&TIM_Handle, TIM_CHANNEL_2);
/* return */
// return FS_OK;
}
//作为从定时器,由主定时器TIM1同步触发产生3路50MHz的PWM波
void MX_TIM3_Init(void)
{
/* enable the clk */
__HAL_RCC_TIM3_CLK_ENABLE();
/* define a struction */
// GPIO_InitTypeDef GPIO_Handle = {0};
TIM_OC_InitTypeDef htim_OC_Handle;
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* clear data */
memset(&htim_OC_Handle,0,sizeof(htim_OC_Handle));
memset(&sSlaveConfig,0,sizeof(sSlaveConfig));
memset(&sMasterConfig,0,sizeof(sMasterConfig));
/* time INIT */
htim.Instance = TIM3; //选择定时器3
htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //从定时器不分频
htim.Init.CounterMode = TIM_COUNTERMODE_UP; //向上计数
htim.Init.Period = 8 - 1; //30Mhz
htim.Init.Prescaler = 1 - 1;
HAL_TIM_PWM_Init(&htim);
/* PWM init */
htim_OC_Handle.OCMode = TIM_OCMODE_PWM1; //选择PWM1模式
htim_OC_Handle.OCPolarity = TIM_OCPOLARITY_LOW; //输出极性
htim_OC_Handle.OCFastMode = TIM_OCFAST_DISABLE;
htim_OC_Handle.Pulse = 1; //移相
/* CHANNEL init */
HAL_TIM_PWM_ConfigChannel(&htim, &htim_OC_Handle, TIM_CHANNEL_1);
htim_OC_Handle.Pulse = 3; //移相
HAL_TIM_PWM_ConfigChannel(&htim, &htim_OC_Handle, TIM_CHANNEL_2);
htim_OC_Handle.Pulse = 5; //移相
HAL_TIM_PWM_ConfigChannel(&htim, &htim_OC_Handle, TIM_CHANNEL_3);
htim_OC_Handle.Pulse = 7; //移相
HAL_TIM_PWM_ConfigChannel(&htim, &htim_OC_Handle, TIM_CHANNEL_4);
/* slaver mode */
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER; //从模式,触发模式
sSlaveConfig.InputTrigger = TIM_TS_ITR0; //触发源TIM1
/* disable master mode */
if (HAL_TIM_SlaveConfigSynchro(&htim, &sSlaveConfig) != HAL_OK)
{
Error_Handler();
}
/* disable master mode */
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; //定时器3不作为主定时器去触发其他定时器
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
/* disable master mode */
if (HAL_TIMEx_MasterConfigSynchronization(&htim, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* LINK DMA with TIM CHNN */
//使能DMA
__HAL_TIM_ENABLE_DMA(&htim, TIM_DMA_CC1);
__HAL_TIM_ENABLE_DMA(&htim, TIM_DMA_CC2);
__HAL_TIM_ENABLE_DMA(&htim, TIM_DMA_CC3);
__HAL_TIM_ENABLE_DMA(&htim, TIM_DMA_CC4);
/* 32bit tim init */
MX_OSC_FIFO_DMA_CONFIG();
/* TIM 1 */
MX_TIM1_Init();
/* return */
// return FS_OK;
}
void MX_DMA_NVIC_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
/* check */
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 1, 1);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}
void MX_OSC_FIFO_DMA_CONFIG(void)
{
/* Define initialization structure */
// DMA_HandleTypeDef hdma_cho;
/* Set sampling frequency */
MX_DMA_NVIC_Init();
/* fill with blank */
// memset(&hdma_cho,0,sizeof(hdma_cho));
/* check mode */
hdma_ch4.Instance = DMA2_Stream0;
hdma_ch4.Init.Request = DMA_REQUEST_TIM3_CH4; //TIM3-CH4发送DMA请求
hdma_ch4.Init.Direction = DMA_PERIPH_TO_MEMORY; //从外设到存储器
hdma_ch4.Init.PeriphInc = DMA_PINC_DISABLE; //外设非增量模式
hdma_ch4.Init.MemInc = DMA_MINC_ENABLE; //存储器增量模式
hdma_ch4.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外设数据长度: 8位
hdma_ch4.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; //存储器数据长度: 8位
hdma_ch4.Init.Mode = DMA_NORMAL; //DMA_CIRCULAR; //外设流控模式: 使用正常模式
hdma_ch4.Init.Priority = DMA_PRIORITY_VERY_HIGH; //高优先级,用于多通道同时请求时的优先响应
hdma_ch4.Init.FIFOMode = DMA_FIFOMODE_DISABLE; //使用FIFO
hdma_ch4.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;//使能FIFO之后,用于FIFO阀值设置
hdma_ch4.Init.MemBurst = DMA_MBURST_SINGLE; //存储器突发单次传输
hdma_ch4.Init.PeriphBurst = DMA_PBURST_SINGLE; //外设突发单次传输
/* enable */
/* 初始化DMA */
if(HAL_DMA_DeInit(&hdma_ch4) != HAL_OK)
{
Error_Handler();
}
/* INIT */
HAL_DMA_Init(&hdma_ch4);
__HAL_LINKDMA(&htim,hdma[TIM_DMA_ID_CC4],hdma_ch4);
/* start DMA with buffer */
/* start */
HAL_DMA_Start_IT(&hdma_ch4, (uint32_t)&GPIOE->IDR,(uint32_t)src_fifo0_3,FIFO_DBS_0);
/* INIT TIM3 CH2 */
hdma_ch2.Instance = DMA2_Stream1;
hdma_ch2.Init.Request = DMA_REQUEST_TIM3_CH2; //TIM3-CH2发送DMA请求
hdma_ch2.Init.Direction = DMA_PERIPH_TO_MEMORY; //从外设到存储器
hdma_ch2.Init.PeriphInc = DMA_PINC_DISABLE; //外设非增量模式
hdma_ch2.Init.MemInc = DMA_MINC_ENABLE; //存储器增量模式
hdma_ch2.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外设数据长度: 8位
hdma_ch2.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; //存储器数据长度: 8位
hdma_ch2.Init.Mode = DMA_NORMAL;//DMA_CIRCULAR; //外设流控模式: 使用正常模式
hdma_ch2.Init.Priority = DMA_PRIORITY_VERY_HIGH; //高优先级,用于多通道同时请求时的优先响应
hdma_ch2.Init.FIFOMode = DMA_FIFOMODE_DISABLE; //不使用FIFO(因为外设长度和内存长度一致,可以不使用)
hdma_ch2.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;//使能FIFO之后,用于FIFO阀值设置
hdma_ch2.Init.MemBurst = DMA_MBURST_SINGLE; //存储器突发单次传输
hdma_ch2.Init.PeriphBurst = DMA_PBURST_SINGLE; //外设突发单次传输
/* 初始化DMA */
if(HAL_DMA_DeInit(&hdma_ch2) != HAL_OK)
{
Error_Handler();
}
/* enable */
HAL_DMA_Init(&hdma_ch2);
__HAL_LINKDMA(&htim,hdma[TIM_DMA_ID_CC2],hdma_ch2);
/* start */
HAL_DMA_Start_IT(&hdma_ch2, (uint32_t)&GPIOE->IDR,(uint32_t)src_fifo0_1,FIFO_DBS_0);
/* INIT TIM3 CH3 */
hdma_ch3.Instance = DMA1_Stream1;
hdma_ch3.Init.Request = DMA_REQUEST_TIM3_CH3; //TIM3-CH3发送DMA请求
hdma_ch3.Init.Direction = DMA_PERIPH_TO_MEMORY; //从外设到存储器
hdma_ch3.Init.PeriphInc = DMA_PINC_DISABLE; //外设非增量模式
hdma_ch3.Init.MemInc = DMA_MINC_ENABLE; //存储器增量模式
hdma_ch3.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外设数据长度: 8位
hdma_ch3.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; //存储器数据长度: 8位
hdma_ch3.Init.Mode = DMA_NORMAL;//DMA_CIRCULAR; //外设流控模式: 使用正常模式
hdma_ch3.Init.Priority = DMA_PRIORITY_VERY_HIGH; //高优先级,用于多通道同时请求时的优先响应
hdma_ch3.Init.FIFOMode = DMA_FIFOMODE_DISABLE; //不使用FIFO(因为外设长度和内存长度一致,可以不使用)
hdma_ch3.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;//使能FIFO之后,用于FIFO阀值设置
hdma_ch3.Init.MemBurst = DMA_MBURST_SINGLE; //存储器突发单次传输
hdma_ch3.Init.PeriphBurst = DMA_PBURST_SINGLE; //外设突发单次传输
/* 初始化DMA */
if(HAL_DMA_DeInit(&hdma_ch3) != HAL_OK)
{
Error_Handler();
}
/* enable */
HAL_DMA_Init(&hdma_ch3);
//关联tim4句柄和DMA句柄
__HAL_LINKDMA(&htim,hdma[TIM_DMA_ID_CC3],hdma_ch3);
/* start */
HAL_DMA_Start_IT(&hdma_ch3, (uint32_t)&GPIOE->IDR,(uint32_t)src_fifo0_2,FIFO_DBS_0);
/* INIT TIM3 CH4 */
hdma_ch1.Instance = DMA1_Stream0;
hdma_ch1.Init.Request = DMA_REQUEST_TIM3_CH1; //TIM3-CH3发送DMA请求
hdma_ch1.Init.Direction = DMA_PERIPH_TO_MEMORY; //从外设到存储器
hdma_ch1.Init.PeriphInc = DMA_PINC_DISABLE; //外设非增量模式
hdma_ch1.Init.MemInc = DMA_MINC_ENABLE; //存储器增量模式
hdma_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外设数据长度: 8位
hdma_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; //存储器数据长度: 8位
hdma_ch1.Init.Mode = DMA_NORMAL;//DMA_CIRCULAR; //外设流控模式: 使用正常模式
hdma_ch1.Init.Priority = DMA_PRIORITY_VERY_HIGH; //高优先级,用于多通道同时请求时的优先响应
hdma_ch1.Init.FIFOMode = DMA_FIFOMODE_DISABLE; //不使用FIFO(因为外设长度和内存长度一致,可以不使用)
hdma_ch1.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;//使能FIFO之后,用于FIFO阀值设置
hdma_ch1.Init.MemBurst = DMA_MBURST_SINGLE; //存储器突发单次传输
hdma_ch1.Init.PeriphBurst = DMA_PBURST_SINGLE; //外设突发单次传输
/* 初始化DMA */
if(HAL_DMA_DeInit(&hdma_ch1) != HAL_OK)
{
Error_Handler();
}
/* enable */
HAL_DMA_Init(&hdma_ch1);
__HAL_LINKDMA(&htim,hdma[TIM_DMA_ID_CC1],hdma_ch1);
// /* start */
HAL_DMA_Start_IT(&hdma_ch1, (uint32_t)&GPIOE->IDR,(uint32_t)src_fifo0_0,FIFO_DBS_0);
}
void OSC_DMA_STOP(void)
{
/* Disable the TIM1 and TIM4 */
TIM3->CR1 &=~ 0x1;
TIM1->CR1 &=~ 0x1;
/* Synchronize counters for all timers */
TIM1->CNT = 0;
TIM3->CNT = 0;
}
void osc_dma_restart(void)
{
/* clear */
DMA1->LIFCR = DMA_FLAG_TCIF0_4;
DMA1->LIFCR = DMA_FLAG_TCIF1_5;
DMA2->LIFCR = DMA_FLAG_TCIF0_4;
DMA2->LIFCR = DMA_FLAG_TCIF1_5;
/* check mode */
/* more than 40mhz freq for test */
DMA1_Stream0->NDTR = FIFO_DBS_0;
DMA1_Stream1->NDTR = FIFO_DBS_0;
DMA2_Stream0->NDTR = FIFO_DBS_0;
DMA2_Stream1->NDTR = FIFO_DBS_0;
/* enable */
DMA1_Stream0->CR |= 0x1;
DMA1_Stream1->CR |= 0x1;
DMA2_Stream0->CR |= 0x1;
DMA2_Stream1->CR |= 0x1;
/* restart DMA */
TIM1->CR1 |= 0x1;
/* end if */
}
unsigned char osc_trig_end_flag = 0;
/**
* @brief DMA2_Stream0_IRQHandler
* @param NONE
* @retval None
*/
void DMA2_Stream0_IRQHandler(void)
{
/* 传输完成中断 */
if((DMA2->LISR & DMA_FLAG_TCIF0_4) != RESET)
{
/* 清除标志 */
DMA2->LIFCR = DMA_FLAG_TCIF0_4;
/* reset */
/* 当前使用的缓冲0 */
if((DMA2_Stream0->CR & DMA_SxCR_CT) == RESET)
{
/* DMA pause */
// OSC_DMA_STOP();
/* set TC flag */
osc_trig_end_flag = 1; //传输完成标志
/* end if data */
}
}
/* 半传输完成中断 */
if((DMA2->LISR & DMA_FLAG_HTIF0_4) != RESET)
{
/* 清除标志 */
str0_len = DMA2_Stream0->NDTR;
DMA2->LIFCR = DMA_FLAG_HTIF0_4;
}
}
//ADC模块的D0~D7数据线
void GPIO_EXTERNAL_ADC_Init(void)
{
GPIO_InitTypeDef GPIO_Handle = {0};
__HAL_RCC_GPIOE_CLK_ENABLE();
//ADC模块的数字输入,通过GPIO来读取
GPIO_Handle.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_Handle.Mode = GPIO_MODE_INPUT; //普通输入模式
GPIO_Handle.Pull = GPIO_NOPULL; //浮空输入
GPIO_Handle.Speed = GPIO_SPEED_FREQ_VERY_HIGH; //高速模式
HAL_GPIO_Init(GPIOE, &GPIO_Handle);
}
void OSC_CURV_TEST(void)
{
unsigned int i = 0;
if(osc_trig_end_flag == 1)
{
for(i = 0; i < FIFO_DBS_0; i ++)
{
printf("<A1>:%d,%d,%d,%d\r\n", src_fifo0_0, src_fifo0_1, src_fifo0_2, src_fifo0_3);
}
osc_trig_end_flag = 0;
osc_dma_restart();
}
}
调试结果发现与DMA2_Stream1绑定的通道的数据采集频率在传输的前半部分是其他三个通道的一半,后半部分一致,这是什么原因
|
-
|