@GNU AS
@.CHARSET CP1251

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

.include  "/src/inc/flash.inc"

.section .rodata

@.desc name=FLASH_SECTOR_ADR type=proc
@ +--------------------------------------------------------------------------+
@ |             Адреса начала и конца секторов STM32F401                     |
@ |                                                                          |
.global FLASH_SECTOR_ADR                                                @    |
FLASH_SECTOR_ADR:                                                       @    |
@      начало сектора    конец сектора   номер сектора   размер     объем    |
.WORD    0x08000000,      0x08003FFF      @ Sector 0      16 кб     16 кб    |
.WORD    0x08004000,      0x08007FFF      @ Sector 1      16 кб     32 кб    |
.WORD    0x08008000,      0x0800BFFF      @ Sector 2      16 кб     48 кб    |
.WORD    0x0800C000,      0x0800FFFF      @ Sector 3      16 кб     64 кб    |
.WORD    0x08010000,      0x0801FFFF      @ Sector 4      64 кб    128 кб    |
.WORD    0x08020000,      0x0803FFFF      @ Sector 5     128 кб    256 кб    |
.WORD    0x08040000,      0x0805FFFF      @ Sector 6     128 кб    384 кб    |
.WORD    0x08060000,      0x0807FFFF      @ Sector 7     128 кб    512 кб    |
@ |                                                                          |
@ +--------------------------------------------------------------------------+
@.ENDDESC

.section .asmcode

@.desc name=WRITE_SECTOR_START type=proc
@ +----------------------------------------------------------------------+
@ |                      ПЕРЕХОД В РЕЖИМ ЗАПИСИ                          |
@ +----------------------------------------------------------------------+
@ | Запись во FLASH производить блоками по 32 бита (инструкцией STR) при |
@ | питании 2.7-3.3v.                                                    |
@ | После записи нужно заблокировать запись flash вызовом WRITE_LOCK     |
@ +----------------------------------------------------------------------+
@.enddesc

.global WRITE_SECTOR_START
WRITE_SECTOR_START:
                    PUSH       { R0, R1, R2, LR }

                    BL         FLASH_UNLOCK

                    BL         wait_for_erase

                    LDR        R1, [ R0, FLASH_CR]
                    LDR        R2, = FLASH_CR_PG + FLASH_CR_PSIZE_32
                    ORR        R1, R1, R2
                    STR        R1, [ R0, FLASH_CR ]

                    POP        { R0, R1, R2, LR }

                    BX         LR

@.desc name=WRITE_LOCK type=proc
@ +----------------------------------------------------------------------+
@ |                      БЛОКИРОВКА ЗАПИСИ В FLASH                       |
@ +----------------------------------------------------------------------+
@.enddesc

.global WRITE_LOCK
WRITE_LOCK:
                    PUSH       { R0, R1 }
                    LDR        R0, = PERIPH_BASE + FLASH_R_BASE

                @ установим защиту записи\стирания
                    MOV        R1, FLASH_CR_LOCK
                    STR        R1, [ R0, FLASH_CR ]

                    DSB           @ синхронизация кеша

                    POP        { R0, R1 }
                    BX         LR


@.desc name=FLASH_UNLOCK type=proc
@ +----------------------------------------------------------------------+
@ |                        Разблокировка записи                          |
@ +----------------------------------------------------------------------+
@.enddesc

FLASH_UNLOCK:
                    LDR        R0, = PERIPH_BASE + FLASH_R_BASE

                 @ снимаем защиту записи
                    LDR        R1, =FLASH_KEYR_FKEYR_K1
                    STR        R1, [ R0, FLASH_KEYR ]

                    LDR        R1, =FLASH_KEYR_FKEYR_K2
                    STR        R1, [ R0, FLASH_KEYR ]

                    BX         LR


@.desc name=wait_for_erase  type=proc
@ +----------------------------------------------------------------------+
@ |                        Ожидание исполнения                           |
@ +----------------------------------------------------------------------+
@.enddesc

                @ ожидаем выполнение операции стирания
wait_for_erase:
                    LDR        R1, [ R0, FLASH_SR ]
                    TST        R1, FLASH_SR_BSY
                    BNE        wait_for_erase

                    BX         LR

@.desc name=ERASE_SECTOR type=proc
@ +----------------------------------------------------------------------+
@ |                        Стирание сектора Flash                        |
@ +----------------------------------------------------------------------+
@ | вход : R3 - номер сектора для стирания                               |
@ | выход : R3 - статус (0 - нет ошибок)                                 |
@ +----------------------------------------------------------------------+
@.enddesc

.GLOBAL   ERASE_SECTOR
ERASE_SECTOR:
                    PUSH       { R0, R1, R2, LR }

                    BL         FLASH_UNLOCK      @ cнимем блокировку записи

                    BL         wait_for_erase    @ ожидаем снятие защиты стирания


        @ большой вопрос нужно ли устанавливать латентность перед записью, ведь это делаем в настройке тактирования

                @ Установим латентность FLASH памяти в зависимости от напряжения питания и частоты ядра
                @ Table 6. Number of wait states according to CPU clock (HCLK) frequency
                @ RM0368 стр. 46
                    LDR        R1, [ R0, FLASH_ACR ]
                    MOV        R2, FLASH_ACR_LATENCY_3
                    BFI        R1, R2, 0, 4
                    STR        R1, [ R0, FLASH_ACR ]
        @ ----------------------------------------------------------------------------------------------------------

                @ очистим регистр статуса
                    LDR        R1, =0x1F3
                    STRH       R1, [ R0, FLASH_SR ]

                @ установим режим стирания сектора, размер записи, номер сектора, старт стирания
                    LDR        R1, [ R0, FLASH_CR ]
                    ldr        r2, =FLASH_CR_SER + FLASH_CR_STRT+FLASH_CR_PSIZE_2
                    ORR        R1, R1, R2
                    BFI        R1, R3, FLASH_CR_SNB_N, 4    @ установим номер сектора
                    STR        R1, [ R0, FLASH_CR ]

                    BL         wait_for_erase    @ ожидаем выполнение операции стирания

                    BL         WRITE_LOCK        @ установка блокировки записи

                    POP        { R0, R1, R2, LR }
                    BX         LR


