@.CHARSET  CP1251

@ GNU AS
.SYNTAX   unified
.CPU      cortex-m3
.THUMB

.INCLUDE   "/src/inc/gpio.inc"
.INCLUDE   "/src/inc/rcc.inc"
.INCLUDE   "/src/inc/spi.inc"

@.DESC     name=SPI_TX_INIT type=proc
@ +----------------------------------------------------------------------+
@ |              Процедура инициализации аппаратного SPI                 |
@ +----------------------------------------------------------------------+
@ | Модуль реализует программный SPI для отправки данных для любого GPIO |
@ | указанного в следующих настройках:                                   |
@ |                                                                      |
.EQU  spi_interface , SPI1         @ имя используемого SPI               |
@ |  Для SPI1 используются пины: PA5  - sck,  PA7  - mosi                |
@ |  Для SPI2 используются пины: PB13 - sck,  PB15 - mosi                |
@ |                                                                      |
.equ SPI1_relocation, Да   @ переопределение пинов SPI1 на GPIO B:       |
@ |                               (PB3 - SCK,  PB5 - MOSI)               |
@ | ВНИМАНИЕ ! При переопределении пинов SPI1 на GPIOB отключается JTAG  |
@ |                                                                      |
@ +----------------------------------------------------------------------+
@ | вызов SPI_TX_INIT параметров не требует, изменяет регистры R0-R4     |
@ +----------------------------------------------------------------------+
@ | видео про данный модуль https://youtu.be/x8-N30mxf5Q                 |
@ | ArmAsmEditor: STM32 на Ассемблере: Настройка аппаратного SPI для     | 
@ | отправки данных. Видео 16                                            |
@ +----------------------------------------------------------------------+

@.ENDDESC

@.ITEM SPI_LIST
.EQU  SPI1               , PERIPH_BASE + SPI1_BASE  @ SPI 1 (PA5  - SCK,  PA7  - MOSI)
.EQU  SPI2               , PERIPH_BASE + SPI2_BASE  @ SPI 2 (PB13 - SCK,  PB15 - MOSI)
@.end

@.CONFIG spi_interface=SPI_LIST

@.item spi1_reloc_q
.EQU  Да            , 1     @ SPI 1 (PB3 - SCK,  PB5 - MOSI)
.EQU  Нет           , 0     @ SPI 1 (PA5 - SCK,  PA7 - MOSI)
@.end

@.CONFIG SPI1_relocation=spi1_reloc_q

.if SPI1_relocation==Нет
   .EQU  crx_sck_pin   , 5
   .EQU  crx_mosi_pin  , 7
   .EQU  gpiox         , GPIOA
   .EQU  gpio_crx      , GPIO_CRL
.ELSE
   .EQU  crx_sck_pin   , 3
   .EQU  crx_mosi_pin  , 5
   .EQU  gpiox         , GPIOB
   .EQU  gpio_crx      , GPIO_CRL
.ENDIF

.if spi_interface==SPI2
   .EQU  crx_sck_pin   , 13 - 8
   .EQU  crx_mosi_pin  , 15 - 8
   .EQU  gpiox         , GPIOB
   .EQU  gpio_crx      , GPIO_CRH
.ENDIF



.SECTION .asmcode

.GLOBAL   SPI_TX_INIT
SPI_TX_INIT:        @ первоначальная настройка
                    MOV        R1, 1

                    LDR        R2, = PERIPH_BASE + PERIPH_BB_BASE + ( RCC_BASE + RCC_APB2ENR ) * 32

.if spi_interface==SPI1
        .if SPI1_relocation==Нет    @ SPI 1 без переназначения пинов
                    STR        R1, [ R2, RCC_APB2ENR_IOPAEN_N * 4 ]      @ включим gpio A
        .else
                   @ SPI 1 с переназначения пинов (на GPIO B)
                    STR        R1, [ R2, RCC_APB2ENR_IOPBEN_N * 4 ]      @ включим gpio B
                    STR        R1, [ R2, RCC_APB2ENR_AFIOEN_N * 4 ]      @ включим AFIO для ремапинга SPI1
        .endif
                    STR        R1, [ R2, RCC_APB2ENR_SPI1EN_N * 4 ]      @ включим SPI1
.else
                    @ настройки для SPI 2
                    STR        R1, [ R2, RCC_APB2ENR_IOPBEN_N * 4 ]      @ включим gpio B
                    LDR        R2, = PERIPH_BASE + PERIPH_BB_BASE + ( RCC_BASE + RCC_APB1ENR ) * 32
                    STR        R1, [ R2, RCC_APB1ENR_SPI2EN_N * 4 ]      @ включим SPI2
.endif

                    @ настройка режима работы пинов GPIO на SPI
                    LDR        R2, = gpiox
                    LDR        R4, [ R2, gpio_crx  ]    @ прочитаем состояние регистра GPIO_CRx
                    MOV        R3, GPIO_CNF_OUT_AFPP << 2 + GPIO_MODE_OUT50
                    BFI        R4, R3, crx_sck_pin * 4, 4
                    BFI        R4, R3, crx_mosi_pin * 4, 4
                    STR        R4, [ R2, gpio_crx  ]    @ сохраним измененное значение GPIO_CRx

.if (SPI1_relocation==Да) & (spi_interface==SPI1)   @ при релокации пинов SPI 1
                    LDR        R2, = AFIO
                    LDR        R3, [ R2, AFIO_MAPR ]

                    MOV        R4, AFIO_MAPR_SWJ_SWD_EN        @ отключим JTAG оставив SWD
                    BFI        R3, R4, AFIO_MAPR_SWJ_CFG_N, 3

                    ORR        R3, R3, AFIO_MAPR_SPI1_REMAP    @ включим ремапинг пинов SPI1
                    STR        R3, [ R2, AFIO_MAPR ]
.endif
                    @ настройка SPI
                    LDR        R2, = spi_interface

     @ настройки интерфейса SPI
.EQU  spi_dir        , SPI_CR1_BIDIOE                       @ Output enabled (transmit-only mode)
.EQU  spi_mode_master, SPI_CR1_MSTR | SPI_CR1_SSI           @ SPI_Mode_Master &  SSI: Internal slave select
.EQU  spi_nss        , SPI_CR1_SSM  | SPI_CR1_SPE           @ SPI_NSS_Soft    & SPI_Enable
.EQU  spi_br_presc   , SPI_CR1_BR_DIV2                      @ делитель частоты для SPI

                    LDR        R3, = ( spi_dir | spi_mode_master | spi_nss | spi_br_presc )
                    STR        R3, [ R2, SPI_CR1 ]

                    BX         LR

@.DESC     name=SPI_TX_SEND type=proc
@ +-----------------------------------------------------------------------+
@ |                      Процедура отправки байта по SPI                  |
@ +-----------------------------------------------------------------------+
@ | Передаваемые данные должны быть переданы в R4                         |
@ | при отправке происходит ожидание конца передачи (флаги TXE, BSY)      |
@ | Процедура не изменяет значения регистров                              |
@ +-----------------------------------------------------------------------+
@.ENDDESC

.GLOBAL   SPI_TX_SEND
SPI_TX_SEND:      @ Отправка байта по spi
                    PUSH       {  R1 }

                    LDR        R1, = spi_interface

                    STR        R4, [ R1, SPI_DR ]   @ отправим байт на SPI

                    POP        {  R1 }

@.DESC     name=SPI_TXE_BSY_WAIT type=proc
@ +-----------------------------------------------------------------------+
@ |             Процедура ожидания завершения передачи по SPI             |
@ +-----------------------------------------------------------------------+
@ | Параметров нет                                                        |
@ | Процедура не изменяет значения регистров                              |
@ +-----------------------------------------------------------------------+
@.ENDDESC

.GLOBAL   SPI_TXE_BSY_WAIT
SPI_TXE_BSY_WAIT:   PUSH       { R0, R1 }

                    LDR        R1, = spi_interface

SPI_TXE_WAIT:       @ проверим флаг занятости TXE
                    LDR        R0, [ R1, SPI_SR ]
                    TST        R0, SPI_SR_TXE
                    BEQ        SPI_TXE_WAIT

SPI_BSY_WAIT:       @ проверим флаг занятости BSY
                    LDR        R0, [ R1, SPI_SR ]
                    TST        R0, SPI_SR_BSY
                    BNE        SPI_BSY_WAIT

                    POP        { R0, R1 }

                    BX         LR




