STM32. CMSIS #3. SysTick - делаем точную задержку через системный таймер
Вставка
- Опубліковано 15 кві 2021
- Скачать PVS-Studio для проверки своего можно бесплатно на:
pvs-studio.com/nr_download
Официальная страничка в UA-cam:
/ pvsstudiotool
Официальная страничка ВКонтакте:
pvsstudio_rus
Знакомимся с системный таймером SysTick по документации и начинаем его программировать для получения необходимого точного значения задержки между двумя любыми процессами. Проверяем запрограммированное значение по осциллографу. Готовый проект можно скачать по ссылке:
github.com/nr-electronics/CMS...
00:08 Введение в видео и проект
03:25 Рассмотрение SysTick
04:40 Регистр STK_CTRL
07:10 Регистр STK_LOAD
08:55 Регистр STK_VAL
09:54 Регистр STK_CALIB
13:13 Создаем проект на CMSIS - SysTick в ARM KEIL
24:24 Проверка программирования по осциллографу
26:23 Проверка правильности написания кода в PVS-Studio
__________________________________________________
Вы можете помочь каналу через Яндекс-деньги:
money.yandex.ru/to/4100115727...
или через банковскую карту:
4377 7237 6190 5714
__________________________________________________
спасибо, я как раз закончил с прошлым роликом, и перенес все в код.
теперь буду с этим возится)
На благо. Отлично, я во время значит!)
Огромное спасибо! Очень интересный цикл видео!
Спасибо! Всем подписываться на канал и смотреть вместе!)
Как всегда великолепно! Стабильность признак мастерства! Спасибищееее!
Благодарю, приятно конечно. Но все мы люди и можем очепятаться например)
@@NRelectronics Не ошибается тот кто ничего не делает. Я про то, что уровень контента стабильно высокий и это радует))) Или я где то очепятался? 😁 В любом случае очень подробно, без воды и позновательно ))) Очень надеюсь ваш запал не угаснет! )))
Вы правы, кто ничего не делает) Вы не очепятались ;) Стараюсь держать планку. О да, запал тоже необходим)
Спасибо за видео. Хотелось бы видеть серии по DMA, ADC и USB)
Пожалуйста. По этой периферии также будут видео!
прекрасно!
Спасибо
сильные лекции для основ стм. подход работы с регистрами cmsis самый правильный при прогр контроллера
Спасибо. С регистрами согласен.
Здравствуйте, подскажите пожалуйста, что произошло на рынке STМ. Решил заказать stmмки и обалдел от цен, если раньше stm32f103 стоило в районе 130 руб, сейчас ~400. С чем связан такой резкий скачок цен?
Здравствуйте. Кризис полупроводниковых микросхем. Ждем к чему это приведет ещё...
такой вопрос, а если я хочу изменить частоту тактирования, что мне нужно закоментировать?
В зависимости от того что нужно меняется тут:
#ifdef SYSCLK_FREQ_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_24MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_36MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_36MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_48MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_56MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_72MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /*!< System Clock Frequency (Core Clock) */
#else /*!< HSI Selected as System Clock source */
uint32_t SystemCoreClock = HSI_VALUE; /*!< System Clock Frequency (Core Clock) */
#endif
В файле system_stm32f10x.c
здравствуйте , подскажите где в кейле можно посмотреть размер получившегося кода ?
Здравствуйте. В окне Build Output.
Переснять бы выдосик, по хорошему. Делитель нужно считать так: SysTick->VAL = SYSLOCK / 1000 - 1, т.е. скобки, меняющие порядок действий, там ошибочны. И, да, нет никакого смысла перед этой строкой что-то там писать в SysTick->VAL.
VAL все же вписать крайне желательно. Скобки через комит отредактирую.
@@NRelectronics В SysTick_Init() запись в VAL имеет смысл, в delay_mS() никакого.
О! Теперь понятно, а то хотел спросить зачем в скобках писать 1000-1, если можно было 999 написать, а так как без скобок тогда уже понятно
Досадная очепятка. Скобки лишние. Правильно SYSCLOCK/1000 - 1. На гитхабе откоммичу. Ну с минус единицей как бы наверное яснее.
Вам про одно и тоже про delay_ms не надоело писать?? Все это понимают давно.
Для тех кто пишет с нуля, функция обработки прерывания должна называться точно как в видео
👍
Все сделал как на видео. Но в SysTick_Handler() не попадаю. Висит в while(SysTick_CNT). Что может быть? В отладчике CVR - CURRENT крутятся значения, а в CSR - все флаги подняты(галочки стоят)
Проверьте код весь, ничего не пропустили. Код мой ведь рабочий.
Подскажите не могу понять, когда мы записываем в BS5, пин 5 выдает 1, и в следующей итерации цикла опять устанавливаем его. То же самое и с BR5. Они сами сбрасываются что ли?
BS5 - Bit Set 5 pin, BR5 - Bit Reset5 pin. Везде активное состояние это единичка.
@@NRelectronics нет я имею в виду что по всему видимому когда мы устанавливаем BS5, то BR5 сбрасывается и наоборот. Иначе они бы установились в BS5=1 и BR5=1 в первой итерации цикла и не менялись. Они сбрасываются программно либо аппаратно
Так и есть, с названия это и следует, я ведь расшифровал, Set - установка единицы, Reset - сброс состояния.
@@NRelectronics да не состояния, а значения этих регистров…
8:40
SYST_CVR
Любая запись сбрасывает регистр в 0, а также сбрасывает бит COUNTFLAG в регистре SYST_CSR.
Когда вы записываете что либо в этот регистр, то значение этого регистра сбрасывается в 0.
В описании этого регистра это и написано.
Может быть не любая запись сбрасывает в ноль, нужно смотреть состояние в Reset каждого регистра.
@@NRelectronics A write of any value clears the field to 0, and also clears the COUNTFLAG bit in the
STK_CTRL register to 0.
При старте счётчика, число из регистра LOAD загружается в регистр VAL.
Для чего перед загрузкой из регистра LOAD регистр VAL обнуляют я не знаю.
Т.к. могут быть старые значения отличные от нулевых, т.е. мусор. Так всегда делают, это правильно.
17:51 Функция SysTick_Handler определена ведь уже где то выше. У меня в файле stm32f4xx_it.c
И здесь 17:51 получаеттся повторное переопределение данной функции.
Как такое возможно?
У меня выдаёт ошибку.
Если повторное выдавал бы ошибку, у меня не выдаёт, норм.
Как это происходит? Частота падает до 71999(Hz) и делится на 1000(Ms). Или как?
Падает до 72000 и делится на 1000.
Автор, поясните, почему Handler. Я не вижу нигде исполнения функции, это какой-то каллбэк?
Где именно? Я ролик не помню в деталях...
@@NRelectronics просто без функции SysTick_Handler ничего не работает, но ее ничто в коде и не вызывает. Выходит, handler придает какое-то значение?
Обработчик вызывается по прерыванию. Его не вызывают в коде программа.
Очень хорошим делом вы занимаетесь, но зачем использовать функции типа delay() ?
Конкретно в данном случае достаточно в основном цикле прописать условие проверки значения счётчика и выполнять нужный код в теле этого условия без прерывания.
Либо выставить значение счётчика в нужный интервал и в прерывании выполнять необходимый код.
Функции delay() делают код неэффективным.
Посыл этого видео системный таймер и работа с ним. А вот следующее видео как раз использование в подобных случаев таймера, об этом я в видео кстати говорил ;)
@@NRelectronics Я понял о чём видео. Но использование функций задержки это очень плохая практика программирования. Не стоит приучать к этому новичков.
А я и не приучаю. Знать тоже нужно как и что настраивается и работает...
К тому же systick полезен во FreeRTOS.
@@NRelectronics Новички которые смотрят ваши видео как раз приучаются. Вы же не сказали что так делать не нужно, что это просто демонстрация возможностей.
Я использую контроллеры серии F0 и написал свою библиотеку для работы с регистрами, вот пример кода без функций задержек. Можно легко реализовать то же самое на CMSIS.
#include "BS.h"
int main(void)
{
_RCC->AHBENR.IOPAEN = ON; // тактирование соответствующего порта
_GPIOA->MODER.Pin5 = OutputMOD; // режим вывода на соответствующем пине
_SYSTICK->RVR.RELOAD = 800000; // значение счетчика
_SYSTICK->CSR.ENABLE = ON; // включаем счетчик
_SYSTICK->CVR.CURRENT = 0; // обнуляем текущее значение
for(;;) // бесконечный цикл
{
if( _SYSTICK->CSR.COUNTFLAG) // проверяем переход счётчика через ноль
{
if( _GPIOA->OUTPUTR.Pin5) // если на выводе высокий уровень
_GPIOA->RESETR.Pin5 = DROP; // включаем низкий уровень на выводе
else // иначе
_GPIOA->SETR.Pin5 = HIGH; // включаем высокий уровень
_SYSTICK->CVR.CURRENT = 0; // обнуляем текущее значение счетчика и COUNTFLAG
}
}
}
А вот код с прерыанием.
#include "BS.h"
void SysTick_Handler( void) // Функция обрабатывает прерывание при переполнении системного таймера
{
if( _GPIOA->OUTPUTR.Pin5) // если на выводе высокий уровень
_GPIOA->RESETR.Pin5 = DROP; // сбрасываем бит, включаем низкий уровень на выводе
else // иначе
_GPIOA->SETR.Pin5 = HIGH; // включаем высокий уровень
}
int main(void)
{
_RCC->AHBENR.IOPAEN = ON; // тактирование соответствующего порта
_GPIOA->MODER.Pin5 = OutputMOD; // режим вывода на соответствующем пине
_SYSTICK->RVR.RELOAD = 800000; // значение счетчика, интервал между прерываниями
_SYSTICK->CSR.ENABLE = ON; // включаем счетчик
_SYSTICK->CSR.TICKINT = ON; // включаем прерывание при переполнении
_SYSTICK->CVR.CURRENT = 0; // обнуляем текущее значение
for(;;); // бесконечный цикл
}
15:05 Почему у Вас подсказки вылетают при вводе? Как сделать так?
Нажать Ctrl+space. Кажется так.
@@NRelectronics Разобрался Ctrl+spacebar
Да, именно так, опечатался.
Пишу функцию на SysTick для микросекунд. Загружаю значение в SysTick->LOAD = 3199, с расчётом что, если частота, 32 МГц, то за 100 микросекунд он дойдёт до нуля, далее проверяю, когда досчитает до 0 через: while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)). Но, судя по осциллограммам, таймер считает в 2 раза быстрее. Не понимаю, почему..
А тактирование мк при этом на 72МГц?
@@NRelectronics в том то и дело, что тактирование 32 МГц, ставлю кварц и умножитель на 4. Буду искать, понятно, что я что-то неправильно сделал.
@@NRelectronics нашёл баг, поделюсь. у меня написаны свои функции setSystemClock и т.д, на что я и надеялся. Но в system_stm32 я не отключил дефайны, и там повторно вызывалась готовая функция установки частоты на 72 по дефайну. С другой стороны, моя функция установки частоты шла после, уже в main. Но видимо из-за того, что я там у себя не сбрасывал регистры в reset state, так и оставалось 72 МГц..
Молодцы что разобрались. Я вас подтолкнул в нужную сторону ;)
Не понял, а как это работает вообще?
Принцип понятен, но обработчика прерываний, который будет запускать ваш хэндлер по завершению отсчета вы же не писали! Значит где-то в инклюдах должен быть обработчик, но у меня его похоже нет - контроллер другой.
Добавлено: перепроверил еще раз, вектор нашел, ошибка в другом была.
Отлично, быстрей меня разобрались 😉👌
не работает, висит в вайле while(SysCnt) бесконечно
Сделайте строго по видео, код рабочий.
16:10
100/(10-1)==11.1111
Так правильно:
(100/10)-1==9
Откуда это и к чему? Там 1000-1.
@@NRelectronics Это как пример, на других цифрах.
SYSLOCK у вас == 72000000
72000000/(1000-1)
72000000/(999)==72 072,072072
А должно быть так:
72000000/1000-1==71 999
Теперь понятно что имели ввиду. Нет, тут не так как вы пишите. Если записать, как вы говорите, просто 1000, считаться будет как раз 1001, так как счёт начинается начинается с 0, поэтому его вычитают - (1000-1). Математически это получается не верно, а по логике счета именно так.
@@NRelectronics Допустим надо остчитать 10.
Для этого в регистр надо положить число 9, потому что считается от 9 до нуля.
0,1,2,3,4,5,6,7,8,9
Давайте пока что без деления.
Если надо посчитать 72 000 000, то в регистр надо положить 72 000 000-1== 71 999 999
Теперь с делением:
Надо посчитать от числа, которое в 1000 раз меньше чем 72 000 000 до нуля:
72 000 000/1000==72 000
72 000-1==71 999
Это неправильно:72 000 000/(1000-1)==72 072,072
Так вы сами пишите 0,1,2,3,4,5,6,7,8,9 - сколько счета? А 10 же! Но записываем как (10-1) 😉
Функция delay_mS работает только потому что SysTick_CNT уменьшается раз в (я не знаю какая частота SYSCLK у Вас) за счёт прерываний.
В функции delay_mS регистр VAL обнуляется, думаю что даже в цикл while не заходит, потому что регистр VAL сбросился и из за этого происходит прерывание. После чего уменьшается SysTick_CNT
Это утверждение или вопрос?) Что работает опять неправильно? 😁
@@NRelectronics
Я разбираюсь пока что))
Мутное дело. Слежу за регистрами.
А, 🆗
@@NRelectronics Мне кажется это просто неудачное описание регистра VAL.
При записи чего либо в данный регистр, обнуляется остчёт и в регистр VAL опять загружается число из регистра LOAD.
То есть если например VAL досчитал от 100 до 50 и в него загрузить что нибудь, то в регистр VAL опять запишется число 100 и по новому начнёт считать до нуля.
А бит COUNTFLAG регистра CTRL действительно сбрасывается в 0 если что либо записать в регистр VAL.
Бит COUNTFLAG регистра CTRL обнуляется в двух случаях, первый описал, а второй случай это если прочитать бит COUNTFLAG.
Здесь Вы 2 раза обнулили отсчёт в регистре VAL.
SysTick->VAL &= ~SysTick_VAL_CURRENT_Msk;
SysTick->VAL = SYSLOCK/1000-1;
Это утверждение)
Я как освобожусь, доберусь до сорцов и всё посмотрю. Спасибо.