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
    __________________________________________________

КОМЕНТАРІ • 83

  • @OpenFrimeTVcom
    @OpenFrimeTVcom 3 роки тому +3

    спасибо, я как раз закончил с прошлым роликом, и перенес все в код.
    теперь буду с этим возится)

    • @NRelectronics
      @NRelectronics  3 роки тому

      На благо. Отлично, я во время значит!)

  • @AndySm1973
    @AndySm1973 3 роки тому +2

    Огромное спасибо! Очень интересный цикл видео!

    • @NRelectronics
      @NRelectronics  3 роки тому +1

      Спасибо! Всем подписываться на канал и смотреть вместе!)

  • @kospov2002
    @kospov2002 3 роки тому

    Как всегда великолепно! Стабильность признак мастерства! Спасибищееее!

    • @NRelectronics
      @NRelectronics  3 роки тому +1

      Благодарю, приятно конечно. Но все мы люди и можем очепятаться например)

    • @kospov2002
      @kospov2002 3 роки тому

      @@NRelectronics Не ошибается тот кто ничего не делает. Я про то, что уровень контента стабильно высокий и это радует))) Или я где то очепятался? 😁 В любом случае очень подробно, без воды и позновательно ))) Очень надеюсь ваш запал не угаснет! )))

    • @NRelectronics
      @NRelectronics  3 роки тому

      Вы правы, кто ничего не делает) Вы не очепятались ;) Стараюсь держать планку. О да, запал тоже необходим)

  • @IgorPolkhanov
    @IgorPolkhanov 3 роки тому +1

    Спасибо за видео. Хотелось бы видеть серии по DMA, ADC и USB)

    • @NRelectronics
      @NRelectronics  3 роки тому

      Пожалуйста. По этой периферии также будут видео!

  • @alexanderurezchenko6446
    @alexanderurezchenko6446 4 дні тому

    прекрасно!

  • @michaelgovorov5083
    @michaelgovorov5083 2 роки тому +3

    сильные лекции для основ стм. подход работы с регистрами cmsis самый правильный при прогр контроллера

    • @NRelectronics
      @NRelectronics  2 роки тому

      Спасибо. С регистрами согласен.

  • @user-lm3vp6hx5c
    @user-lm3vp6hx5c 3 роки тому

    Здравствуйте, подскажите пожалуйста, что произошло на рынке STМ. Решил заказать stmмки и обалдел от цен, если раньше stm32f103 стоило в районе 130 руб, сейчас ~400. С чем связан такой резкий скачок цен?

    • @NRelectronics
      @NRelectronics  3 роки тому

      Здравствуйте. Кризис полупроводниковых микросхем. Ждем к чему это приведет ещё...

  • @user-yg4mu7rm7k
    @user-yg4mu7rm7k 3 роки тому

    такой вопрос, а если я хочу изменить частоту тактирования, что мне нужно закоментировать?

    • @NRelectronics
      @NRelectronics  3 роки тому

      В зависимости от того что нужно меняется тут:
      #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

  • @user-qc7ib5fj9n
    @user-qc7ib5fj9n 3 роки тому

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

    • @NRelectronics
      @NRelectronics  3 роки тому

      Здравствуйте. В окне Build Output.

  • @amn5021
    @amn5021 3 роки тому +4

    Переснять бы выдосик, по хорошему. Делитель нужно считать так: SysTick->VAL = SYSLOCK / 1000 - 1, т.е. скобки, меняющие порядок действий, там ошибочны. И, да, нет никакого смысла перед этой строкой что-то там писать в SysTick->VAL.

    • @NRelectronics
      @NRelectronics  3 роки тому

      VAL все же вписать крайне желательно. Скобки через комит отредактирую.

    • @amn5021
      @amn5021 3 роки тому +1

      @@NRelectronics В SysTick_Init() запись в VAL имеет смысл, в delay_mS() никакого.

    • @Shinsei75
      @Shinsei75 3 роки тому

      О! Теперь понятно, а то хотел спросить зачем в скобках писать 1000-1, если можно было 999 написать, а так как без скобок тогда уже понятно

    • @NRelectronics
      @NRelectronics  3 роки тому

      Досадная очепятка. Скобки лишние. Правильно SYSCLOCK/1000 - 1. На гитхабе откоммичу. Ну с минус единицей как бы наверное яснее.

    • @NRelectronics
      @NRelectronics  3 роки тому

      Вам про одно и тоже про delay_ms не надоело писать?? Все это понимают давно.

  • @user-qi5li3wv6i
    @user-qi5li3wv6i 4 місяці тому

    Для тех кто пишет с нуля, функция обработки прерывания должна называться точно как в видео

  • @user-kc8ec6vl9d
    @user-kc8ec6vl9d Рік тому

    Все сделал как на видео. Но в SysTick_Handler() не попадаю. Висит в while(SysTick_CNT). Что может быть? В отладчике CVR - CURRENT крутятся значения, а в CSR - все флаги подняты(галочки стоят)

    • @NRelectronics
      @NRelectronics  Рік тому

      Проверьте код весь, ничего не пропустили. Код мой ведь рабочий.

  • @glebuchitel1577
    @glebuchitel1577 2 роки тому

    Подскажите не могу понять, когда мы записываем в BS5, пин 5 выдает 1, и в следующей итерации цикла опять устанавливаем его. То же самое и с BR5. Они сами сбрасываются что ли?

    • @NRelectronics
      @NRelectronics  2 роки тому

      BS5 - Bit Set 5 pin, BR5 - Bit Reset5 pin. Везде активное состояние это единичка.

    • @glebuchitel1577
      @glebuchitel1577 2 роки тому

      @@NRelectronics нет я имею в виду что по всему видимому когда мы устанавливаем BS5, то BR5 сбрасывается и наоборот. Иначе они бы установились в BS5=1 и BR5=1 в первой итерации цикла и не менялись. Они сбрасываются программно либо аппаратно

    • @NRelectronics
      @NRelectronics  2 роки тому

      Так и есть, с названия это и следует, я ведь расшифровал, Set - установка единицы, Reset - сброс состояния.

    • @glebuchitel1577
      @glebuchitel1577 2 роки тому

      @@NRelectronics да не состояния, а значения этих регистров…

  • @namename2031
    @namename2031 2 роки тому

    8:40
    SYST_CVR
    Любая запись сбрасывает регистр в 0, а также сбрасывает бит COUNTFLAG в регистре SYST_CSR.
    Когда вы записываете что либо в этот регистр, то значение этого регистра сбрасывается в 0.
    В описании этого регистра это и написано.

    • @NRelectronics
      @NRelectronics  2 роки тому

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

    • @namename2031
      @namename2031 2 роки тому

      @@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 обнуляют я не знаю.

    • @NRelectronics
      @NRelectronics  2 роки тому

      Т.к. могут быть старые значения отличные от нулевых, т.е. мусор. Так всегда делают, это правильно.

  • @namename2031
    @namename2031 2 роки тому

    17:51 Функция SysTick_Handler определена ведь уже где то выше. У меня в файле stm32f4xx_it.c
    И здесь 17:51 получаеттся повторное переопределение данной функции.
    Как такое возможно?
    У меня выдаёт ошибку.

    • @NRelectronics
      @NRelectronics  2 роки тому +1

      Если повторное выдавал бы ошибку, у меня не выдаёт, норм.

  • @user-kc8ec6vl9d
    @user-kc8ec6vl9d Рік тому

    Как это происходит? Частота падает до 71999(Hz) и делится на 1000(Ms). Или как?

    • @NRelectronics
      @NRelectronics  Рік тому +1

      Падает до 72000 и делится на 1000.

  • @IlxlI
    @IlxlI Рік тому

    Автор, поясните, почему Handler. Я не вижу нигде исполнения функции, это какой-то каллбэк?

    • @NRelectronics
      @NRelectronics  Рік тому

      Где именно? Я ролик не помню в деталях...

    • @IlxlI
      @IlxlI Рік тому

      @@NRelectronics просто без функции SysTick_Handler ничего не работает, но ее ничто в коде и не вызывает. Выходит, handler придает какое-то значение?

    • @NRelectronics
      @NRelectronics  Рік тому

      Обработчик вызывается по прерыванию. Его не вызывают в коде программа.

  • @sergeyvp
    @sergeyvp 3 роки тому +3

    Очень хорошим делом вы занимаетесь, но зачем использовать функции типа delay() ?
    Конкретно в данном случае достаточно в основном цикле прописать условие проверки значения счётчика и выполнять нужный код в теле этого условия без прерывания.
    Либо выставить значение счётчика в нужный интервал и в прерывании выполнять необходимый код.
    Функции delay() делают код неэффективным.

    • @NRelectronics
      @NRelectronics  3 роки тому

      Посыл этого видео системный таймер и работа с ним. А вот следующее видео как раз использование в подобных случаев таймера, об этом я в видео кстати говорил ;)

    • @sergeyvp
      @sergeyvp 3 роки тому +2

      @@NRelectronics Я понял о чём видео. Но использование функций задержки это очень плохая практика программирования. Не стоит приучать к этому новичков.

    • @NRelectronics
      @NRelectronics  3 роки тому

      А я и не приучаю. Знать тоже нужно как и что настраивается и работает...

    • @NRelectronics
      @NRelectronics  3 роки тому

      К тому же systick полезен во FreeRTOS.

    • @sergeyvp
      @sergeyvp 3 роки тому

      @@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(;;); // бесконечный цикл
      }

  • @Expert69RUS
    @Expert69RUS 3 дні тому

    15:05 Почему у Вас подсказки вылетают при вводе? Как сделать так?

    • @NRelectronics
      @NRelectronics  3 дні тому

      Нажать Ctrl+space. Кажется так.

    • @Expert69RUS
      @Expert69RUS 3 дні тому

      @@NRelectronics Разобрался Ctrl+spacebar

    • @NRelectronics
      @NRelectronics  День тому

      Да, именно так, опечатался.

  • @stm32Lab
    @stm32Lab Рік тому

    Пишу функцию на SysTick для микросекунд. Загружаю значение в SysTick->LOAD = 3199, с расчётом что, если частота, 32 МГц, то за 100 микросекунд он дойдёт до нуля, далее проверяю, когда досчитает до 0 через: while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)). Но, судя по осциллограммам, таймер считает в 2 раза быстрее. Не понимаю, почему..

    • @NRelectronics
      @NRelectronics  Рік тому

      А тактирование мк при этом на 72МГц?

    • @stm32Lab
      @stm32Lab Рік тому

      @@NRelectronics в том то и дело, что тактирование 32 МГц, ставлю кварц и умножитель на 4. Буду искать, понятно, что я что-то неправильно сделал.

    • @stm32Lab
      @stm32Lab Рік тому

      @@NRelectronics нашёл баг, поделюсь. у меня написаны свои функции setSystemClock и т.д, на что я и надеялся. Но в system_stm32 я не отключил дефайны, и там повторно вызывалась готовая функция установки частоты на 72 по дефайну. С другой стороны, моя функция установки частоты шла после, уже в main. Но видимо из-за того, что я там у себя не сбрасывал регистры в reset state, так и оставалось 72 МГц..

    • @NRelectronics
      @NRelectronics  Рік тому +1

      Молодцы что разобрались. Я вас подтолкнул в нужную сторону ;)

  • @zeraphialchemy523
    @zeraphialchemy523 Рік тому

    Не понял, а как это работает вообще?
    Принцип понятен, но обработчика прерываний, который будет запускать ваш хэндлер по завершению отсчета вы же не писали! Значит где-то в инклюдах должен быть обработчик, но у меня его похоже нет - контроллер другой.
    Добавлено: перепроверил еще раз, вектор нашел, ошибка в другом была.

    • @NRelectronics
      @NRelectronics  Рік тому

      Отлично, быстрей меня разобрались 😉👌

  • @Mozobretenie
    @Mozobretenie 2 роки тому

    не работает, висит в вайле while(SysCnt) бесконечно

    • @NRelectronics
      @NRelectronics  2 роки тому

      Сделайте строго по видео, код рабочий.

  • @namename2031
    @namename2031 2 роки тому

    16:10
    100/(10-1)==11.1111
    Так правильно:
    (100/10)-1==9

    • @NRelectronics
      @NRelectronics  2 роки тому

      Откуда это и к чему? Там 1000-1.

    • @namename2031
      @namename2031 2 роки тому

      @@NRelectronics Это как пример, на других цифрах.
      SYSLOCK у вас == 72000000
      72000000/(1000-1)
      72000000/(999)==72 072,072072
      А должно быть так:
      72000000/1000-1==71 999

    • @NRelectronics
      @NRelectronics  2 роки тому

      Теперь понятно что имели ввиду. Нет, тут не так как вы пишите. Если записать, как вы говорите, просто 1000, считаться будет как раз 1001, так как счёт начинается начинается с 0, поэтому его вычитают - (1000-1). Математически это получается не верно, а по логике счета именно так.

    • @namename2031
      @namename2031 2 роки тому

      @@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

    • @NRelectronics
      @NRelectronics  2 роки тому

      Так вы сами пишите 0,1,2,3,4,5,6,7,8,9 - сколько счета? А 10 же! Но записываем как (10-1) 😉

  • @namename2031
    @namename2031 2 роки тому

    Функция delay_mS работает только потому что SysTick_CNT уменьшается раз в (я не знаю какая частота SYSCLK у Вас) за счёт прерываний.
    В функции delay_mS регистр VAL обнуляется, думаю что даже в цикл while не заходит, потому что регистр VAL сбросился и из за этого происходит прерывание. После чего уменьшается SysTick_CNT

    • @NRelectronics
      @NRelectronics  2 роки тому

      Это утверждение или вопрос?) Что работает опять неправильно? 😁

    • @namename2031
      @namename2031 2 роки тому

      @@NRelectronics
      Я разбираюсь пока что))
      Мутное дело. Слежу за регистрами.

    • @NRelectronics
      @NRelectronics  2 роки тому

      А, 🆗

    • @namename2031
      @namename2031 2 роки тому

      @@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;
      Это утверждение)

    • @NRelectronics
      @NRelectronics  2 роки тому +1

      Я как освобожусь, доберусь до сорцов и всё посмотрю. Спасибо.