Перейти к содержанию
    

Как вывести ШИМ таймера на пин? STM32F030F4P6

Пытаюсь при помощи кодгенератора STM32CubeIDE вот по этой инструкции вывести для микроконтроллера STM32F030F4P6 (TSSOP-20) на пины PA7 и PB1 ШИМ с таймеров TIM17 и TIM14.
И чего-то не получается. Проверил выводы ногодрыгом - контакт есть, всё выводится. Вроде всё, что нужно указал:

  • Channel1 - PWM Generator CH1
  • auto-reload preload - Enable
  • Counter period - 500
  • Pulse - 250

В Clock Configuration вроде тоже всё ок, затактировался от HSI, напрямую, не через PLL - 8 МГц.

Пробежал глазами по коду, вроде всё должно работать. Но почему-то на выходах PB1 и PA7 полная тишина.

Может кто-нибудь подсказать, в чём дело?

Spoiler
#include "main.h"

TIM_HandleTypeDef htim14;
TIM_HandleTypeDef htim17;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM14_Init(void);
static void MX_TIM17_Init(void);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM14_Init();
  MX_TIM17_Init();
  while (1)
  {
	  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_9);
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL4;
  RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_TIM14_Init(void)
{
  TIM_OC_InitTypeDef sConfigOC = {0};

  htim14.Instance = TIM14;
  htim14.Init.Prescaler = 1;
  htim14.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim14.Init.Period = 600;
  htim14.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim14.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim14) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim14) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim14, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }

  HAL_TIM_MspPostInit(&htim14);
}

static void MX_TIM17_Init(void)
{

  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

  htim17.Instance = TIM17;
  htim17.Init.Prescaler = 1;
  htim17.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim17.Init.Period = 500;
  htim17.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim17.Init.RepetitionCounter = 0;
  htim17.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim17) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim17) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 250;
  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_PWM_ConfigChannel(&htim17, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  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_ENABLE;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim17, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }

  HAL_TIM_MspPostInit(&htim17);
}

static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);

  GPIO_InitStruct.Pin = GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void Error_Handler(void)
{
  __disable_irq();
  while (1)
  {
  }
}

#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{

}
#endif

STM32timer.png

Изменено пользователем haker_fox
Уточнил название МК. Также длинный код нужно прятать под спойлер!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 hours ago, sidy said:

Где у Вас в коде настройка пина на альтернативную функцию?

STM32CubeIDE делает её в отдельном файле - stm32f0xx_hal_msp.c - в функции HAL_TIM_MspPostInit, которая вызывается в конце MX_TIM17_Init, который в main.c. Я попробовал (а вдруг!) вытащить (скопипастить) оттуда инициализацию пинов в MX_GPIO_Init, и поставить его после MX_TIM17_Init в main(void). Но это не помогло.

Spoiler
#include "main.h"

void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);

void HAL_MspInit(void)
{
  __HAL_RCC_SYSCFG_CLK_ENABLE();
  __HAL_RCC_PWR_CLK_ENABLE();
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
  if(htim_base->Instance==TIM1)
  {
    __HAL_RCC_TIM1_CLK_ENABLE();
  }
  else if(htim_base->Instance==TIM14)
  {
    __HAL_RCC_TIM14_CLK_ENABLE();
  }
  else if(htim_base->Instance==TIM17)
  {
    __HAL_RCC_TIM17_CLK_ENABLE();
  }
}

void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(htim->Instance==TIM14)
  {
    __HAL_RCC_GPIOB_CLK_ENABLE();
    GPIO_InitStruct.Pin = GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF0_TIM14;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  }
  else if(htim->Instance==TIM17)
  {
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitStruct.Pin = GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
    GPIO_InitStruct.Alternate = GPIO_AF5_TIM17;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  }
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
  if(htim_base->Instance==TIM1)
  {
    __HAL_RCC_TIM1_CLK_DISABLE();
  }
  else if(htim_base->Instance==TIM14)
  {
    __HAL_RCC_TIM14_CLK_DISABLE();
  }
  else if(htim_base->Instance==TIM17)
  {
    __HAL_RCC_TIM17_CLK_DISABLE();
  }
}

Причём, когда я в редакторе .ioc , в разделе TIM17 на вкладке GPIO Settings, в выпадающем списке GPIO Pull-up/Pull-down выбрал Pull-up, пин подтянулся к питанию.

Изменено пользователем haker_fox
Длинный код нужно прятать под спойлер.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 6/9/2023 at 3:51 PM, flammmable said:

Я попробовал (а вдруг!) 

Метод научного тыка конечно хорош, но далеко не всегда прокатывает.

Может, все-таки, попытаться ознакомиться с документацией на микроконтроллер ? 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 минут назад, flammmable сказал:

STM32CubeIDE делает её в отдельном файле

"Грешно смеяться над больным человеком"(С)

Не особо надейтесь на куб, у меня была ситуация для F030F4, когда куб для ацп генерил тактирование от RC генератора, а не от системной шины как в настройках.

Проверьте бит:

TIM14->CCER |= TIM_CCER_CC1E;                            //канал1 как выход

TIM14->CR1 |= TIM_CR1_CEN;                                 //включили ШИМ (куб обычно не включает устройства, надо делать это в ручную).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 6/9/2023 at 4:00 PM, dimka76 said:

Метод научного тыка конечно хорош, но далеко не всегда прокатывает.

Может, все-таки, попытаться ознакомиться с документацией на микроконтроллер ? 

Референс мануал на STM32F0x0 составляет 779 страниц, а попробовать - 1 минута. Моё мнение, нужно идти от простых решений к сложным.

On 6/9/2023 at 4:02 PM, Vlad_G said:

Проверьте бит:

TIM14->CCER |= TIM_CCER_CC1E;                            //канал1 как выход

TIM14->CR1 |= TIM_CR1_CEN;                                 //включили ШИМ (куб обычно не включает устройства, надо делать это в ручную).

Спасибо, но не возымело. Ну, видимо, придётся действительно начать ковырять регистры, сверяясь с даташитом. STM32 и его инфраструктура сделаны специально так, чтобы программистов МК никогда не заменил бы ChatGPT. Это и плохо и хорошо одновременно.
 

 



 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 6/9/2023 at 4:14 PM, flammmable said:

Референс мануал на STM32F0x0 составляет 779 страниц, а попробовать - 1 минута.

Ну как, уложились в одну минуту ?

On 6/9/2023 at 4:14 PM, flammmable said:

STM32 и его инфраструктура сделаны специально так, чтобы программистов МК никогда не заменил бы ChatGPT.

Все у них с инфраструктурой в порядке.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 6/9/2023 at 4:19 PM, dimka76 said:

Ну как, уложились в одну минуту ?

Ну да. А что?

On 6/9/2023 at 4:19 PM, dimka76 said:

Все у них с инфраструктурой в порядке.

Учитывая, что "была ситуация для F030F4, когда куб для ацп генерил тактирование от RC генератора, а не от системной шины как в настройках", можно сказать, что ваше заявление противоречит инженерному опыту.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 6/9/2023 at 4:23 PM, flammmable said:

Ну да. А что?

Учитывая, что "была ситуация для F030F4, когда куб для ацп генерил тактирование от RC генератора, а не от системной шины как в настройках", можно сказать, что ваше заявление противоречит инженерному опыту.

Я опасаюсь продолжать тему обсуждения Куба и Хала, т.к. это может выльется в очередной холивар.
Поэтому оставлю этот вопрос без ответа :wink:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 минуты назад, dimka76 сказал:

Поэтому оставлю этот вопрос без ответа :wink:

Отвечу я. Да, такая ситуация была, поначалу понять не мог, что логический анализатор показывает не то, что по настройкам. Дело было когда куб еще был как отдельная сущность. Но и плюс был в этом - перешёл на регистры. Долговато, копать DS надо, но зато работает.

Ну а с ШИМ на TIM 14, 16, 17, если всё сделать правильно, то всё работает. Тут точно подводных камней нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Внутрисхемный отладчик (ST-Link/Jlink) есть? Можете им прочитать значения нужных GPIOx->MODER, GPIOx->AFR, GPIOx->OTYPER (а вдруг?) и регистров таймера? Убедиться, что их значения соответствуют ожидаемым, что значение TIMx->CNT меняется, если программу запустить и снова остановить.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 часа назад, flammmable сказал:

Референс мануал на STM32F0x0 составляет 779 страниц

Прям вот реально нужно весь его проштудировать от корки до корки, чтобы разобраться в работе простейшего таймера???  :umnik2:

Если не набрасывать на вентилятор, то окажется, что достаточно всего с десяток страниц мануала просмотреть. Что в сумме окажется быстрее: лазания по инету в поисках кубо-примеров + ковыряния в натасканном из инета + написания пространных полотенец постов в форум.

И к тому же, если пойти путём мануала, то в следующий раз времени потребуется меньше. Так как в голове что-то останется от предыдущего раза. А если искать чужие решения, то и все следующие разы потребуют столько же времени, как первый.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 Может, так проще?

Вбиваем в Гугле, качаем, читаем.

 

AN4776_General-purpose_timer_cookbook.pdf

AN4013-stm32-crossseries-timer-overview-stmicroelectronics.pdf

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Убедиться, что их значения соответствуют ожидаемым, что значение TIMx->CNT меняется, если программу запустить и снова остановить.
Больше того, скажу, программу можно остановить сразу после инициализации таймера и пускать\останавливать его в отладчике (TIMx_CNT видно как меняется), и мненять всё что нужно. И на выводе сигнал будет без работающего ядра.

AN4776_General-purpose_timer_cookbook.pdf
AN4013-stm32-crossseries-timer-overview-stmicroelectronics.pdf

А всю доступную "доку" на "подопытного" (тем более у ST это всё на одной странице, хотя и длинной) - выкачивать сразу без вариантов, даже не обсуждается ;-)
Изменено пользователем Obam

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...