Небольшой рассказ о граблях, встреченных на пути познания ARM на примере stm32f103c8t6 и stm32l151rct6.
Мое знакомство с микроконтроллерами началось с AVR. Ими я занимался довольно долго, пройдя путь от плат с процарапанными дорожками и ассемблера в AtmelStudio4 до нормального лута и самописных makefile'ов для работы в блокноте (в моем случае — KWrite) и командной строке.
Но пришло время потыкать палочкой и в их старших братьев — ARM. Выбор конкретного семейства был долгим и пассивным (потому что прямой надобности нет, вот и не спешил), но в конце концов закончился на stm32f1, как самом, пожалуй, распиаренном. Покупать программатор, отладочную плату вроде Discovery или blue pill? Что вы, я же мастер по AVR-кам! Любую плату можно сделать ЛУТом, да еще так, как тебе нужно, без лишнего обвеса. Поэтому покупаю голый stm32f103c8t6 и начинаю шаманить с трассировкой платы. Что же мне понадобится? Хотя бы два порта вывести на гребенки… упс, выводить порты целиком неудобно. Да и ладно, выведу по 8 ножек — от порта A младшие (0-7), от B — старшие (8-15). Еще, конечно, светодиоды и кнопки, как же без индикации и управления. Вот что меня удивляет в готовых отладочных платах так это отсутствие хотя бы 2-3 светодиодов и 1-2 кнопок, которые бы ни с чем не конфликтовали. Как они вообще себе представляют отладку? Под кнопки сами просятся PA8, PA9, они удобно расположены. Еще пригодятся USB, джамперы BOOT0, BOOT1 и разъем батарейки для часов. И разъемы для кварцев, чтоб совсем красиво (впоследствии ни разу не воспользовался разъемами для кварцев). Для питания контроллеру нужно не более 3.6 В, а с USB идет 5 В. Надо ставить стабилизатор. Много читал, как народ выбирает стабилизаторы с низким падением напряжения… зачем? Разница полтора вольта, да тут дубового 78l33 хватит. А теперь разъем JTAG. У Atmel разъем программирования был стандартный ISP10 или ISP6. Наверное JTAG тоже штука стандартная. Оказывается, да… но только для отдельного производителя или даже устройства. Смотрим разъем на st-link: красивый, 10-контактный. Смотрим на каком-то программаторе для AVR: упс, уже 20-контактный. Смотрим еще где-то: больше несовместимых разъемов богу несовместимых стандартов. Ну, раз так, будем изобретать свой. Если что, переходник между ними будет не сложнее переходника ISP-6 на ISP-10. Вроде бы все готово, можно делать плату. Как оказалось, шаг 0,5 мм вполне достижим на любительском уровне, даже почти маркером подрисовывать не пришлось.
Теперь чем ее прошивать. Раз есть USB, наверное, через него и умеет. Читаю даташит — ага, через USB не умеет, зато через UART1 умеет. Упс, как раз его-то я и забыл вывести. Мало того, он еще и с кнопкой конфликтует, с той что на PA9 висит. Ну да ладно, выведу на проводочках, а кнопка все равно еще одна есть. Немного шаманства и плата готова и даже определяется в stm32flash.
С железом вроде бы разобрался, пора переходить к коду. Почитав несколько статей в интернете нашел готовый архив под gcc-arm-none-eabi. Разбираться, как именно задавать последовательность сборки, буду потом. Пока что занимаюсь hello-world'ами на кнопках и светодиодах. Поскольку это мое первое знакомство с данным семейством, никаких оберток вроде HAL — только ручная работа с регистрами. Впрочем, это вполне естественный подход, как мне кажется, можно было и не упоминать. Немного напрягает все время дергать питание и BOOT0 на плате, ну да ладно, когда-нибудь сделаю JTAG-программатор. Как ни сранно, на грабли с отключенным тактированием периферии не наступил. Вспомнил молодость, когда на TurboPascal'е писал обработку трехмерной графики. Здесь у меня есть дисплей на ili9341 от raspberry pi и контроллер на целых 72 МГц. Вот что получилось — до 200 точек на модель и 11 fps. Конечно же, все матрицы трансформаций считаются в числах с фиксированной точкой.
В какой-то момент захотелось сделать носимое устройство, чтобы долго работало от батарейки. Посмотрел я в даташит и огорчился: знаменитые ARM по потреблению в разы хуже тех же AVR-ок! Если у вторых (ткнул в первый попавшийся контроллер, которым оказался ATmega88p) потребление составляет 0,8 мкА в учетом часов, то у первых даже в самом экономичном режиме сна* — 25 мкА ± 1.4 мкА на RTC. Это никуда не годится. Впрочем, stm32f103 и не позиционируется как экономичная серия. Смотрю на сайте STmicroelectronics другие серии контроллеров и выбираю серию stm32l1: помимо потребления порядка 1 мкА, там есть еще емкостный датчик и контроллер ЖКИ. Правда, максимальная частота поменьше, всего 36 МГц (или 24 МГц если используется USB), но это я как-нибудь переживу. Решено: беру пару stm32l151rct6 аж с 32 кБ оперативки (еще там 256 кБ флеша, но слабо представляю чем его можно забить. Разве что совсем диким говнокодом или массивами данных).
- ) не путать режимы сна (sleep, stop) с отключением (standby)
Параллельно делаю из запасной stm32f103 программатор st-link v2, просто потому что надоело возиться с BOOT0 и питанием, да и быстрее он. Впрочем, программирование по UART оставлю — мало ли что. Там тоже было немного шаманства, но ничего выдающегося. Разве что найти командную строку для openocd оказалось проблемой. Для будущих поколений оставлю ее:
openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c "init" -c "reset halt" -c "flash write_image erase "$(firmware).bin" 0x08000000" -c "reset run" -c "exit"
Для stm32l151 надо, само собой, поправить target на "target/stm32l1.cfg"
Чуть забегу вперед по хронологии, но чтоб не возвращаться. Господа, не экономьте на толщине текстолита! Или хотя бы добавляйте подпорки, или не используйте smd-компоненты. Так получилось, что на плате программатора я предусмотрел всего два крепежных отверстия в рандомных местах. А места оказались довольно далеко от разъема JTAG. И через какое-то время я заметил, что программатор работает нестабильно. То работает, то нет, то через UART приходится стереть "жертву", тогда подхватит. Оказалось, что резистор, идущий от вывода контроллера к разъему, сломался. У него просто отвалилась контактная площадка от корпуса. Резистор я перепаял. Потом перепаял остальные. Потом догадался, что даже той малой деформации платы, которая возникала при втыкании-выдирании шлейфа, хватало для несчастных компонентов. В результате воткнул подпорку прямо рядом с разъемом. Пока держит.
Как читатель уже догадался, программирование все также идет в текстовом редакторе, а компиляция и прошивка — в консоли. Естественно, покупная отладочная плата под l151 меня вдохновляла не больше, чем всякие IDE. Потирая следы от граблей, оставленных первой платой, развожу вторую (считая программатор — третью, но он все-таки не отладочная плата). Раз уж собрался отлаживать энергоэффективное устройство, надо заморочиться с питанием. Стабилизатор 78l33 менять не буду, но его выход я разорвал джампером, чтобы туда можно было ткнуться амперметром (надеюсь все-таки на микроамперметр, но там уж как пойдет). Гребенки пусть будут такие же, как на предыдущей плате — совместимость! Ну и пару светодиодов и кнопок, конечно. Грабли с UART1 призывно поблескивают, но я все же ставлю его разъем и не получаю по лбу. Конечно, JTAG у меня уже есть, но страховка не повредит. Так же, как и предыдущую (и плату программатора тоже) удалось развести по одной стороне, даже перемычек не слишком много.
А вот при запаивании контроллера возникла проблема. Я как-то наивно полагал, что на корпусе микросхем должен быть ключ, обозначающий первую ногу. Кто бы ожидал, что молодцы из ST сделают ДВА ключа, симметрично. Вот и какой стороной его запаивать теперь? Подумав, я решил, что это не ключи, а технологические углубления. Мало ли, для позиционирования чипа при изготовлении, например. Или прижать основание для заливки пластиком. Тогда надо ориентироваться по надписи. Логично же, что надпись должна быть читаема если расположить микросхему "стандартно", то есть когда первая нога в левом верхнем углу. Так и начал припаивать. То ли дефект ЛУТа, то ли кривые руки, но припаялась микросхема криво, благо вовремя заметил, прежде, чем запаял целиком. Не беда, есть же старый способ отпаивания многоножек с помощью лезвия бритвы: оно не смачивается припоем и достаточно тонкое чтобы не слишком погнуть. Оказалось, руки все-таки недостаточно прямые, поскольку ножки погнулись. Но не вверх, а вбок, хорошо хоть не сильно и их удалось кое-как выпрямить. Вторая попытка запаивания шла уже под микроскопом, но прежде я решил доправить ножки. И одна из них отломалась. Из чего их делают, что один раз согнуть-разогнуть нельзя? У выводных-то компонентов такой проблемы нет. Ну все, думаю, микросхему в брак, придется запаивать другую. Но вдруг это не критичная ножка? Ну там, вывод общего назначения, или одно из питаний. Пока что запаяю без нее, а там видно будет. На этот раз удалось запаять ровно, правда ножка попала на I2C, с которым я хотел поразвлекаться, но хоть не на жизненно важные разъемы вроде USB, JTAG, UART или BOOT. Подключаю — не работает, программаторы плату не видят. Какое-то время шаманю с пропаиванием ножек, но не помогает. Блуждающий по даташиту взгляд натыкается на картинку контроллера, расположенную где-то в подвале документа. Вот как можно было придумать нанести надпись БОКОМ?! То есть если повернуть контроллер так, чтобы надпись читалась, первая нога окажется в правом верхнем углу. Попутно выяснилось, что одно из "технологических углублений" таки является ключом. Правда, не поясняется, как его отличить от симметричного… Ну, хоть какая-то зацепка. Выпаиваю контроллер строительным феном, чтобы не доломать выводы, и запаиваю на этот раз боком. Отломанный вывод попадает аккурат на TX вывод UART1, то есть на разъем программирования и отладки. Это совсем нехорошо, но перед тем, как менять контроллер, надо хотя бы убедиться что с ориентацией угадал чтобы при перепаивании на живой не убить его неправильным подключением. Подключаю программатор — работает. Ура. Остались мелочи — впаять разъемы, диоды и прочую обвязку.
Работать с контроллером без UART1 не хочется, да и хуже чем сейчас уже не будет. А если и будет, так все равно менять, поэтому принимаю решение поиграть в хирурга и сделать контроллеру протез ноги из волосинки МГТФа. Как раз под рукой валяется хороший электропроводный клей, которым волосинка решительно приляпывается к площадке на корпусе микросхемы. Тот клей, который попал на соседние ножки, безжалостно удаляется скальпелем. А что вы хотите, попасть в полумиллиметровую площадку и не попасть по соседним торчащим ножкам? Проверяю — работает. Пока не отвалилось, а чтобы не отвалилось и потом, заливаю цианакрилатом.
Возможно, так бы я этой платой и пользовался, если бы ножка не отвалилась повторно. А она залита клеем. Впрочем, он довольно мягкий и режется скальпелем, поэтому успешно счищается. Но использовать тот же электропроводный клей второй раз почему-то не хочется. Попробую-ка я ножку припаять. Обычным жалом паяльника туда не подлезть, но в комплекте шло коническое (вообще-то, коническое изначально было единственным, но ввиду его очевидной неудобности, было заменено обычным, с клиновидной заточкой), которое туда вполне подлезает. Как ни странно, "операция трансплантация" прошла успешно и ножка заработала как ей положено (фотография ножки крупным планом на КДПВ).
Итак, железо готово, пора перейти к коду. Хорошо бы найти готовый пример под gcc и библиотеки CMSIS. Что для этого подойдет лучше, чем официальный сайт производителя? Как оказалось, STmicroelectronics не разделяют моего оптимизма. То, что навигация на сайте сделана через неприличное место — уже привычно, сейчас трудно найти сайт, сделанный людьми для людей. Но они не позволяют ничего с сайта скачать! Возможно, позволили бы после регистрации, но у меня и раньше не было желания регистрироваться где попало, а после такого отношения к разработчикам — и подавно. На кой ляд вам моя почта или что вы там требуете? Собирать персональные данные, спам слать? Идите лесом, а я в свободном доступе найду! Кстати, немного удивило что соответствующего пакета не оказалось в репозитории, но, возможно, ST придумали какой-то лицензионный геморрой. Посему шлю лучи поноса маркетологам, придумавшим такую политику, да и за неудобный сайт тоже.
Как бы то ни было, библиотека прекрасно нашлась на просторах интернета (ссылки давать не буду, мало ли что с сайтом случится). Альтернативный вариант — скачать среду разработки или CubeMX, где эти библиотеки вшиты. Правда, скачать их с официального сайта точно так же невозможно, так что ищем на сторонних и устанавливаем на виртуалку, просто на случай "если вдруг что".
С железом разобрались, с сорцами тоже. Пришло время разбираться наконец с контроллером. Первый сюрприз ждал при попытке воспользоваться сторонним кодом под Discovery. Там применен контроллер stm32l152, который на первый взгляд почти не отличается от stm32l151, установленного у меня. Помимо мелких отличий, оказалось, что в "мой" контроллер не установлен модуль ЖКИ. Немножко обидно, но я все равно не планировал им пользоваться. Хотя вот такое различие могли бы и более явно выделить, чем сносочкой в даташите. Но более интересным оказалось поведение часов реального времени. Они упорно не хотели работать, причем в интернете пишут просто "делай так, делай так, оно работает". А оно не работает. Кое-где, впрочем, упоминалось об "известных проблемах с RTC в данной серии". Как бы то ни было, часы все же завелись, правда, только на встроенном RC-генераторе. Попытки запстить часовой кварц приводили к бесконечному ожиданию бита готовности LSE. Я попытался проверить не отвалились ли ножки микросхемы от дорожек на плате и подергал ими в режиме обычных GPIO. Отвалился высокочастотный кварц. WTF?! В общем, вместе эти два кварца работать не желают, но хотя бы по отдельности худо-бедно функционируют.
И тут я догадался: суперклей, которым была залита половина контроллера (он ведь жидкий, его точечно не нанесешь, да и кто бы мог подумать...), дает утечку и кварцы своими наводками мешают друг другу. Ну, снаружи отскрести клей нетрудно, но ведь он затек даже под низ микросхемы. И если утечек по нему достаточно для кварцев, это ведь и на потреблении скажется. Ищу в гугле, чем люди удаляют цианакрилат. Предлагается теплая вода (что???) и диметилсульфоксид. В теплую воду я не верю, поэтому покупаю ДМСО. После более чем часового нахождения капли химиката на поверхности клея, разницы я не заметил. Зато заметили кварцы и стали работать более-менее нормально (интересно, почему? Димексид вытеснил влагу, впитанную клеем?). Впрочем, меня это не убедило, да и остатки клея все равно мозолят глаза… даром что находятся на нижней стороне платы и особо не видны. Кстати, теплая вода, которой я смывал димексид, на клей не повлияла (я не удивлен). Обнаружил, что существует такая штука, как удалитель клея, в таком же тюбике, как и сам клей, только фиолетовом. Ну хоть она-то должна сработать! Как оказалось, она может и работает, но по консистенции напоминает сметану и под микросхему просто не лезет. Ну и толку с тебя, удалитель?! Снаружи я и так почистить могу. Последний шанс: изредка упоминается ацетон. Немножко опасаюсь за пластиковые детали, но как раз их заменить несложно. Заливаю ацетон в стеклянную банку, кидаю туда плату и оставляю на ночь. Наутро выяснилось, что ацетон и правда работает, да еще как! От клея не осталось и следа. Мало того, растворился толкатель одной из кнопок. Что интересно, вторая уцелела, наверное, была сделана из более устойчивого пластика. Немного удивлен был, что и прочий пластик остался нетронутым, даже надписи уцелели. Ну и отлично, а кнопку можно и заменить.
Вот теперь удалось запустить и RTC от часового кварца, и режим сна потрогать, да и с другой периферией пообщаться. А еще, чтобы совсем фен-шуйно было, нанес подписи на плату. Но не маркером (вдруг снова купать в растворителях?) а процарапал скальпелем. На века!
Ну и для будущих поколений оставлю примеры кода для обоих контроллеров, вместе с библиотеками, makefile'ами и прочим. Останется только установить gcc-arm-none-eabi, openocd, stm32flash и прочую мелочь.
stm32f103
stm32l151
Выводы:
- Делать отладочные платы под себя при желании можно, они не хуже покупных. А вот программатор-отладчик все же лучше купить, если он не слишком дорогой. Сделать его, конечно, можно, но схему-то вы менять не будете, а раз так — лучше покупного он не будет. Дешевле, скорее всего, тоже. Разве что если контроллер лишний остался или с доставкой проблемы.
- Не забывайте про резервный разъем программирования UART1, ну и заодно джамперы BOOT0, BOOT1. Помимо собственно программирования, по UART'у довольно удобно отлаживать программу.
- На корпусе LQFP64 два ключа, один из которых фальшивый. Ориентироваться придется на надпись чтобы смотрела ногами вправо.
- Паять компоненты с малым шагом стоит только под микроскопом. Иначе сложно определить все ли пропаялось и нет ли "соплей". Ну либо на "профессиональном" оборудовании вроде специального фена, паяльной пасты и т.п. Тут уж не знаю, я пишу про любительскую технологию.
- Не экономьте на толщине текстолита. Он гнется и этого может хватить для повреждения smd резисторов и, наверное, конденсаторов. Выводным это не страшно, да и компоненты с гнутыми выводами (транзисторы, микросхемы), пожалуй, переживут.
- Делать разъемы для кварцев — пустая трата времени. Вы не будете их менять, поэтому просто запаяйте на плату.
- Выпаивать многоножку с помощью лезвия бритвы стоит только в самом крайнем случае, когда нет фена. Иначе слишком велик риск ее повредить
- Даже если у микросхемы отвалилась ножка, ее можно восстановить! Даже когда шаг 0,5 мм. Главное пользоваться пайкой, а не проводящим клеем.
- Никогда не заливайте микросхему цианакрилатным клеем (суперклеем)! Он не обладает должными электрическими, да и механическими, характеристиками.
- Для удаления суперклея из труднодоступных мест лучше всего подходит ацетон. Растворяет полностью. Главное убедиться что окружающие компоненты не пострадают. Из не-труднодоступных мест можно и механически удалить.