Назад в библиотеку  

Работа с оперативной памятью

  • Описание: Описание принципа взаимодействия с памятью в контроллерах avr

    Источник: https://www.radiokot.ru/start/mcu_fpga/avr/14/

  • Итак, наши знания контроллеров расширяются, наши потребности возрастают, и шестнадцати отведенных нам судьбой регистров общего назначения становится уже недостаточно. Недостаточно??? Ну тогда вот вам еще: 128 байт оперативки.

    Слышу нервные смешки в аудитории… Опять кто-то вспомнил свой 3-х гиговый Пентиум? Понимаю, случается. Но я уже где-то говорил: контроллер не стоит сравнивать с современными компьютерами ни по каким параметрам. У контроллера несколько иная сфера деятельности, и имеющихся у него параметров вполне достаточно для выполнения большинства задач в этой сфере.

    Итак, мы имеем 128 байт оперативной памяти (ОЗУ). Смотрим рисунок из даташита:


    Рисунок 1 – Вся оперативная память, имеющаяся в контроллере. Она занимает диапазон значений $00…$DF , то есть – 224 байта.

    Младшие 96 байт отведены для РОН (32 байта) и регистров ввода вывода (64 байта). К регистрам ввода-вывода относятся регистры конфигурации таймеров, портов, прочего железа, статус-регистр SREG , контрольный регистр MCUCR и прочие. Короче, все, которые мы можем записать командой out или прочитать командой in . Вот они, полюбуйтесь:


    Диапазон $60…$ DF занимает «оперативка» - ячейки памяти, с которыми мы можем делать все, что душе угодно.

    А что может быть угодно душе:

        sts - Store Direct to SRAM - прямая запись в ОЗУ.
        ds - Load Direct from SRAM - прямая загрузка из памяти
    
        Пример:
        sts 0x62, Temp           ;ячейка памяти задана адресом
        sts MemoryCell,Temp      ;ячейка памяти задана именем
        lds Temp1, 0x71
        lds Temp1, MemoryCell_2
        

    Пока что пусть этого душе будет достаточно.

    Итак, самый простой способ – это взять бумажку, выписать на нее все переменные, которые хотим хранить в памяти, и присвоить им адреса из диапазона $60..$ DF .

    Еще один момент: если мы юзаем стек, то лучше ничего не писать в старшие несколько байт оперативки, потому что именно старшая область ОЗУ отведена для стека.

    Однако, бумажка имеет свойство теряться. Кроме того – это лишняя головная боль: назначать адреса ячейкам памяти. Да и работать с программой, в которой все переменные обозваны шестнадцатеричными числами, довольно затруднительно.

    Выход есть! Мы можем взвалить эту неблагодарную работу на плечи компилятора! Ура товарищи, радостно выдохнули и читаем дальше.

    Оказывается, компилятор сам в состоянии решить подобные проблемы. Нам даже не придется заморачиваться с адресами – он сам раскидает переменные по адресам, как ему покажется удобно. Все что нам нужно – это прописать имена переменных и указать, сколько ячеек памяти необходимо выделить каждой переменной. Мы уже называли страшные слова CSEG и DSEG .

    CSEG – это программный сегмент – в нем пишется непосредственно, программулина. DSEG – это сегмент данных. В нем выделяется оперативная память. Сегмент данных прописывается в тексте раньше программного сегмента.

        .include "d:avravrasmappnotes2313def.inc"
    
    
                .def    Temp1=R16
                .def    Temp2=R17
                .def    Temp3=R18
                .def    Temp4=R19
                .def    Temp=R20
    
        .dseg
    
        Digit:   .byte 4
        Input:    .byte 2
        Status:   .byte 1
        

    Таким образом, мы только что выделили 7 ячеек памяти:

    4 ячейки под переменную Digit ,

    2 ячейки под переменную Input ,

    1 ячейку под переменную Status.

    1-байтные переменные пишутся непосредственно командой sts и читаются командой lds .

    Если переменная состоит из нескольких ячеек, то при операции следует указывать относительный адрес той, к которой мы обращаемся. При этом, имя переменной всегда указывает на нулевую ячейку.


    Для того чтобы переместиться на n -ю ячейку, нужно обратиться к адресу, на n большему нулевой ячейки.

    Обращение происходит так:

        lds Temp, Digit   ;загружаем в Temp
                          ;0-ю ячейку переменной Digit
    
        lds Temp1,Digit+1 ;в Temp1 - 1-ю ячейку Digit
        lds Temp2,Digit+2 ;в Temp2 - 2-ю ячейку
        lds Temp3,Digit+3 ;в Temp3 - 3-ю ячейку
        

    Вот так все хитро и запущено в этом несовершенном мире. Дальше будет еще хуже.