@.CHARSET CP1251

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

.section .asmcode

@ +----------------------------------------------------------------------------------------------+
@ |                                                                                              |
@ |                          Модуль чтения\записи данных  в\из flash                             |
@ |                                                                                              |
@ +----------------------------------------------------------------------------------------------+
@ | Номер сектора для хранения данных:                                                           |
.equ DATA_SECTOR, 4      @ номер сектора в котором хранятся данные для операции записи\чтения    |
@                                                                                                |
@ Адрес буфера для операции чтения записи, буфер для чтения должен располагаться в ОЗУ           |
.equ BUF_OPER, SRAM_BUF  @ разместите SRAM_BUF в ОЗУ (.section .bss) объявив  буфер размером     |
@ |                        BUF_SIZE байт, например, используя директиву .space                   |
@ | Например, в каком то из файлов вашего проекта:                                               |
@ |                                                                                              |
@ | .section .bss                                                                                |
@ | .global SRAM_BUF                                                                             |
@ | SRAM_BUF:  .space 32  @ данные сохраняемые во flash памяти                                   |
@ |                                                                                              |
@ | либо вместо SRAM_BUF укажите метку размещенного вами буфера в ОЗУ                            |
@ |                                                                                              |
@ Размер буфера для чтения \ записи (фиксировано), кратно 4 байтам !!!                           |
.equ BUF_SIZE, 32                                                                              @ |
@                                                                                                |
@ | Сектор для хранения заполняется последовательно с каждой записью, при чтении читается        |
@ | последняя запись. При полном заполнении сектора, он стирается и данные записываются в его    |
@ | начало при попытке чтения пустого сектора - чтения не происходит                             |
@ |                                                                                              |
@ +----------------------------------------------------------------------------------------------+

@.desc name=STORAGE_WRITE_BASE_CONFIG type=proc
@ +--------------------------------------------------------+
@ |                      Запись во FLASH                   |
@ +--------------------------------------------------------+
@.enddesc

.global STORAGE_WRITE_BASE_CONFIG
STORAGE_WRITE_BASE_CONFIG:
                    PUSH       { R0, R1, R2, R3, LR }

                    MOV        R0, DATA_SECTOR          @ номер сектора для записи !

                    BL         SearchFreeSpace

                    CMP        R0, R1          @ проверка выхода за границу сектора
                    ITTET       EQ
                    MOVEQ      R0, R2          @ если вышли - то ставим адрес начала = адресу начала сектора

                    MOVEQ      R3, DATA_SECTOR           @ номер сектора для стирания

                    ADDNE      R0, R0, 1        @ если мы не вышли за границу сектора, то увеличим адрес записи на 1
                                                @ потому что он указывает на последний ЗАПИСАННЫЙ байт, а не на свободный
                    BLEQ       ERASE_SECTOR    @ сотрем сектор, по идее команда должна быть третьей, но BL может быть только
                                               @ последней в IT блоке, поэтому такой порядок :-)

                 @ разрешим запись во флеш
                    BL         WRITE_SECTOR_START

                 @ копирование данных
                    LDR        R1, = BUF_OPER
                    MOV        R2, BUF_SIZE

STORAGE_WRITE_BASE_CONFIG_loop:
                    LDR       R3, [ R1 ], 4
                    STR       R3, [ R0 ], 4

                    SUBS       R2, R2, 4
                    BNE        STORAGE_WRITE_BASE_CONFIG_loop

                 @ заблокируем запись во flash
                    BL         WRITE_LOCK

                    POP        { R0, R1, R2, R3, PC }


@.desc name=STORAGE_READ_BASE_CONFIG type=proc
@ +--------------------------------------------------------+
@ |             Чтение настроек базы из FLASH              |
@ +--------------------------------------------------------+
@.enddesc

.global STORAGE_READ_BASE_CONFIG
STORAGE_READ_BASE_CONFIG:
                    PUSH       { LR }

                    MOV        R0, DATA_SECTOR    @ конфигурация базы в секторе
                    BL         SearchFreeSpace

                    CMP        R2, R0    @ проверим что есть записанная конфигурация
                    BEQ        STORAGE_READ_BASE_CONFIG_exit

                    sub r0, r0, BUF_SIZE-1
                    ldr r1, =BUF_OPER
                    mov r2, BUF_SIZE

STORAGE_READ_BASE_CONFIG_loop:
                    ldrb r3, [r0], 1
                    strb r3, [r1], 1
                    subs r2, r2, 1
                    bne STORAGE_READ_BASE_CONFIG_loop

STORAGE_READ_BASE_CONFIG_exit:
                    POP        { PC }


@.desc name=SearchFreeSpace type=proc
@ +----------------------------------------------------------+
@ |            поиск свободного места в хранилище            |
@ +----------------------------------------------------------+
@ | на входе:  R0 - номер сектора                            |
@ |                                                          |
@ | на выходе: R0 - первый свободный адрес                   |
@ |            R1 - адрес последнего байта сектора           |
@ |            R2 - адрес первого байта сектора              |
@ +----------------------------------------------------------+
@.enddesc

SearchFreeSpace:
                    PUSH       { R3, R4 }
                    LDR        R1, = FLASH_SECTOR_ADR
                    MOV        R2, 8
                    MUL        R2, R2, R0
                    LDR        R0, [ R1, R2 ]    @ адрес начала сектора
                    ADD        R2, R2, 4
                    LDR        R1, [ R1, R2 ]    @ адрес конца сектора
                    ADD        R1, R1, 32
                    MOV        R2, R0            @ сохраним адрес начала сектора
                    MOV        R4, R1
SearchLoop:
                    LDRB       R3, [ R4 ]
                    CMP        R3, 0xFF
                    BNE        NullFound

                    SUB        R4, R4, 1         @ уменьшим адрес поиска

                    CMP        R4, R0            @ проверим достижение начала сектора
                    BNE        SearchLoop
                    B          SearchFreeSpace_Exit

NullFound:         @ найдено свободное место
                    mov        R0, R4
SearchFreeSpace_Exit:
                    POP        { R3, R4 }
                    BX         LR


