SysTick.txt 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. Сам таймер 24 разрядный. И тикает вниз от предзагруженного значения до
  2. нуля, после чего перезагружается вновь и генерирует прерывание.
  3. Источником тактирования является системная тактовая частота SYSCLK, либо
  4. та же частота, но поделенная на 8 – SYSCLK/8.
  5. Управляется он четырьмя регистрами:
  6. 0xE000E010 SYST_CSR RW SysTick control and status register
  7. 0xE000E014 SYSCT_RVR RW SysTick reload value register
  8. 0xE000E018 SYSCT_CVR RW SysTick current value register
  9. 0xE000E01C SYSCT_CALIB RO SysTick calibration value register
  10. *SYST_CSR* — SysTick Control and Status Register
  11. Регистр управления и статуса. Несмотря на то, что он 32 битный заняты там всего 4 бита :)
  12. * Бит 0 — ENABLE — бит разрешающий таймеру считать. 1 можно, 0 — нельзя. Когда
  13. мы ставим ENABLE в 1 то таймер автоматически загружает свои счетные регистры
  14. значением из регистра SYST_RVR и начинает тикать вниз.
  15. * Бит 1 — TICKINT — разрешение прерывания. Когда этот бит 1, то на
  16. обнулении будет прерывание таймера.
  17. * Бит 2 — CLKSOURCE — откуда брать тики. Варианта два 0 — внешнее
  18. тактирование эталонного генератора, 1 — с частоты процессора.
  19. * Бит 16 — COUNTFLAG — флаг отсчета. Первый раз ставится в 1 после
  20. первого обнуления. При чтении, как я понял, автоматом обнуляется.
  21. Возвращает 1 если с последнего его чтения таймер перешел через ноль.
  22. Позволяет отследить были ли переполнения. Удобно.
  23. *SYST_RVR* — SysTick Reload Value Register
  24. Регистр предзагрузки. Именно отсюда берет таймер свое значение для
  25. перезагрузки при обнулении. Фактически вот сюда и нужно грузить требуемое
  26. число задержки. Регистр 32 разрядный, но используются только первые 24
  27. бита.
  28. Класть туда можно любое число в диапазоне 0x00000001-0x00FFFFFF. Можно и
  29. 0 положить, но ничего не будет. Т.к. у таймера весь экшн происходит с
  30. перехода из 0x00000001 в 0x00000000. А на ноль и получается ноль. Разве
  31. что COUNTFLAG вскочит. Только и всего. Поэтому значение SYST_RVR должно
  32. быть N-1 от желаемого количества тактов. Т.е. если надо получить
  33. прерывание на каждые 10000 тактов, то кладем 9999.
  34. *SYST_CVR* — SysTick Current Value Register
  35. Это, собственно, и есть счетный регистр. Тут оно тикает! В первых трех
  36. байтах. Есть у этого регистра особенность одна забавная. Из него можно
  37. только читать. А вот запись любого значения сразу его обнуляет. С
  38. обнулением флага COUNTFLAG.
  39. Т.е. если надо занулить таймер — пиши сюда :)
  40. *SYST_CALIB* — SysTick Calibration Value Register
  41. Это, как ясно из названия, регистр калибровки. Его можно только читать, и
  42. возвращает он следующее:
  43. * SKEW — Показывает что записано в TENMS 0 — там реальные калибровочные
  44. константы. 1 — какой то мусор который не имеет значения. Ну или ноль.
  45. * NOREF — показывает есть ли у девайса эталонная тактовая частота. 0 —
  46. есть, 1 — нет. Это зависит от производителя, позаботился ли он о такой
  47. штуке :) Если эталонных часов нет, то бит CLKSOURCE из регистра SYST_CSR
  48. читается как 1 и его нельзя изменить.
  49. * TENMS — калибровочная константа. Содержит значение для 10мс задержки.
  50. Как я понял, для эталонного генератора. Которого может и не быть.
  51. *** Адреса и имена ***
  52. Осталось залезть в CMSIS и поискать там описание и дефайны SysTick.
  53. Находятся быстро в core_cm3.h:
  54. *------------------ File Begin -------------------*
  55. typedef struct
  56. {
  57. __IO uint32_t CTRL; /*!< Offset: 0x00 SysTick Control and Status Register */
  58. __IO uint32_t LOAD; /*!< Offset: 0x04 SysTick Reload Value Register */
  59. __IO uint32_t VAL; /*!< Offset: 0x08 SysTick Current Value Register */
  60. __I uint32_t CALIB; /*!< Offset: 0x0C SysTick Calibration Register */
  61. } SysTick_Type;
  62. /* SysTick Control / Status Register Definitions */
  63. #define SysTick_CTRL_COUNTFLAG_Pos 16 /*!< SysTick CTRL: COUNTFLAG Position */
  64. #define SysTick_CTRL_COUNTFLAG_Msk (1ul << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
  65. #define SysTick_CTRL_CLKSOURCE_Pos 2 /*!< SysTick CTRL: CLKSOURCE Position */
  66. #define SysTick_CTRL_CLKSOURCE_Msk (1ul << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
  67. #define SysTick_CTRL_TICKINT_Pos 1 /*!< SysTick CTRL: TICKINT Position */
  68. #define SysTick_CTRL_TICKINT_Msk (1ul << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
  69. #define SysTick_CTRL_ENABLE_Pos 0 /*!< SysTick CTRL: ENABLE Position */
  70. #define SysTick_CTRL_ENABLE_Msk (1ul << SysTick_CTRL_ENABLE_Pos) /*!< SysTick CTRL: ENABLE Mask */
  71. /* SysTick Reload Register Definitions */
  72. #define SysTick_LOAD_RELOAD_Pos 0 /*!< SysTick LOAD: RELOAD Position */
  73. #define SysTick_LOAD_RELOAD_Msk (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos) /*!< SysTick LOAD: RELOAD Mask */
  74. /* SysTick Current Register Definitions */
  75. #define SysTick_VAL_CURRENT_Pos 0 /*!< SysTick VAL: CURRENT Position */
  76. #define SysTick_VAL_CURRENT_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick VAL: CURRENT Mask */
  77. /* SysTick Calibration Register Definitions */
  78. #define SysTick_CALIB_NOREF_Pos 31 /*!< SysTick CALIB: NOREF Position */
  79. #define SysTick_CALIB_NOREF_Msk (1ul << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
  80. #define SysTick_CALIB_SKEW_Pos 30 /*!< SysTick CALIB: SKEW Position */
  81. #define SysTick_CALIB_SKEW_Msk (1ul << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
  82. #define SysTick_CALIB_TENMS_Pos 0 /*!< SysTick CALIB: TENMS Position */
  83. #define SysTick_CALIB_TENMS_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick CALIB: TENMS Mask */
  84. /*@}*/ /* end of group CMSIS_CM3_SysTick */
  85. *------------------ File End -------------------*
  86. Нам там нужны имена битов. Вот они:
  87. SysTick_CTRL_CLKSOURCE_Msk, SysTick_CTRL_TICKINT_Msk, SysTick_CTRL_ENABLE_Msk.
  88. Конфигурация таймера на тик в 1ms, таким образом, будет выглядеть примерно
  89. так:
  90. *------------------ File Begin -------------------*
  91. #define F_CPU 72000000UL // Тактовая у нас 72МГЦ
  92. #define TimerTick F_CPU/1000-1 // Нам нужен килогерц
  93. SysTick->LOAD=TimerTick; // Загрузка значения
  94. SysTick->VAL=TimerTick; // Обнуляем таймеры и флаги. Записью, помните?
  95. SysTick->CTRL= SysTick_CTRL_CLKSOURCE_Msk |
  96. SysTick_CTRL_TICKINT_Msk |
  97. SysTick_CTRL_ENABLE_Msk;
  98. *------------------ File End -------------------*
  99. *** Обработчик прерывания SysTick ***
  100. Где взять имя обработчика? Да из таблицы прерываний. Поглядеть, если кто
  101. не помнит, можно в STM32F10x.s
  102. Вот ее кусочек:
  103. *------------------ File Begin -------------------*
  104. ; Vector Table Mapped to Address 0 at Reset
  105. AREA RESET, DATA, READONLY
  106. EXPORT __Vectors
  107. __Vectors DCD __initial_sp ; Top of Stack
  108. DCD Reset_Handler ; Reset Handler
  109. DCD NMI_Handler ; NMI Handler
  110. DCD HardFault_Handler ; Hard Fault Handler
  111. DCD MemManage_Handler ; MPU Fault Handler
  112. DCD BusFault_Handler ; Bus Fault Handler
  113. DCD UsageFault_Handler ; Usage Fault Handler
  114. DCD 0 ; Reserved
  115. DCD 0 ; Reserved
  116. DCD 0 ; Reserved
  117. DCD 0 ; Reserved
  118. DCD SVC_Handler ; SVCall Handler
  119. DCD DebugMon_Handler ; Debug Monitor Handler
  120. DCD 0 ; Reserved
  121. DCD PendSV_Handler ; PendSV Handler
  122. DCD SysTick_Handler ; SysTick Handler
  123. *------------------ File End -------------------*
  124. Имя есть. Осталось организовать прерывание:
  125. *------------------ File Begin -------------------*
  126. //SysTick Interrupt
  127. void SysTick_Handler(void)
  128. {
  129. // Тут будем делать нечто полезное. Например, ставить бит B.05
  130. GPIOB->BSRR = GPIO_BSRR_BS5; // Set bit
  131. }
  132. *------------------ File End -------------------*
  133. А сбрасывать его будет в главном цикле. В результате мы получим иголки с
  134. частотой 1Кгц которые хорошо видно осциллографом :)
  135. Вот так выглядит полный код примера:
  136. *------------------ File Begin -------------------*
  137. #include "stm32f10x.h"
  138. #define F_CPU 72000000UL
  139. #define TimerTick F_CPU/1000-1
  140. void Delay(uint32_t Val);
  141. //SysTick Interrupt
  142. void SysTick_Handler(void)
  143. {
  144. GPIOB->BSRR = GPIO_BSRR_BS5; // Set bit
  145. }
  146. int main(void)
  147. {
  148. SystemInit();
  149. RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
  150. // Config CRL
  151. GPIOB->CRL &= ~GPIO_CRL_CNF5; // Clear CNF bit 5. Mode 00 - Push-Pull
  152. GPIOB->CRL |= GPIO_CRL_MODE5_0; // Set bit MODE0 for pin 5. Mode 01 = Max Speed 10MHz
  153. SysTick->LOAD=TimerTick;
  154. SysTick->VAL=TimerTick;
  155. SysTick->CTRL= SysTick_CTRL_CLKSOURCE_Msk |
  156. SysTick_CTRL_TICKINT_Msk |
  157. SysTick_CTRL_ENABLE_Msk;;
  158. while(1)
  159. {
  160. GPIOB->BSRR = GPIO_BSRR_BR5; // Clear bit
  161. }
  162. }
  163. *------------------ File End -------------------*
  164. *** Функции CMSIS ***
  165. У Таймера, раз он часть ядра, есть функция конфигурации в CMSIS. Описана
  166. она в core_cm3.h и выглядит так:
  167. *------------------ File Begin -------------------*
  168. static __INLINE uint32_t SysTick_Config(uint32_t ticks)
  169. {
  170. if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
  171. SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
  172. NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
  173. SysTick->VAL = 0; /* Load the SysTick Counter Value */
  174. SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
  175. SysTick_CTRL_TICKINT_Msk |
  176. SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
  177. return (0); /* Function successful */
  178. }
  179. *------------------ File End -------------------*
  180. То же самое, что и мы сделали вручную. Только есть проверка на
  181. корректность значения и обрезка лишних битов. Возвращает 1 если данные
  182. некорректные. Ну и еще там приоритет ставится если ядро М0 (это кстати хз
  183. зачем? У M0 же должна быть своя версия CMSIS?)
  184. Так что таймер можно загрузить и следующей фигней:
  185. SysTick_Config(TimerTick);
  186. Для LPC все совершенно аналогично. До последней буковки можно сказать.
  187. Т.к. это фича не STM32, а ядра и описана в CMSIS. Т.е. едина для всех.
  188. ===============================================================================
  189. Для конфигурации таймера в файле core_cm3.h есть функция
  190. SysTick_Config(uint32_t ticks), в качестве аргумента которой передается
  191. коэффициент деления тактовой частоты для получения необходимой временной
  192. задержки.
  193. ~~~~~~~~~~~~~~~~~~~~
  194. static __INLINE uint32_t SysTick_Config(uint32_t ticks)
  195. {
  196. if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
  197. SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
  198. NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
  199. SysTick->VAL = 0; /* Load the SysTick Counter Value */
  200. SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
  201. SysTick_CTRL_TICKINT_Msk |
  202. SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
  203. return (0); /* Function successful */
  204. }
  205. ~~~~~~~~~~~~~~~~~~~~
  206. Это значение заносится в регистр перезагрузки. В самом начале выполняется
  207. проверка на то, что данная величина не выходит за максимальный предел,
  208. поскольку счетчик 24-разрядный, а передаваемый аргумент функции является
  209. 32-разрядным числом и необходимо об этом помнить.
  210. Далее в функции конфигурации SysTick_Config() задается уровень приоритета
  211. прерывания, обнуляется счетный регистр, разрешается генерация прерывания,
  212. задается источник тактирования и разрешается работа таймера – запускается
  213. счет.
  214. По умолчанию тактовая частота этого таймера будет равна системной тактовой
  215. частоте SYSCLK. Если же нужно задать частоту тактирования таймера как
  216. SYSCLK/8, то уже после этой функции инициализации можно вызвать функцию
  217. SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8),
  218. которая находится в файле misc.c. Для этого к проекту необходимо
  219. подключить файлы misc.c и misc.h.
  220. В данных примерах таймер настраивается на генерацию прерывания через
  221. “базовый” промежуток времени, равный 1 миллисекунде. Затем, уже с помощью
  222. программного цикла формируется задержка, равная 1 секунде. Через каждую
  223. секунду происходит попеременное зажигание/гашение светодиодов платы, здесь
  224. я не стал особо мудрить, поскольку основной задачей была настройка
  225. системного таймера для генерации прерываний через определенный интервал.
  226. Для задания длительности между двумя последующими прерываниями от таймера,
  227. в регистр перезагрузки необходимо записать значение, которое
  228. рассчитывается по простой формуле:
  229. * Reload Value = SysTick Counter Clock (Hz) x Desired Time base (s), где
  230. * Reload Value – величина перезагружаемого значения для таймера
  231. * SysTick Counter Clock (Hz) – тактовая частота таймера
  232. * Desired Time base (s) – желаемое время формируемой временной задержки между прерываниями
  233. Системная тактовая частота задается при начальной инициализации микроконтроллера.
  234. На плате STM32VL-DISCOVERY микроконтроллер конфигурируется на работу с
  235. внешним кварцем частотой 8 МГц, при этом его системная тактовая частота
  236. после начальной инициализации будет равна 24 МГц.
  237. На плате STM32L-DISCOVERY внешнего кварца нет и после начальной
  238. инициализации системная тактовая частота формируется внутренним источником
  239. MSI и равна 2,097 МГц.
  240. Расчет перезагружаемых значений приведен ниже, в комментариях примеров программ для этих плат.
  241. Код программы для платы STM32VL-DISCOVERY (контроллер STM32F100)
  242. ~~~~~~~~~~~~~~~~~~~~
  243. #include "stm32f10x.h"
  244. static __IO uint32_t TimingDelay;
  245. void Delay_ms(__IO uint32_t nTime);
  246. GPIO_InitTypeDef GPIO_InitStruct;
  247. int main()
  248. {
  249. /*Вызов функции конфигурации системного таймера SysTick.
  250. Эта функция находится в файле core_cm3.h и:
  251. --Задает источник тактирования системного таймера (по умолчанию это SYSCLK = 24 МГц,
  252. другой возможный вариант - SysTick тактируется от SYSCLK/8);
  253. --Задает уровень приоритета прерывания;
  254. --Сбрасывает флаг ожидания прерывания, если он выставлен;
  255. --Заносит в нужный регистр перезагружаемое значение для декрементирующего счетчика,
  256. которое вычисляется по формуле:
  257. Reload Value = SysTick Counter Clock (Hz) x Desired Time base (s),
  258. для базовой задержки длительностью 1 мс получим величину
  259. Reload Value = 24 000 000 Гц х 0,001 с = 24 000
  260. (Необходимо самостоятельно посчитать эту величину и вставить в качестве
  261. параметра при вызове функции);
  262. --Обнуляет счетчик
  263. --Запускает счет системного таймера*/
  264. SysTick_Config(24000);
  265. //Включаем тактирование порта GPIOC
  266. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  267. //Конфигурируем выводы, к которым подключены светодиоды платы
  268. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; //Выбираем выводы PC8, PC9
  269. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //Максимальная скорость работы
  270. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //Выход Push-Pull
  271. GPIO_Init(GPIOC, &GPIO_InitStruct); //Заносим заданные настройки в регистры порта
  272. while(1)
  273. {
  274. GPIO_ResetBits(GPIOC, GPIO_Pin_9); //Гасим зеленый LED
  275. GPIO_SetBits(GPIOC, GPIO_Pin_8); //Зажигаем синий LED
  276. Delay_ms(1000); //Временная задержка на 1 с
  277. GPIO_ResetBits(GPIOC, GPIO_Pin_8); //Гасим синий LED
  278. GPIO_SetBits(GPIOC, GPIO_Pin_9); //Зажигаем зеленый LED
  279. Delay_ms(1000); //Временная задержка на 1 с
  280. }
  281. }
  282. //Функция временной задержки
  283. void Delay_ms(__IO uint32_t nTime)
  284. {
  285. TimingDelay = nTime;
  286. while(TimingDelay != 0);
  287. }
  288. void TimingDelay_Decrement(void)
  289. {
  290. if (TimingDelay != 0x00)
  291. {
  292. TimingDelay--;
  293. }
  294. }
  295. //Обработчик прерывания системного таймера
  296. void SysTick_Handler(void)
  297. {
  298. TimingDelay_Decrement();
  299. }
  300. ~~~~~~~~~~~~~~~~~~~~
  301. Код программы для платы STM32L-DISCOVERY (контроллер STM32L152)
  302. ~~~~~~~~~~~~~~~~~~~~
  303. #include "stm32l1xx.h"
  304. static __IO uint32_t TimingDelay;
  305. void Delay_ms(__IO uint32_t nTime);
  306. GPIO_InitTypeDef GPIO_InitStruct;
  307. int main()
  308. {
  309. /*Вызов функции конфигурации системного таймера SysTick.
  310. Эта функция находится в файле core_cm3.h и:
  311. --Задает источник тактирования системного таймера (по умолчанию это SYSCLK = 2.097 МГц,
  312. другой возможный вариант - SysTick тактируется от SYSCLK/8);
  313. --Задает уровень приоритета прерывания;
  314. --Сбрасывает флаг ожидания прерывания, если он выставлен;
  315. --Заносит в нужный регистр перезагружаемое значение для декрементирующего счетчика,
  316. которое вычисляется по формуле:
  317. Reload Value = SysTick Counter Clock (Hz) x Desired Time base (s),
  318. для базовой задержки длительностью 1 мс получим величину
  319. Reload Value = 2 097 000 Гц х 0,001 с = 2097
  320. (Необходимо самостоятельно посчитать эту величину и вставить в качестве
  321. параметра при вызове функции);
  322. --Обнуляет счетчик
  323. --Запускает счет системного таймера*/
  324. SysTick_Config(2097);
  325. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); //Включаем тактирование GPIOB
  326. //Конфигурируем выводы, к которым подключены светодиоды платы
  327. GPIO_InitStruct.GPIO_Pin = (GPIO_Pin_6 | GPIO_Pin_7); //Выбираем выводы PB6, PB7
  328. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //Выводы порта в режиме выхода
  329. GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //Выход Push-Pull
  330. GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; //Выход без подтягивающих резисторов
  331. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz; //Скорость порта максимальная
  332. GPIO_Init(GPIOB, &GPIO_InitStruct); //Заданные настройки сохраняем в регистрах GPIOB
  333. while(1)
  334. {
  335. GPIO_ResetBits(GPIOB, GPIO_Pin_7); //Гасим зеленый LED
  336. GPIO_SetBits(GPIOB, GPIO_Pin_6); //Зажигаем синий LED
  337. Delay_ms(1000); //Временная задержка на 1 с
  338. GPIO_ResetBits(GPIOB, GPIO_Pin_6); //Гасим синий LED
  339. GPIO_SetBits(GPIOB, GPIO_Pin_7); //Зажигаем зеленый LED
  340. Delay_ms(1000); //Временная задержка на 1 с
  341. }
  342. }
  343. //Функция временной задержки
  344. void Delay_ms(__IO uint32_t nTime)
  345. {
  346. TimingDelay = nTime;
  347. while(TimingDelay != 0);
  348. }
  349. void TimingDelay_Decrement(void)
  350. {
  351. if (TimingDelay != 0x00)
  352. {
  353. TimingDelay--;
  354. }
  355. }
  356. //Обработчик прерывания системного таймера
  357. void SysTick_Handler(void)
  358. {
  359. TimingDelay_Decrement();
  360. }
  361. ~~~~~~~~~~~~~~~~~~~~
  362. ===============================================================================
  363. *** Литература: ***
  364. Cortex-M3 Devices Generic User Guide
  365. Cortex-M3 Peripherals > System timer, SysTick
  366. 4.4. System timer, SysTick
  367. http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Babieigh.html
  368. ARM. Учебный Курс. SysTick — Системный таймер
  369. http://easyelectronics.ru/arm-uchebnyj-kurs-systick-sistemnyj-tajmer.html
  370. STM32. Системный таймер SysTick.
  371. http://chipspace.ru/stm32-systick/