Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Voprosy_po_Arkht_EVM_i_Yazyk_assemblera.docx
Скачиваний:
61
Добавлен:
01.04.2022
Размер:
5.16 Mб
Скачать

Назначения регистра sp. И принцип работы с ним.

Стек, или указатель стека – это специальный регистр, который предназначен для организации стековой памяти.

Можно сказать, что стек (точнее стековая память, стек состоит из двух частей: указатель стека и стековая память) – это туннель с тупиком в конце, состоящий из ячеек памяти. По мере заполнения ячеек памяти первые данные уходят в глубь стека, и добраться до них можно, только вытащив сначала последние введенные данные. Допустим, если мы запишем в стек последовательно три числа: 10,20 и 30, то для того, чтобы затем извлечь из стековой памяти число 10, предварительно придется извлечь числа 30 и 20. Т.е., значение запиФ

Назначения регистра watchdog. И принцип работы с ним.

Watchdog Timer (WDT) – это сторожевой таймер (а если перевести дословно, "сторожевой пёс"), который представляет собой аппаратно-реализованную схему контроля над зависанием системы. Это таймер, который периодически сбрасывается контролируемой системой. Если вдруг сброса не произошло за определённый интервал времени после предыдущего сброса данного таймера, то происходит принудительная перезагрузка системы (в нашем случае микроконтроллера).

Например, мы ждём ответа от какой-нибудь шины в виде отслеживания состояния определённого бита регистра. И вдруг произойдёт кратковременное отсоединение провода этой шины. После этого скорей всего произойдёт зависание программы, так как в шине будет сбой, и даже если что-то после и придёт от присоединённого узла, то мы вряд ли уже это отследим изменением состояния бита. Желательно, чтобы после какого-то таймаута система перезагрузилась. Тут-то и приходит нам на помощь WDT, который установлен на определённый интервал. Команду на перезагрузку сторожевого таймера мы расположим в нашем коде после того, как мы дождёмся отклика от шины. А если мы так его и не дождёмся, то мы не дойдём до команды перезагрузки WDT и через заветный интервал времени система будет перезагружена. После этого произойдёт заново инициализация шины и всё будет опять работать нормально.

Работа с Flash-памятью микроконтроллера.

http://s-engineer.ru/assemblernaya-zagotovka-dlya-avr-atmega8/ ТУТ ЛУЧШЕ ПРОЧИТАТЬ, ТАМ НЕМНОГО ВВЕДИ FLASH в поиск

Директива «.cseg» обозначает начало программного сегмента, все что ниже, относиться к коду (или константам, об этом позже). Программатор разместит данный сегмент в FLASH памяти микроконтроллера, а по какому адресу? За это, отвечает следующая директива «.org» с параметром «0x00». В данном случае, её использовать не обязательно, т.к. начала программного кода всегда записывается с адреса 0x00.

.cseg ;данная директива означает, что дальше идет код программы

.org 0x00;данная директива означает, что код программы будет располагаться с 0 ого адреса в FLASH

;ВЕКТОР ПРЕРЫВАНИЙ

rjmp initial ;прерывание от RESET, ссылаемся на обработчик прерывания - initial

rjmp 0 ;rjmp service_INT0 ;внешнее прерывание 0

rjmp 0 ;rjmp service_INT1 ;внешнее прерывание 1

rjmp 0 ;rjmp service_OC2 ;совпадение TCNT2 и OCR2

rjmp 0 ;rjmp service_OVF2 ;переполнение TCNT2

rjmp 0 ;rjmp service_ICP1 ;захват в ICP1

rjmp 0 ;rjmp service_OC1A ;совпадение TCNT1 и OCR1A

rjmp 0 ;rjmp service_OC1B ;совпадение TCNT1 и OCR1B

rjmp 0 ;rjmp service_OVF1 ;переполнение TCNT1

rjmp 0 ;rjmp service_OVF0 ;переполнение TCNT0

rjmp 0 ;rjmp service_SPI ;прерывание от модуля SPI

rjmp 0 ;rjmp service_URXC ;получение байта по USART

rjmp 0 ;rjmp service_UDRE ;опустошение UDR в USART

rjmp 0 ;rjmp service_UTXC ;передача байта по USART

rjmp 0 ;rjmp service_ADCC ;прерывание от АЦП

rjmp 0 ;rjmp service_ERDY ;завершение записи в EEPROM

rjmp 0 ;rjmp service_ACI ;прерывание от компаратора

rjmp 0 ;rjmp service_TWI ;прерывание от модуля TWI

rjmp 0 ;rjmp service_SPMR ;завершение выполнения spm

.org 0x20;данная директива означает, что код программы будет располагаться с слова 0x20 в FLASH или с адреса 0x40 (т.е. с 0x40 байта).

;В FLASH адресация осуществляется по словам, а не по байтам, одно слово равно двум байтам.

;УСТАНОВКА СТЕКА

initial: ldi R16,low(RAMEND) ;скопируем в R16 младщий байт из константы RAMEND, которая определена в m8def.inc и хранит размер SRAM

out SPL,R16 ;скопируем значение из R16 в SPL

ldi R17,high(RAMEND) ;скопируем в R16 старший байт из константы RAMEND, которая определена в m8def.inc

out SPH,R17 ;скопируем значение из R17 в SPH

Директива «.cseg» обозначает начало программного сегмента, все что ниже, относиться к коду (или константам, об этом позже). Программатор разместит данный сегмент в FLASH памяти микроконтроллера, а по какому адресу? За это, отвечает следующая директива «.org» с параметром «0x00». В данном случае, её использовать не обязательно, т.к. начала программного кода всегда записывается с адреса 0x00.

После вектора прерывания следует директива «.org 0x20», она здесь не обязательна, таким образом, я хотел показать, что программный сегмент можно помещать в разные области в памяти FLASH. Первая мысль, что 0x20 это адрес в байтах, но на самом деле в FLASH Atmega адресация происходит по словам (машинная инструкция), одно слово это 2 байта. Выходит, следующий фрагмент кода будет располагаться с 0x40 ого байта. Скомпилированный код, можно запустить в модели ATmega8 в программе Proteus, там же есть возможность посмотреть что находится в FLASH памяти контроллера. Зеленым я обозначил инструкции, которые представляют собой вектор прерывания, а голубым инструкции отвечающие за установка стека. Видно, что между инструкциями есть разрыв в виде 0xFF и инструкции по установки стека начинаются с адрес 0x40, как мы и установили.

Если закомментировать «.org 0x20» и скомпилировать код, инструкции в FLASH  буду расположены следующим образом.

Ниже, я разместил небольшую памятку по работе с FLASH и SRAM памятью на ассемблере. В main демонстрируется:

  • как считать данные из программной памяти FLASH в регистры;

  • как записывать данные из SRAM в регистры и наоборот, как считывать эти данные из SRAM в регистры.

В памятке опущены моменты как считывать данные из памяти EEPROM, т.к. это отдельное устройство с своими регистрами ввода/вывода. Также я пропустил запись данных в FLASH память самой программой, еще это называют самопрограммирование, данную возможность используют bootloader контроллера при прошивке. Перед записи в FLASH, необходимо выполнить ряд процедур по стиранию, по работе с буфером и т.д. Эти две темы требуют отдельных постов.

; ------------------- ПРОСТО ПОМЕЩАЕМ В РЕГИСТР КОНСТАНТУ ----------------------

ldi r16,'C' ;в регистре r16 будет хранится константа 'C'

; ---------------- КОНЕЦ ПРОСТО ПОМЕЩАЕМ В РЕГИСТР КОНСТАНТУ -------------------

ldi ZH,high(2*PAUSE2) ;второй вариант, значение константы PUASE2 лежит в FLASH (значение и адрес (0x50) мы задали ниже, т.е. данные туда помещаются при прошивке), на который указывает регистр Z

ldi ZL,low(2*PAUSE2) ;повторюсь, в FLASH адресация происходит не по байтно как в EERPROM и SRAM, а словами по 2-а байта, поэтому метка PAUSE находится

;на 0x50 слове, а т.к. ldi работает с адресами то поэтому умножаем на 2 -> "ldi ZH,high(2*PAUSE)"

lpm r17,Z;считываем значение из FLASH в регистр r17

; ----------- КОНЕЦ СЧИТЫВАЕМ ЗНАЧЕНИЕ КОНСТАНТЫ ИЗ FLASH ----------------

; ============== ЗАПИСЫВАЕМ ЗНАЧЕНИЕ ПЕРЕМЕННОЙ В SRAM ===================

ldi YH,high(PAUSE3) ;третий вариант, записываем значение константы PUASE3 лежит из SRAM (область мы выделили ниже размером 1 байт)

ldi YL,low(PAUSE3) ;на адрес где находится константа указывает регистр Y

ldi r18,'S' ;данные для SRAM можно взять откуда угодно, например из портов ввода, из FLASH/EEPROM/SRAM, в резульатате какого нибудь расчета

st Y,r18 ;примитивный способ, мы поместим константу 'S' в r18 и запишем её в SRAM

clr r18 ;очистим регистр, мы его использовали в качестве буфера

clr YH ;очистим регистр YH

clr YL ;очистим регистр YL

; =========== КОНЕЦ ЗАПИСЫВАЕМ ЗНАЧЕНИЕ ПЕРЕМЕННОЙ В SRAM ================

; ----------- СЧИТЫВАЕМ ЗНАЧЕНИЕ ПЕРЕМЕННОЙ ИЗ SRAM ----------------------

ldi YH,high(PAUSE3) ;третий вариант, значение переменной PUASE3 лежит в SRAM (область мы выделили ниже размером 1 байт, значения мы положили кодом выше)

ldi YL,low(PAUSE3) ;на адрес указывает регистр Y

ld r18,Y ;результат кладем в r18

; ----------- КОНЕЦ СЧИТЫВАЕМ ЗНАЧЕНИЕ ПЕРЕМЕННОЙ ИЗ SRAM ----------------

; ============ ПРИ ПРОШИВКЕ МК В FLASH БУДЕТ ПОМЕЩЕНА КОНСТАНТА PAUSE2 С ЗНАЧЕНИЕМ 'F' ===============

.cseg

org 0x50

PAUSE2: .dw 'F'

; =========== КОНЕЦ ПРИ ПРОШИВКЕ МК В FLASH БУДЕТ ПОМЕЩЕНА КОНСТАНТА PAUSE2 С ЗНАЧЕНИЕМ 0xA ==========

; СЕКТОР ДЛЯ SRAM

; ============ ПРИ ПРОШИВКЕ МК В SRAM БУДЕТ ЗАРЕЗЕРВИРОВАНО МЕСТО ПОД ПЕРЕМЕННУЮ PAUSE2 РАЗМЕРОМ 1 БАЙТ ===============

dseg ;данная директива означает, что дальше идет код секция SRAM

org 0x60

PAUSE3:

byte 1 ;резервирование байта в ОЗУ

; ============ КОНЕЦ ПРИ ПРОШИВКЕ МК В SRAM БУДЕТ ЗАРЕЗЕРВИРОВАНО МЕСТО ПОД ПЕРЕМЕННУЮ PAUSE2 РАЗМЕРОМ 1 БАЙТ ===============

резервирует в ОЗУ один байт, к которому можно обращаться по метки PAUSE3 с помощью соответствующих команд ассемблера.

 

Для секции кода «.cseg», т.е. для FLASH памяти, также возможно резервировать области памяти, но с помощью директив «.db» и «.dw».

  • «.db»  — Резервирует байт, параметр это значение, которое будет находится в данной области. Значение должно быть размером не более одного байта.

  • «.dw» — Резервирует слово, другими словами 2-а байта, параметр это значение, которое будет находится в данной области. Значение должно быть размером не более 2-ух байт.