USB программатор PIC из Arduino

В предыдущей моей статье про программатор spi flash и ic eeprom из arduino после её публикации самый первый вопрос-комментарий был «программирует ли он PIC-и?». Вопрос, конечно, от невнимательного читателя, но он лишний раз подтвердил, что, хоть микроконтроллеры PIC довольно старые, но до сих пор ещё пользуются большим интересом у радиолюбителей, так как за долгое время было разработано огромное количество устройств на их базе. Но вот прошивать эти микроконтроллеры — то ещё приключение. Как известно для PIC-ов есть множество различных программаторов: простейшие, типа несколько проводков для LPT или COM портов (типа JDM и других), USB программаторы (PICKIT1,2,3 и их самодельные клоны). У обоих видов есть свои плюсы и минусы: первые — очень просты в сборке, но требуют наличия соответствующих портов, которые не всегда есть в современных ПК, а тем более в ноутбуках. Вторые — очень удобно использовать, так как они подключаются по USB, их можно подключать к любому современному и не очень ПК/ноутбуку, но! у них тоже есть весомый недостаток — они не очень дешёвые (даже на известном китайском маркетплейсе PICKIT2 стоит порядка 15-20$, а микроконтроллер PIC18F2550 для сборки самодельного PICKIT2 порядка 10$ и то не факт, что не нарвётесь на подделку/перемаркировку/горелку). Не каждый начинающий и даже более опытный радиолюбитель захочет покупать такой программатор, если ему он может пригодиться раз-два в год. 

Так вот, после того самого комментария у меня возник спортивный интерес, смогу ли я сделать свой программатор для PIC-ов? Тем более, ранее я уже пытался «бороться» с этими микроконтроллерами. И скажу честно, у меня в первый раз не получилось ничего, от слова «совсем». Даже ID PIC16F73 не смог прочитать. Но уже тогда я понял, что эта задача — крайне сложная. Даже не из-за моего неудачного опыта. Просто я почитал несколько «Programming datasheet» на разные линейки PIC-ов и был просто в ужасе: оказалось что у этих «камней» куча подсемейств, состоящих от 1-2 представителей до нескольких десятков. И таких подсемейств — просто огромное количество. А самое интересное, что все они программируются по разному: у некоторых всего 6-8 команд, а в некоторые вообще нужно пихать ассемблерные коды через программатор! Единственное, что их объединяет — это название пинов для подключения программатора (PGC, PGD, PGM и MCLR). На этом сходства заканчиваются. Даже, например, PIC16F84 и PIC16F84A или PIC16F628 и PIC16F628A в плане программирования — это совсем разные «камни»! Но и это ещё не всё!!! Вторая, не менее важная проблема — это HEX-файлы для PIC-ов. У них тоже нет никакого стандарта! В одном единственном файле располагается CODE сегмент (т.е. основная программа), DATA сегмент (т.е. EEPROM) и слова конфигурации. А самое смешное, что у каждого подсемейства все эти сегменты располагаются по разным адресам смещения и количество конфигурационных слов — тоже у всех разное. Наверное, после этого до меня дошло, почему PICKIT такой дорогой? Это ж у программиста может съехать крыша в попытках хоть как-то стандартизовать алгоритмы программирования такого «приятного разнообразия». Представляю, как инженеры Microchip в своё время вели разработку: «А давайте, следующая линейка будет программироваться не командами, а ассемблерными кодами ядра и желательно развёрнутыми задом-наперёд… А что? Нечего программистам расслабляться». 

 Но вот, прошло некоторое время, у меня появились свои наработки в плане программного обеспечения и схемотехники, и я решил попробовать снова побороть PIC-и. Накидал в голове приблизительный алгоритм, как можно более-менее унифицировать софт. А также продумал «железную» часть программатора. С описания которой я, пожалуй, и начну.

За основу программатора я решил взять пятивольтовый микроконтроллер, так как логические уровни большинства PIC-ов именно 0 — 5 вольт (не считая PIC24, dsPIC, но о них я даже и думать не хотел). Я мог взять что-то очень дешёвое, типа STC8, но решил, что они не очень популярны и сделал свой выбор в пользу AVR. Тем более, что они используются в известнейших платах arduino, которые найдутся в загашниках почти любого радиолюбителя, да и стоят не очень дорого (относительно). Но одной лишь платы arduino или микроконтроллер AVR для программирования PIC-ов будет недостаточно. Наверное, многие знают, что микроконтроллеры PIC (большинство PIC16, PIC18) используют высоковольтное программирование, т.е. для входа в режим программирования необходимо подавать на определённый пин (MCLR) повышенное напряжение 12-13 вольт. Нужен дополнительный источник повышенного напряжения и схема управления подачей этого самого напряжения. Так вот, в первом варианте схемы я решил использовать повышающий преобразователь напряжения на микросхеме MC34063A, чтобы питать программатор исключительно от USB. И он заработал!!! Но радость «победы» длилась недолго. Программатор читал прошивку, читал ID, конфигурационные биты, но упорно отказывался стирать/записывать. В Programming datasheet я увидел, что операции записи/стирания требуют напряжения питания VDD 4,5-5,5 вольт. Я решил померять напряжение VDD во время процесса чтения и получил огромную просадку до 3,8 вольта. Естественно, при такой просадке о записи/стирании и речи идти не могло. Поэтому, я решил отказаться от идеи с преобразователем напряжения в пользу дополнительного источника питания 12 вольт. И это дало результаты — с внешним источником 12 вольт процессы стирания и записи пошли! В итоге уже второй вариант схемы — стал окончательным. Схема получилась очень простая. Я не стал использовать буферных элементов на дискретной логике, а сделал ключи управления напряжениями VPP и VDD (12в и 5в) на транзисторных ключах (2 каскада каждый). Также в схеме используется линейный стабилизатор на 5 вольт (7805). Стабилизацию по 12 вольтам я решил не ставить, так как боялся, что некоторые PIC-и могут потребовать более высокое напряжение (12,5-13,5 вольт) и с установленным стабилизатором типа 7812 поменять напряжение VPP уже не получится. В итоге, получилось не очень сложная схема. Под силу даже новичку с советским паяльником толщиной с палец:

Схема USB программатора PIC из Arduino

Выглядит как-то так (все детали в SMD исполнении, расположены на нижней стороне платы):

USB программатор PIC из Arduino

На фото — первый вариант платы, я его показываю исключительно для наглядности, как можно скомпоновать плату-шилд для arduino nano.

Окончательный вариант своего программатора я сделал в виде отдельной платки с ATmega328P. Схема её следующая:

Я не рисовал ключи управления напряжениями на этой схеме, иначе бы она заняла  пол экрана. Здесь изображена схема подключения атмеги к USB-UART конвертеру и ключам управления напряжениями. Моя окончательная плата программатора выглядит следующим образом (сразу извиняюсь за остатки флюса и ваты, которой я пытался отмыть флюс):

Платка получилась достаточно компактная, всего 44х47 мм, это всё благодаря миниатюрной микросхеме USB-UART преобразователя CH340E, которая к тому же не требует подключения кварцевого резонатора и атмеге в корпусе TQFP32, которая тоже занимает места не очень много. Линейный стабилизатор и вся мелочёвка также в SMD исполнении. Кстати, транзисторы я использовал Q1,Q2 — MMBT3904 (маркировка корпуса 1AM), Q3,Q4 — BC856 (маркировка корпуса 3B). Рисунок своей печатной платы я выложу в конце статьи. Хотя, плату каждый может сделать под имеющиеся компоненты. Кстати, при наличии у USB-UART преобразователя сигнала DTR, его необходимо повесить на пин RESET атмеги через конденсатор 0,1uF, чтобы работал автоматический сброс при программировании атмеги через UART bootloader. Как раз у CH340E этого сигнала нет и приходится сбрасывать атмегу вручную кнопкой.

Теперь поговорим о софте. Программу для ПК я традиционно написал в среде MS Visual Studio на C#. Внешний вид первой версии программы такой:

Интерфейс программы, думаю, не окончательный, потому что я не в силах предугадать, какие ещё параметры могут быть у каких либо семейств PIC и что надо добавить/убавить. Будет видно потом, в ходе добавления новых МК.

Как видите, есть два больших текстовых поля с данными CODE (верхнее) и DATA (нижнее) сегментов прошивки. Семь текстовых полей для слов конфигурации (брал за максимум PIC18F4550). Поле выбора модели PIC. Куча кнопок с интуитивно понятными по названиям функциями. В нижнем правом углу — текстовое поле для вывода информации. Три поля «Oscal» делал про запас, они пока никак не задействованы, но знаю что в 8-ногих пиках есть байты калибровки RC-генератора, которые можно случайно затереть, поэтому — могут пригодиться.

Работать с программой очень просто: подключаем программатор к USB. Должен появиться COM порт. В верхнем правом углу программы выбираем COM, на котором висит наш программатор (если программатор был подключен после запуска программы, то надо нажать кнопку «Scan» для получения списка доступных портов) и нажимаем кнопку «Open», если всё правильно, она должна стать зелёной и появится соответствующее сообщение в консоли внизу справа. Чтобы проверить, отзывается ли программатор, нажимаем кнопку «Check», в консоли должно появиться сообщение «Программатор подключен». Дальше надо выбрать модель PIC в окошке «Device». И только после этого можно читать, писать, стирать. Есть некоторые особенности работы с конфигурационными словами: при загрузке HEX-a они автоматически вставляются в соответствующие окошки (Config1 — Config7), при нажатии кнопки «Write» они будут записаны автоматом после CODE и DATA сегментов, либо при нажатии кнопки «WR Cfg» они запишутся отдельно. Но значение Config-ов пишутся не напрямую из HEX-а, а именно из этих окошек, то есть если после открытия HEX-файла переписать свои корректные значения в эти окошки, то будут записаны именно они. 

Так как программа очень сырая, многие исключения в ней не обрабатываются, то есть, если сделать что-то неверно, программа вылетит с ошибкой. Например, если выбрать модель PIC и открыть HEX для совершенно другой модели. Или вписать некорректные значения в окошки Config (кириллицу или не 16-ричные знаки не «0-9,A-F»).

Что касается скорости работы программатора, то она — вполне достойная. Конечно, скорость чтения/записи зависит от модели PIC. Но если взять PIC18F4550 как наиболее «жирный» из уже поддерживаемых, то скорость чтения около 2 Килобайт в секунду, запись, естественно, чуть медленнее. При 32 Килобайтах CODE сегмента время чтениязаписи не напрягает.

Программу я старался написать таким образом, чтобы она была универсальна для любого семейства PIC, и не требовала никаких изменений при добавлении поддержки новых моделей. Для добавления новых устройств используется файл настроек («pic.xml»), который находится в папке с программой. В нём содержатся однотипные структуры с необходимыми параметрами микроконтроллера, которые программа использует в первую очередь для разбора HEX-файла. Таким образом работа по добавлению новых моделей PIC ведётся в файле настроек и в большей степени в прошивке атмеги. Вид файла настройки следующий:

  <name model="PIC16F628A"> 	<id>0x1060</id> 	<type>2</type> 	<f_size>4096</f_size> 	<f_psize>1</f_psize> 	<ee_size>128</ee_size> 	<f_start>0</f_start> 	<ee_start>002100</ee_start> 	<ee_type>0</ee_type> 	<conf1>002007</conf1> 	<conf2>none</conf2> 	<conf3>none</conf3> 	<conf4>none</conf4> 	<conf5>none</conf5> 	<conf6>none</conf6> 	<conf7>none</conf7> 	<oscal1>none</oscal1> 	<oscal2>none</oscal2> 	<oscal3>none</oscal3> 	<delay>4</delay> 	<word>3FFF</word>   </name>

Как видите, параметров много, хотя если сравнить с подобным файлом настроек программатора K150, то и не особо.

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

Что касается прошивки атмеги. Никаких скетчей для arduino вы не увидите, вопреки названию статьи. Код написан на Си. Для написания кода я использовал среду Eclipse с плагином для AVR (использует AVR-GCC, точно такой же как и Atmel studio). Поэтому все *.h и *.c файлы проекта могут быть спокойно перенесены в Atmel studio без изменений. Также можно с минимальными изменениями перенести код на другие модели AVR с бОльшим объёмом флеш памяти (например, ATMEGA64, ATMEGA128 и др.). Из специфических функций там только USART (настроен на скорость 57600, передача и приём плюс прерывание по приёму байта). И то модуль USART у большинства атмег почти одинаковый, достаточно подправить названия регистров (например UDR на UDR0, UCSR0A на UCSRA и т.д.). Все остальные функции — реализованы с помощью «ногодрыга». Настройка пинов PGD,PGC,PGM,VPP и VDD реализована с помощью макросов:

 #define PGD_PIN		1		//D9 #define PGD_PORT	PORTB #define PGD_DDR		DDRB #define PGD_IDR		PINB #define PGC_PIN		2		//D10 #define PGC_PORT	PORTB #define PGC_DDR		DDRB #define PGM_PIN		0		//A0 #define PGM_PORT	PORTC #define PGM_DDR		DDRC #define VDD_PIN		7		//D7 #define VDD_PORT	PORTD #define VDD_DDR		DDRD #define VPP_PIN		6		//D6 #define VPP_PORT	PORTD #define VPP_DDR		DDRD  #define PGD_HIGH	PGD_PORT |= (1 << PGD_PIN); #define PGC_HIGH	PGC_PORT |= (1 << PGC_PIN); #define PGM_HIGH	PGM_PORT |= (1 << PGM_PIN); #define VDD_HIGH	VDD_PORT |= (1 << VDD_PIN); #define VPP_HIGH	VPP_PORT |= (1 << VPP_PIN); #define PGD_LOW		PGD_PORT &= ~(1 << PGD_PIN); #define PGC_LOW		PGC_PORT &= ~(1 << PGC_PIN); #define PGM_LOW		PGM_PORT &= ~(1 << PGM_PIN); #define VDD_LOW		VDD_PORT &= ~(1 << VDD_PIN); #define VPP_LOW		VPP_PORT &= ~(1 << VPP_PIN);

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

Прошить сам программатор HEX-файлом можно двумя способами: любым программатором для AVR, если это чистая атмега или с помощью программ для загрузки HEX-а в arduino, таких как XLoader, ArduinoUploader и других (можно найти, например, тут. Это не реклама стороннего сайта!). 

На данный момент прошивка занимает 5 Килобайт с небольшим из 30 доступных в ATMEGA328Р (2 Кб занимает bootloader arduino). Так что места ещё навалом, можно добавить поддержку многих семейств.

Теперь — самое главное. Поддержку каких камней удалось добавить? Скажу сразу, пока — не густо. Так как пока что от начала разработки до момента написания статьи прошло около недели, и то я вёл разработку в свободное время, на данный момент добавлена поддержка и проверена работа (с реальным устройством на данном МК) PIC16F628A (в его подсемействе есть ещё два камня 627A и 648A). PIC16F73 (проверена работа методом сравнения прочитанного и записанного с референсным JDM программатором), у этого «камня» есть ещё три одногрупника (F74, F76, F77). Также добавлена поддержка и проверена работа с PIC18F4550, добавлен PIC18F2550 (так как это в плане программирования одно и то же). Единственное, не смог победить чтение ID у этого семейства, возможно, мой экземпляр работает некорректно. У последних двух «камней» в одногрупниках — несколько десятков МК, поддержку которых легко сделать всего лишь правкой конфигурационного файла без изменения прошивки атмеги. Должны работать, но мне пока не на чем проверить.

В ближайших планах добавить поддержку таких старичков как PIC16F84A и его одногрупников (так как он у меня есть для тестов), PIC16F87X. Дальнейшая поддержка будет зависеть от интереса к устройству и, возможно, помощи в тестировании программатора. Так как мне одному не под силу и не по карману сделать это самому (покупать разнообразные PIC-и только для тестов). 

На этом пока всё. Спасибо за внимание. Адекватная критика в комментариях приветствуется.

Список радиоэлементов

Обозначение Тип Номинал Количество Примечание Магазин Мой блокнот
Схема №1 (на arduino nano)
U1 Плата Arduino Arduino Nano 3.0 1
Q1, Q2 Биполярный транзистор КТ3102 2
Q3, Q4 Биполярный транзистор КТ502Е 2
U2 Линейный регулятор LM78M05 1
D1 Диод Шоттки 1N5819 1
R1-R4 Резистор 1 кОм 4
R5, R6 Резистор 4.7 кОм 2
R7, R8 Резистор 10 кОм 2
C1, C2 Конденсатор 0.1 мкФ 2
Схема №2 (на atmega328p)
U1 Микросхема CH340E 1
U2 МК AVR 8-бит ATmega328P 1
D1 Диод Шоттки 1N5819 1
Led1 Светодиод любой 1
C1 Конденсатор 0.1 мкФ 1
C2, C3 Конденсатор 16 пФ 2
R1 Резистор 560 Ом 1
R2 Резистор 10 кОм 1
XT1 Кварцевый резонатор 16MHz 1
KEY1 Тактовая кнопка любая 1