4927 subscribers

Микроконтроллеры для начинающих. Часть 12. Память и процессор в AVR

695 full reads
1,4k story viewsUnique page visitors
695 read the story to the endThat's 47% of the total page views
3,5 minutes — average reading time

После общего обзора архитектур памяти я более подробно рассматривал STM8 и PIC

Теперь пришло время рассмотреть более подробно последнюю архитектуру AVR. Пожалуй, это сегодня самая популярная архитектура у любителей благодаря Arduino. Но в ее основе все таки лежат обычные микроконтроллеры, которые выпускает Atmel. Точнее выпускала, так теперь это принадлежит Microchip.

AVR устроены немного проще, чем две уже рассмотренные архитектуры. Но своих хватает и здесь. Да, AVR тоже бывают разные. Как минимум, большинство вспомнят ATtiny и ATmega. Но между ними нет столь принципиальных различий, как между PIC. Если говорить про архитектуру памяти. Поэтому я буду просто упоминать различия в ходе изложения.

Общие замечания по архитектуре AVR

В Atmel очень хотели сделать микроконтроллер достаточно универсальным и при этом простым. И это им удалось. Классическая Гарвардская архитектура сочетается с не столь строгими ограничениями в RISC подходе. Это еще не позволяет отнести микроконтроллер к CISC, но зато делает его "продвинутым RISC" (advanced RISC, как говорит сама Atmel). В общем, популярность AVR заслужена.

Здесь нет единого адресного пространства, как в STM8. И нет многоуровневого конвейера. А команды нельзя выполнять из ОЗУ. Зато здесь процессор имеет гораздо больше регистров, так что их даже можно (хоть и чрезвычайно условно, с большой натяжкой) назвать подобием кэш памяти данных. Хотя это, собственно говоря, просто расширение понятия регистр-аккумулятор.

При этом здесь нет и банков, и страниц, что сильно путают и пугают новичков в PIC. Зато есть нелогичное адресное пространство ввода-вывода. Почему не логичное скажу чуть позже. И есть "двойные стандарты" при распределении регистров внешних устройств. Но давайте со всем разбираться по порядку.

Регистры процессора AVR

Я опять не буду перечислять абсолютно все регистры, которые можно отнести к процессору. Но назову основные, которые важны для нас в контексте рассматриваемого в статье вопроса. Все регистры процессора имеют свои адреса, но говорить об этом я буду немного позже, когда доберемся до адресных пространств.

Регистр адреса команды PC

Как и во всех микроконтроллерах является указателем в адресном пространстве команд и содержит адрес команды, которая будет выбираться в следующем машинном цикле.

Регистр флагов состояния SREG

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

Указатель стека SP

Сам стек в AVR располагается в памяти данных, обычно, в самом ее конце. А регистр SP является указателем на вершину стека. Собственно говоря, регистр SP является регистровой парой SPH:SPL, причем SPH может отсутствовать в микроконтроллерах с малым объемом ОЗУ. Просто количество бит регистра SP может быть разным, в зависимости от доступного объема памяти данных.

Для работы со стеком существуют команды POP и PUSH.

Регистры общего назначения

Всего доступны 32 8-битных регистра общего назначения, с R0 по R31. Такое количество регистров общего назначения в процессоре, вместе с тем, что в командах можно указывать любой из них (а в некоторых командах сразу два) и позволило мне сказать, что это похоже на регистровый кэш, управляемый вручную. Тем более, что арифметические и логические команды работают с регистрами, а вот что бы поработать с данными из ОЗУ нужно их сначала перенести в один из регистров, а потом вернуть результат обратно в память.

Индексные регистры

Часть регистров общего назначения выполняют и специальные функции - индексных регистров. Всего есть три 16-битных индексных регистра.

Регистры R26 и R27 образуют регистровую пару R27:R26, которая соответствует паре XH:XL соответствующей индексному регистру X.

Регистры R28 и R29 образуют регистровую пару R29:R28, которая соответствует паре YH:YL соответствующей индексному регистру Y.

Регистры R30 и R31 образуют регистровую пару R31:R30, которая соответствует паре ZH:ZL соответствующей индексному регистру Z.

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

Адресное пространство ввода-вывода

В микроконтроллерах AVR есть команды IN и OUT, которые работают в адресном пространстве ввода вывода. Всего в этом пространстве может быть до 64 регистров внешних устройств.

При этом здесь же располагаются и уже упомянутые выше регистры процессора (SREG, SP). А это уже не логично. Но и это еще не все. Однако, для этого мы должны посмотреть на адресное пространство данных.

Адресное пространство данных (на самом деле объединенное)

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

Распределение адресного пространства данных микроконтроллеров AVR с необходимым количеством регистров оборудования не превышающих 64. Иллюстрация моя
Распределение адресного пространства данных микроконтроллеров AVR с необходимым количеством регистров оборудования не превышающих 64. Иллюстрация моя
Распределение адресного пространства данных микроконтроллеров AVR с необходимым количеством регистров оборудования не превышающих 64. Иллюстрация моя

Я не стал здесь показывать область стека. Она обычно располагается в самом конце памяти данных. Однако, стек можно разместить в любом месте памяти данных просто проинициализировав регистр SP соответствующим значением при запуске программы. Сам же микроконтроллер загружает в SP при старте адрес последней ячейки памяти данных.

Обратите внимание, что здесь воедино соединены сразу три сущности! Во первых, регистры общего назначения. Во вторых, адреса ввода-вывода, но со смещением 20h. В третьих, собственно память данных (включая стек) начиная с адреса 60h.

Таким образом, мы можем обратиться к любому регистру общего назначения и просто указав его номер в соответствующей команде, и по его адресу в пространстве данных (например, загрузив его адрес в индексный регистр).

Более того, есть два способа получения доступа и к регистрам оборудования. Так регистр SREG имеет адрес 3Fh в пространстве ввода-вывода. И к нему можно обратиться например так

IN R5,3F

Но одновременно, он же доступен по адресу 3Fh+20h= 5Fh. А значит, возможно и такое

CLR XH

LDI XH,$5F

LD R5,X

Или просто

LDS R5,$5F

Но и это еще не все! Микроконтроллеры получали все новые встроенные модули и адресного пространства ввода-вывода стало не хватать. Поэтому часть регистров оборудования в некоторых моделях микроконтроллеров вынесли в отдельный блок "расширения регистров ввода-вывода". И разместился этот блок с адреса 60h.

Распределение адресного пространства данных микроконтроллеров AVR с необходимым количеством регистров оборудования больше 64. Иллюстрация моя
Распределение адресного пространства данных микроконтроллеров AVR с необходимым количеством регистров оборудования больше 64. Иллюстрация моя
Распределение адресного пространства данных микроконтроллеров AVR с необходимым количеством регистров оборудования больше 64. Иллюстрация моя

Всего может быть до 160 дополнительных регистров оборудования. И доступ к ним командами IN и OUT уже невозможен. А собственно память данных (включая стек) теперь начинается с адреса 100h.

Как определить, есть в микроконтроллере этот дополнительный блок регистров, или нет? Посмотрев в документации, это самый надежный способ. Дело в том, что название начинающееся с ATmega еще ни о чем не говорит, в данном случае. Так у ATmega32A дополнительного блока нет и данные можно размещать с адреса 60h. А вот ATmega328 или ATmega 644 такой блок имеют, а значит и данные могут размещаться только с адреса 100h.

Ничего данная организация памяти не напоминает? Нет, я не про STM8 с его единым адресным пространством и выделенным под регистры оборудования диапазоном. Я про PIC. Если убрать лишнее (по своей сути) пространство ввода-вывода, то мы получим тот же принцип размещения регистров и данных в едином пространстве!

Режимы адресации операндов в памяти данных

Я опущу описания неявной адресации, равно как и непосредственной (константа или литерал). Здесь нет никаких отличий от уже многократно рассмотренных случаев.

Регистровая прямая

Прямая регистровая адресация в AVR. Иллюстрация моя
Прямая регистровая адресация в AVR. Иллюстрация моя
Прямая регистровая адресация в AVR. Иллюстрация моя

Как я уже говорил, номер регистра общего назначения задается прямо в коде команды. Всего у нас 32 регистра, значит нужно 5 бит номера. При этом в некоторых командах нужно указывать два регистра. Сам принцип не будет отличаться от уже показанного на рисунке, просто добавится еще одно поле с номером регистра.

Адресация ввода-вывода

По большому счету, не отличается от прямой регистровой

Адресация ввода-вывода в AVR. Иллюстрация моя
Адресация ввода-вывода в AVR. Иллюстрация моя
Адресация ввода-вывода в AVR. Иллюстрация моя

Разница только в том, что теперь нужно 6 бит адреса регистра ввода-вывода. Обратите внимание, что в данном случае адреса начинаются с 0!

Прямая адресация

В данном случае в коде команды задается полный адрес в пространстве памяти данных, а сама команда становится 4-байтной

Прямая адресация в AVR. Иллюстрация моя
Прямая адресация в AVR. Иллюстрация моя
Прямая адресация в AVR. Иллюстрация моя

Обратите внимание, что в данном случае мы можем обратиться к любой ячейке в адресном пространстве данных, включая регистры общего назначения и регистры ввода-вывода. При обращении к регистрам ввода вывода нужно учитывать, что адресное пространство ввода-вывода размещается в адресном пространстве данным начиная с адреса 20h.

Косвенная (индексная) адресация

Косвенная (индексная) адресация в AVR. Иллюстрация моя
Косвенная (индексная) адресация в AVR. Иллюстрация моя
Косвенная (индексная) адресация в AVR. Иллюстрация моя

Здесь нам тоже все знакомо. Адрес нужной ячейки данных помещается в один из индексных регистров.

Косвенная (индексная) с автоувеличением или автоуменьшением адреса

Отличается от предыдущего случая только тем, что содержимое соответствующего индексного регистра увеличивается или уменьшается на 1. Причем уменьшение производится ДО использования, а увеличение ПОСЛЕ.

Косвенная со смещением

Косвенная адресация со смещением в AVR. Иллюстрация моя
Косвенная адресация со смещением в AVR. Иллюстрация моя
Косвенная адресация со смещением в AVR. Иллюстрация моя

Обратите внимание, здесь нужно использовать индексные регистры Y или Z!

Адресация памяти команд как данных

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

Адресное пространство программ

Тут все очень просто. Адресное пространство программ линейное и непрерывное. Общий объем памяти программ (и разрядность регистра PC) зависит от конкретного микроконтроллера.

В некоторых микроконтроллерах, например, в семействе ATmega в конце памяти программ располагается область загрузчика (Bootloader). В этом случае память программ делится на два блока. Первый - область приложений, или собственно прикладной программы. Второй - область загрузчика. При этом разбиением памяти программ на зоны можно, в некоторой степени, управлять.

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

Режимы адресации в памяти команд

В данном случае речь идет об адресации в командах передачи управления (условные и безусловные переходы, вызов подпрограмм).

Прямая и косвенная адресация в командах перехода

Это очень простые режимы адресации и я не буду приводит иллюстрации. В случае прямой адресации адрес перехода просто задается в коде команды, откуда и загружается в регистр PC. В случае косвенного перехода в PC загружается содержимое индексного регистра Z (которое может быть результатом некоторых вычислений, например).

Относительная адресация в командах перехода

Адресация в командах относительного перехода в AVR. Иллюстрация моя
Адресация в командах относительного перехода в AVR. Иллюстрация моя
Адресация в командах относительного перехода в AVR. Иллюстрация моя

Как видите, тут тоже все просто. Содержимое регистра PC увеличивается на 1 и к нему прибаляется (со знаком!) содержимое поля смещения из кода команды. Получившийся результат становится новым сожержимым PC. То есть, адресом команды, которая и будет выполняться.

Обратите внимание, что в коде команды пол смещение отводится 12 бит, но поскольку число со знаком, то оно лежит в диапазоне от +2047 до -2048.

Заключение

Вот так все довольно просто, и при этом довольно гибко, устроено в микроконтроллерах AVR. Теперь вы понимаете, почему они столь популярны и почему именно они тали основой для Arduino.

До новых встреч!