скрытое меню

HAL_TIM_PWM_Start_DMA

Итак пришло время разобраться как послать несколько импульсов на выходной контакт контроллера. Причем с возможностью менять скважность импульсов.

Но самое приятное будет то , что сделав вызов HAL_TIM_PWM_Start_DMA можно не беспокоится об отслеживании процесса . В дальнейшем импульсы через DMA будут выводится на ножку контроллера не занимая время контроллера.

Посылка 10 импульсов сводится к такой конструкции:


uint16_t pData [ 15 ] =
{ 50 , 50 , 50 , 50 , 50 , 50 , 50 , 50 , 50 , 50 , 50 , 50 , 50 , 50 , 50};
			
if ( HAL_TIM_PWM_Start_DMA ( & htim3 , TIM_CHANNEL_3 , (uint16_t*)pData , 10 ) != HAL_OK )
	printf ( "ERROR HAL_TIM_PWM_Start_DMA TIM12\n" ); 

Попробуем использовать таймер TIM3 для вывода сигнала на внешний динамик , который подключен через контакт PB0 к контроллеру.

В настройках таймера расположенных на нескольких закладках мелочей нет. Но сначала надо понять от какого источника тактируется наша ножка PB0. Сначала было решили , что это APB1 Peripheral Clocks (30MHz). Но как оказалось в дальнейшем это APB1 Timer Clocks (60MHz).

Одна из самых непростых задач оказалась - понять какие значения Prescaler и Counter Period надо выставлять. Кстати по-видимому есть только один верный способ увидеть какой сигнал на выходе - это осциллограф , либо еще лучше (у нас к счастью оказался) логический анализатор LA1010 (сёсе Китай).

фотка 1

Теперь если мы хотим получить частоту на выходе 440Hz нам надо 60MHz/440Hz и получившуюся величину раскидать между значениями Prescaler и Counter Period. То есть 60MHz/440Hz = 136363,63 = 136364 и сделаем например Prescaler =1363 , а Counter Period = 100 .

фотка 2

Обращаем внимание на Pulse - он у нас оставлен 0. Потому , что Pulse мы как раз и будем задавать в массиве pData . То есть его будем устанавливать программно.

Если все правильно настроено , то должны появиться примерно такие 10 импульсов на PB0. Частота 435MHz не совсем чтобы равна 440MHz , но это детали.

фотка 3

После вызова HAL_TIM_PWM_Start_DMA канал DMA отошлет все данные и вызовет прерывание HAL_TIM_PWM_PulseFinishedCallback , в котором надо не забыть вызвать HAL_TIM_PWM_Stop_DMA для выключения канала, иначе если этого не сделать в следующий раз HAL_TIM_PWM_Start_DMA выдаст ошибку.

void HAL_TIM_PWM_PulseFinishedCallback ( TIM_HandleTypeDef *htim )
{
	if ( htim->Instance == TIM3 )
	{
		if ( htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3 )
		{
			HAL_TIM_PWM_Stop_DMA ( htim , TIM_CHANNEL_3 );

Теперь обратим внимание почему у нас uint16_t pData [ 15 ] (почему тип uint16_t используем). Это важно , так как у нас в Кубе выбрано увеличение адреса HalfWord, то есть uint16_t.

Можно например переключиться на вариант Byte , но тогда тип pData надо тоже изменить на uint8_t . И это НЕ сработает , так как значение нашего таймера 12 битное и запихать все 12 битные значения Pulse в байтовый массив как-то не логично.

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

Таким образом если переключиться на на вариант Word , изменить тип pData на uint32_t , то это тоже сработает нормально, но этот вариант предназначен по-видимому для 32 битных таймеров и в нашем случае просто приведет к излишнему расходу памяти и больше ничего.

фотка 1

Далее можно обратить внимание , что прерывания самого таймера нам использовать не надо. Их можно просто отключить.

фотка 2

И не следует забывать - а на какую ножку-то вы выводите импульсы , проверяем здесь:

фотка 3

Ну вот теперь вроде бы можно признаться себе , что картина с HAL_TIM_PWM_Start_DMA вполне себе проясняется.