@ GNU AS
@.CHARSET CP1251

@ +--------------------------------------------------------+
@ |           Модуль управления генерацией звука           |
@ |  Звук генерируется при помощи TIM2 CH1 (режим PWM)     |
@ +--------------------------------------------------------+

.syntax unified
.cpu cortex-m4
.thumb
.fpu fpv4-sp-d16

@.DESC name=BUZZER_SET_FILL type=proc
@ +-------------------------------------------------+
@ |      Установка заполнения периода  звука        |
@ +-------------------------------------------------+
@ | на входе: R4 - значение заполнения от 0 до 100  |
@ +-------------------------------------------------+
@.enddesc

.INCLUDE  "/src/inc/tim2-5.inc"

.SECTION .asmcode

.GLOBAL BUZZER_SET_FILL
BUZZER_SET_FILL:
                    PUSH       { R2 }

                    LDR        R2, = TIM2
@                    MOV        R4, 2             @ значение от 0 до 100 -
                    STR        R4, [ R2, TIM2T5_CCR1 ]    @ сохраняем значение сравнения

                    POP        { R2 }

                    BX         LR


@.DESC name=BUZZER_SET_FREQ type=proc
@ +---------------------------------------------------------------+
@ |                   Установить частоту звука                    |
@ +---------------------------------------------------------------+
@ |                                                               |
@ | вход: R4 - номер частоты звука из звукового ряда              |
PREDIV_ARR:                                    @                  |
             .WORD      42000000 / 65000 - 1    @ 65 гц   ДО       |
             .WORD      42000000 / 73000 - 1    @ 73 гц   РЕ       |
             .WORD      42000000 / 82000 - 1    @ 82 гц   МИ       |
             .WORD      42000000 / 87000 - 1    @ 87 гц   ФА       |
             .WORD      42000000 / 98000 - 1    @ 98 гц   СИ       |
             .WORD      42000000 / 110000 - 1   @ 110 гц  ЛЯ       |
             .WORD      42000000 / 123000 - 1   @ 123 гц  СОЛЬ     |
@ |                                                               |
@ +---------------------------------------------------------------+
@.enddesc

.GLOBAL BUZZER_SET_FREQ
BUZZER_SET_FREQ:
                    PUSH       { R0, R2 }

                    LDR        R2, = PREDIV_ARR
                    ADD        R2, R2, R4, LSL 2
                    LDR        R0, [ R2 ]
                    LDR        R2, = TIM2
                    STR        R0, [ R2, TIM2T5_PSC ]

                    POP        { R0, R2 }

                    BX         LR

@.DESC name=BUZZER_ON type=proc
@ +---------------------------------------------------------------+
@ |                   Включить генерацию звука                    |
@ +---------------------------------------------------------------+
@.enddesc

.global BUZZER_ON
BUZZER_ON:
                    PUSH       { R0, R2 }

                    LDR        R2, = TIM2

                    LDR        R0, = TIM2T5_CCMR1_OC1M_PWM1    @ режим pwm 1 для OC1M ( CH1 )
                    STR        R0, [ R2, TIM2T5_CCMR1 ]

                    POP        { R0, R2 }

                    BX         LR

@.DESC name=BUZZER_OFF type=proc
@ +---------------------------------------------------------------+
@ |                  Выключить генерацию звука                    |
@ +---------------------------------------------------------------+
@.enddesc

.GLOBAL   BUZZER_OFF
BUZZER_OFF:
                    PUSH       { R0, R2 }

                    LDR        R2, = TIM2

                    LDR        R0, = TIM2T5_CCMR1_OC1M_FORSEINACT    @ выключим вывод сигнала сравнения на CH1
                    STR        R0, [ R2, TIM2T5_CCMR1 ]

                    POP        { R0, R2 }

                    BX         LR


.section .bss
ToneCounter:        .space     2    @ счетчик длительности тона
ToneLink:           .SPACE     4    @ указатель на текущий звук

.section .asmcode

@.desc name=BUZZER_TONE type=proc
@ +--------------------------------------------------------------------+
@ |                    Включить звуковой тон                           |
@ +--------------------------------------------------------------------+
@ |  вход: R0 - адрес описателя звукового тона                         |
@ |  выход: нет                                                        |
@ |  изменение регистров по выходу: нет                                |
@ |                                                                    |
@ | формат описателя звукового тона (3 варианта):                      |
@ | [0]  .short <time>  - длительность звукового тона в мс (1\1000 с.) |
@ |                       где time от 1 до 0xFFFE                                           |
@ | [1]  .byte <note>  - частота                                       |
@ | [2]  .byte <fill>  - заполнение частоты (от 1 до 100)              |
@ |                                                                    |
@ | [0]  .short 0 -  описатель звукового тона закончен                 |
@ |                                                                    |
@ | [0]  .short  0xFFFF - задать адрес другого звукового тона          |
@ | [1]  .word  <adr>   - адрес следующего звукового тона              |
@ |                                                                    |
@ +--------------------------------------------------------------------+
@.enddesc

.GLOBAL   BUZZER_TONE
BUZZER_TONE:
                    PUSH       { R1, R2, R4, LR }

                @ сохраним адрес текущего тона
                    LDR        R1, = ToneLink
                    STR        R0, [ R1 ]

                    LDRH       R1, [ R0 ], 2    @ загрузим длительность звука
                    LDR        R2, = ToneCounter
                    STRH       R1, [ R2 ]       @ сохраним значение длительности

                    LDRB       R4, [ R0 ], 1    @ загрузим номер частоты
                    BL         BUZZER_SET_FREQ

                    LDRB       R4, [ R0 ], 1    @ загрузим заполнение периода
                    BL         BUZZER_SET_FILL

                    BL         BUZZER_ON        @ включим звук

                    POP        { R1, R2, R4, PC }

@.desc name=BUZZER_PLAY type=proc
@ +----------------------------------------------------------------+
@ |                  Обработка воспроизведения звуков              |
@ +----------------------------------------------------------------+
@ | Процедура вызывается из прерывания, и генерирует длительности  |
@ | воспроизводимых звуков и смену тона согласно описателю         |
@ +----------------------------------------------------------------+
@.enddesc
.global BUZZER_PLAY
BUZZER_PLAY:
               @ воспроизводим звук пока не истечет его время
                    LDR        R1, = ToneCounter
                    LDRH       R2, [ R1 ]
                    LDR        R3, = 0xFFFF

                    CMP        R2, R3         @ маркер отсутствия звука
                    BEQ        BUZZER_PLAY_exit

                    CMP        R2, 0x00           @ закончим воспроизведение звука
                    BEQ        BUZZER_PLAY_NEXT

                    SUB        R2, R2, 1
                    STRH       R2, [ R1 ]
BUZZER_PLAY_exit:
                    BX         LR

BUZZER_PLAY_NEXT:
                    LDR        R0, = ToneLink
                    LDR        R0, [ R0 ]
                    ADD        R0, R0, 4
                    LDRH       R2, [ R0 ]    @ загрузим длительность следующего тона

                    CMP        R2, 0x00                @ проверим окончание последовательности звуков
                    BNE        BUZZER_PLAY_NEXT_TONE   @ если не окончена, продолжаем проверку

                    STRH       R3, [ R1 ]
                    B         BUZZER_OFF

BUZZER_PLAY_NEXT_TONE:
                    CMP        R2, R3    @ проверим необходимость загрузки нового тона
                    BNE        BUZZER_TONE    @ переходим на загрузку нового тона

                    LDR        R0, [ R0, 2 ]
                    B          BUZZER_TONE



