Теория по КМПУ | Готовые элементы систем | Технологии и хитрости | Прочее | Магазин | Контакты | |||
![]()
23.01.25
Основная цель данной вводной заметки – рассказать, каким образом можно из говна и палок собрать программатор для микроконтроллера LGT8F328P. Кроме того, коснемся вопроса софта, при помощи которого прошивку можно залить в камень. Ну и, естественно, поморгаем светодиодом, а также разберемся, как настроить тактовую частоту кирпича в условиях, когда такого понятия, как «фузы», для него просто не существует.
• программатор LGT8F328P из «Arduino» за пять минут;
Ну а тех, кому тоже интересно поглубже разобраться в вопросе, приглашаю продолжить чтение (наливайте чай/кофе/алкоголь – заметка, как обычно, получилась достаточно объемной). ![]()
Вроде как по выводам он совместим с Arduino Pro Mini, но тут я не специалист, может это и не так. Для меня важно, что на данной плате есть необходимый минимум для первого знакомства с пациентом, ну а остальное со временем приложится. От автора
Не секрет, что в настоящее время почти вся более-менее сложная электроника содержит на борту как минимум один микроконтроллер. И так же не секрет, что камни постоянно совершенствуются, усложняются, становятся всё более интересными. Поэтому львиная доля разработчиков периодически «пересаживается» на более свежую и производительную платформу, благо выбор их весьма и весьма богат. Но вот лично у меня с этим как-то не сложилось – я как начал в 2007 году использовать микроконтроллеры семейства AVR, так по сей день ими и пользуюсь, ибо они практически полностью покрывают весь спектр моих задач. При этом нельзя сказать, что я не пытался переехать на более могучие кирпичи – я моргал светодиодом на STM-ках, немного ковырялся в ESP8266, а ESP32 мне настолько понравились, что я сразу начал строчить заметку с их нормальным русским описанием и даже создал под эти камни встраиваемый модуль с USB-интерфейсом. Однако, все перечисленные платформы оказались для меня избыточны, т.к. требуемые задачи всегда удавалось решить при помощи старых добрых AVR-ок. Думаю, немалую роль в этом сыграло то, что обычно я весь проектируемый дывайс распиливаю на отдельные модули, общающиеся по стандартным шинам, а для реализации такого модуля обычно за глаза хватает камня из линейки ATmegaX8. Во всяком случае, платы для модулей ESP32 до сих пор валяются без дела: ![]()
и как-то даже не предвидится проекта, где они мне потребовались бы. Простейший программатор («LGTISP»)
При переезде на незнакомую аппаратную платформу разработчика обычно интересует три момента:
• где взять софт, на котором можно написать программу для микроконтроллера, и который умеет генерить бинарный файл, заливаемый непосредственно в камень;
Отмечу, что с программным обеспечением проблем обычно не возникает. И если уж вы дочитали заметку до этого места, то хотя бы софт, на котором можно написать прошивку и сгенерить бинарный файл для китайского МК, у вас уже есть. Предположение это основано на том, что камни LGT8F328P вряд ли будут интересны новичкам – платформы STM и ESP намного интереснее, а сто́ят не сильно дороже. А значит, ранее вы уже работали с микроконтроллерами AVR, и ваше ПО вполне подойдет для китайских чипов, ибо они шьются теми же файлами «HEX», что и обычные AVR-ки. С софтом, через который прошивка будет заливаться в камень, тоже проблем нет – он известен, бесплатен и его можно много где скачать (см. ниже). А вот по поводу программатора, судя по различным статьям и форумам, могут возникнуть серьезные вопросы (еще раз повторю, что здесь не рассматриваются модули «Arduino», у которых на борту есть вся аппаратная часть, позволяющая просто воткнуть плату в USB-порт компа и нажать кнопку «Загрузить в МК»). ![]()
что неудивительно, ибо даже ссылка с сайта разработчика LGT8F328P ведет в никуда. И есть еще вариант «Offline», который позиционируется как «SWDISP автономный программатор». Данная модель, видимо, позволяет шить (и только шить!) камни без использования ПК загруженной ранее в программатор прошивкой. Данный товар можно купить через сайт разработчика (см. ссылку «LGTMCU Offline HV»), а также на AliExpress, но там всего два лота, стоимость дывайса получается весьма неслабая, а самое главное – не особо понятно, как этим программатором пользоваться.
• линия данных «SWD» («совмещенный» аналог линий «MISO» и «MOSI» у AVR);
Таким образом, задача программатора для китайского камня – преобразовать интерфейс USB (как наиболее популярный на данный момент) в сигналы «RSTN», «SWD» и «SWC»: ![]()
Причем, в настоящее время доступен целый ворох дешевых китайских чипов типа CH340G/CH340N/и т.д., поэтому целесообразно разбить эту задачу на две: сначала посредством моста USB<=>UART преобразовать данные от компа в стандартный «последовательный» вид, и уже при помощи знакомого UART-ового формата сформировать сигналы «RSTN», «SWD» и «SWC», используя какой-нибудь микроконтроллер. При этом камень в программере, по большому счету, может быть вообще любым, лишь бы у него хватило памяти и прочих ресурсов на поставленную задачу. Но поскольку кирпичи LGT8F328P идут на смену AVR-кам, то опыт работы с последними у вас должен быть в наличии, поэтому собирать программатор будем именно на микроконтроллере от Atmel (или Microchip).
• D10 (PB2) – линия сброса «RSTN» (порт PC6 кирпича LGT8F328P);
Обратите внимание на фразу ![]()
И как следствие, загрузчик начнет шиться не в китайца, а в ардуиновую Мегу328, что нам совсем не улыбается. Изменить это никак нельзя, среда просто работает таким образом – перед загрузкой прошивки в плату «Arduino» она сбрасывает камень на ней при помощи упомянутого выше сигнала «DTR», и пока кирпич не очухался после сброса, заливает в него требуемый скетч. Если же замкнуть точки «RESET» и «VCC» ардуинового модуля, то время перезарядки конденсатора C4 на схеме выше станет практически нулевым, и Мега328 просто не успеет сброситься. А это значит, что дальше «Arduino» продолжит работать в режиме именно программатора и начнет пересылать загрузчик именно в LGT8F328P, что нам, собственно, и было нужно. Конечно, такое решение сильно нагружает выход «DTR» USB-моста, ведь на время перезарядки емкости C4 он будет накоротко замкнут с шиной питания +5,0В. Но, как было сказано ранее, это продлится очень недолго, да еще и процесс этот разовый, так что, скорее всего, одну процедуру заливки загрузчика выход «DTR» выдержит. Главное – не забыть потом разомкнуть точки «RESET» и «VCC» на плате «Arduino», а то можно долго думать, почему же перестала шиться 328-я Мега (да и USB-преобразователь рискуете спалить). Однако, нам-то требуется не разовый прошиватель загрузчика, а программатор LGT8F328P «вообще», и заливать в камень мы будем не бутлоадер, а свою собственную программу. Поэтому использовать среду «Arduino» нам нет никакой необходимости, а остальной софт, при помощи которого можно прошить микроконтроллер, состояние линии «DTR» самостоятельно не изменяет – он просто шлет в последовательный порт требуемую прошивку и всё. А посему в нашем случае лучше не закорачивать точки «RESET» и «VCC» ардуинового модуля, дабы лишний раз не рисковать здоровьем USB-моста.
Таким образом, простейший способ получения программатора для работы с микроконтроллерами LGT8F328P выглядит так:
• скачиваем архив со скетчем «LGTISP» (оригинал проекта находится здесь); ![]()
Можно отпраздновать данное событие. Только имейте ввиду, что подключать собранный программатор к китайскому камню напрямую можно лишь тогда, когда питание у LGT8F328P составляет +5,0В. В противном случае потребуются цепи согласования логических уровней (примеры которых рассмотрены, например, здесь).
Далее пойдет речь о том, как можно привести данный программатор в более культурный вид, но если вам достаточно того, что получилось (работать-то оно точно будет), можно сразу перейти к проверке программера. Программатор «LGTISP-nRF»
Несмотря на дешевизну и быстроту изготовления, простейший вариант программатора «LGTISP» имеет серьезный недостаток в виде крайне низкой надежности. Исходя из своего опыта могу сказать, что собранной поделки надолго не хватит – рано или поздно обязательно либо где-то отвалится провод, либо USB-шнур сломается, либо еще что-нибудь произойдет. Конечно, для первого знакомства с китайскими чипами программатора из ардуины более чем достаточно, но «на долгую» всяко нужно что-то понадежнее. Поэтому категорически рекомендую оформить программер в виде отдельного устройства с платой, заточенной именно под функцию прошивки. ![]()
Однако, я бы порекомендовал принять во внимание еще несколько моментов. Во-первых, если глянуть повнимательней на код скетча «LGTISP», можно заметить, что данная прошивка поддерживает работу с тремя светодиодами: «Programming», «Error» и «Heartbeat». При этом в файле «readme.md» про лампочки почему-то нет ни слова, однако, в само́м листинге программы есть и их краткое описание (строки №№18…21), и объявление соответствующих портов (строки №№56…58). Первый из указанных светодиодов загорается при каждом доступе Ардуины к памяти программируемого кирпича, второй – если «что-то идет не так» (в частности, если пропала синхронизация), третий же просто плавно мигает, пока на программатор подано питание. Отмечу, что для использования индикаторов «Programming» и «Error» каких-то дополнительных действий выполнять не требуется (только повесить лампочки с резисторами на необходимые порты ардуины), а вот для активации «сердцебиения» нужно будет раскомментировать строки 83, 119 и 133 (на всякий случай проверьте эти номера́ путем поиска «LED_HB» и «heartbeat» по тексту программы). По умолчанию индикация процесса программирования выведена на порт D7 Ардуины, индикация наличия ошибки – на порт D8, ну а светодиод «Heartbeat» – на порт D9. Однако, пользователь может использовать и другие порты, если они ему более удобны – для этого нужно просто указать требуемые цифры в строках №№56…58 кода скетча. Только при этом следует учитывать, что «сердцебиение» будет плавным лишь в случае задействования ШИМяных выводов Ардуины, ну и, естественно, нужно, чтобы «световые» порты не совпадали с линиями интерфейса SWD (по умолчанию D10, D12 и D13): ![]()
Во-вторых, скетч «LGTISP» весит сравнительно немного, поэтому он спокойно влазит не только в камень ATmega328P, традиционно используемый в Ардуине, но и в pin-to-pin совместимые, но более дешевые кирпичи ATmega168(P/PA), ATmega88(P/PA) и ATmega8(A). Конечно, особых денег здесь не выгадать, особенно с учетом того, что программаторов для камней LGT8F328P вам вряд ли понадобится сильно больше одного, но всё же для 8-й меги в том же Китае иногда можно встретить довольно выгодные лоты. Кроме того, лично я при малейшей возможности пытаюсь воткнуть в проект именно ATmega8A, поскольку у меня имеются достаточные запасы данных кирпичей, а вот 328-е зачастую приходится покупать. В общем, если вас заинтересовала данная возможность, нужно пройти в папку с установленной средой «Arduino», далее идем в «\hardware\arduino\avr» и открываем файл «boards.txt». В данном файле описываются различные модели плат из мира ардуины, в частности, установленный на них камень, его характеристики, а также тактовая частота МК. Собственно, там вроде бы всё понятно и без комментариев, но на всякий случай приведу пример, в котором изменены куски кода для компиляции скетча «LGTISP» под кирпич ATmega8A. Изменения вносились для платы «Arduino Uno», поэтому и проект тоже должен собираться под нее (см. «Инструменты => Плата» в среде «Ардуино»). Оригинальный ардуиновский код закомментирован символом «#» в начале строки, все изменения выделены жырным:
uno.upload.tool=avrdude
В данном примере типовая модель камня («atmega328p») заменена на требуемую («atmega8»), а также скорректирован объем FLASH и SRAM (512 байт из «полных» 8192 байт флэша у 8-й меги отводится на загрузчик). Кроме того, в нем заметны мои попытки сплавить хоть куда-то давно валяющуюся кучу кварцев на 11,0592МГц (см. параметр «uno.build.f_cpu»), однако, здесь оказалось не всё так просто. Сама по себе шина SWD нормально работает и шьет камень хоть на 16МГц-ах, хоть на 11,0592МГц. Однако, если при этом на кирпич с программатора приходит еще и линия «RSTN», то система начинает глючить через раз. Замечу – не наглухо затыкается, а непредсказуемо дуркует. Например, она может запросто работать в течение часа, после чего тупо разучиться шить камни LGT8F328P. После этого надо переткнуть программатор несколько раз, затем сплясать с бубном, затем подождать, затем сделать еще что-то, после чего всё опять приходит в норму (или не приходит). Особо ковыряться с данной проблемой мне было некогда, да и не проблема это на самом деле, ведь с «родной» частотой всё работает без вопросов, а если не использовать линию сброса, то программатор перестает глючить даже на «кривой» частоте. Однако, рискну предположить, что дело в формировании длительностей и пауз у сигналов на шине SWD, ведь для этого используются обычные NOP-ы, и временами, видимо, где-то что-то перестает успевать или, наоборот, начинает сильно торопиться. В общем, если вам действительно требуется изменить тактовую частоту работы МК, то разобраться в данном вопросе, думаю, будет не особо сложно. Однако, веских причин для ее изменения лично я не вижу – снижать потребление камня в программаторе вроде бы бессмысленно, ибо он питается от USB и лишних 10мА здесь ничего не решат. Если же вам нужно прошивать LGT8F328P, питающийся от напряжения +3,3В или ниже, гораздо эффективней использовать схему согласования уровня логических сигналов, чем понижать тактовую частоту МК (напомню, что при низком питании AVR-ки на 16МГц-ах работать не будут): ![]()
Данный согласователь – это третий момент, на котором я хотел бы заострить ваше внимание. Вещь крайне полезная, и если включить ее в схему программатора, не надо будет постоянно думать о согласовании питания прошивающего и прошиваемого камней. При этом предлагаемое решение довольно просто́, сто́ит три копейки, а также широко известно в узких кругах, поэтому принцип его работы рассматривался многими (в том числе и мной). Отмечу, что мне лень было рисовать согласователь уровней с нуля, из-за чего на картинке выше приведен кусок схемы готового устройства, и на кривую нумерацию деталей обращать внимание не нужно. Кроме того, если вы зададите вопрос «а зачем на линии SWC, заведомо работающей только в одну сторону (от программатора к МК), поставлен двухсторонний преобразователь?», я вам не смогу на него ответить – видимо, в момент проектирования устройства мой разум помутил Ктулху. Поэтому резистор R1 и полевик VT1 можно смело выкинуть, поставив взамен последнего диод BAT54C (как это сделано на линии сброса), однако, в целом все номиналы деталей проверены в железе и согласователь работает без нареканий даже в приведенном выше виде. Возможно, вас могут смутить сравнительно большие номиналы резисторов на схеме, но здесь нужно учитывать относительно низкую скорость работы интерфейса SWD, реализованного в скетче «LGTISP»: ![]()
На данном рисунке приведены осциллограммы прошивки камня LGT8F328P при помощи рассматриваемого скетча. Синим цветом показан сигнал «RSTN», а желтым – сигнал «SWC». Нетрудно видеть, что частота синхроимпульсов на шине SWD составляет не более 500кГц, причем, скетч «LGTISP» позволяет сформировать только такую частоту. Время между спадом сигнала сброса и началом изменений на линии «SWC» всегда больше 2мкс, а если брать разность между спадом сброса и передним фронтом первого тактового импульса, она будет больше 3мкс. При таких временах, как было показано в моей заметке про CH340N, вполне достойно работают номиналы подтягивающих резисторов 5кОм…10кОм, поэтому излишне грузить шины питания я не стал. Конечно, лучшим доказательством здесь были бы фотографии сигналов после схемы согласования, но я забыл их сделать, так что в этом вопросе вам придется поверить мне на слово. ![]()
И мне очень хотелось бы представить вам здесь устройство, собранное именно по такой структуре. Однако, как оказалось, в архиве моих разработок уже был дывайс, из которого элементарно получается программатор китайских кирпичей, а главное – под него уже имеется пара десятков изготовленных печатных плат. Данный дывайс имеет форм-фактор «USB-свисток», собран на базе камня ATmegaX8, на его борту присутствует преобразователь USB<=>UART, три светодиода, управляемых МК, и даже на выходной разъем выведены порты PB2, PB4 и PB5, т.е. линии «RSTN», «SWD» и «SWC» из скетча «LGTISP». Таким образом, в нем присутствует практически всё, о чем говорилось ранее, кроме схемы согласования уровней логических сигналов, ну и еще печатная плата у дывайса двухсторонняя (что однозначный минус с точки зрения радиолюбителя). И в итоге я решил, что для обкатки различных ньюансов мне пока хватит и такого программатора ![]()
ну а в дальнейшем можно будет сделать его вторую версию, расширенную и учитывающую все предыдущие косяки. ![]()
Обратите внимание на то, что элементы с неуказанными марками или номиналами в устройство не устанавливаются, и по количеству таких элементов видно, что проект не разрабатывался с нуля, а был тупо переделан из другого. Основой программатора является камень ATmega8A, за преобразование данных из USB-формата в UART и обратно отвечает китайский мост CH340N (больно уж я люблю эти чипы за дешевизну, небольшой корпус и за минимум обвеса). Тактовая частота кирпича равна стандартным ардуиновским 16МГц (выше я уже объяснял почему), питание берется напрямую с шины USB через самовосстанавливающийся предохранитель FU1. Конечно, для удешевления предохранитель можно не ставить и замкнуть вместо него джампер JP1, однако, лишняя защита USB-порту, думаю, не повредит. ![]()
либо специально сделанный для данной цели шлейф (хотя, ради одной прошивки камня лично я не стал бы с ним заморачиваться). ![]()
Как и говорил выше, основной ее минус, наверное, в том, что она является двухсторонней. В остальном плата довольно «щадящая» – минимальная толщина дорожки составляет 0,55мм (да и то лишь местами), минимальный диаметр дырки 0,7мм, пояса́ на пятаках не менее 0,3мм, типоразмер элементов не меньше 0805. Конечно, фломастером такую плату не нарисуешь, но при использовании хоть ЛУТа, хоть фоторезиста проблем возникнуть не должно. Исходный файл с платой есть в общем архиве проекта, название файла – «LGTISP-nRF_PCB.dip». Нарисована плата в САПР DipTrace; у данной программы есть полностью бесплатная версия под названием Freeware.
• «Arduino_Nano_Pinout.jpg» – файл с цоколевкой платы «Arduino Nano»;
Как видно из этого списка, архив уже содержит бинарный файл для заливки в камень, поэтому если вы решили выбрать первый путь (использование готового решения), всё достаточно просто. Берем собранный программатор для LGT8F328P и подключаем его к вашему программатору для камней AVR: ![]()
Соединить программаторы можно при помощи упоминавшихся выше проводов для макетных плат, либо специально сделанного для этой задачи шлейфа. Если AVR-программер имеет собственное питание, и оба свистка вставляются в один и тот же комп, точки «+5.0V» и «VCC» соединять не нужно. А дальше шьем фузы камня в программаторе «LGTISP-nRF» (я сделал Lock = 0x3F; High = 0xD1; Low = 0x3F), после чего заливаем в него файл «LGTISP-nRF_m8_16000000Hz.hex». На этом всё – прошивальщик кирпичей LGT8F328P готов. Если же вы решили пойти по второму пути, вам сначала потребуется открыть в среде «Arduino» файл «LGTISP-nRF.ino», после чего произвести все необходимые изменения и сгенерить бинарный файл для прошивки камня самостоятельно («Скетч => Экспорт бинарного файла»). Отмечу, что изменения могут носить самый разный характер – от простейших, типа смены модели камня и его тактовой частоты (подробнее об этом было рассказано в начале данного пункта) до навешивания на программатор вороха дополнительных функций (благо и памяти, и неиспользуемых портов в 328-й меге остается более чем достаточно). Тут давать какие-то рекомендации сложно, ведь всех требований заранее не предусмотреть, да и навряд ли человек, пошедший по второму пути, нуждается в моих советах. Скажу лишь, что среда «Arduino» позволяет генерить не только «обычные» HEX-файлы для МК, но и файлы, содержащие загрузчик – возможно, кому-то это будет полезно (оба файла создаются автоматически при нажатии на «Скетч => Экспорт бинарного файла»). Ну и еще не нужно забывать, что фузы, прошиваемые в камень создаваемого программатора, должны учитывать все особенности вашего проекта: тактовая частота и напряжение питания кирпича, наличие и размер бутлоадера, необходимость защиты от чтения/записи и т.д. И последнее напоминание – чтобы в среде «Adruino» у вас всё нормально собралось, необходимо в стандартном ардуиновском файле «HardwareSerial.h» (расположен в папке «…\hardware\arduino\avr\cores\arduino») изменить значение константы SERIAL_RX_BUFFER_SIZE с 64 на 250. Софт для программатора
Собранный программатор камней LGT8F328P – это, конечно, прикольно, но толку от него одного не особо много. Зачастую железо становится полезным только при наличии софта, обеспечивающего его общение с компом, и рассматриваемый программер – не исключение. Как было сказано выше, программатор, созданный на базе скетча «LGTISP», с точки зрения компьютера работает по протоколу STK500, поэтому он, по идее, должен видеться любой программой, поддерживающей работу с данным протоколом. Однако, при попытке достучаться до него из, например, AVR Studio 4.19.730, среда шлет вас нахер, мол, больно уж я стара́ для вашей версии программатора: ![]()
и общаться с китайским камнем не дает (правда, сам программатор при этом она видит, тут всё ок). Возможно, какие-то другие программы, понимающие STK500, тоже будут глючить при работе с рассматриваемым программером, не знаю. Однако, я точно знаю, какой софт прекрасно с ним уживается – это (вот уж «неожиданность») утилита AVR Dude, широко известная в узких кругах как «дудка». Данная программа снискала себе огромную популярность у AVR-разработчиков из-за того, что поддерживает кучу кирпичей и программаторов, а если она чего и не знает, то обычно это можно довольно легко в нее добавить. Однако, дудка является консольной, т.е. работает из-под командной строки, а я это дело не очень люблю (имеется ввиду процесс разработки поделки, а не работа с уже́ доведенной до ума партией устройств). Поэтому для прошивки камней через AVR Dude я использую графическую оболочку «SinaProg», которая не только позволяет пользователю работать с привычным «виндосовским» интерфейсом, но и умеет самостоятельно рассчитывать состояние фузов (правда, для LGT8F328P это умение не актуально, см. ниже). Вообще говоря, краткое описание данной оболочки, а также пример работы в ней я давал в заметке про FT232RL и здесь повторяться смысла не вижу. Скажу лишь, что если вы таки будете работать с дудкой из командной строки, то программатор на базе скетча «LGTISP» она видит как «stk500v1», либо как «avrisp» (ключ «-c»; работают оба варианта), камень для работы с LGT8F328P (ключ «-p») надо задавать как «m328p», при этом значение, указываемое в поле «bitclock» (ключ «-B»), на скорость программирования ожидаемо не влияет (в отличие от битбангового программера на FT232RL): ![]()
Таким образом, для того, чтобы собранный программатор превратился из бесполезной железки в полезный дывайс, рекомендую следующую последовательность действий:
• подключаем программер к камню LGT8F328P в соответствии со следующей схемой: ![]()
Обратите внимание на то, что если у китайского кирпича есть собственное питание (а по уму оно так и должно бы быть), подключать шину «+5.0V» программатора к камню не требуется. Кроме того, при отсутствии схемы согласования уровня сигналов (см. выше) питание LGT8F328P должно составлять +5,0В ![]()
Напомню, что «скорость программирования» может быть любой (она ни на что не влияет), но в правом окне секции «Programmer», должно всё-таки быть какое-то число, а не значение «х-», как это будет после запуска синапроги. Ну а далее жмем «кнопку-галочку» для открытия окна, отображающего процесс работы дудки, после чего пробуем найти китайский камень при помощи нажатия на кнопку «Search». Если всё было сделано верно, то кирпич найдется, а справа выведется следующее: ![]()
Причем, заметьте, там даже сигнатура правильная определяется, хотя, у LGT8F328P, судя по всему, нет даже такого понятия, как «сигнатура» (во всяком случае, меня поиск в официальном даташыте по фразам «1e» и «0f» ни к чему не привел); ![]()
Собственно говоря, на этом первый этап знакомства с микроконтроллерами LGT8F328P можно считать завершенным – мы получили аппаратную и программную базу для заливки в кирпич бинарного файла. Лично для меня это означает, что можно смело начинать изучение данных МК – по крайней мере, мы сможем прошить в чип результаты наших исследований и посмотреть, работают они или нет. Так что теперь имеет смысл разобраться с тем, как писа́ть программы для китайского камня, чему будет посвящен следующий пункт данной вводной заметки. Софт для написания программы
Теперь, когда мы можем заливать файлы прошивки в камни LGT8F328P, самое время разобраться с тем, как эти файлы формировать. Иными словами, неплохо было бы научиться писать программы для именно китайских кирпичей, причем, крайне желательно, чтобы софт при этом остался старым и привычным. И тут нас ожидает приятный сюрприз – во-первых, на уровне ассемблерных команд обычные меги и китайские МК полностью совместимы. Я специально потратил полдня, сравнивая мнемоники инструкций и их описание для LGT8F328P и для ATmega328P – совпадение практически 100%. Не полные 100% получились из-за того, что а) LGT не поддерживает команду записи данных во FLASH («SPM») и б) китайский документ – это всё-таки китайский документ. С записью данных ожидать другого было бы странно, если учесть особенности организации памяти у LGT8F328P (про это будет написана отдельная заметка). Ну а про качество китайских даташытов ходят легенды, и в нашем случае всё еще более-менее сносно – просто забыли про инструкции «SEH» и «CLH», продублировали описание для «LD», «LDD», «LDS», «NOP» и «SLEEP», ну и в нескольких местах указали не те флаги регистра статуса SREG, которые реально должны изменяться. ![]()
дабы убедиться в этом. Из представленной таблицы видно, что внутренний мир у китайца существенно богаче AVR-овского, но при этом для всех регистров Меги у камня LGT8F328P существует брат-близнец, расположенный по такому же адресу и имеющий такое же название. Да, есть некоторые расхождения в именах (все они на рисунке выше выделены красным), но единственное существенное несовпадение – это регистр, расположенный по адресу 0x57. В AVR-ках данная ячейка памяти управляет процессом записи данных во FLASH и носит название «SPMCSR». В камнях LGT вышеупомянутый процесс реализован при помощи специализированного контроллера E2PCTL, поэтому вроде как логично, что по адресу 0x57 у него располагается один из регистров данных этого контроллера (E2PD2), а не бесполезный для LGT8F328P регистр SPMCSR. Так что с учетом того, что в обычной AVR-ной программе (т.е. не в загрузчике) регистр SMPCSR вам вряд ли встретится, можно считать рассматриваемое несовпадение имен абсолютно некритичным. Что же до остальных «красных» ячеек, то там разница в названиях чисто декоративная и обусловлена наличием у китайских кирпичей более жирной периферии:
• EEDR / E2PD0 (адрес 0x40) – отличие, опять же, из-за наличия на борту китайца контроллера E2PCTL. Обратите внимание – при описании работы данного контроллера в режиме совместимости с AVR даташыт на LGT8F328P вовсю оперирует именно «старым» названием EEDR, а «новое» используется только в 32-битном режиме обмена. Таким образом, функционал рассматриваемых регистров в AVR и LGT идентичен, ну а в том, что одному адресу в ОЗУ МК соответствует два разных имени, нет ничего необычного;
Из приведенных выше фактов ясно, что для компилятора микроконтроллер ATmega328P (да и его «младшие» модели тоже) абсолютно ничем не отличается от камня LGT8F328P – те же самые инструкции производят те же самые операции над ячейками памяти с теми же самыми адресами (я, конечно, не проверял идентичность функционала всех битов во всех регистрах китайского камня, но выборочная проверка дала строго положительный результат). Поэтому очевидно, что код, написанный, собранный и откомпилированный под ATmega328P, можно вообще безо всяких переделок залить в LGT8F328P. Таким образом, ваш привычный софт для работы с AVR подойдет и к китайскому камню, так что переезжать на другую программную платформу вряд ли придется. Другое дело, что если в коде вообще ничего не трогать, то китаец сможет работать лишь от внутреннего генератора и только на дефолтной частоте 4МГц (если, конечно, в программе не меняется значение регистра CLKPR). Связано это с тем, что камни LGT8F328P, в отличие от AVR, не знают такого понятия, как «фузы», и тактовая частота кирпича (как и ее источник) устанавливается прямо в теле программы при помощи регистров ввода-вывода (см. ниже). Поэтому если вам захочется эту частоту поменять (или, например, тактировать камень от внешнего кварца), то придется общаться с данными регистрами, а для этого надо будет сообщить компилятору их адрес и (для наглядности) описать соответствующие биты. Конечно, в случае тактовой частоты таких регистров будет всего два, причем, один из них уже́ есть в ATmega328P – это CLKPR. Ну а уж для одного-то регистра прописать все нужные константы-определения можно тупо вручную прямо в теле основной программы. И точно так же можно поступать каждый раз при использовании «эксклюзивных» возможностей LGT8F328P: как только мы решили использовать какой-либо «нестандартный» регистр китайца (например, откалибровать опору АЦП), надо просто его объявить где-нибудь выше и в дальнейшем со спокойной душой пользоваться объявленным именем. Однако, гораздо удобнее воспользоваться готовыми файлами-определениями, где всем регистрам камня LGT8F328P уже́ присвоен необходимый адрес, а их битам – требуемые названия. И теперь осталось только понять, где взять эти готовые файлы.
• скачиваем файл с описанием регистров ввода-вывода LGT8F328P и их битов для древней AVR-Студии. Оригинал данного файла был создан Юрием Ревичем, взять его можно здесь. Отмечу, что рассматриваемый источник не является безупречным – даже такой новичок в плане LGT8F328P, как я, уже нашел в нем пару косяков (не были определены биты «EEPM3» и «EEPM2» в регистре EECR, не было внесено определение регистра E2PD0 и т.д.). Однако, с точки зрения «фундамента» автором была проведена большая работа, ну а небольшие огрехи можно исправить и самостоятельно;
.include "m328pdef.inc".
И если заменить ее на строку
.include "lg328Pdef.inc",
нам автоматически станут доступны все плюшки китайского камня (естественно, с поправкой на возможные косяки начального файла Юрия Ревича);
Если же вы пишете программы для камней AVR на Си, то могу дать лишь приблизительные рекомендации по переходу на LGT8F328P, поскольку с высокоуровневыми языками программирования я не особо знаком. В моем понимании, такой софт при выборе, например, камня ATmega328P по умолчанию подключит вам к проекту файл с определением регистров/битов для 328-й меги, и для обеспечения возможности работы с LGT8F328P нужно будет только добавить к нему «эксклюзивные» регистры китайца. Файл с описанием оных несложно нашарить в Интернете, однако, я рекомендую взять его из фирменного SDK, распространяемого изготовителем рассматриваемых камней (см. ниже). Если зайти в «…\LGTSDK_Builder_1.5beta29\SDK\LGT8F328P\inc», то можно найти аж шесть файлов-определений, относящихся к LGT8F328P, однако, нас в первую очередь интересует файл «lgt8f328p_spec.h» (если вы используете компилятор «AVR-GCC») или «lgt8f328p_ioavr.h» (если вы работаете с IAR-ом). Именно в них содержатся описание недостающих регистров и их битов, и именно их надо прикрутить к проекту после подключения стандартного файла 328-й Меги. В остальных файлах, насколько я могу судить, расположены куски кода, относящиеся к векторам прерываний, делителю тактовой частоты, выбору типа этой частоты и прочим вспомогательным вещам. Вообще говоря, вещи эти довольно полезны, однако, в простейших проектах, наверное, можно обойтись и без них. ![]()
Достаточно в этом окне просто щелкнуть на нужную функцию камня, как софт сразу же переносит нас в нужный раздел, где можно настроить соответствующий узел по своему усмотрению. Например, если нажать на прямоугольник с надписью «ADC0», в окне «Device View» отобразятся настройки модуля АЦП, где можно активизировать данный модуль, а также установить его требуемые характеристики (опора, тактовая частота, выравнивание результата и т.д.): ![]()
Но с другой стороны, если после завершения всех настроек щелкнуть на кнопку «Build», то начинают сыпаться сообщения «Invalid Argument» и «Clean Error». Наверное, в этом можно разобраться и как-то всё исправить, но я не думаю, что данный геморрой поспособствует росту интереса пользователя к камню LGT8F328P. С третьей стороны, нужные файлы с расширениями «*.c» и «*.h» «LGTSDK Builder» всё-таки генерит, так что, возможно, и есть смысл поковыряться в нем поподробнее. Ну и в любом случае – в состав пакета входят не только файлы, описывающие «эксклюзивные» регистры LGT8F328P и их биты (см. выше), но и исходники для работы с различными узлами китайского камня, учитывающие его специфику. Расположены они в папке «…\LGTSDK_Builder_1.5beta29\SDK\LGT8F328P\inc», и для тех, кто пишет на Си, вполне могут быть интересны хотя бы в качестве примеров. Нюансы работы с LGT8F328P
В завершение данной вводной заметки рассмотрим несколько ньюансов работы с микроконтроллерами LGT8F328P (естественно, не в «общем» смысле, а относительно кирпичей AVR). Сразу отмечу, что я в этом вопросе пока являюсь новичком, и особенностей у LGT8F будет явно побольше, чем упомянуто ниже. Однако, ньюансы, перечисленные в данном пункте, важны именно с точки зрения начинающего, ибо они касаются фундаментальных отличий камней, а без понимания этих отличий китайца даже на нужной тактовой частоте не запустишь. При этом следует понимать, что мой опыт работы с LGT8F328P ограничен лишь ассемблером, и в высокоуровневых языках различия камней вообще могут учитываться автоматически (см., например, фирменный SDK «LGTSDK Builder», упоминавшийся выше). Однако, даже в этом случае понимать разницу между китайцем и AVR-ками на аппаратном уровне будет нелишним. ▪ Отсутствие фузов
На мой дилетантский взгляд, прямо вот кардинальных отличий между пациентами три. Первое – отсутствие в китайском чипе такого понятия, как «FUSE». Все параметры и режимы работы камня, которые в AVR-ках устанавливаются при помощи фузов (тактовая частота кирпича, ее источник, уровень срабатывания BOD и т.д.), в LGT8F задаются прямо в теле программы на общих основаниях, т.е. при помощи регистров ввода-вывода. И это, на самом деле, просто охеренное решение, которое, с одной стороны, позволяет не выполнять «лишних» действий при прошивке МК, а с другой – исключает возможность превращения камня в настоящий кирпич путем записи в него неправильных фузов. Думаю, вы прекрасно знаете, как можно наглухо залочить чип AVR при помощи тех же битов «CKSEL[3:0]», особенно на первых порах, когда ты еще не в курсе, что «For all fuses “1” means unprogrammed while “0” means programmed.». В кирпичах же LGT8F328P этого нельзя сделать в принципе – камень всегда будет стартовать на «внутренней» частоте 4МГц, и только потом пользователь сможет установить разные значения ее предделителя и/или выбрать другой источник тактирования. ![]()
а управление данной системой осуществляется при помощи двух регистров PMCR и CLKPR: ![]() ![]()
Первый регистр включает/выключает разные источники тактирования, а также определяет, от какого из этих источников будут браться тактовые импульсы для ядра камня и для сторожевого таймера. Второй регистр позволяет при необходимости поделить эту частоту на 2/4/8/16/32/64/128/256, а также вывести результат деления в порт PB0 и/или PE5. Соответственно, чтобы кирпич заработал, например, на 32 мегагерцах от встроенного RC-генератора, регистр PMCR трогать не надо (там работа от «быстрых» внутренних часов прописана по умолчанию), а в CLKPR нужно записать нуль (чтоб делитель стал равен 1). А для того, чтобы тактироваться от внешнего кварца без предделителя, нужно установить биты «CLKSS» и «OSCMEN» в регистре PMCR, а CLKPR, опять же, обнулить. При этом следует помнить, что изменение содержимого PMCR и CLKPR производится несколько хитрее, чем обычно – сначала нужно установить бит №7 соответствующего регистра, и только потом можно писать в него требуемое значение. Причем, нужно обязательно успеть это сделать за 4 машинных такта – в противном случае старший бит автоматически сбросится, и дальнейшие попытки изменения содержимого регистра ни к чему не приведут. Именно поэтому в файлах «lgt8f328p_gcc.h» и «lgt8f328p_iar.h», входящих в состав программного пакета «LGTSDK Builder» (см. выше), куски кода, относящиеся к установке параметров системы тактирования, оформлены в виде ассемблерных вставок. Такой подход позволяет с гарантией успеть произвести запись требуемого значения в регистры PMCR и CLKPR до того, как бит №7 соответствующего регистра будет автоматически сброшен.
• «SUT[1:0]» – биты, определяющие задержку начала выполнения программы после того, как все источники сброса станут неактивны. Судя по всему, в LGT8328P аналогов у данных фузов нет. Во всяком случае, на всех картинках, где изображен процесс сброса, приводятся просто конкретные цифры, а не настраиваемое значение «tOUT»: ![]()
На рисунке выше показаны примеры работы схемы «POR» (сброс при включении питания) для LGT8328P (слева) и для обычной AVR-ки (справа). Примерно такие же картинки приводятся в китайской документации для внешнего сброса, для детектора пониженного напряжения (Brown-Out Detector) и для сторожевого таймера, только цифры на них будут другими. Отсюда я делаю вывод, что заморачиваться по поводу настраиваемой задержки при сбросе китайцы не стали, хотя, при дальнейшем изучении LGT8F328P, возможно, окажется, что это не так;
На этом рассказ про отсутствие фузов в LGT8F328P завершен. На мой взгляд, от этого отсутствия китайские камни абсолютно ничего не потеряли, а в ряде случаев даже приобрели. Единственный момент, где с этим можно хоть как-то поспорить, относится к фузам задержки включения SUT[1:0], однако, лично я никогда их не настраивал – просто ставил задержку на максимум и всё. Возможно, в будущем придется следить, чтобы скорость нарастания напряжения питания МК была пошустрее, но здесь никаких проблем я не вижу. Конечно, отсутствие фузов повлечет дополнительные затраты памяти на начальную конфигурацию кирпича, но с учетом того, сколько флэша есть на борту LGT8F328P, сокрушаться по данному поводу просто смешно. Зато все настройки камня будут находиться в коде программы, а не раскиданы одно здесь, другое там (сколько раз бывали ситуации, когда файл прошивки в наличии, а какие фузы шить – хер его знает). Ну и невозможность случайно убить камень неправильной установкой битов конфигурации тоже, на мой взгляд, весьма полезная фича. ▪ Отсутствие EEPROM
Перейдем к следующему существенному отличию китайцев от AVR – отсутствию EEPROM. Вообще говоря, организация памяти у LGT8F328P заслуживает отдельной заметки, но для начала работы будет достаточно и базовых сведений. Основной факт здесь – на борту китайского камня не существует «настоящей» памяти EEPROM, в качестве оной используется кусок общей FLASH-памяти кирпича. Причем, прелесть именно модели LGT8F328P состоит в том, что пользователь сам может выбрать размер данного куска, а может и вовсе оставить всю память МК под программу, если сохранять данные в EEPROM не нужно. Доступные комбинации размеров областей «FLASH» и «E2PROM» приведены на рисунке ниже: ![]()
Обратите внимание на то, что каждый килобайт памяти данных отожрет целых два килобайта памяти программ (пока нам не особо важно, почему так получается – просто запомним сей факт). Физически область «E2PROM» будет располагаться в самом конце флэша: ![]()
а адрес ее начала может быть вычислен как суммарный объем доступной FLASH-памяти минус удвоенный объявленный размер еепрома. Соответственно, для камней LGT8F328P с их 32 килобайтами флэша адрес «E2P_BEGIN» на рисунке выше может принимать следующие значения:
• 0x7800 (если размер области «EEPROM» равен 1КБ);
И вроде бы на первый взгляд здесь всё просто, однако, без нормального гайда при переезде с AVR на LGT8F могут возникнуть проблемы – какие регистры/функции использовать, где разместить данные и т.д. В китайской документации, как обычно, черт ногу сломит, да к тому же некоторых сведений в ней тупо нет (например, попробуйте найти адреса́, по которым будет располагаться выделенный вам кусок памяти EEPROM – лично мне пришлось выяснять это экспериментально). Поэтому ниже я коротко расскажу, как можно переделать код, написанный для обычной Меги и относящийся к данным пользователя, под камень LGT8F328P.
* – хер его знает, что это означает, ибо ни одна аббревиатура в даташыте не расшифровывается;
Исходники функций для работы китайских камней с EEPROM есть в папке «…\LGTSDK_Builder_1.5beta29\SDK\LGT8F328P\src» программного пакета «LGTSDK Builder»; файл «DrvEEPROM.c». Категорически рекомендую сравнить функции «DrvEEPROM_ProgByte» и «DrvEEPROM_ReadByte», находящиеся в этом файле, с подпрограммами записи/чтения байта в/из EEPROM, которые использует ваш софт. ![]() ![]()
При помощи регистра ECCR мы разрешаем использовать кусок общей памяти камня в качестве «EEPROM», а также задаем размер этого куска (см. биты «EEN» и «ECS[1:0]» соответственно). В регистре же EECR путем сброса флагов «EEPM3:0» мы должны установить 8-битный режим работы контроллера E2PCTL (только в этом режиме будет достигнута совместимость LGT8F с AVR). Обратите внимание на то, что перед внесением каких-либо изменений в регистр ECCR необходимо установить его старший бит «EWEN», и лишь затем можно будет записывать требуемое значение. Причем, сделать это нужно в течение 6 машинных тактов, иначе бит «EWEN» автоматически сбросится, после чего попытки изменения содержимого ECCR ни к чему не приведут. Кроме того, для корректной работы контроллера E2PCTL в 8-битном режиме требуется, чтобы биты «CP1» и «CP0» были установлены (вообще говоря, это их состояние по умолчанию, но я решил-таки заострить внимание на данном моменте, дабы вы их случайно не сбросили). ![]()
(для языка «Си» рекомендации будут даны ниже). На приведенной картинке кусок кода для EEPROM тупо скопирован в конец программы, а директива «.ORG» указывает на адрес, с которого будет начинаться этот кусок во FLASH-памяти. Значение «7800» в данной директиве говорит нам о том, что размер области «EEPROM» в проекте был выбран равным 1КБ (выше приводились адреса́ начала еепрома для всех возможных его размеров в камне LGT8F328P). Деление же этого адреса́ на два необходимо из-за того, что память программ в кирпичах AVR и LGT8F имеет 16-разрядную, а не побайтовую организацию.
…
то есть, переписывать придется все строки, содержащие имена соответствующих ячеек памяти. Правда, этого геморроя можно избежать, если переименовать переменную, например, в «ee_Current_H1», после чего вручную прописать
.equ ee_Current_H = ee_Current_H1*2
но здесь тоже предстоит писанина, и не факт, что ее будет меньше. Во-вторых, если для объявления двухбайтовых переменных вы используете директиву «.DW» (что, в общем-то, более правильно), можете радоваться – в сегменте «.cseg», точно так же, как и в сегменте «.eseg», первым в памяти будет расположен младший байт, так что здесь ничего менять не потребуется. Но, в-третьих, для всех однобайтовых переменных придется выбирать – либо мы экономим память и в ряде случаев теряем возможность использования прямого имени переменной, либо оставляем всё, как есть, что приведет к избыточному расходованию флэша. Чтобы было понятней, поясню. В примере, приведенном на рисунке выше, все переменные являются однобайтовыми, поскольку для их объявления используется директива «.DB»*. Поэтому при компиляции проекта для каждой строки области «EEPROM» будет выведено предупреждение – мол, вы пытаетесь забить память программ байтами, а она организована пословно, поэтому неиспользованный байт в каждом слове мы заполним нулём. В итоге под 6 переменных будет отведено целых 12 байт памяти, что увеличит расход флэша вдвое, однако, при этом мы сможем напрямую использовать имя каждой переменной, т.к. все метки сохранились. В качестве альтернативы можно рассмотреть вариант, при котором все ячейки памяти будут заполнены «полезной» информацией – для этого надо просто записать по два/четыре/шесть… значений переменных в одной строке, например, вот так: ![]()
При таком подходе все предупреждения компилятора исчезнут, а переменные займут в памяти положенные 6 байт, однако, к половине из них нельзя будет обратиться напрямую по имени, т.к. соответствующие метки пропали. Какой вариант инициализации памяти выбрать в итоге – решать вам, всё зависит от вашего стиля написания кода программы. Например, мне намного больше нравится первый подход, поскольку я активно использую имена переменных, и количество исправлений из-за отсутствия половины имен у меня будет значительным. Поэтому мне проще распрощаться с небольшим «лишним» куском памяти – с учетом того, что под данные пользователя в камне LGT8F328P можно отвести аж 8КБ, а суммарный объем его флэша составляет 32КБ, такая расточительность не особо напрягает. Необходимо только помнить, что при этом каждая переменная в области «EEPROM» будет занимать не один байт (как это задумывалось изначально), а два – это нужно учитывать, например, при работе с массивами и целыми блоками данных в еепроме. Однако, если вы привыкли работать с двухбайтными переменными как именно с двухбайтными, то, возможно, есть смысл рассмотреть второй подход к инициализации области «EEPROM».
* – я привык отдельно объявлять старший и младший байты двухбайтной переменной, хотя, повторюсь, правильней было бы столбить под нее сразу целое слово при помощи директивы «.DW».
Это что касается ассемблера. Совсем другие расклады будут, если вы пишете на Си. Там, со слов коллеги, данные, располагаемые в памяти EEPROM, объявляются и инициализируются как обычные переменные, только с атрибутом «EEMEM» (на примере связки «avr-gcc» + «Eclipse»):
#include <avr/eeprom.h>
При этом программисту вообще похер, по каким адресам в памяти будут лежать эти данные – там при сборке проекта комп сам со всем разберется. Поэтому когда встал вопрос о переносе данных пользователя из EEPROM во FLASH, коллега только почесал репу – мол, я не знаю, как это сделать. Пришлось затеять расследование, в результате которого оказалось, что под переменные еепрома создается отдельная секция «.eeprom» (см. файл «avr/eeprom.h»):
#define EEMEM __attribute__((section(".eeprom")))
и если при объявлении данных перед их именем указано «EEMEM», то для компилятора и линковщика они будут ассоциироваться именно с энергонезависимой памятью, а не с ОЗУ. Проблема заключается в том, что при сборке проекта все эти переменные отправятся в отдельный файл с расширением «.eep», и как перенаправить их во FLASH, т.е. в HEX-файл, мы так и не нашли. Однако, было установлено, что если определить свою собственную секцию данных, то вот ее можно расположить в любом месте памяти программ, главное – не забыть сообщить об этом линкеру. И в итоге рабочий алгоритм по созданию инициализированной области «EEPROM» в камне LGT8F328P будет выглядеть следующим образом (опять же, на примере связки «avr-gcc» + «Eclipse»):
• определяем в программе собственную секцию для хранения данных пользователя (по аналогии с EEMEM/eeprom):
#define E2PROM __attribute__((section(".e2prom")))
• объявляем/инициализируем требуемые переменные, которые должны быть ассоциированы с созданной секцией:
uint8_t E2PROM value1 = 0x00;
• говорим линкеру, с какого адреса во FLASH-памяти должна начинаться созданная секция. Делается это при помощи опции (ключа) «-Wl»; для области «EEPROM» размером 1КБ заветная фраза будет звучать так:
-Wl,--section-start=.e2prom=0x7800
(для размеров 2КБ/4КБ/8КБ значение «0x7800» нужно заменить на 0x7000/0x6000/0x4000 соответственно). Однако, тут нужно знать, куда именно вставить эту заветную фразу. В «Эклипсе» она прописывается в общих свойствах линкера (на рисунке ниже фраза выделена синим) ![]()
а вот насчет других сред программирования сказать ничего не могу – предлагаю вам разобраться в данном вопросе самостоятельно.
В результате выполнения вышеперечисленных действий, после компиляции и линковки в код вашей программы добавятся значения всех переменных, у которых есть атрибут «E2PROM». Располагаться они будут, начиная с адреса 0x7800 (или какой вы там указали) – в этом можно убедиться, просмотрев файл с расширением «.lss». То есть для того, чтобы переделать существующий AVR-овский проект под китайский кирпич, вам просто понадобится определить секцию «.e2prom», заменить все «EEMEM» на «E2PROM» и сказать линковщику, откуда должна начинаться новоиспеченная секция. Никаких удвоений адресов и еботни с укладыванием в память однобайтовых переменных (как в случае с ассемблером) не потребуется – комп сам со всем разберется. И это, наверное, первый раз в жизни, когда я действительно ощутил пользу от языка «Си». ▪ Таблица векторов прерываний
Третье серьезное отличие камней LGT8F328P – размер таблицы векторов прерываний: ![]()
1 – при запрограммированном фузе «BOOTRST» вектор сброса будет располагаться в начале загрузчика.
Как следует из данного рисунка, у китайских кирпичей таблица больше, чем у AVR-ок, и включает в себя прерывание от дополнительного компаратора AC1, от таймера/счетчика T3, а также от «недостающих» портов ввода-вывода (отметим, что вектор PCI4 относится к портам PF0…PF7, которые в корпусе TQFP-32 отсутствуют). При этом для меня несколько странен тот факт, что прерывание ANA_COMP1 введено взамен прерывания SPM READY, а следующая строка в таблице тупо не используется. Вроде бы, логичнее было перекинуть компаратор в вектор #27, а неиспользуемым сделать вектор #26, но разработчикам, конечно, виднее (к тому же, прерывание по готовности памяти программ обычно юзается только в области загрузчика, а у китайцев такой области просто нет). Однако, если в «обычной» программе для AVR вы для каких-то целей используете прерывание SPM READY, об этой особенности таблицы векторов LGT8F328P следует помнить (как и об отсутствии в ней данного прерывания как такового).
* – если, конечно, речь не идет о камне ATmega328PB, но он вообще стоит особняком, и в качестве «обычной» Меги его рассматривать не сто́ит. ▪ Прочие отличия
Остальные попавшиеся мне отличия китайских камней от AVR-ок не столь фундаментальны, но не менее интересны. Конечно, мое знакомство с LGT8F328P только-только начинается, но и того, на что я успел наткнуться, уже́ с лихвой хватит для принятия решения о переезде на китайца (даже если не обращать внимания на то, что он тупо дешевле):
• максимальная частота работы у LGT8F328P составляет 32МГц при любом напряжении питания, в то время, как у AVR – всего 20МГц и только при Vcc = +5,0В. Да, я знаю, что про это уже́ говорилось выше (собственно, с этого и начиналась заметка), но упомяну данные фичи еще раз, ибо прирост скорости работы камня на 60% – неплохой, мягко говоря, аргумент в пользу китайца;
И в завершение данного пункта хотел бы обратить ваше внимание на следующее. В большинстве случаев увеличенная скорость выполнения инструкций китайцем – это, конечно, благо. Однако, есть ряд задач, где критична длительность определенных временных интервалов, и если команды выполняются быстрее, программа будет работать некорректно. Например, у меня есть AVR-овский проект, формирующий на выходе импульсы с точной задержкой относительно входных, так там всё завязано на количество машинных тактов, которое требуется для выполнения инструкций SBI/CBI/LD/RJMP и т.д. И если данный проект портировать на LGT8F328P, код программы придется переделывать, иначе задержки будут неверными. Конечно, дописать несколько NOP-ов – это не проблема; гораздо сложнее было бы решить обратную задачу (сформировать такие же задержки на более укуренном кирпиче). Однако, сама по себе эта особенность при переезде на китайца может всплыть, поэтому упомянуть о ней следовало.
Обсудить эту заметку можно в
Телеге или в
ВК
|
Место для разного (сдается) |