@.CHARSET  CP1251

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

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

@.DESC     name=W25Q_INIT type=proc
@ +----------------------------------------------------------------------+
@ |                 SPI                 |
@ +----------------------------------------------------------------------+
@ |    SPI      GPIO |
@ |    :                                   |
@ |                                                                      |
.EQU  spi_interface , SPI1       @   SPI               |
@ |                                                                      |
@ |  GPIO    SPI    - |
@ |                                                             |
@ +----------------------------------------------------------------------+
@ |  SPI_TX_INIT   ,   R0-R4     |
@ +----------------------------------------------------------------------+
@.ENDDESC

@.ITEM     SPI_LIST
.EQU  SPI1          , PERIPH_BASE + SPI1_BASE    @ SPI 1
.EQU  SPI2          , PERIPH_BASE + SPI2_BASE    @ SPI 2
.EQU  SPI3          , PERIPH_BASE + SPI3_BASE    @ SPI 3
.EQU  SPI4          , PERIPH_BASE + SPI4_BASE    @ SPI 4
@.END

@.CONFIG   spi_interface=SPI_LIST



.SECTION       .bss
W25Q_Rx_BUF:        .SPACE          256    @       
W25Q_ID:            .WORD           0

.SECTION       .asmcode

.GLOBAL        W25Q_INIT
W25Q_INIT:          @  
                    @  SPI1
                    LDR             R2, = PERIPH_BB_BASE + ( RCC_BASE + RCC_APB2ENR ) * 32
                    MOV             R1, 1
                    STR             R1, [ R2, RCC_APB2ENR_SPI1EN_N * 4 ]

                    @  SPI
                    LDR             R2, = spi_interface

     @   SPI
.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_DIV_2    @    SPI

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

                    BX              LR


@-----------------------------------------------------------------------------------------
.MACRO         m_BSY_WAIT
.\@:
                    LDR             R0, [ R1, SPI_SR ]
                    TST             R0, SPI_SR_BSY
                    BNE              .\@
.ENDM
@-----------------------------------------------------------------------------------------
.MACRO         m_TXE_WAIT
.\@:
                    LDR             R0, [ R1, SPI_SR ]
                    TST             R0, SPI_SR_TXE
                    BEQ              .\@
.ENDM
@-----------------------------------------------------------------------------------------
.MACRO         m_RXNE_WAIT
.\@:
                    LDR             R0, [ R1, SPI_SR ]
                    TST             R0, SPI_SR_RXNE
                    BEQ              .\@
.ENDM
@-----------------------------------------------------------------------------------------


@.DESC     name=W25Q_READ_ID type=proc
@ +-----------------------------------------------------------------------+
@ |                 Read JEDEC ID (9Fh)                    |
@ +-----------------------------------------------------------------------+
@ |   0x9F    3     ID          |
@ | Manufacturer ID (  0xEF  Winbond)                        |
@ | 0x40    (  )                                         |
@ |     . 0x16  32Mb, 0x17  64Mb         |
@ +-----------------------------------------------------------------------+
@.ENDDESC

.GLOBAL        W25Q_READ_ID
W25Q_READ_ID:       PUSH            { LR }
                    LDR             R1, = spi_interface    @  SPI
                    LDR             R2, = W25Q_ID    @    ID   
                    MOVS            R3, 4    @   
                    MOVS            R4, 0X9F    @   ID
                    STR             R10, [ R12, 4 * 4 ]    @ PA4 CS LOW ------------------------------

READ_DATA_LOOP1:    STR             R4, [ R1, SPI_DR ]    @    ID 0x9F

                    m_RXNE_WAIT        @    RXNE

                    LDRB            R0, [ R1, SPI_DR ]    @    SPI 
                    STRB            R0, [ R2 ], #1    @     

                    SUBS            R3, R3, 1    @   
                    BNE             READ_DATA_LOOP1    @     6,   

                    STR             R11, [ R12, 4 * 4 ]    @ PA4 CS HIGH  ------------------------------
                    POP             { PC }


@.DESC     name=W25Q_READ_DATA type=proc
@ +-----------------------------------------------------------------------+
@ |                 Read Data (03h)                  |
@ +-----------------------------------------------------------------------+
@ |     Read Data 0x03                          |
@ |   3                             |
@ |                             |
@ +-----------------------------------------------------------------------+
@ |                                            |
@ |  R0                                         |
@ |  R3                                        |
@ +-----------------------------------------------------------------------+
@.ENDDESC

.GLOBAL        W25Q_READ_DATA

W25Q_READ_DATA:     PUSH            { LR }
                    LDR             R1, = spi_interface    @  SPI
                    LDR             R2, = W25Q_Rx_BUF    @       
                    LDR             R4, = 0x03    @  ,    W25Q_SEND_CMD_ADR
                    STR             R10, [ R12, 4 * 4 ]    @ @ PA4 CS LOW ------------------------------

                    BL              W25Q_SEND_CMD_ADR    @     
                    m_BSY_WAIT         @   SPI
                    LDR             R4, [ R1, SPI_DR ]    @   RXNE

READ_DATA_LOOP2:    STRB            R0, [ R1, SPI_DR ]    @      

                    m_RXNE_WAIT        @    RXNE

                    LDRB            R0, [ R1, SPI_DR ]    @    SPI 
                    STRB            R0, [ R2 ], #1    @     

                    SUBS            R3, R3, 1    @   
                    BNE             READ_DATA_LOOP2    @    ,   

                    STR             R11, [ R12, 4 * 4 ]    @ @ PA4 CS HIGH  ------------------------------
                    POP             { PC }


@.DESC     name=W25Q_PAGE_PROG type=proc
@ +-----------------------------------------------------------------------+
@ |                Page Program (02h)                      |
@ +-----------------------------------------------------------------------+
@ |     Page Program 0x02                       |
@ |   3                             |
@ |                              |
@ +-----------------------------------------------------------------------+
@ |                                            |
@ |  R5                                         |
@ |  R3                                        |
@ +-----------------------------------------------------------------------+
@.ENDDESC

.GLOBAL        W25Q_PAGE_PROG

W25Q_PAGE_PROG:     PUSH            { LR }
                    LDR             R1, = spi_interface    @  SPI
                    LDR             R2, = W25Q_Rx_BUF    @       
                    LDR             R4, = 0x02    @  ,    W25Q_SEND_CMD_ADR

                    BL              W25Q_WRITE_ENABLE    @  

                    STR             R10, [ R12, 4 * 4 ]    @ @ PA4 CS LOW ------------------------------

                    BL              W25Q_SEND_CMD_ADR    @     

WRITE_DATA_LOOP:    m_TXE_WAIT         @    TXE
                    STRB            R6, [ R1, SPI_DR ]    @     


                    SUBS            R3, R3, 1    @   
                    BNE             WRITE_DATA_LOOP    @    ,   
                    m_BSY_WAIT

                    STR             R11, [ R12, 4 * 4 ]    @ @ PA4 CS HIGH  ------------------------------
                    BL              W25Q_BSY_WAIT    @     
                    POP             { PC }

@-----------------------------------------------------------------------------------------
W25Q_WRITE_ENABLE:  PUSH            { LR }
                    STR             R10, [ R12, 4 * 4 ]    @ @ PA4 CS LOW ------------------------------
                    MOV             R0, 0x06    @   Write Enable (06h)
                    STRB            R0, [ R1, SPI_DR ]    @   
                    m_TXE_WAIT
                    m_BSY_WAIT
                    STR             R11, [ R12, 4 * 4 ]    @ @ PA4 CS HIGH  ------------------------------
                    BL              W25Q_WEL_WAIT    @      WEL
                    POP             { PC }
@-----------------------------------------------------------------------------------------


@-----------------------------------------------------------------------------------------
W25Q_WEL_WAIT:      @    Write Enable Latch (WEL)   
                    PUSH            { LR }
                    STR             R10, [ R12, 4 * 4 ]    @ @ PA4 CS LOW ------------------------------
                    MOV             R0, 0x05    @   Read Status Register-1 (05h)
                    STRB            R0, [ R1, SPI_DR ]    @   
                    m_TXE_WAIT

read_status_loop:   STRB            R0, [ R1, SPI_DR ]
                    m_RXNE_WAIT        @    RXNE
                    LDRB            R0, [ R1, SPI_DR ]    @    SPI 
                    TST             R0, 2    @ 2    WEL   
                    BEQ             read_status_loop

                    m_TXE_WAIT
                    m_BSY_WAIT
                    STR             R11, [ R12, 4 * 4 ]    @ @ PA4 CS HIGH  ------------------------------
                    POP             { PC }
@-----------------------------------------------------------------------------------------

@-----------------------------------------------------------------------------------------
W25Q_BSY_WAIT:      @    Erase/Write In Progress (BUSY)   
                    PUSH            { LR }
                    STR             R10, [ R12, 4 * 4 ]    @ @ PA4 CS LOW ------------------------------
                    LDR             R0, [ R1, SPI_DR ]    @   RXNE
                    MOV             R0, 0x05    @   Read Status Register-1 (05h)
                    STRB            R0, [ R1, SPI_DR ]    @   
                    m_RXNE_WAIT        @    RXNE
                    LDR             R0, [ R1, SPI_DR ]    @   RXNE

read_status_loop2:  STRB            R0, [ R1, SPI_DR ]
                    m_RXNE_WAIT        @    RXNE
                    LDRB            R0, [ R1, SPI_DR ]    @    SPI 
                    TST             R0, 1    @ 1    BUSY   
                    BNE             read_status_loop2

                    m_TXE_WAIT
                    m_BSY_WAIT
                    STR             R11, [ R12, 4 * 4 ]    @ @ PA4 CS HIGH  ------------------------------
                    POP             { PC }
@-----------------------------------------------------------------------------------------


@.DESC     name=W25Q_SEND_CMD_ADR type=proc
@ +-----------------------------------------------------------------------+
@ |                                        |
@ +-----------------------------------------------------------------------+
@ |     R4                                     |
@ |                           |
@ |       R5 ,         |
@ +-----------------------------------------------------------------------+
@.ENDDESC

W25Q_SEND_CMD_ADR:  PUSH            { LR }

                    REV             R5, R5    @  
                    ORR             R5, R5, R4    @        R4
                    MOVS            R4, 4    @   

SPI_TX_loop:        m_TXE_WAIT         @    TXE
                    STRB            R5, [ R1, SPI_DR ]    @   
                    LSR             R5, R5, 8
                    SUBS            R4, R4, 1    @   
                    BNE             SPI_TX_loop    @     4,   

                    POP             { PC }
@-----------------------------------------------------------------------------------------
@-----------------------------------------------------------------------------------------

@-----------------------------------------------------------------------------------------
@
@SPI_BSY_WAIT:       @    BSY
@                    LDR             R0, [ R1, SPI_SR ]
@                    TST             R0, SPI_SR_BSY
@                    BNE             SPI_BSY_WAIT
@                    BX              LR
@@-----------------------------------------------------------------------------------------
@
@SPI_TXE_WAIT:       @    TXE
@                    LDR             R0, [ R1, SPI_SR ]
@                    TST             R0, SPI_SR_TXE
@                    BEQ             SPI_TXE_WAIT
@                    BX              LR
@@-----------------------------------------------------------------------------------------
@
@SPI_RXNE_WAIT:      @    RXNE
@                    LDR             R0, [ R1, SPI_SR ]
@                    TST             R0, SPI_SR_RXNE
@                    BEQ             SPI_RXNE_WAIT    @   
@                    BX              LR
@-----------------------------------------------------------------------------------------


