3 заметки с тегом

Atmel AVR

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

Atmel AVR 8-bit: пишем бутлоадер

Это пока ещё черновик, но всё равно уже публикую, вдруг кому-то пригодится.

Эта запись — конспект того, как делал я.

Задача: написать бутлоадер для ATmega16, занимающий 512 слов. Микроконтроллер соединяется с компьютером через USART, есть возможность выполнить сброс, сигнал break при нормальной работе не используется, миллисекундная задержка при включении неважна.

Решение: при включении питания управление передаётся на бутлоадер (BOOTRST = 0). После выполнения всяких инициализаций (портов) он читает ножку Rx. Если там отсутствует break более определённого времени, управление передаётся основной программе (jmp 0). Если присутствует, ждём снятия и переходим к циклу общения с компьютером по USART...

Соответственно, извне это выглядит следующим образом: если хотим шить, нужно подать на USART break и перезагрузить прибор (включить питание или замкнуть ножку /RESET на землю). Если же break не подавать, то всё влияние бутлоадера проявляется лишь в том, что после сброса требуется дополнительное время (для человека пренебрежимо малое) на запуск устройства. И, ясное дело, в том, что основная прошивка должна быть короче, чем вся флешка.

Реализованы следующие команды:

  • Пинг
  • Запись страницы из адресного пространства основной программы (сам бутлоадер перезаписать нельзя — защита от дурака)
  • Чтение любой страницы
  • Сброс (передача управления основной программе — jmp 0)

Кроме того, по выделенному адресу расположена 64-байтная строка — версия бутлоадера. Компьютер может достать её с помощью команды чтения страницы.

Настройки Atmel Studio 7.0:
Проект C exe.
Toolchain
Optimization = None
Memory settings (в словах):
.text=начало секции бутлоадера (в соответствии с фьюз-битами)
.version=в конце секции бутлоадера, чтобы вместилась соответствующая строка
Device ...

Для ATmega32(A):
.text=0x3e00
.version=0x3fe0

Для ATmega16(A):
.text=0x1e00
.version=0x1fe0

В обоих случаях весь бутлоадер занимает 512 слов, а версия — 64 байта.

В целом проект написан на Си, но именно функции, связанные с чтением/записью страниц, — на ассемблере.

Для компьютера было написано 2 разных прошивальщика: на Java 6 (консольная программа) и на LabWindows/CVI 2013 (GUI).

На этом пока всё...

2017   Atmel AVR

Atmel AVR 8-bit: локбиты и фьюзбайты

Эта запись — краткий конспект, а не полное руководство.

Сленг: Lock bits = локбиты = локи. Fuse bytes (bits) = фьюзбайты (биты) = фьюзы.

1 = unprogrammed = неустановленный = незаписанный = выключенный = отключенный = снятый = зелёный Off = флажок снят
0 = programmed = установленный = записанный = включенный = красный On = флажок стоит

Локи можно устанавливать. Единственный способ снять (причём все одновременно, то есть по умолчанию они все сняты) — команда chip erase. Нужны для секретности (чтобы нельзя было прочитать прошивку).

Фьюзы можно как устанавливать, так и снимать; по умолчанию они не все 1; команда chip erase не влияет. Нужны для всяких настроек, связанных с аппаратным обеспечением конечного устройства (например, тактовая частота), поэтому обновление прошивки, как правило, не требует их изменения.

Локбиты

Похоже, они одинаковы вообще для всех AVR 8-бит. Проверено для ATmega16A, ATmega32, ATmega1284P.

7
6
5 BLB12
4 BLB11
3 BLB02
2 BLB01
1 LB2
0 LB1

BLB — Boot Lock bits, влияют, в частности, на возможность самомодификации кода бутлоадером. LB — Lock bits, влияют на возможность программирования программатором.

Если без тонкостей, то получается так:
Boot Lock Bit0 Protection Modes (Application Section):
11 = бутлоадер может писать и читать Application Section
10 = бутлоадер может только читать Application Section

Boot Lock Bit1 Protection Modes (Boot Loader Section):
11 = бутлоадер может писать и читать Boot Loader Section
10 = бутлоадер может только читать Boot Loader Section

LB:
11 = ограничений нет
10 = программатор может только читать flash, eeprom, fuse
00 = программатор не может даже читать flash, eeprom, fuse

Итого:
0xff = никакой защиты
BLB11 = 0 (0xef) — только защита бутлоадера от самопереписывания

Фьюзбайты

Для ATmega16A и ATmega32.

Старший фьюзбайт:

7 OCDEN Enable OCD
6 JTAGEN Enable JTAG
5 SPIEN Enable SPI Serial Program and Data Downloading
4 CKOPT Oscillator options
3 EESAVE EEPROM memory is preserved through the Chip Erase
2 BOOTSZ1 Select Boot Size
1 BOOTSZ0 Select Boot Size
0 BOOTRST Select reset vector

Младший фьюзбайт:

7 BODLEVEL Brown-out Detector trigger level
6 BODEN Brown-out Detector enable
5 SUT1 Select start-up time
4 SUT0 Select start-up time
3 CKSEL3 Select Clock source
2 CKSEL2 Select Clock source
1 CKSEL1 Select Clock source
0 CKSEL0 Select Clock source

Биты программаторов и отладчиков:
OCDEN — включить On-chip Debug. У меня отладчика нет, так что оставлю 1.
JTAGEN — аналогично для JTAG. У меня JTAG нет, а лишаться части ножек не хочу, так что переключу на 1.
SPIEN — аналогично для последовательного программатора. Имеется защита от дурака: при использовании последовательного программатора выключить этот бит невозможно.

Биты частоты и включения:
CKOPT, SUT, CKSEL — из значения зависят друг от друга, так что просто читайте раздел System Clock and Clock Options.

EESAVE — не стирать EEPROM командой Chip Erase.

Для бутлоадера:
BOOTRST — с какого адреса начинать исполнение программы после сброса. Обычно, если бутлоадера нет, то с нулевого (бит снят), если есть, то в соответствии с битами BOOTSZ (бит установлен). Они определяют длину бутлоадера с конца адресного пространства. В словах:

ATmega16A ATmega32
11 128 256
10 256 512
01 512 1024
00 1024 2048

Сброс при просадке напряжения:
BODEN — если включить, то низкое напряжение питания приведёт к сбросу. Полезно при использовании бутлоадера, чтобы избежать ошибок записи. Но увеличивает энергопотребление во всех режимах.
BODLEVEL — уровень срабатывания Brown-out Detector (если BODEN установлен): 1 = 4 В (для нормального напряжения 5 В), 0 = 2,7 В (для нормального напряжения 3,3 В).

The default (10011001, 11100001) clock source setting is therefore the 1 MHz Internal RC Oscillator with longest startup time.

2017   Atmel AVR