Atmel AVR

Таймеры

0 = BOTTOM <= TOP <= MAX = 0xFF/0xFFFF/...

TCNTn (Timer/Counter) — регистр собственно таймера
OCRn (Output Compare Register) — с чем сравнивать, то есть там лежит TOP. Флаг взводится на следующем тике таймера после того, как TCNTn равен OCRn.
TIFR (Timer Interrupt Flag Register), TIMSK (Timer Interrupt Mask Register) — общие для всех таймеров
TCCRn (Timer/Counter Control Register)

Clear Timer on Compare Match (CTC) Mode

Задача: вызывать прерывание с определённой частотой. Тут всё просто: прерывание срабатывает каждые OCRn + 1 тиков таймера. Единственная проблема — изменение OCRn без выключения таймера: если новое значение близко к BOTTOM, то можно его перескочить, и тогда придётся ждать переполнения.

Предделитель

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

Ошибки в документации

ATmega32U4: в одном месте написано, что микросхемы поставляются с выключенным JTAG, в другом — что с включенным. Оказалось, с включенным (2010 год).

ATmega1284P. Stack pointer после reset: 0x10FF согласно надписи, но 0x20FF согласно картинке в Atmel-42719C-ATmega1284P_Datasheet_Complete-10/2016; 0x10FF согласно картинке в 8059D—AVR—11/09; 0x40FF в симуляторе Atmel Studio 7 (и этому же равна константа RAMEND), что соответствует размеру памяти.

——

SPI-программирование (МК — ведомый)
in = MOSI (Master Out Slave In) = PDI (Programming Data Input)
out = MISO (Master In Slave Out) = PDO (Programming Data Output)

Atmel Studio 7

Если проект Си++, то и файлы пусть будут cpp, даже если просто скопированы из проекта Си (вручную переименовать). Иначе отладчик не работает. И делать clean после включения новых файлов. А вот включение оптимизации на отладчик не влияет (косвенно влияет: из ассемблерного кода вообще может исчезнуть то место, на котором была точка останова в Си-коде).

И всё же я не понимаю, почему строчка while ( !(UCSR0A & 0x80) ) {}; (C++, O1), совершенно логично преобразующаяся в 2 ассемблерных команды SBIS 0x0B,7; RJMP PC-0x0001, не проходится в отладчики при ручной установке этого самого бита 7 (0x80, RXC0) в этом самом регистре 0x0B (UCSR0A). И в Си, и в ассемблере на каждой строчке тыкал бит мышкой — ставится, но после шага сбрасывается и не влияет на ход исполнения. Есть костыль: ввести volatile-переменную, и сначала в неё копировать регистр, а потом её тестировать в условии цикла. Вот значение переменной отладчик позволяет изменить. Но это костыль. Кажется, в более старых версиях «Студии» такого (сбрасывания флага RXC) не было.

Назначение адреса ОЗУ

Задача: раположить статическую переменную по заданному до момента компиляции адресу в ОЗУ (internal data SRAM) микроконтроллера ATmega128A.

Из документации на микроконтроллер, раздел AVR Memories: ОЗУ начинается с адреса 0x100 и содержит 4 КБ. На ассемблере работа с ОЗУ происходит с помощью команд LD, ST, LDS, STS, LDD, STD, а также PUSH и POP. В принципе, это всё, что нужно знать, если программировать на чистом ассемблере.

А что насчёт Си и Си++, встроенных в «Атмель Студию 7»? Из документации avr-libc 2.0.0: в связи с тем, что архитектура AVR гарвардская, а компоновщик разрабатывался под фоннеймановскую, для SRAM добавляется смещение 0x800000.

Уже есть что проверить? Так и проверим! Заводим статическую переменную volatile unsigned short test = 0xabcd, каким-либо образом (просто в порт, в USART... Да хотя бы отладчиком в симуляторе!) выводим её адрес:

volatile unsigned char address = 0;
address = (((unsigned long)(void*)(&test))>>0);
address = (((unsigned long)(void*)(&test))>>8);
address = (((unsigned long)(void*)(&test))>>16);
address = (((unsigned long)(void*)(&test))>>24);

Хотя известно, что указатели 16-битные (а long — 32, и компилятор выдаёт предупреждение), я намеренно использовал именно long, чтобы туда могло бы влезть смещение 0x00800000. А теперь отыщем переменную test в файле *.map.

Результат: адрес, выданный непосредственно микроконтроллером, — 0x100; адрес в файле *.map — ровно на 0x800000 больше. Всё как и предполагалось.

Дело за малым: указать компоновщику, что именно эта переменная должна всегда располагаться именно по адресу 0x00800100, даже если в дальнейшем в код программы добавят другие переменные до неё.

В общем случае я решения не нашёл. Но можно сдвинуть секцию .data, а перед ней создать секцию для своих переменных. Например, нам надо 10 байт. Тогда в свойствах компоновщика в SRAM segment добавляем: «.MySram=0x100», «.data=0x10a» (смещение 0x800000 тут добавлять не надо). И у всех своих переменных прописываем

__attribute__ ((section (".MySram")))

.

И получается такая непонятность: во-первых, внутри секций порядок неочевидный. Во-вторых, секции могут перекрываться, но ошибки компиляции не возникает. В-третьих, я ещё не читал про malloc. В-четвёртых, надо ещё разобраться, что с секцией .bss.

Можно заводить свою секцию на каждую переменную. А можно завести структуру. Внутри структуры всё понятно. Но за размером всё равно придётся следить руками.

Выводы: получать адрес статической переменной из *.map-файла научились. А вот задавать свой адрес сложнее.

Atmel ICE

Сам не питает микроконтроллер, но вход VTG должен быть подключен к VCC для мониторинга напряжения.

Даже в максимальной комплектации нет разъёма ISP 10 pin 100 mil. Ниже картинка для подключения отдельных проводов (на всякий случай также для 6 pin, хотя такой разъём есть).

Имеющийся разъём 10 pin 100 mil предназначен только для JTAG, причём ключа на самом разъёме нет (есть только метка на плате).

Прерывания

При входе в прерывание аппаратно сбрасывается флаг разрешения прерываний (cli), при выходе (reti) — устанавливается (sei). Таким образом, вложенных прерываний самих по себе нет.

Если же они нужны (и есть уверенность, что это безопасно), можно вызвать sei(). А в компиляторе avr-gcc проще прописать атрибут ISR_NOBLOCK (если это безопасно с самого начала, без дополнительных действий программиста).

Для атомарной работы с многобайтовыми переменными (в том числе некоторыми регистрами) можно использовать cli/sei, если оптимизация отключена. А с оптимизацией в avr-gcc для этого есть util/atomic.h. Дополнительно переменная должна быть volatile, а the standard level of the
compiler (option —std=) is set to either c99 or gnu99.

Поделиться
Отправить
Запинить
2017   Atmel AVR
Популярное