Дело было как-то вечером. Есть у меня дома контроллер wirenboard. Пока идет знакомство, наладка и отстройка, управляет светом около стола, да и меряет температуру по всему дому. Но не суть. наткнулся я на одну интересную багофичу: если пощелкать переключателями, а потом тут же обрубить питание, то эти самые переключатели после загрузки окажутся в рандомном состоянии.
Небольшое расследование со службой поддержки wirenboard показало, что дело в одном маленьком файлике. Вернее с тем, как linux с ним обращается. Верхнеуровневый софт честно в него пишет нужное, а вот линукс, желая сберечь ресурс emmc, начинает активно кешировать и сбрасывает файловый кеш тогда, когда в 99% уже поздно.
Казалось бы, фигня вопрос: засунь в крон sync и дело в шляпе. Ок, не в крон, это перебор, а после inotify и всё. Но сбрасывать всю FS ради одного файла… В общем, рецепт ниже.
# cat /etc/systemd/system/libwbmqtt-saver.service
[Unit]
Description=Drop file cache for libwbmqtt.db if it changed
[Service]
ExecStart=/bin/bash -c 'inotifywait -qq -e modify /var/lib/wb-mqtt-gpio/libwbmqtt.db && dd of=/var/lib/wb-mqtt-gpio/libwbmqtt.db oflag=nocache conv=notrunc,fdatasync count=0 status=none'
Restart=always
[Install]
WantedBy=multi-user.target
Всё написано на скорую руку, но тем не менее, прекрасно работает. Вся магия в том, что dd открывает фаил на запись, записывает 0 байт и закрывает, сбрасывая кеш. Такую оптимизацию подсмотрел где-то в инете, мое первоначальное решение было гораздо страшнее (и нет, не покажу).
mail.ka12.co замените на свой домен. Принцип простой – сначала любым привычным способом получаете сертификат через LE, а потом запуская скрипт выше засовываете сертификат в zimbra
Одним из самых распространенных вариантов обмена информации с внешним устройством это последовательный порт. Давно известная технология, куча примеров для любых языков программирования и все ошибки давно уже найдены и описаны. Сейчас обычно используется COM-over-USB, так как переписывать ничего не надо.
Но разрабатывая очередное устройство у меня возникли смутные ощущения, что есть некие тормоза про общении с устройством. Решил проверить.
Для начала сгенерировал в STM32CubeMX пустой проект. В котором есть только USB и он определен как CDC.
Потом прямо в коде приема блока тут же его отправляю его назад. Кусок из usbd_cdc_if.c
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
CDC_Transmit_FS(&Buf[0], *Len);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
}
import time
import threading
import serial
# f042
#ser = serial.Serial(port='/dev/cu.usbmodem2058335047481')
# f303
ser = serial.Serial(port='/dev/cu.usbmodem2057385756311')
ser.isOpen()
# For windows
#ser.set_buffer_size(rx_size=262144, tx_size=262144)
bytesReceived = 0
minimalSpeed = 10000000
maximumSpeed = 0
counterStep = 0
blockSize = 1
shallExit = 0
def res():
global bytesReceived
global minimalSpeed
global maximumSpeed
global counterStep
global blockSize
global ser
global shallExit
if minimalSpeed > bytesReceived:
if bytesReceived > 0:
minimalSpeed = bytesReceived
if maximumSpeed < bytesReceived:
maximumSpeed = bytesReceived
bytesReceived = 0
counterStep = counterStep + 1
if counterStep > 60:
print("BlockSize:", blockSize, "Minimal:", minimalSpeed, "Maximum:", maximumSpeed,
"Average:", round((minimalSpeed+maximumSpeed)/2048), "kb/s")
with open("result.csv", "a") as myfile:
myfile.write(str(blockSize) + "," + str(minimalSpeed) + "," + str(maximumSpeed) + "\n")
ser.read(ser.inWaiting())
counterStep = 0
minimalSpeed = 100000000
maximumSpeed = 0
blockSize = blockSize * 2
if shallExit == 0:
threading.Timer(1, res).start()
with open("result.csv", "w") as myfile:
myfile.close()
res()
while 1:
if blockSize > 65536:
shallExit = 1
exit(0)
s = "A" * blockSize
b = s.encode()
ser.write(b)
bytesReceived = bytesReceived + ser.inWaiting()
ser.read(ser.inWaiting())
Сильно я не заморачивался, поэтому указать нужный порт придется вам самим прямо в коде. “Человекочитаемые” программа пишет в консоль и попутно генерирует result.csv для импорта в excel или другую подобную программу
Под рукой у меня оказалось только два stm32 с usb: F042 и F303. Оранжевая линия это максимальная скорость, синяя – минимальная. Такие прыжки максимальной скорости вызваны буферизацией у всех участников процесса. Ну по крайней мере я сейчас так думаю.
Результаты довольно показательные. Как найду еще процессоров – попробую повторить. Но пока можно сказать, что не стоит использовать блоки больше 128-256 байт и можно надеяться на скорость не менее 200 килобайт в секунду.
UPDATE1: Добавил график от F779. Суть та же. Видимо, где-то прямо в коде CDC у stm большие проблемы
Чего-то зачесалось у меня в старые игрушки поиграть. Но быстрый поиск показал, что фиг вам там. Либо надо ставить эмуляторы и искать образы, либо идти и платить непонятно за что с каким качеством (у меня до сих пор в голове свежи воспоминания, как угробили pac-man, mario и boulder dash).
Ну если оно не получается, то почему бы не взять и не написать самому? В тех играх не ни графики, ни звука, ни работ на 100500 мульонов денег. А интерес-то тот же …
В общем, отряхнул я руки и за пол-дня написал первую игру: Пинг-Понг.
Получилась простая и тупая до безобразия игрушка. Но по-прежнему захватывает и дальше 20 я уйти не смог 🙂
Получив очередной счет от gitlab и github одновременно, я как-то задумался: а нафига я им плачу, когда я все это могу поднять на своем сервере? “Все это” – это кучку приватных git и простую ci/cd систему. Поставил и решил написать напоминалку, что бы в следующий раз не гуглить.
Процесс установки не вильно отличается от описанного на сайте, но есть несколько НО:
Во-первых, в centos7 nginx идет без поддержки passenger. Поэтому обновляем на версию из “пассажирской” репы.
Во-вторых, нигде в мануале не указано, что gitlab требует nodejs для работы
yum install nodejs
И наконец, нигде не указано, что gitlab не работает без unicorn. Во всех мануалах написано, что если у вас внешний nginx, отрубите встроенный и unicorn. Так вот, этого делать нельзя, иначе получите неработающий gitlab-workhouse
Из других неочевидных тюнингов стал вынос порта unicorn с 8080 и изменение размера буферов у постгреса. Иначе на моем загруженном сервере он отказывался запускаться.
В остальном единственной засадой было изменение прав на сокеты, но это только из-за моей конфигурации, где куча всяких пользователей лезут в в один каталог. Так как сервер “домашний”, проще стало дать всем права на запись.
Больше никаких отступлений от официального руководства.
Ну или подобными вопросами заполнены тематические конференции. И большинство из них без ответов.
Суть проблемы проста: если в STM32CubeMX включить в АЦП один канал, то все работает изумительно. Примеры есть повсюду и код работает стабильно. Но если включить несколько, то все ломается. При вызове HAL_ADC_GetValue на выходе получается “мусор”, содержащий случайную выборку с каналов.
Решение: в коде HAL содержится ошибка. В функции HAL_ADC_ConfigChannel индусы заложили такую логику, которая препятствует работе более чем с одним каналом. Согласно ей, перед измерением надо каждый канал конфигурировать с Rank = ADC_RANK_NONE, а затем снова его же конфигурировать, но уже с другим rank.
Если делать по документации, то вместо конфигурирования одного канала происходит конфигурирование всех каналов.
У меня уже была версия 1, но недавно с испытаний вернулась более новая и улучшенная версия. Теперь она выглядит так:
Это по-прежнему шилд для Arduino Nano, но функционал немного поменялся.
Во-первых, эта версия умеет “распознавать” на входе сигналы уровнем как 220В, так и 24В. При этом без разницы, постоянное или переменное напряжение. Бонусом добавил световую индикацию состояния входов.
Во-вторых, плата теперь имеет два выхода 0-10В. Мелочь, но это очень приятная мелочь.
И наконец, сделал “закладку” для универсального порта. Это маленькая плата-расширение на снимке снизу
Сам порт с испытаний не вернулся, но если все будет хорошо, он обеспечит вход/выход 0-10В, вход-выход 0-20мА и измерение сопротивлений от 100Ом до 100кОм. Разрабатывался в расчете на “закрытие” всех потребностей обычных автоматизаторов. Или говоря другими словами, для тех кому не нужны защиты в 5кВ, гальванические развязки и прочее. Благодаря этому конечная цена данной версии колеблется в районе 2000 рублей в зависимости от объемов.
Но нет пределов совершенству. Скоро будет 3я версия платы, которая закроет найденные недочеты. Например, можно и нужно выровнять реле. И добавить еще немного индикации. И … в общем, все некритично, но практично.
Любой, кто интересовался этой темой, знают, что данное сокращение произошло от Development и Operations. Или если перевести на русский – Программисты и Сисадмины. Да, operations дословно переводится не так, но здесь я использую слово «сисадмины» в самом широком смысле.
Кто такие «сисадмины»? Если кратко, то это именно те люди, на руках которых держится вся инфраструктура. Где-то этим словом называют приходящих «аникейщиков», которые меняют картриджи в принтере и изредка чистят компьютеры от вирусов и троянов. А где-то это целые залы людей, разбитых на свои касты. Кто-то занимается сетями, кто-то базами данных, а кто-то обслуживанием датацентров и их инфраструктуры. Титаны антистрессовых методик.
Точно такое же широкое определение имеют и «программисты». И тот, кто пишет на javascript проверку ввода на сайт и тот, кто добавляет код во внутренний модуль корпоративной системы – все они «программисты». И даже тот, кто пишет на встроенном языке 1С, тоже программист, что бы об этом не думали другие.
В чем же основная причина, приведшая к появлению девопсов? Для этого необходимо немного углубиться в специфику работы каждой «секты».
Для сисадмина самое важное это то, что бы вверенная ему система работала без перебоев. Не обращая внимания на тупых пользователей, идиотов-разработчиков, отключения питания и поломок оборудования. Все, абсолютно все, рассматривается с точки зрения надежности. И венцом этой надежности является достижение времени доступности системы в 99,999% (или «5 девяток»). Поверьте, заставить современные системы работать так, чтобы их время недоступности не превышало 5 минут в год – это очень сложная задача. И когда вы добиваетесь, что максимальное время, когда подчиненная система может сказать «ой, я не могу» – это 6 секунд в сутки, то спокойно можете брать с полки пирожок.
У разработчиков же другое положение. Над ними коршунами вьются кровососы-менеджеры, которые постоянно требуют новый функционал, который должен работать быстрее или лучше. И всё это великолепие не должно поломать уже существующий функционал. И код, который прекрасно работает на твоей машине, почему-то отказывается работать как надо даже в тестовом окружении. А еще эти гамадрилы-сисадмины не дают нормально покопаться в получившейся у них системе и понять, что пошло не так даже после успешно пройденных тестов. Эти чудаки на букву «м» постоянно орут как резанные и набрасывают говен на вентилятор при любом чихе. И никто кроме коллег не способен оценить красоты получившегося кода или изящества алгоритма.
А рядом вьются … коллеги из отдела тестирования. Эти вообще постоянно нудят про то, что с говнокодом пора кончать и им опять нужна свежая копия базы данных.
В эту сложную и нервную обстановку добавляет перцу то обстоятельство, что «сисадмины» никогда не писали код размером больше чем на пару страниц, а «разработчики» никогда не обслуживали написанные ими системы (а часто даже и не пользовались ими). Результат абсолютно предсказуемый: тотальное непонимание друг друга и подковёрные войны.
Вот в горниле этих битв и родилось новая каста – DevOps или девопсы. Как водится, поначалу были перегибы с обоих сторон и презрение к «переметнувшимся». Плюс из-за молодости самого термина у него множество толкований и определений. Кто-то считает девопс методологией, направленной на автоматизацию и увеличение числа релизов, а кто-то – на уменьшение ошибок. Я же считаю, что девопс – это прежде всего человек, главной задачей которого является снижение головной боли у программеров, сисадминов и QAшников. А те уже сами напишут, отконфигурят и оттестируют нужное.
Ибо если поглядеть с любой стороны, девопс будет выглядеть как некий недоучка, лишь в редких случаях способный выдать что-то толковое. Бегает со своими скриптами наперевес, чего-то там курочит в коде и лишь принадлежность к «своим» не позволяет его послать в очень далекое эротическое путешествие. У меня нет ни капли сомнения, что программер переиграет девопса в программировании, сисадмин – в администрировании, а тестировщик – на своем тестировочном поле.
Но ценность девопса именно в стоянии нараскоряку в постоянном процессе разрушения стен непонимания между «сейчас зальем, а там разгребут» и «чего там эти опять одноклеточные выделили». Да, сложно, но как показывает практика, вполне возможно.
Сейчас, в самом начале жизни девопсов (с 2009 года же), самой основной их задачей является автоматизация. Объёмы того, что необходимо автоматизировать – поистине ужасающие. Ведь все (программеры и сисадмины) непрерывно трудятся над увеличением завалов не один десяток лет.
Что обычно автоматизируют?
– Развертывание очередного релиза кода. В тест, в стейджинг, в продакшн. Да хоть на машину разработчика. С необходимыми сервисами и данными. Разных версий.
– Обновление. Сервера, сервисы и сайты. Быстро и еще быстрей.
– Управление инфраструктурой. Сегодня 100 серверов в одном датацентре, завтра 500 в трех, а послезавтра 1000 снова в одном. Мониторинг, сбор логов и куча других мелких задач, которые раньше выполнялись вручную или не выполнялись совсем.
Это самые общие задачи. Где-то спектр для автоматизации побольше, а где-то поменьше.
Широкий характер выполняемых задач автоматически формирует и необходимые требования к девопсам:
– Необходимо знать все используемые продукты, языки и технологии. Только тогда стандартная для девопса задача «скрестить ужа с ежом и заставить их летать» автоматически становится выполнимой. Сисадмин сделал бекап? А девопс должен забрать этот бекап, выкинуть из него всякую конфиденциальную информацию и засунуть в систему (которую построил он же), которая позволит разработчикам и тестировщикам без опаски гонять свои творения на «почти продакшене».
– Наличие знаний (есть еще умное слово «компетенций») по всему процессу разработки. Причем знания должны быть реальными и боевыми. Потому что некому кроме девопса остановить программера, когда он решит напрямую засовывать json в обычную базу данных. Для разработчика в этом нет ничего крамольного (база поддерживает? поддерживает!), для сисадмина тоже (ну растет база и требует больше ресурсов – это нормально), а DBA по привычке обматерит всех и молча пойдет строить индексы и партиционировать базу. А то, что полученная конструкция могла быть быстрее и надежней – это никому не интересно. Кроме девопсов.
Нет ни того, ни другого? Тогда получаются люди, которые прекрасно характеризуются как «чуваки с накачанным ЧСВ и недержанием кода».
Требования большие? Да, большие. Зато и награда велика.
Сама возможность пощупать возведенное твоими трудами, а не какого-нибудь сферического коня в вакууме стоит дорого. Причем ощутить весь процесс возведения от «долбанное ничего» до «обалдеть какая няшка». Ни разработчики, ни сисадмины, ни тестировщики такой возможностью не обладают …
Как-то раз ко мне пришел заказчик. И захотел он странного для меня: шилд для ардуины. Вернее, первоначально задача была поставлена еще проще: вот есть нцать шилдов, собери их в одну кучу, что бы без проводов. И что бы arduino uno управляла всем этим. После выяснения, где и что будет этим управлять, я немного офигел. Оказывается, в вентиляции и теплоснабжении есть куча мест, которые требуют простого и тупого управления в духе “вон там сигнал появился? Ну и щелкни вот тут”. И ничего больше не надо. Вообще.
Но почему-то ничего простого не доступно от слова совсем. Либо дорогущие контроллеры от именитых производителей, либо чуть более доступные, но от наших. Но все равно стоимость получается внушительной.
Поговорили, почесали макушки и ударили по рукам. Я пошел делать, заказчик пошел переводить денег.
Долго ли, коротко, но я сделал первую версию контроллера. 4 входа 220в, 4 переключающих реле, выход 0-10В, и развязанный rs-485. Плюс пара подтянутых выходов для 1-Wire и все это под управлением ардуинки, запрограммированной в fl-prog. Ну и питаться может от 7В до 40В.
В общем-то ничего особенного от слова вообще. Обычный навороченный шилд для ардуины и особенного в нем только то, что он у меня первый. Ну не делал я раньше шилдов для ардуинок 🙂
Первым же неприятным фактом стало то, что ардуинка отказывалась прошиваться, когда она стоит в контроллере. Это 100% мой косяк, ибо “сделай как там” привело к тому, что я использовал драйвер rs-485 “как у китайцев”. А этот ADM485 при отсутствии сигнала на линии тупо подтягивает линию RX в 1. Ну ладно, прошить можно и вытащив ардуинку из платы.
Второй проблемой стало то, что при “автономной” работе rs-485 не работал. То есть питаешь плату через ардуинку – все ок. Питаешь через внешний источник – rs-485 мертв. Проблема осложнялась тем, что у меня все работало, а у заказчика – нет. На одном и том же коде.
Опуская подробности, оказалось, что в мире существует две версии arduino nano. “Дешевая” версия и “дорогая”. Естественно, что “дешевой” версией забиты все магазины Москвы и алиэкспресса. Разница только в одном – чипы мостов usart-usb. На дешевой версии стоит CH340, на дорогой – FTDI.
И этот дешевый CH340 при питании “снаружи” видя, что на входе usb у него ничего нет, тупо подтягивает RX/TX в ноль. А дорогой FTDI – ставит в Z.
Вышли из положения, заиспользовав Software Serial, откусили ножки на самой ардуине и тупо бросили два проводка на плате. То, что у меня заинвертирован RE/DE сигнал, решили ручной правкой кода. Ну не умеет flprog в такое. У них все прямо …
Следующей претензией стало, что “даю 220в, датчик показывает 0, но это ок. Не ок, когда секунд через 40 он переходит в 1, и еще через 40 обратно”. Тут я офигел мрачно.
После разбирательств стало понятно, что ардуинка насколько перегружена кодом от flprog, что тупо не успевает реагировать на полуимпульсы от опторазвязки. А в прерывания оно не умеет. Мы взяли 20МГц чип и тормознули его до 50Гц. Ну почти до 50 …
Не, я и там дунул-плюнул и поправил.
И тут оказалось, что вообще-то такие простые контроллеры очень нужны совершенно другим людям. Например, местные любители самогоноварения очень возбудились на характеристики и стоимость контроллера. Настолько, что наплевав на все, отобрали у меня единственный рабочий экземпляр (остальные у заказчика) на тест.
В результате по вечерам я проектирую новую, улучшенную версию контроллера. Для безопасности добавлю опторазвязку вообще на все выходы, ибо пользователи явно его будут совать куда не попадя, наплевав на правила техники безопасности. Будет изолировано все от всего. Люблю ночью спать спокойно.
В качестве главного процессора будет STM32F072. Мощный, умеет программироваться через USB и имеет кучку ножек. А ардуинка … ну дам ей “кроватку”. Пусть используют те, кто привык 🙂
… про реальную разработку устройств на stm32. Поэтому думаю обновления если и будут, то нерегулярным и в основном в виде кусочков из книги. Ну прёт меня пока.
Что бы не было скучно, вот вам малюсенький кусочек, можно сказать бета-версия про кварцевые резонаторы и вообще частоты.
Почему-то в интернете мало документации про qbs, пора немного исправить эту ситуацию.
Как-то у меня сложилось так, что практически исчезли проекты, в которых надо сделать что-то одно. Обычно надо и написать прошивку для микроконтроллера и управляющую программу для смартфона или десктопа. Можно делать все по старинке: писать код для каждого устройства в родной для него среде разработки.
Но поверьте, это довольно быстро задалбывает. Под виндовс – MSVC, под ARM – CooCox или Keil (приношу свои соболезнования вынужденным работать под IAR), под MSP – CCS, под андроид – eclipse, под ios – Xcode, под пики – MPLAB. И ладно бы, со всем этим работать можно было бы, но ведь фиг: везде свои заморочки, тонкости и неписанные правила. Все это накладывается на общую тормознутость так популярного эклипса помноженную на криворукие дополнения от производителей.
Некоторое время назад я начал сводить все свои разработки под мобильные и десктопные приложения под одну платформу. После довольно долгого чеса по интернетикам мой выбор остановился на Qt. Есть все, что надо, при необходимости можно подцепить нативный код. В общем, задача закрылась.
Но вот с микроконтроллерами ситуация не желала складываться категорически. В основном из-за того, что везде свои хотелки и желалки. Ну ладно, про это я уже жаловался. Я бы еще долго мучался, пока внезапно не наткнулся на краткое описание qbs.
Желающие могут пошариться по инету сами, но если кратко, то это заменитель всяких make и cmake, использующая нормальный (тут должен быть смаил) язык программирования. И сам QtCreator собирается с ее помощью, значит она уже вылезла из штанишек …
Да, документации по ней как обычно кот наплакал, но исходники еще никто не отменял, поэтому довольно быстро ко мне пришло понимание, что это практически то, что я искал. Посудите сами: сидишь в одной среде разработки (самой по себе очень приятной и быстрой) и спокойно пишешь и редактируешь файлы под несколько платформ. И тебе, как кодописателю, пофиг на наличие всяких там заморочек с “родными” средами.
Хватит излияний, пора попробовать. Создадим очень простой проект, в котором у нас будет десктопная и микроконтроллерная составляющая.
Открываем QtCreator, выбираем создать Non-Qt Project (что бы пока не заморачиваться сильно) и далее выбираем то, где присутствует C и Qbs. Обратите внимание на приятные взгляду слова Platform independent
В результате получаем один main.c и qbs. Можно уже нажать “build” и получить вывод Hello World.
Открываем qbs и ничего не понимаем. Поэтому все стираем, вооружаемся интернетом и начинаем писать. Яваскрипт и все такое.
import qbs
Так, тут вроде понятно. Импортируем всякое необходимое для работы самого qbs.
Project {
name: "simple"
}
Сохраняем и наблюдаем исчезновение main.c с левой панели. При попытке запустить проект QtCreator спросит: а чего пускать-то? В принципе пока все логично.
Из чего состоит проект в терминологии qbs? Из продуктов. И их может быть несколько, но пока я сделаю один.
При попытке скомпилировать не изменится ровным счетом ничего. Подсмотрим в некоторые обучалки и добавим зависимость от cpp и укажем, что вообще-то это приложение.
И вот теперь при попытке собрать приложение QtCreator пошуршит немного диском и в панельке Application Output появится искомое
Ага, значит мы на верном пути. Осталось разобраться, что делают те самые две магические строки.
Depends {name: "cpp"}
Читаю документацию и понимаю, что данной командой я устанавливаю зависимость проекта от какого-то модуля с именем cpp. Понятней стало? Мне нет.
Простым поиском нахожу что-то подобное в /usr/share/qtcreator/qbs/share/qbs/modules/ (Если у вас другая операционка, то скорее всего аналогичное лежит где-то неподалеку от QtCreator). Если говорить коротко, то там куча яваскрипта, которая в зависимости от платформы подбирает компилятор под эту платформу. Полностью повторять подобное мне смысла нет, поэтому оставляю как есть.
type: "application". Из документации: The file tags matching the product’s target artifacts. Артефакт … An Artifact represents a single file produced by a Rule or Transformer. … ерр .. Rule? Creates transformers for input tags. Напоминает ситуацию про сепулькарий .. Transformer? Creates files, typically from other files.
Ползаю по доступному и понимаю, что примерно это некий набор правил, который говорит системе сборки, как надо собирать скомпилированное. Ну грубо говоря, на выходе надо получить приложение, библиотечку или вообще что-то иное. Опять же, хоть и стало немного понятней, но ненамного. Опять пока примем за данность.
Но вернемся к нашему проекту. Давайте добавим еще один продукт, только уже для микроконтроллера
При попытке что-то сделать, нам сразу выскочит сообщение, что вообще-то файла blink.c нет. Ну, ок, добавим в проект фаил blink.c. Как видно из названия, это тот же HelloWorld, только для микроконтроллеров. Я взял из примеров для микроконтроллера семейства msp430.
while (1) {
P1OUT ^= 0x01;
__delay_cycles(1000000); // 1 second @ 1MHz
}
return 0;
}
Будучи скомпилированным и залитым, он начнет дергать ножкой P1.0 с интервалом в одну секунду. А так как на этой ножке у большинства демо- и девелоперских плат висит светодиодик, то он замигает.
Теперь QtCreator не ругается, но и в микроконтроллер ничего не заливается. Странно, да?
Добавлять Depends {name: “cpp”} смысла нет, потому что установленный в системе родной gcc не в курсе про существование такой платформы, да и в дальнейшем пригодится, например для пиковских контроллеров, где вообще все свое.
Теперь воспользуемся обрывками тех сакральных буковок, что встретились раньше.
Для начала, я предпочитаю в микроконтроллерных проектах расписывать каждый функционал в своем файле. Записывать каждый файл руками? Лень. Подсматриваем решение и переписываем блок
Тут создаем группу файлов, которые обзываем “msp430 sources” и тупо включаем в нее все файлы, которые подходят под маску src/*.c. Для дальнейшей работы с ними тегируем их буквой С.
Что с ними делать? У qbs есть на этот случай две штуки – Rule и Transformer. По сути они близки, но немного разные. Счас попробую описать на пальцах разницу.
Rule умеет срабатывать на каждый файл, попадающий под что-то. Может срабатывать по разу на каждый фаил (например, для вызова компилятора), а может один раз на все (линкер).
Transformer предназначен для срабатывания только на один фаил, с заранее определенным именем. Например, прошивальщик или какой-нибудь хитрый скрипт.
Ок, добавляем правило, которое должно будет сработать на все наши файлы, промаркированные как “с”.
Product {
name: "micro"
Group {
name: "msp430 sources"
files: 'src/*.c'
fileTags: ['c']
}
Rule {
inputs: ["c"]
prepare: {
var cmd = new JavaScriptCommand();
cmd.description = "file passing"
cmd.silent = false;
cmd.highlight = "compiler";
cmd.sourceCode = function() {
print("Nothing to do");
};
return cmd;
}
}
}
В принципе из синтаксиса уже все понятно. Есть inputs, есть prepare, в который засовывается яваскрипт, который выполняет необходимое. В данном случае он должен в окошке Compile Output показать file passing, и куда-то вывести Nothing to do. Ну по документации вроде так.
Запускаем перекомпиляцию всего и смотрим. Не знаю, как у вас, но я ничего не вижу. Почему? Потому что qbs больно умный, а документация к нему страдает лакунами.
Правило не срабатывает, потому что qbs считает, что оно не производит никаких действий в системе и от него ничего не зависит. В принципе это соответвует реальности, но провести проверку мешает.
Ок, за это отвечают те самые артефакты. Под ними подразумеваются результаты деятельности Rule или Transformer. Лучше всего это объяснить на примере компиляции. Когда мы компилируем .с файл, то на выходе мы получим объектный файл .о. Он нам нужен для дальнейшей линковки, но с другой стороны, мы его можем удалить, так как потом спокойно сможем сгенерировать заново.
Опять копируем пример из документации и чуть-чуть модернизируем.
Теперь мы говорим, что после нашей деятельности останутся артефакты в каталоге .obj (ну и я добавил вывод того, над каким файлом мы сейчас работаем). Запускаем. Опять ничего в ответ. Почему? Ответ тот же – никому не нужны файлы с тегом ‘obj’.
Хорошо, для проверки сделаем так, что они нужны нам. И вообще, наше приложение – это один сплошной obj.
Пробуем, и удача! В окошке появился заветный “Compiling blink.c”. Теперь давайте добавим, что бы оно реально компилировало и сразу по-быдлокодерски, то есть тупо забив все необходимое в одну кучу.
prepare: {
var args = [];
args.push("-mmcu=cc430f5137")
args.push("-g")
args.push("-Os")
args.push("-Wall")
args.push("-Wunused")
args.push('-c');
args.push(input.filePath);
args.push('-o');
args.push(output.filePath);
var compilerPath = "/usr/bin/msp430-elf-gcc"
var cmd = new Command(compilerPath, args);
cmd.description = 'compiling ' + input.fileName;
cmd.highlight = 'compiler';
return cmd;
}
Перекомпилируем все с нуля и смотрим в каталог .obj
$ ls -R1
.:
f27fede2220bcd32
./f27fede2220bcd32:
blink.c.o
Ура! Файлик появился. Теперь, для проверки я делаю еще один файлик, с хитрым названием hz.с. Если я прав, то после перекомпиляции рядом появится еще один объектный файл.
В выводе появилось
compiling blink.c
compiling hz.c
а в каталоге
./f27fede2220bcd32:
blink.c.o
hz.c.o
Все вроде ок. Теперь необходимо все это дело слинковать. А значит опять правило, только теперь для линковки.
for (i in inputs["obj"])
args.push(inputs["obj"][i].filePath);
args.push('-o');
args.push(output.filePath);
var compilerPath = "/usr/bin/msp430-elf-gcc"
var cmd = new Command(compilerPath, args);
cmd.description = 'linking ' + project.name;
cmd.highlight = 'linker';
return cmd;
}
}
Где отличия? Во-первых, добавился флаг multiplex, который говорит о том, что это правило обрабатывает сразу все файлы данного типа скопом. А во-вторых, во входных параметрах исчез input. Появился inputs, который является массивом файлов данного типа. Ну и я вопользовался именем продукта, что бы брать имя для финальной прошивки.
Ставим тип приложения elf и пробуем собрать. Через некотрое время мы в каталоге для сборки обнаружим файл simple.elf
$ file simple.elf
simple.elf: ELF 32-bit LSB executable, TI msp430, version 1, statically linked, not stripped
То, что нам и необходимо. Его можно уже заливать в плату и наслаждаться мигающим светодиодиком.
Исходная цель достигнута: мы в одной среде разработки делаем все: и редактирование и компиляцию.
В принципе, в программировании микроконтроллеров под Linux нет ничего сложного. Более-менее доступны средства разработки, а некоторые производители и вовсе официально поддерживают Linux как среду разработки.
TI тоже имеет свою фирменную среду, но она … скажем так, для хардкорных железячников. Старый, тормознутый эклипс и какие-то невнятные настройки. Залитие прошивки и ее отладка тоже доставляют много удовольствия привыкшим к нормальным средам.
В общем, долой разврат – будем делать все по-правильному, что бы программирование доставляло удовльствие, а не требовало героического преодоления трудностей.
Расписывать я буду под Fedora Linux (21), потому что я сейчас под ней. Под другие дистрибутивы инструкций как-то больше.
В чем проблема с федорой? Ведь они кровь и плоть от редхата, а тот официально поддерживает msp430-gcc, который использует и сама TI. Проблема в том, что это федора, а значит в ней все нестабильное и вообще может не работать.
И с MSP430 случилось ЭТО. В 20й версии он работал, а в 21й – уже нет. Подробнее можно посмотреть тут. Если кратко, то в федоре сломали линкер.
Что делать? Есть несколько вариантов, из которых самый простой это взять старую версию компилятора из CCS или Energia. Но добрый Brandon Nielsen решил эту проблему по-другому: просто сделал репозиторий со правильными версиями.
Открываем рутовую консоль и подключаем нужный репозитарий
dnf copr enable nielsenb/msp430-development-tools
И ставим все необходимое, соглашаясь с тем, что никто ни за что не отвечает.
Теперь скопипастим Makefile #
# Makefile for msp430
#
# 'make' builds everything
# 'make clean' deletes everything except source files and Makefile
# 'make install' builds everything, and programs the MSP430 using MSPFLASHER
# You need to set TARGET, MCU and SOURCES for your project.
# TARGET is the name of the executable file to be produced
# $(TARGET).elf $(TARGET).hex and $(TARGET).txt nad $(TARGET).map are all generated.
# The TXT file is used for BSL loading, the ELF can be used for JTAG use
#
TARGET = project0
MCU = msp430f5529
# MSP430Flasher name
MSPFLASHER = MSP430Flasher
# List all the source files here
# eg if you have a source file foo.c then list it here
SOURCES = main.c delay.c
# Include are located in the Include directory
INCLUDES = -IInclude
# Add or subtract whatever MSPGCC flags you want. There are plenty more
#######################################################################################
CFLAGS = -mmcu=$(MCU) -g -Os -Wall -Wunused $(INCLUDES)
ASFLAGS = -mmcu=$(MCU) -x assembler-with-cpp -Wa,-gstabs
LDFLAGS = -mmcu=$(MCU) -Wl,-Map=$(TARGET).map
########################################################################################
CC = msp430-elf-gcc
LD = msp430-elf-ld
AR = msp430-elf-ar
AS = msp430-elf-gcc
NM = msp430-elf-nm
OBJCOPY = msp430-elf-objcopy
RANLIB = msp430-elf-ranlib
STRIP = msp430-elf-strip
SIZE = msp430-elf-size
READELF = msp430-elf-readelf
MAKETXT = srec_cat
CP = cp -p
RM = rm -f
MV = mv
########################################################################################
# the file which will include dependencies
DEPEND = $(SOURCES:.c=.d)
# all the object files
OBJECTS = $(SOURCES:.c=.o)
all: $(TARGET).elf $(TARGET).hex $(TARGET).txt
$(TARGET).elf: $(OBJECTS)
echo "Linking $@"
$(CC) $(OBJECTS) $(LDFLAGS) $(LIBS) -o $@
echo
echo ">>>> Size of Firmware <<<<"
$(SIZE) $(TARGET).elf
echo
%.hex: %.elf
$(OBJCOPY) -O ihex $< $@
%.txt: %.hex
$(MAKETXT) -O $@ -TITXT $< -I
unix2dos $(TARGET).txt
# The above line is required for the DOS based TI BSL tool to be able to read the txt file generated from linux/unix systems.
%.o: %.c
echo "Compiling $<"
$(CC) -c $(CFLAGS) -o $@ $<
# rule for making assembler source listing, to see the code
%.lst: %.c
$(CC) -c $(ASFLAGS) -Wa,-anlhd $< > $@
# include the dependencies unless we're going to clean, then forget about them.
ifneq ($(MAKECMDGOALS), clean)
-include $(DEPEND)
endif
# dependencies file
# includes also considered, since some of these are our own
# (otherwise use -MM instead of -M)
%.d: %.c
echo "Generating dependencies $@ from $<"
$(CC) -M ${CFLAGS} $< >$@
.SILENT:
.PHONY: clean
clean:
-$(RM) $(OBJECTS)
-$(RM) $(TARGET).*
-$(RM) $(SOURCES:.c=.lst)
-$(RM) $(DEPEND)
install: $(TARGET).txt
$(MSPFLASHER) -n $(MCU) -w "$(TARGET).txt" -v -z [VCC]
Если при попытке компиляции Вы получите
Makefile:48: *** missing separator. Stop.
то это означает лишь то, что вы нарвались на tab-hell. Все отступы выше – это не пробелы, а символы табуляции. Если отвлечься и открыть этот фаил в mc, то вы должны увидеть следующее:
Обратите внимание на символы “<---->” – именно ими mc показывает табуляцию. Поправьте где надо.
Теперь осталось поправить параметры MCU под мой процессор и SOURCES под мой проект и запустить make. Если все сделано правильно, то вы должны увидеть побежавшие строки, завершающиеся чем-то похожим.
Linking blink.elf
>>>> Size of Firmware <<<<
text data bss dec hex filename
2906 214 152 3272 cc8 blink.elf
unix2dos: converting file blink.txt to DOS format...
Если оно так, то можете себя поздравить. Теперь можно развиваться дальше.
PS С автором, чьи наработки я использовал, можно познакомиться тут
Есть в далекой загранице такая компания – 4D Systems. Основной продукт – “интеллектуальные дисплеи”. По роду деятельности я с ними очень глубоко познакомился, так что устриц ел.
Задумка совершенно шикарная. Купив такую штуку, разработчик получает полностью готовый блок, где есть дисплей с тачскрином и в который можно загрузить программу, воткнуть микро-sd карточку и подцепить какие-то внешние датчики или устройства.
Причем последние версии дисплеев отличаются только разрешением или формой (да, у них есть круглые дисплеи) – все остальное у них одинаково.
Как заведено в “корпративном” мире, к этим дисплеям полагается софт для их программирования. Софт работает только под Windows и может загонять дисплеи в три режима работы.
1. Режим тупого usart терминала. Цепляем к дисплею любой внешний микроконтроллер через совершенно стандартный usart и отправляете в дисплей команды в духе “нарисуй точку”, “смонтируй флешку”, “покажи картинку с флешки”. Работает очень медленно.
2. Написание “визуальных программ”. Есть библиотечка страшненьких контролов, из которых делаются экраны, а потом в специально отведенные места записывается код. Что-то сложное написать невозможно.
3. “Полноценный”. Можно писать программы на 4DL – некой смеси паскаля и си.
Плюс прямо в IDE встроено немного утилиток типа калибровки экрана, разметки microsd карточек и терминалки. В принципе штуки полезные в плане “все свое ношу с собой”.
В общем, почти счастье любого программиста встраиваемых систем. Но как обычно, все портит реализация.
Начинается всё с редактора. Эта штука абсолютно не умеет форматировать код. Ни работы с блоками, ни нормального свертывания. Зато раздражающие комментарии – в полном объеме. Короче, этакий notepad с подсветкой. Результат – очень страшно выглядящий код.
Компилятор тоже доставляет немного удовольствия: иногда программа компилируется, но отказывается заливаться в дисплей. Добавляем где-нибудь в незначащем месте лишний пробел или что-нибудь типа i:=i; и все прекрасно компилируется и заливается. Еще больше доставляют ошибки, когда программа на дисплее просто падает на ровном месте, которое в прошлые разы не вызывало никаких нареканий. Лечится точно так же: либо лишние команды, либо просто поменять что-нибудь местами.
“Исполнятор” тоже не свободен от греха: например, если вы “примонтировали” с microsd файловую систему и с нее только читаете, то при падении программы вы с 50% вероятностью получите “убитую” флешку, которую надо снова форматировать.
Да, и большие microsd не поддерживаются. Если вам удалось найти карточку на 2Гб, то вам повезло. Если у вас больше – то будьте добры сделать раздел на 2Гб, а про остальное – забудьте.
Где еще проблемы? Перечислю кратко:
– Ошибки в документации. Неправильные аргументы, неправильные примеры, код скопипащен из примера для другой функции.
– Программисту не дают доступа ни к прерываниям, ни к какой-либо многозадачности. Вообще. Делай большой цикл на все и молись, что бы стек не переполнился.
– Сильно грузить порты ввода-вывода нельзя. Например, если включить проигрывание wav-ки с карточки и побежать исполнять код дальше, то вместо “чистого” звука услышишь его же с треском. Начнешь много и часто читать с карточки – получишь мешанину байт вместо ожидаемого. Рисуешь картинку – будь готов к потерям байт в последовательном порту.
– Отладчика нет. Вообще ни в каком виде. Отладочный вывод? Ну можно писать в usart, если он не занят. Но проще тупо на экран.
После всего этого проблемы вида “есть возможность загрузить шрифты, но нет ни описания формата, ни редактора для них” кажутся такими пустяками …
Но с другой стороны, если вы достаточно сильны духом, то за $185 долларов (сама дорогая модель) вы получите готовую уберштуку, в которой 7″ дисплей (800х480), маленький динамик и слот для карточек. Попутно будет доступно нцать выводов, на которые можно повесить всякие енкодеры, пзушки (внутри хоть и есть флеш, но писать не дают) и прочие штуковины. И после кучки оптимизаций все это будет крутиться довольно быстро и не раздражать пользователя.
В этой реальности я бы посоветовал найти отдельно 7″ дисплей и какой-нибудь контроллер. Будет и дешевле и быстрее и удобней.
Как-то раз попросили меня посмотреть на одно очень дорогостоящее устройство. Проблема была одна: среди использующих это устройство возникло стойкое убеждение, что 99,99% его цены происходит от того факта, что производитель этого устройства монополист в своей сфере и деваться пользователям этого устройства некуда.
Вооружившись осциллографом, я полез внутрь.
Через некоторое время поиски привели к двум проводкам, которые были в жгуте, соединявшем блоки устройства. Осциллограмма показала, что в проводках почти обычный USART. Почти — потому что «туда» данные бежали на скорости 9600, а обратно на 115200.
Одним из основных препятствий для перехода на STM32 является обилие текстов, инструкций и мануалов, описывающих работу с контроллером. Виновником этого обилия стала сама STMicroelectronics, которая поначалу планомерно запутывала своих пользователей, а затем предлагала неверные варианты выхода.
Проблема заключается в многообразии выпускаемых контроллеров, которые почему-то требовали разных процедур инициализации даже для одной и той же периферии. И код, работающий на одном контроллере, отказывался работать на другом. В результате по сети гуляют сборники шаманских рецептов, для понимания которых требуется куча времени и воскуривание даташитов.
Но не так давно ST поняла, в какую яму она угодила и начала усиленно из нее выбираться, привлекая новые силы. И именно благодаря этому сейчас время старта сократилось до несуразно маленьких величин. Как это выглядит на практике?
Program space used F9h ( 249) of 2000h words ( 3.0%)
Data space used 49h ( 73) of 200h bytes ( 14.3%)
А теперь добавим const перед i, показывая компилятору, что неплохо бы переменную перенести в “программную” часть.
Program space used D9h ( 217) of 2000h words ( 2.6%)
Data space used Bh ( 11) of 200h bytes ( 2.1%)
Хм. 249-217=32 байт освободили в программной части и 73-11=62 (!) байта в области данных
Говоря другими словами, родной компилятор XC8, если не сказать другого, при любом использовании переменной хранит 2 копии переменной в программной памяти и 2 копии в области данных. Сказать, что я офигел мрачно, значит ничего не сказать.
После этого становится понятно, откуда компилятор берет ресурсы для оптимизации и гордо сообщает при любом удобном случае Running this compiler in PRO mode, with Omniscient Code Generation enabled, produces code which is typically 40% smaller than in Free mode.
(Чуть позже) решил перепроверить, а то вдруг всякие библиотеки/типа навязались
Сделал пустой проект с одним файлом для PIC16F1503.
void main(void) {
char i[30]="123456789012345678901234567890";
int q;
q=i[2];
}
Ничего больше, ни инклюдов, ни библиотек, ни инициализаций.
Program space used 4Ah ( 74) of 800h words ( 3.6%)
Data space used 42h ( 66) of 80h bytes ( 51.6%)
добавляем const
Program space used 2Fh ( 47) of 800h words ( 2.3%)
Data space used 6h ( 6) of 80h bytes ( 4.7%)