Параллельный программатор / фьюз-бит доктор для контроллеров avr
Получив из Китая очередную партию чипов ATtiny2313 для изготовления шлюзов UART-to-I2C/SPI/1W я, вдруг, обнаружил, что эти чипы совершенно невозможно прошить последовательным внутрисхемным (ICSP) программатором. Чипы при этом были в заводской упаковке и без следов пайки. Ранее я уже сталкивался с ситуациями, когда китайцы продавали новые рабочие чипы, но заранее прошитые под какие-либо устройства (например, — вот). Такие чипы прошивают нужной прошивкой прямо на заводе, но, видимо, время от времени случаются накладки, заказчик не забирает партию и чипы попадают в открытую продажу.
Ситуация в общем-то обычная, сложность же конкретно с контроллерами AVR заключается в том, что при сбросе определённых фьюзов, прошить контроллер становится возможно только параллельным программатором в режиме высоковольтного программирования (с использованием напряжения +12 Вольт). Схемы фьюз-докторов для AVR можно найти в интернете, однако минус всех этих схем заключается в полном отсутствии описания их работы. Выложена просто готовая прошивка, которую нужно залить в управляющий схемой контроллер, включить, нажать кнопку и будет вам счастье. Ни исходников, ни подробностей, вообще никаких объяснений.
Для меня, как для радиохламера, такой подход совершенно невозможен и невыносим, поэтому решено было разработать свой собственный программатор / фьюз-бит доктор для микроконтроллеров AVR, описать как он работает и выложить в открытый доступ не только прошивку, но и исходники программы для микроконтроллера с комментариями. Итак, поехали:
В любом даташите на микроконтроллеры AVR есть глава «Memory Programming». Если микроконтроллер поддерживает параллельное программирование (здесь и далее в этой статье под этим термином понимается заливка прошивки в микроконтроллер), то в этой главе есть раздел «Parallel Programming». В этом разделе, во-первых, описано какие сигналы и ноги используются при параллельном программировании, во-вторых, описаны используемые при этом команды и алгоритмы и, в третьих, приводятся диаграммы сигналов. В общем, — всё, что нужно для успеха операции.
Для начала разберёмся с сигналами. Сигналы используются следующие:
- 8 сигналов для параллельного приёма/передачи байта данных DATA[7:0]. Сигналы передаются в обоих направлениях в зависимости от сигнала OE.
- 9 служебных сигналов:
- RDY/BSY — уровень на этой линии сигнализирует о готовности контроллера принимать новые команды. Данные передаются от контроллера к программатору
- OE — служит для переключения линий данных на вход (высокий уровень) или на выход (низкий уровень)
- WR — используется для старта выполнения каких-либо действий (стирание / запись …)
- BS2, BS1 — эти две линии используются для выбора старших или младших байт
- XA1, XA0 — по уровням на этих двух линиях определяется какое действие будет выполняться по наличию тактового импульса
- PAGEL — используется при программировании Flash/EEPROM
- XTAL1 — используется для подачи тактовых импульсов
Кроме этого нам потребуется напряжение +12 Вольт (для перехода в режим программирования), +5 Вольт — для питания контроллера, ну и естественно нужно будет подключить нулевой провод, относительно которого задаются +12 и +5 Вольт, к ноге GND.
В некоторых контроллерах какие-то сигналы могут быть объединены (например, в ATtiny2313 объединены ноги BS1 и PAGEL, а также XA1 и BS2), кроме того, могут отличаться номера ног, на которые заводятся эти сигналы (например, в ATmega8 для данных используются два младших бита порта C и 5 младших бит порта B, а в ATtiny2313 для данных используется только порт B целиком).
С алгоритмами тоже всё оказалось довольно просто, — вся задача сводится к выставлению нужных уровней на некоторые служебные линии (XA1, XA0, BS2, BS1, OE) и линии данных, а также к генерированию положительных или отрицательных импульсов на других служебных линиях (XTAL1, WR, PAGEL). Плюс нужно управлять питанием +5 Вольт (+1 линия) и напряжением +12 Вольт (ещё +1 линия). Управление всеми нужными линиями решено было сделать командами через UART (для этого нужно ещё 2 линии).
Исходя из всего выше описанного, для реализаци устройства нужно иметь 21 линию I/O (8 — данные + 9 — служебные сигналы + 2 — управление линиями +5 и +12 Вольт + 2 — uart), что, согласитесь, довольно много. Чтобы ног на всё хватило, в качестве управляющего контроллера была выбрана ATmega8 (для прототипа, естественно, в dip-корпусе), — у неё 23 линии I/O.
Справа на схеме нарисовано как подключать к ней микроконтроллеры ATtiny2313.
Места печатной платы для которых показаны связи, но отсутствуют медные дорожки, должны быть соединены изолированными проводами, навесным монтажом (ниже будет фото собранной платы). При разработке печатной платы прототипа основным параметром оптимизации было удобство изготовления и сборки, поэтому плата выглядит достаточно громоздко, имеет кучу навесных перемычек и откровенно уродливый вид. Как я уже говорил, плюсы этой платы заключаются в другом:
- разводка выполнена для одностороннего текстолита (не нужно совмещать разные стороны при переносе рисунка на плату)
- использован контроллер в dip-корпусе (возможность установки в кроватку + большие расстояния между ножками обеспечивают лёгкость пайки)
- все нужные контакты выведены на линейки с большим шагом (2,54 мм)
- есть разъём для внутрисхемного программирования управляющего контроллера (для отладки очень удобно прошивать контроллер прямо на плате, не вынимая из кроватки)
При разводке платы я также предусмотрел установку конденсаторов по линиям питания +5 и +12 Вольт (прямо рядом с разъёмом питания). Эти конденсаторы на схеме не нарисованы, но я решил их на всякий случай поставить. Большого тока схема не потребляет, поэтому будет достаточно конденсаторов на 10-47 мкФ, рассчитанных на максимальное напряжение 16-25 Вольт и выше.
После сборки устройство выглядит вот так:
В соответствии с приведёнными в даташитах алгоритмами и диаграммами наш программатор должен уметь делать следующие вещи:
- переходить в режим программирования
- устанавливать и считывать уровни на линиях DATA[7:0]
- выставлять правильные уровни на линиях XA1, XA0, BS2, BS1, OE
- генерировать импульсы заданной ширины на линиях WR, XTAL1, PAG
Учитывая, что переходить в режим программирования нужно из какого-то начального состояния, а также то, что линия PAG может быть совмещена с BS1, — для реализации заявленного выше функционала нам хватит всего 11-дцати UART-команд, которые я просто пронумеровал от 0x1 до 0xB:
- 0x01 — установить все используемые для программирования выводы (включая выводы, управляющие линиями +5 и +12 вольт) в начальное состояние
- 0x02 — выполнить алгоритм перехода в режим программирования
- 0x03 — выполнить алгоритм выхода из режима программирования
- 0x04 — установить нужное состояние на линиях XA1/XA0 и BS2/BS1
- 0x05 — установить нужное состояние на линии OE
- 0x06 — сформировать положительный импульс на линии BS1
- 0x07 — сформировать положительный импульс на линии PAG
- 0x08 — сформировать положительный импульс на линии XTAL1
- 0x09 — сформировать отрицательный импульс на линии WR
- 0x0A — установить нужные уровни на линиях Data[7:0]
- 0x0B — прочитать состояния линий Data[7:0]
Теперь некоторые моменты обсудим более детально:
Во-первых. В даташитах написано, что перед переходом в режим программирования нужно установить сигналы XA1, XA0, BS1 и WR (они называются Prog_enable) в ‘0000’. Поскольку сигнал на линии WR инвертирован (active low) и далее на всех диаграммах он начинается с высокого уровня, то логично было бы предположить, что его начальное состояние — это высокий уровень (именно он для него означает 0). На деле оказалось, что это работает только после подачи питания, а до подачи питания для всех ног 0 — это низкий уровень, и перед переходом в режим программирования все ноги, входящие в группу Prog_enable должны быть притянуты к низкому уровню.
Сам алгоритм перехода в режим программирования банален, — после того, как все линии Prog_enable притянуты к низкому уровню — нужно включить питание +5 Вольт и далее через 20-60 мкс включить напряжение +12 Вольт. Через 10 мкс после этого можно начинать переключать линии Prog_enable, а через 300 мкс — загружать каманды.
Выйти из режима программирования можно отключив от программируемого чипа +12 Вольт или +5 Вольт (или оба сразу).
Далее. Как можно заметить, для выполнения некоторых команд из приведённого выше списка нужны дополнительные данные. Например, команда «установить нужное состояние на линии OE» не позволяет сделать никаких выводов о том, что это за нужное состояние. Для таких команд мы будем устанавливать специальные флаги, которые будут означать, что следующий принимаемый по UART байт — это не новая команда, а те самые данные о «нужных состояниях» линий (состояния линий будут соответствовать определённым битам полученного байта).
Ну и, наконец, чтобы как-то сообщить компьютеру о том, что предыдущий принятый байт обработан и можно посылать следующий — будем отсылать обратно на компьютер 0x00 в случае успешной обработки очередного принятого байта или 0xFF в случае его неуспешной обработки. Вот, собственно, и вся концепция.
Исходя из всего вышеописанного получилась следующая программа:
;— radiohlam.ru — .device ATmega8 .include «m8def.inc» .list ;— по-умолчанию фьюзы CSEL = 0001 (1 МГц), нужно поставить CSEL = 0100 (8 МГц) ;— определяем свои переменные (и раздаём под них регистры) .def w=r16 ; аккумулятор (обменник) .def wait_flags=r17 ; флаги ожидания данных (0 — XA1/XA0/BS2/BS1, 1 — OE, 2 — Data) .def fd_reg=r19 ; счётчик для организации быстрых (маленьких) задержек (шаг 1 мкс) .def ld_reg=r20 ; счётчик для организации медленных (больших) задержек (шаг 200 мкс) .def w2=r21 ; ещё одна переменная для временного хранения всякой фигни ;— определяем названия выводов и портов .equ Data_Out = 0x18 ; порт B — вывод данных (линии данных на выход) .equ Data_In = 0x16 ; порт B — ввод данных (линии данных на вход) .equ RDY = 0 ; PC0 .equ BS1 = 1 ; PC1 .equ BS2 = 2 ; PC2 .equ XA0 = 3 ; PC3 .equ XA1 = 4 ; PC4 .equ PAG = 5 ; PC5 .equ OE = 2 ; PD2 .equ XTAL1 = 3 ; PD3 .equ WR = 4 ; PD4 .equ Ctrl_12 = 6 ; PD6 .equ Ctrl_5 = 7 ; PD7 .equ RxD = 0 ; PD0 .equ TxD = 1 ; PD1 .equ MinCommandNumber = 0x1 ; минимальный номер команды .equ MaxCommandNumber = 0xB ; максимальный номер команды ;—————————————— ;— начало программного кода .cseg .org 0 rjmp Init ; переход на начало программы (вектор сброса) ;— дальше идут вектора прерываний ;— если не используем — reti, иначе — переход на начало обработчика reti ; внешнее прерывание INT0 reti ; внешнее прерывание INT1 reti ; Timer2 COMP reti ; Timer2 OVF reti ; Timer1 CAPT reti ; Timer1 COMPA reti ; Timer1 COMPB reti ; Timer1 OVF reti ; Timer0 OVF reti ; SPI, STC rjmp RX_INT ; USART, Rx complete reti ; USART, DataRegister Empty reti ; USART, Tx complete reti ; ADC conversion complete reti ; EEPROM ready reti ; Analog comparator reti ; TWI (two-wire serial interface) reti ; Store Program Memory Ready ;— начало программы Init: ;— устанавливаем указатель вершины стека на старший байт RAM ldi w,Low(RAMEND) out SPL,w ; младший байт адреса ldi w,High(RAMEND) out SPH,w ; старший байт адреса ;— отключаем лишнее sbi ACSR,ACD ; выключаем компаратор ;— инициализируем порты ;— DDR — направление работы (0 — вход, 1 — выход) ;— PORT — состояние защёлок / подтяжек (0 — низкий уровень / нет подтяжки, 1 — высокий уровень / есть подтяжка) ;— настраиваем PORTD (состояние — все, кроме PD2(OE), PD4(WR), PD7(+5) — нули, направление — все на выход) ldi w,0b10000000 out PORTD,w ldi w,0b11111111 out DDRD,w ;— настраиваем PORTC (состояние — все нули, направление — все на выход, кроме PC0(RDY)) clr w out PORTC,w ldi w, 0b11111110 out DDRC,w ;— настраиваем PORTB (состояние — все нули, направление — все на выход) clr w out PORTB,w ser w out DDRB,w ;— инициализируем UART clr w out UBRRH,w ; UBRR (для кварца 8 МГц и скорости 38400) ldi w,12 ; равен 12, т.е. UBRRH = 0, UBRRL = 12 out UBRRL,w ldi w,0b10001110 ; поднимаем биты USBS, UCSZ1:0 + старший бит (URSEL) должен быть 1 при записи в UCSRC ; в примере из оф.доки на мегу — косяк, они просто скопировали пример из 2313 ; (в 2313 старший бит был не важен) out UCSRC,w ; формат: 1 старт, 8 данные, 2 стоп ldi w, (1
Добавить комментарий Отменить ответ
Для отправки комментария вам необходимо авторизоваться.
Источник
Доктор фьюзов для AVR
Всем привет! Наверное у каждого, кто занимается или занимался прошивкой микроконтроллеров были случаи, когда вы неправильно зашивали фьюз-биты и тем самым приводили микроконтроллер в «залоченное» состояние. В этой статье я расскажу о том, как сделать AVR doctor. AVR doctor – это устройство, которое позволяет вернуть к жизни микроконтроллер с неправильно прошитыми фьюзами. Идея собрать его появилась у меня после того, как испортил 3 микроконтроллера ATtiny2313. Выбросить их было жалко, поэтому и решил их «вылечить».
Схема доктора фузов
Вот принципиальная схема данного устройства:
Итак, приступим к сборке.
1) Печатная плата
Так как дорожки на плате не очень узкие, можно изготовить плату по технологии ЛУТ. Я так и сделал, но принтер у меня печатает не очень хорошо, поэтому получилось не совсем удачно. На фото процесс изготовления платы.
Сборка устройства
Для сборки нам понадобится:
1. Резисторы:
10к-1шт.
4,7к-2шт.
1к-19шт.
330 Ом – 1шт.
2. Конденсаторы:
100 мкФ 16в. – 1шт.
10 мкФ 16в. – 1шт.
10 нФ — 1шт.
3. Транзисторы:
BC547 – 1шт.
BC557 – 2шт.
4. Светодиоды – 2 шт. (красный и зеленый)
5. Панели под микроконтроллеры
40 выводов – 1шт.
28 выводов – 2шт.
20 выводов – 1шт.
6. Кнопка 4-х контактная – 1 шт.
7. Терминальный блок на 2 контакта – 1шт.
8. Стабилизатор напряжения 7805 в корпусе ТО-220 – 1 шт.
Вот собственно и все детали. Можно приступать к сборке АВР доктора.
Первым делом, нужно залудить контактные площадки на плате. Я обычно покрываю слоем припоя всю плату, так надежнее. Следует внимательно осмотреть плату на обрыв дорожек и другие дефекты. После того, как залудили плату, её нужно обмыть от флюса. Для этого можно воспользоваться водой с мылом или моющим средством. Если флюс не отмывается или вы использовали канифоль, следует промыть плату ацетоном или спиртом. Если нет не того, не другого, можете промыть плату перекисью водорода или на крайний случай растворителем. (при использовании растворителя, плата в дальнейшем будет иметь не очень приятный запах).
Когда все элементы впаяны, нужно еще раз промыть плату. После того как она высохнет, возьмите увеличительное стекло и внимательно осмотрите плату. Я иногда нахожу на плате сопли и непропаянные места. Если вы устраните все найденные дефекты до первого включения платы, вы можете избежать неприятностей. Вот так выглядит готовая плата:
Прошивка микроконтроллера
Следующим этапом будет прошивка микроконтроллера. Для этого вам нужно иметь:
- Микроконтроллер ATmega 8
- Программатор для AVR микроконтроллеров.
Чтобы прошить микроконтроллер нужно иметь программатор и компьютер с соответствующим программатору ПО. Я использую AVR Studio 4. Прошивку оставлю в архиве вместе с печатной платой и принципиальной схемой.
Фьюз-биты нужно установить следующим образом:
Lock Bits = 0x 3F; High Fuse = 0x D1; Low Fuse = 0x E1; Ext. Fuse = 0x 00
Если микроконтроллер успешно прошит, можно приступать к разблокировке микроконтроллеров. Для этого вставьте прошитую атмегу в панельку возле светодиодов. А «залоченный» мк вставьте в соответствующую ему пустую панельку. Далее нужно подключить питание к плате через терминальный блок, который вы припаяли. Напряжение следует подавать 6-12 вольт, иначе плата не запуститься. Когда питание подключили загорится красный светодиод (если конечно вы все правильно собрали).
Если светодиод горит, то нажимайте на кнопку. Должен загореться зеленый светодиод, а красный погаснет. Если все так и произошло, то поздравляю – плата собрана правильно и вы разблокировали микроконтроллер.
Теперь несколько слов о джампере, который стоит на плате. Если вы поставите на него перемычку, то при разблокировке МК также очиститься его память, то есть удалиться прошивка. Если же перемычки не будет — прошивка сохраниться.
Если при нажатии на кнопку не произошли действия описанные выше, то что-то пошло не так как нужно. Причина может быть в том, что вы ошиблись при сборке платы или прошивке атмеги. Также причина может быть в том, что микроконтроллер, который вы хотите восстановить, неисправен. Дополнительная информация — на форуме. Всем удачи!
|