@GNU AS
@.CHARSET  CP1251

@.DESC     type=module
@ +----------------------------------------------------------------------+
@ |                         Модуль таймера SysTick                       |
@ +----------------------------------------------------------------------+
@ |                                                                      |
@ | Для работы модуля необходима таблица прерываний не менее Core        |
@ | с минимальной таблицей прерывания модуль работать не сможет !        |
@ |                                                                      |
@ | Для использования необходимо инициализировать модуль вызовом:        |
@ |     BL   SYSTICK_INIT                                                |
@ |                                                                      |
@ | В дальнейшем при необходимости осуществления задержки:               |
@ |    MOV R0, <время задержки в милисекундах>                           |
@ |    BL  SYSTICK_DELAY                                                 |
@ |                                                                      |
@ +----------------------------------------------------------------------+
@ |                                                                      |
@ | Период таймера определяется значением пересчета, SysTick считает     |
@ | от установленного значения до нуля и возникает прерывание.           |
@ |                                                                      |
@ | Настройка модуля заключается в указании частоты тактирования (AHB) и |
@ | необходимой частоты счета, для частоты 1000 гц период равен          |
@ | 1/1000= 0.001 сек, или 1 милисекунда                                 |
@ |                                                                      |
@ | Для частоты AHB=24 Мгц                                               |
.EQU  AHB_Freq      , 24000000    @ тактовая частота (AHB)               |
@ |                                                                      |
@ | Частота счета                                                        |
.EQU  STK_Period    , 1000        @ частота счета, в гц                  |
@ |                                                                      |
@ +----------------------------------------------------------------------+
@ |                                                                      |
@ | Видеоурок про данный модуль:                                         |
@ | ArmAsmEditor: STM32 на Ассемблере: Прерывания микроконтроллера       |
@ | STM32, модуль SysTick, Видео 22                                      |
@ | https://youtu.be/cDfZsWPQQWw                                         |
@ |                                                                      |
@ +----------------------------------------------------------------------+
@.ENDDESC

.SYNTAX   unified             @ синтаксис исходного кода
.THUMB                        @ тип используемых инструкций Thumb
.CPU      cortex-m3           @ процессор

@ определение констант
.EQU  SCB_BASE      , 0xE000ED00                   @ System control block (SCB)
.EQU  SHPR3         , 0x20                         @ System handler priority registers (SHPRx)
.EQU  SYSTICK_BASE  , 0xE000E010                   @ System timer
.EQU  STK_CTRL      , 0x00                         @ Регистр статуса и управления
.EQU  STK_LOAD      , 0x04                         @ Значение для перезагрузки счетчика
.EQU  STK_VAL       , 0x08                         @ Текущее значение счетчика
.EQU  STK_CTRL_CLKSOURSE, 0x00000004               @ (RW) источник тактирования: 0: AHB/8; 1: AHB
.EQU  STK_CTRL_TICKINT, 0x00000002                 @ (RW) при установке генерирует прерывание при переходе через 0
.EQU  STK_CTRL_ENABLE, 0x00000001                  @ (RW) включает счетчик.


.SECTION  .bss
.align (4)
@ Переменная в ОЗУ
SYSTICK_COUNTER:
                    .WORD      0                  @ Значение необходимой задержки


@.DESC     name=IRQ_SysTick type=proc
@ +----------------------------------------------------------------------+
@ |            Обработчик прерывания системного таймера SysTick          |
@ +----------------------------------------------------------------------+
@ |                                                                      |
@ | Прерывание уменьшает значение счетчика SYSTICK_COUNTER на "1" (в     |
@ | случае если значение счетчика больше "0"                             |
@ |                                                                      |
@ +----------------------------------------------------------------------+
@.ENDDESC

.SECTION  .asmcode

.GLOBAL   IRQ_SysTick
IRQ_SysTick:
                    LDR        R1, = SYSTICK_COUNTER
                    LDR        R0, [ R1, 0 ]
                    ORRS       R0, R0, 0          @ Проверка R0 на 0
                    ITT        NE                 @ Если R0<>0 уменьшаем его на 1
                    SUBNE      R0, R0, 1
                    STRNE      R0, [ R1, 0 ]
                    BX         LR

@.DESC     name=SYSTICK_INIT type=proc
@ +----------------------------------------------------------------------+
@ |               Инициализация системного таймера SysTick               |
@ +----------------------------------------------------------------------+
@ |                                                                      |
@ | Процедура настраивает STK, значение регистров не изменяются          |
@ | Проект обязательно должен в себя включать таблицу векторов прерыва-  |
@ | ний (isr.asm) не ниже Core                                           |
@ |                                                                      |
@ +----------------------------------------------------------------------+
@.ENDDESC

.EQU  systick_val   , AHB_Freq / STK_Period

@ Включение SysTick
.GLOBAL   SYSTICK_INIT

SYSTICK_INIT:
                    PUSH       { R0, R1 }
                    LDR        R0, = SYSTICK_BASE

                    @ установка значения пересчета для получения частоты 1000 гц
                    LDR        R1, = systick_val - 1
                    STR        R1, [ R0, STK_LOAD ]

                    @ источник частоты AHB + прерывания + включаем SYSTICK
                    LDR        R1, = ( STK_CTRL_CLKSOURSE + STK_CTRL_TICKINT + STK_CTRL_ENABLE )
                    STR        R1, [ R0, STK_CTRL ]

                    @ установка приоритета прерываний от SysTick
                    LDR        R0, = SCB_BASE
                    LDR        R1, [ R0, SHPR3 ]
                    ORR        R1, R1, 0xF0 << 24
                    STR        R1, [ R0, SHPR3 ]

                    POP        { R0, R1 }
                    BX         LR

@.DESC     name=SYSTICK_DELAY type=proc
@ +----------------------------------------------------------------------+
@ |             Задержка средствами системного таймера SysTick           |
@ +----------------------------------------------------------------------+
@ |                                                                      |
@ | Входной параметр: R0 - задержка в милисекундах                       |
@ | Выходной параметр: R0 = 0                                            |
@ | Изменение других регистров: нет                                      |
@ |                                                                      |
@ +----------------------------------------------------------------------+
@
@.ENDDESC

.GLOBAL   SYSTICK_DELAY

SYSTICK_DELAY:
                    PUSH       { R1 }

                    @ сбросим счетчик
                    LDR        R1, = SYSTICK_BASE
                    STR        R0, [ R1, STK_VAL ]      @ запись любого значения сбросит STK_VAL

                    LDR        R1, = SYSTICK_COUNTER    @ адрес счетчика
                    STR        R0, [ R1, 0 ]            @ сохраним начальное значение
DELAY_LOOP:
                    LDR        R0, [ R1, 0 ]            @ ждем обнуления счетчика
                    ORRS       R0, R0, 0
                    BNE        DELAY_LOOP

                    POP        { R1 }

                    BX         LR


