Преобразование АЦП, вызванное таймером 1 мс, не работает, STM32F4
Я использую плату STM32F429, и моя конечная цель - получить преобразование АЦП (настроено на доставку 2,7 Кбит / с или 2,7 выборки каждые 1 мс) с использованием триггера TIM8, собрать 1000 выборок в буфере и выполнять передачу DMA каждую секунду. Мне удалось запустить таймер, но по какой-то причине преобразование АЦП не сработало. Без таймера АЦП работает хорошо, а DMA работает (только не каждые 1 мс, но быстрее).
Часы таймеров APB2 имеют частоту 168 МГц. Периферийные часы APB2 имеют частоту 84 МГц.
Функция инициализации TIM8:
void MX_TIM8_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_SlaveConfigTypeDef sSlaveConfig;
TIM_OC_InitTypeDef sConfigOC;
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
__HAL_RCC_TIM8_CLK_ENABLE();
htim8.Instance = TIM8;
htim8.Init.Prescaler = TIM_CLOCKPRESCALER_DIV8; // 1/(168MHz / 2^8) = 1.5238us
htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
htim8.Init.Period = 655; // 1.5238us * 656 = 0.999ms ~ 1ms
htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim8.Init.RepetitionCounter = 0;
if (HAL_TIM_Base_Init(&htim8) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
HAL_TIM_Base_Start(&htim8);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_DISABLE;
sSlaveConfig.InputTrigger = TIM_TS_ITR1;
if (HAL_TIM_SlaveConfigSynchronization(&htim8, &sSlaveConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_OC_Init(&htim8) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigOC.OCMode = TIM_OCMODE_TIMING;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_OC_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
Функция инициализации АЦП:
void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
__HAL_RCC_GPIOA_CLK_ENABLE();
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; // 84MHz / 2^6 = 1312.5 KHz
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 2;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK) {
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_5;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES; // 1312.5KHz / 480cyc per sample = 2.7Ksps
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_7;
sConfig.Rank = 2;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
_Error_Handler(__FILE__, __LINE__);
}
}
Основной код:
int main(void)
{
//MCU Configuration----------------------------------------------------------
// Reset of all peripherals, Initializes the Flash interface and the Systick.
HAL_Init();
// Configure the system clock
SystemClock_Config();
// Initialize all configured peripherals
MX_DMA_Init();
MX_ADC1_Init();
MX_TIM8_Init();
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_buf, ADC_BUFFER_LENGTH);
DBGMCU->APB2FZ |= (DBGMCU_APB2_FZ_DBG_TIM8_STOP); //Stop timer if code hit a breakpoint
int timerValue = 0;
while (1)
{
timerValue = __HAL_TIM_GET_COUNTER(&htim8);
if (halfConvFlag != false)
{
println ("Half Conversion callback");
halfConvFlag = false;
}
else if (fullConvFlag != false)
{
println ("Full Conversion callback");
fullConvFlag = false;
}
}
}
При отладке, __HAL_TIM_GET_COUNTER
дает мне счет, который доказывает, что это работает, но ADC_buf
не собирает никаких ценностей. Что мне не хватает, конфигурации часов должны быть правильными, 2 канала, 2 выборки в мс, а таймер близок к 1 мс. Я сгенерировал конфигурацию таймера, используя STM32CubeMX.