Здравствуйте, меня зовут Евгений, и мне надоело писать прошивки для микроконтроллеров. Как это это случилось и что с этим делать, давайте разберемся.
После того как поработаешь в большом программировании С++, Java, Python, и т. Д. Возвращаться к маленьким и пузатым микроконтроллерам совсем не хочется. К их скудным инструментам и библиотекам. Но делать иногда нечего, задачи real-time и автономности, не оставляют выбора. Но есть некоторые типы задач, которые просто выбешивает в этой области решать.
К примеру тестирование оборудования, что-либо более скучного и занудного занятия в embedded программировании, вряд ли можно придумать. Вообщем как и удобных инструментов для этого. Пишешь… Прошиваешь… моргаешь… светодиодиком (иногда логи по UART). Все ручками, без специализированных инструментов для тестирования.
Еще удручает что нет инструментальных тестов, для наших маленьких микроконтроллеров. Все только через прошивочку и через дебагер тестировать.
Да и изучение работы с новыми устройствами и периферией требует много сил и времени. Одна ошибка и программу надо каждый раз перекомпилировать и заново запускать.
Для таких экспериментов больше подходит что-то типа REPL, дабы можно было просто и безболезненно делать вот такие, хотя бы банальные, вещи:
\
Как к этому прийти, посвящен этот цикл статей.
И в этот раз мне попался проект где потребовалось тестировать довольно сложное устройство, с уймой всяких датчиков и прочих, неизвестных мне ранее, микросхем, которые использовали множество периферии МК и кучу разных интерфейсов. Особое веселье было, то что к плате у меня не было исходных кодов прошивки, так что все тесты пришлось бы писать с нуля, без использования наработок из исходного кода.
Проект обещал хорошего тамаду и конкурсы интересные на месяца два так ( а скорее всего и больше).
Ладно, мы же тут не плакаться собрались. Надо либо снова окунуться в дебри С и бесконечных прошивок, либо отказаться либо что-то придумать, что бы облегчить себе это занятие. В конце концов лень да любопытство — двигатель прогресса.
В прошлый раз, когда разбирался с OpenOCD, наткнулся на такой интересный пункт в документации как
http://openocd.org/doc/html/General-Commands.html
15.4 Memory access commands
mdw, mdh, mdb — позволяют считывать значению по физическому адресу на микроконтроллере
mww, mwh, mwb — позволяют записывать по физическому адресу на микроконтроллере
Интересно…. А регистры периферии читать и писать с их помощью можно?.. оказывается можно, да к тому же эти команды можно выполнять удаленно через TCL сервер, который запускается при старте openOCD.
Вот пример моргания светодиодиком для stm32f103C8T6
// Step 1: Enable the clock to PORT B
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
// Step 2: Change PB0's mode to 0x3 (output) and cfg to 0x0 (push-pull)
GPIOC->CRH = GPIO_CRH_MODE13_0 | GPIO_CRH_MODE13_1;
// Step 3: Set PB0 high
GPIOC->BSRR = GPIO_BSRR_BS13;
// Step 4: Reset PB0 low
GPIOC->BSRR = GPIO_BSRR_BR13;
и аналогичный ему последовательность команд openOCD
mww 0x40021018 0x10
mww 0x40011004 0x300000
mww 0x40011010 0x2000
mww 0x40011010 0x20000000
А теперь, если задуматься о вечном и рассмотреть прошивки для МК… то основное предназначение этих программ это запись в регистры чипа; прошивка, которая будет просто что-то делать и работать только с процессорным ядром, не имеет никакого практического применения!
Хотя конечно можно и крипту считать(=
Многие вспомнят, еще про работу с прерываниями. Но они не всегда требуются, и в моем случае можно обойтись и без них.
И так, жизнь налаживается. В исходниках openOCD можно даже найти, интересный пример использования данного интерфейса.
Очень хорошая заготовочка на питоне.
Вполне можно конвертировать адреса регистров из заголовочных файлов, и начать писать на кошерном скриптовом языке. Уже можно готовить шампанское, но мне показалось этого мало, ведь хочется вместо возни с регистрами использовать Standard Peripherals Library или новый HAL для работы с периферией.
Портировать библиотеки на питон … в каком-нибудь страшном сне этим займемся. Значит надо как использовать эти библиотеки в С или … С++. А в плюсах же можно переопределить почти все операторы … для своих классов.
А базовые адреса в заголовочных файлах, подменить на объекты своих классов.
К примеру в файле stm32f10x.h
#define PERIPH_BB_BASE ((uint32_t)0x42000000) /*!< Peripheral base address in the bit-band region */
Заменить на
class InterceptAddr;
InterceptAddr addr;
#define PERIPH_BB_BASE (addr) /*!< Peripheral base address in the bit-band region */
Но игры с указателями в библиотеке, рубят на корню эту идею...
Вот к примеру файл stm32f10x_i2c.c :
FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG)
{
__IO uint32_t i2creg = 0, i2cxbase = 0;
….
/* Get the I2Cx peripheral base address */
i2cxbase = (uint32_t)I2Cx;
….
Значит надо как-то по другому перехватывать обращения к адресам. Как это делать наверно стоит посмотреть у Valgrind, не зря у него есть memchecker. Уж он то точно должен знать как перехватывать обращения по адресам.
Забегая вперед скажу, что лучше туда не заглядывать… мне почти удалось сделать перехват обращений по адресам. Почти для всех случаев, кроме такого
Int * p = ...
*p = 0x123;
Перехватить адрес есть возможность, а вот перехватить записываемые данные уже не получалось. Только название внутреннего регистра в котором это значение лежит, но до которого не добраться из memcheck.
На самом деле Valgrind удивил меня, внутри используется древний монстр libVEX, о котором я вообще не нашел никакой информации в интернете. Хорошо что немного документации удалось найти в заголовочных файлах.
Потом были другие инструменты DBI.
Frida, Dynamic RIO, еще какой-то, и наконец попался Pintool.
У PinTool оказалась неплохая документация и примеры. Хотя мне их все равно не хватило, и с некоторыми вещами пришлось делать эксперименты. Инструмент оказался очень мощный, единственно огорчает закрытый код и ограничение только платформой intel (хотя в дальнейшем это можно будет обойти)
Итак, нам нужно перехватывать запись и чтение по определенным адресам. Посмотрим какие инструкции отвечают за это https://godbolt.org/z/nJS9ci.
Для х64 это будет MOV для обоих операций.
А для х86 это будет MOV для записи и MOVZ для чтения.
Примечание: лучше всего не включать оптимизацию, иначе могут повылазить другие инструкции.
INS_AddInstrumentFunction(EmulateLoad, 0);
INS_AddInstrumentFunction(EmulateStore, 0);
.....
static VOID EmulateLoad(INS ins, VOID *v) {
// Find the instructions that move a value from memory to a register
if ((INS_Opcode(ins) == XED_ICLASS_MOV ||
INS_Opcode(ins) == XED_ICLASS_MOVZX) &&
INS_IsMemoryRead(ins) && INS_OperandIsReg(ins, 0) &&
INS_OperandIsMemory(ins, 1)) {
INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(loadAddr2Reg),
IARG_MEMORYREAD_EA, IARG_MEMORYREAD_SIZE, IARG_RETURN_REGS,
INS_OperandReg(ins, 0), IARG_END);
// Delete the instruction
INS_Delete(ins);
}
}
static VOID EmulateStore(INS ins, VOID *v) {
if (INS_Opcode(ins) == XED_ICLASS_MOV && INS_IsMemoryWrite(ins) &&
INS_OperandIsMemory(ins, 0)) {
if (INS_hasKnownMemorySize(ins)) {
if (INS_OperandIsReg(ins, 1)) {
INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(multiMemAccessStore),
IARG_MULTI_MEMORYACCESS_EA, IARG_REG_VALUE,
INS_OperandReg(ins, 1), IARG_END);
} else if (INS_OperandIsImmediate(ins, 1)) {
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)multiMemAccessStore,
IARG_MULTI_MEMORYACCESS_EA, IARG_UINT64,
INS_OperandImmediate(ins, 1), IARG_END);
}
} else {
if (INS_OperandIsReg(ins, 1)) {
INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(storeReg2Addr),
IARG_MEMORYWRITE_EA, IARG_REG_VALUE,
INS_OperandReg(ins, 1), IARG_MEMORYWRITE_SIZE, IARG_END);
} else if (INS_OperandIsImmediate(ins, 1)) {
INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(storeReg2Addr),
IARG_MEMORYWRITE_EA, IARG_UINT64,
INS_OperandImmediate(ins, 1), IARG_UINT32,
IARG_MEMORYWRITE_SIZE, IARG_END);
}
}
}
}
В случае чтения из адреса мы вызываем ф-цию loadAddr2Reg и удаляем оригинальную инструкцию. Исходя из этого loadAddr2Reg нам должна возвращать необходимое значение.
С записью все сложнее… аргументы могут быть разных типов и к тому же передаваться по разному, поэтому приходится перед командой вызывать разные ф-ции. На 32-битной платформе multiMemAccessStore, а на 64 будет вызываться storeReg2Addr. Причем здесь инструкцию из конвеера не удаляем. Удалить проблем её нет, но вот сымитировать её действие в некоторых случаях не получается. Программа почему-то иногда валится в sigfault. Для нас это не критично, пусть себе пишет, главное что есть возможность перехвата аргументов.
Дальше надо посмотреть, а какие адреса нам надо перехватывать, посмотрим на Memory Map для нашего чипа stm32f103C8T6:
Нас интересуют адреса с SRAM и PERIPH_BASE, т.е с 0x20000000 по 0x20000000 + 128*1024 и с 0x40000000 по 0x40030000. Отлично, вернее не совсем, как помним инструкцию записи мы удалить не смогли. Поэтому запись по этим адресам будет вываливаться в sigfault. К тому же есть неиллюзорная вероятность того что на эти адреса будет приходится данные нашей программы, не у этого чипа так у другого. Поэтому однозначно надо их куда-то отремапить. Допустим на какой нибудь массив.
Создаем массивы нужного размера, и дальше их указатели подставляем в дефайны базовых адресов.
В нашей программе, в заголовчниках вместо
#define SRAM_BASE ((uint32_t)0x20000000) /*!< SRAM base address in the alias region */
#define PERIPH_BASE ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */
Делаем
#define SRAM_BASE ((AddrType)pAddrSRAM)
#define PERIPH_BASE ((AddrType)pAddrPERIPH)
и где pAddrSRAM и pAddrPERIPH указатели на заранее выделенные массивы.
Теперь нашему PinTool клиенту надо как-то передать как мы отремапили необходимые адреса.
Самое простое что мне показалось, как сделать это перехват ф-ции, которая возвращает структуру массив с такого формата:
typedef struct
{
addr_t start_addr; //адрес массива куда ремапятся нужные адреса
addr_t end_addr; //размер этого массива
addr_t reference_addr; // отремапленные адрес
} memoryTranslate;
К примеру для нашего чипа это будет так заполняться
map->start_addr = (addr_t)pAddrSRAM;
map->end_addr = 96*1024;
map->reference_addr = (addr_t)0x20000000U;
Перехватить ф-цию и взять из нее требуемые значения не составляет большого труда:
IMG_AddInstrumentFunction(ImageReplace, 0);
....
static memoryTranslate *replaceMemoryMapFun(CONTEXT *context,
AFUNPTR orgFuncptr,
sizeMemoryTranslate_t *size) {
PIN_CallApplicationFunction(context, PIN_ThreadId(), CALLINGSTD_DEFAULT,
orgFuncptr, NULL, PIN_PARG(memoryTranslate *),
&addrMap, PIN_PARG(sizeMemoryTranslate_t *), size,
PIN_PARG_END());
sizeMap = *size;
return addrMap;
}
static VOID ImageReplace(IMG img, VOID *v) {
RTN freeRtn = RTN_FindByName(img, NAME_MEMORY_MAP_FUNCTION);
if (RTN_Valid(freeRtn)) {
PROTO proto_free =
PROTO_Allocate(PIN_PARG(memoryTranslate *), CALLINGSTD_DEFAULT,
NAME_MEMORY_MAP_FUNCTION,
PIN_PARG(sizeMemoryTranslate_t *), PIN_PARG_END());
RTN_ReplaceSignature(freeRtn, AFUNPTR(replaceMemoryMapFun), IARG_PROTOTYPE,
proto_free, IARG_CONTEXT, IARG_ORIG_FUNCPTR,
IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_END);
}
}
memoryTranslate * getMemoryMap(sizeMemoryTranslate_t * size){
...
return memoryMap;
}
Что же самая нетривиальная работа сделана, осталось сделать клиента к OpenOCD, в PinTool клиенте мне не хотелось его реализовать, поэтому я делал отдельным приложением, с которым наш PinTool клиент общается через named fifo.
Таким образом схема интерфейсов и коммуникаций получается такая:
А упрощенный workflow работы на примере перехвата адреса 0х123:
Давайте разберемся по порядку что же здесь происходит:
- запускается PinTool клиент, делает инициализацию наших перехватчиков, запускает программу
- Программа запускается, ей нужно отремапить адреса регистров на какой-нить массив, вызывается ф-ция getMemoryMap, которую перехватывает наш PinTool. Для примера один из регистров отрепамился на адрес 0х123, его будем отслеживать
- PinTool клиент сохраняет значения отремапленных адресов
- Передает управление обратно нашей программе
- Дальше где-то происходит запись по нашему отслеживаемому адресу 0x123. Ф-ция storeReg2Addr отслеживает это
- И передает запрос на запись в OpenOCD клиент
- Client возвращает ответ, тот парсится. Если все нормально, то возращается управление программе
- Дальше где-то в программе происходит чтение по отслеживаемому адресу 0x123.
- loadAddr2Reg отслеживает это и посылает запрос OpenOCD клиенту.
- OpenOCD клиент обрабатывает его и возвращает ответ
- Если все нормально, но в программу возвращается значение из регистра МК
- Программа продолжается.
На этом пока все, полные исходники и примеры будут в следующих частях.
Комментарии (72)
avf1906
20.12.2018 13:49Абсолютно противоположное впечатление: «После того как поработаешь
в большом программировании С++, Java, Python, и т. Дс микроконтроллерами, возвращатьсяк маленьким и пузатым микроконтроллерамк большому программированию С++, Java, Python совсем не хочется. К ихскудныммонстроузным инструментам и библиотекам. Но делать иногда нечего, задачиreal-time и автономностиUI, хранения и обработки данных, не оставляют выбора.»Amomum
20.12.2018 14:03+2Подозреваю, что просто усталость от того, чем чаще занимаешься.
Я лично подустал от невозможности использовать динамическую память, от медленных компиляторов, от кривой поддержки хотя бы С++11, от безумных аппаратных косяков в процах и ошибок монтажа…
Все мы страдаем от несовершенства мира в своем углу.avf1906
20.12.2018 20:44Скорее от недостатка понимания и/или отсутствия мотивации (неинтересно). А за статью спасибо, интересно, и, главное, применимо
Vadimatorikda
21.12.2018 08:23невозможности использовать динамическую память
Запрет на предприятии? Если так, то да, больно. Если нет, то при использовании FreeRTOS все более чем шикарно. Работа с динамической памятью (при достаточном выделении ресурсов под ее дефрагментацию и прочее) очень удобна.
кривой поддержки хотя бы С++11
GCC адекватно может в C++14 (около года пишу так).
от безумных аппаратных косяков в процах
В самих ядрах косяков либо нет совсем, либо их не много. А вот периферия… Да.
ошибок монтажа…
С опытом такие вещи достаточно быстро раскрываются. Особенно если монтаж осуществлял не ты сам.
Лично мне нравится под МК программировать. Как только ты доходишь до понимания того, что твоего кода 5-10 кб, а остальное библиотеки и ты закидываешь их в отдельное место и больше почти не шьешь, то прошивка занимает не более 2-3 секунд. Очень удобно. А остальные 200 кб BSP лежат себе тихонько в конце flash и все. Как-нибудь напишу статью на эту тему. Как организовать это правильно. Есть подводные камни.
За статью спасибо. Приятно было почитать. Однако именно так я врят ли буду вопрос. Все же я когда-то давно написал универсальное средство вывода и отладки (да-да, на базе UART-а. Вернее USB-UART-а, но ни суть. Надо кстати задокументировать будет и описать...). Его мне хватает с головой.eternalego
21.12.2018 11:19GCC безусловно может C++14, но, позвольте, всегда ли доступна соответствующая версия компилятора для определённой платформы? Лет пять назад, когда цивилизованный мир давно уже перелез на С++11 и линукс 3.х, приходилось страдать с ядром 2.6.х и дремучим GCC для одной из вариаций ARM, на поддержку которой производитель (Texas Instruments) забил.
esaulenka
21.12.2018 13:55А на что именно так крепко забил TI?
И что, поддержка этого ядра исчезла из транка gcc?
Или просто их Code Composer старый? Не велика беда, мне кажется…eternalego
21.12.2018 14:28Их композером вообще не пользовался. Работа велась с DM3730, и последняя сборка под эту платформу была в конце 11-го года: www.ti.com/tool/linuxdvsdk-dm37x
В ядрах третьей версии поддержки нужного чипа я тогда не нашёл, а делать порт самостоятельно было не в моих силах. Со сборкой более новых версий gcc для кросс-компилирования под эту платформу тоже были какие-то проблемы, сейчас уже не вспомню, какие.
Amomum
21.12.2018 12:20+1Запрет на предприятии? Если так, то да, больно. Если нет, то при использовании FreeRTOS все более чем шикарно. Работа с динамической памятью (при достаточном выделении ресурсов под ее дефрагментацию и прочее) очень удобна.
Ну, прямого запрета нет, только рекомендации MISRA :) Но с фриртосом действительно удобно, хотя бы heap_1 можно себе позволить и стеки руками не создавать.
В самих ядрах косяков либо нет совсем, либо их не много. А вот периферия… Да.
Кхе-кхе… Миландр 1986ВЕ1… Кхе-кхе…
Но да, ошибки в периферии существенно чаще попадаются.
С опытом такие вещи достаточно быстро раскрываются. Особенно если монтаж осуществлял не ты сам.
Ну, понятное дело, что раскрываются, просто каждый раз тратится уйма времени на поиски этих ошибок. А переделать печатную плату — это дело нескольких недель; пока оплата пройдет, пока ее изготовят, пока доставят…
GCC адекватно может в C++14 (около года пишу так).
Keil, к сожалению, только частично умеет в С++11, причем стандартная библиотека осталась от С++98. А их новый компилятор armclang пока сыроват.
IRainman
23.12.2018 18:36Ну, я просто оставлю это здесь.
Страдаю с AnalogDevice SC-589 based платой. Там нет даже С++11 и попытка его включить натом говне мамонтатой версии GCC приводит к внутренней ошибке линкера ибо линкер древний и забагованный в этом месте, а обновлять это никто не будет. Шёл 20189 год, а мне приходиться писать на C++03 под эту жопуелезку. И вот это дно происходит на железке которая даже не микроконтроллер, а трёх ядерная система ARM + 2 DSP с 2 ГБ ОЗУ. Всё очень плохо в этом королевстве :'(
DrGluck07
21.12.2018 16:50Вот да, с какой радостью я недавно клепал бутлоадер на xmega. Сидишь себе, пишешь, отлаживаешь, красота. Единственная проблема, мне надо было впихнуть 13кБ программы и библиотек в 8кБ бутлоадера. И от этого я получил ещё большее удовольствие. На ПК такое испытать можно, но только если делать что-то в ядре или типа того.
drblez
20.12.2018 14:30Форт. мне кажется, для микроконтроллеров с достаточным объемом ОЗУ (от 8Кб, скажем) и достаточным объемом FLASH (от 64Кб, скажем) форт будет хорошим решением для того, что бы сделать хоть прототип, хоть готовое приложение ))
А еще можно делать кровавый патчинг через терминал, тоже очень мило ))
Давеча попробовал mecrisp.sourceforge.net и остался доволен результатами. Как раз надо было сопрячь железку со странным протоколом с МК. Получилось хорошо и быстро.
Прототип сделал. Теперь думаю, что может его не перекладывать на Си, а продолжать писать на форте.
В этой, конкретной, реализации очень удобно разрабатывать тем, что можно слова создавать в ОЗУ, а потом пересоздавать их во FLASH. А если есть возможность подключить SD, то набросав редактор можно полностью вести процесс разработки на МК.FForth
21.12.2018 01:34Mecrisp stellaris unoficial doc
hightechdoc.net/mecrisp-stellaris/_build/html/index.html
Ещё можно этого автора почитать и его директорию проекта с Форт кодом на Github
jeelabs.org/2016/02/dive-into-forth
P.S. Экспериментировал, в частности, с www.mpeforth.com/xc7.htm
esaulenka
21.12.2018 13:49+1Голову вывернуть полностью надо с этим вашим фортом…
Когда-то давно коллега в «толстый» STM32 (тогда «толстым» был STM32F4) запихивал Lua.
apro
20.12.2018 14:59А почему просто не воспользоваться возможностями которые идут из коробки?
С кросс-компилятором идет gdb, openocd умеет работать как gdb сервер,
подключаемся gdb к openocd и вот у нас repl, gdb умеет и скрипты запускать,
и интерпретироваться подмножество языка С, типа*(int *)0x4 = 5;
,
и можно даже вызывать отдельные функции из загруженного кода в память МК.
Ну и скрипты на python он поддерживает.ser-mk Автор
20.12.2018 15:28Хорошее замечание. Тоже об этом думал. Но давайе по порядку…
У GDB нет REPL, это скорее консоль для исполнения уже встроенных команд и откомпилированных команд программы. Может интерпретровать простые констуркции С но и только.
Проблематично вызывать ф-ции из программы, а допустим иницилизировать структуры и классы и передавать их в аргументы это будет жуткая боль.
Скрипты и расширения на python отчасти спасают, но всеравно читаемость и масштабируемость будет хромать.
Во второй части будет наглядный пример, как все довольно просто работать будет. В этой статье мы всего лишь готовим инструмент для этого.
roboqueer
20.12.2018 17:36BSDL? Не, не слышал!
ser-mk Автор
20.12.2018 17:38Я тоже не слышал. Может раскроете свою мысль?
madprogrammer
20.12.2018 18:05Boundary Scan Description Language — с помощью такого файла-описания чипа и JTAG Boundary Scan (который как раз был в первую очередь придуман с целью упрощения тестирования плат с большим количеством взаимосвязанных чипов, а не для отладки/прошивки чипов, как многие думают), можно дрыгнуть любой ногой любого чипа, «сидящего на JTAG-chain, считать состояние любого пина и т.д., и все это без знания регистров и внутреннего устройства чипа (т.к. JTAG Boundary Scan-функционал реализован независимо от остальных частей кристалла, включая CPU). Минусом технологии является низкая скорость, т.к. данные последовательно загоняются с первый чип, потом во второй, третий и т.д., и потом возвращаются обратно в JTAG-железку, через которую идет управление.
ser-mk Автор
20.12.2018 18:35Могу ошибаться, но еще наверно стоит к минусам отнести:
то что у микросхемы должен быть обязательно JTAG интерфейс — на той тестируемой плате это не прокатывало, так как там была единственная stm32 и у нее был выведен SWD только
стоимость такого решения — было бы интересно узнать у людей кто в теме
Ну и BSDL решает только вопрос тестирования соединений микросхем ( на сколько я понял )
Допустим более сложные тесты уже не провернуть — к примеру проверить работу трансформатора на определенной частоте, корректность работы микросхем (на случай их брака)
r44083
20.12.2018 18:07По-моему автор просто перестал ценить ту изюминку и детерминированность встраиваемых систем. Это целый мир. Бывает. Со временем само проходит.
ser-mk Автор
20.12.2018 20:41-1Все относительно. Сейчас могут набежать, те кто топит за функциональное программирование, кто за хайповые golang и Котлин и закидать вас монадами, коурутинами и прочими плюшками.
Под каждую задачу свой инструмент. И что-то громоздкое городить на бедном мк, не всегда рационально.
P.s. не холивара ради.
yetanotherman
21.12.2018 02:52У меня проект был попроще, электроника скорее моё хобби, и я наоборот решил попробовать применить приёмы из «большого» программирования прямо «в лоб». Сначала жестко разделил в коде логику и физику, хотя казалось, что логики было намного меньше — по факту оказалось наоборот. Логику тестировал прямо на x86, написал на неё юнит-тесты. Потом, написал что-то типа интеграционных тестов, но без физики — gpio и работа с uart/spi и прочим io — пробрасывалась программно на код, который работал с «той стороны» чипа (то есть на хостовой системе или в соседнем чипе). Это тоже гонялось какое-то время на x86, пока я доделывал устройство. Последним шагом создал тестовый стенд из готового устройства и raspberry pi, который своими gpio зацеплен за тест-поинты и может шить чипы устройства через бутлоадер по uart. На нем бегает агент от гитлаба, который по изменению кода в репозитории шьет новую версию и прогоняет ранее написанные тесты уже на железе с полноценной интеграцией всех компонент (тесты и код хостовой системы бегают на малине, в чипах прямо продакшн-прошивка без каких-либо тестовых инструментов живёт). Плюс к этому есть агент на x86, который гоняет ранее написанные юниты, дабы лишний раз не насиловать флеш контроллера, когда я делаю глупую ошибку.
Может конечно будь у меня OpenOCD я бы пошел по пути близкому к вашему, но так через test driven development и автоматизацию деплоя удалось упростить большую часть экспериментов с освоением периферии чипа, бонусом получив дополнительное покрытие тестами.
Пока у меня не до конца закрыт вопрос с аналоговым трактом, но его для успешного завершения проекта всё равно решать, лень мне руками несколько десятков модулей тестировать, поэтому, видимо, стенд обрастёт парочкой программируемых источников напряжения для генерации тестовых сигналов (хотя может хватит фильтрованного ШИМа с малины опять же).
truebest
21.12.2018 06:16Крик души.
Как же меня достали эти микроконтроллеры. Я больше так жить не хочу. Я устал. Это супергеморой. Я устал от того количества проводов, и места, которое занимает устройство на столе. От того что иногда приходится подготавливаться, припаиваться, чтобы посмотреть события на шине, чтобы отладить периферию. Инструменты отладки и программирования есть разные, нужно разбираться в различных программаторах, методах, способах, и чего-там нового напридумывали разработчики этого софта. Самый ужасное это программирование периферии. Помимо хороших знаний схемотехники, конкретной схемы, особенностей, нужно вкуривать дотащит. Если у вас 5-10 различных периферийных устройств на разных шинах, в среднем вам нужно досконально знать и понимать как это устройство лучше использовать. Средний даташит до 100 страниц (ADE7878A), потом нужно написать под него LL драйвер, если у вас RTOS, на одной шине, реализовать атомарный доступ, драйвер ос по сути. Читать Datasheet, App note, Reference Manuals, Programming Manuals и понимать как лучше реализовывать те или иные фишки. И это только для конкретного проца или серии. Хороший проект, и вы прочитаете > 1000 страниц.
Если вы более-менее сложную электронику разрабатываете, вам нужна техника, которую нужно переодически обновлять. За этот год только купил: анализатор спектра, осциллограф, лаб БП. Есть хороший мультиметер, анализатор логический. А мне еще генератор сигналов векторный нужен. Периодически RF занимаюсь. До кучи вы должны быть электронщиком-схемотехником.
Прошивки могут быть достаточно большими, например текущий проект: 20к строк бутлоадер + 80к строк основная. Это без либ конечно. Недавно ступил и не поставил скобочки в условии у функции, как итог, прошивка неожиданно падала, а компилятор молчал. Или решил обновить freertos на свежий, поставил скомпилировал и устройство стало падать раз в день. От чего? Как найти? Вернул в зад. Отладка сложная, невозможна без таких подходов, как у автора например. В свое время создал для себя UART логгер на SD, тк устройство не для работы на столе предназначалась.
Единственный критерий исправной прошивки — работа устройства без всяких ватчдогов в течении недели/месяца. Это значит что код должен быть качественным.
Софт: Нормальный софт платный, я пользуюсь Visual Studio + VisualGDB + ReSharper. Две последних позиции более 10к в год. Не понимаю людей как можно пользоваться Keil, IAR, CooCox, Eclipse и тд. Пользовался всем, ужасный софт.
Документация: Все нужно документировать, иначе никто кроме тебя не разберет, особенно те места, где пересекаются границы программистов.
Иногда требуется софт на ПК для настройки, или сам пишешь если нет документации или программиста. Лучше делать его кроссплатформенный.
Зарплата: разРаб на stm32 — 100к в СПБ, ну и чуть больше в МСК, а в регионах… Знать нужно ВООООО, опыта — ВООООО лет от 5-ти.
Для меня большое счастье, когда нужно писать например на Go или Java. А SQL — это кайф. А mongoDB — еще больший кайф. А знаешь Java можно сказать что знаешь Android, несмотря на то что нужно в тренде быть, знать что нового в ОС напридумывали и как это правильно в коде реализовать.
Все, кто ко мне приходят с целью узнать, как быть разрабом МК, отговариваю, показываю этот супергеморой, показываю ЗП на HH, говорю что лучше быть Android программистом. Go, Java, Kotlin.
Один мои приятель, с появлением второй дочери, в регионе, денег перестало хватать, бросил МК, и ушел в Go. Можно быстро переучиться с C/C++. Спустя год зарабатывает хорошие деньги, и гораздо счастлив.
Другие мои знакомые, кто хоть раз писали прошивки, сразу поняв что это геморой, ушли в системное C++/C# и БД.
Не занимайтесь этими микроконтроллерами, не тратьте свое драгоценное время, они его отбирают, отбирают эмоции, которые вы могли бы потратить на родных и близких и задолжали, будьте программистом и хорошо зарабатывайте. Вы не будете писать такие эпосы, а в вашей жизни будет время больших чудес, а не штудированная даташитов.vvzvlad
21.12.2018 10:25Угу-угу, все так, программировать можно и в более комфортных условиях. Только вот ни одна из этих областей не дает то самое чувство, когда берешь в руки железку, которую сделал и запрограммировал ты, и она работает. Когда видишь, что твоя работа — не просто биты в памяти и пиксели на экране.
truebest
21.12.2018 13:18Согласен, меня самого это и привлекает, когда бездушная железка начинает «дышать».
Но с опытом, считаю железка это проблемы — ее нужно произвести, ее нужно продать. Иногда нужны компоненты, которые нужно еще и растаможить.
Софт легко поправить и выслать новую версию, с железом так не получится, будешь рекламации собирать от заказчиков, и ответственность выше, потому что железка должна работать надежно.
eternalego
21.12.2018 10:52+2До кучи ещё можно вспомнить ПЛИС и VHDL, тоже зона отладочного кошмара. Четыре года назад ушёл с микроконтроллеров и микропроцессоров на более высокоуровневое программирование, и не жалею. Тоже конечно не везде можно нормально отлаживаться, не для всех языков и не для всех окружений удаётся построить удобную инфраструктуру. В общем, на самом деле всё это, конечно, вопрос в основном опыта и личных пристрастий: чем их больше в какой-то области, там и хорошо :)
truebest
21.12.2018 13:22В ПЛИС не имею большого опыта, пару раз с циклоном 4 в картусе поигрался, сделал аппаратный вывод на VGA монитор рядом параметром, еще что там много, но ничего серьезного. Даже понравилось. Но тут хотя-бы симулятор есть полноценный, как у xilinx так и alterra, можно побочно отлаживаться.
Mih-mih
21.12.2018 10:52Ваш пост читается как «разработка встраиваемых систем — это очень интересно, но не для всех» :). Настоящее удовольствие приходит тогда, когда ты еще и разработчик собственно железки, которую отом оживляешь. А самое-самое удовольствие, когда в проекте есть место и для
легкого безумияПЛИС, программу/не программу для которой тоже пишешь ты.
Полное слияние железа и софта для него.
Ну да, это должно нравиться, иначе боль, тоска и в лучшем случае уход в чистые программисты. С зарплатами увы, есть такая проблема, которая усугубляется еще и тем, что работа начинает «держать». Уходить с нее, собственно, некуда, только на другую такую же.Mogwaika
21.12.2018 10:54Так, на какой язык проще переучиваться после верилога?
Mih-mih
21.12.2018 11:20На VHDL ). Языки описания аппаратуры слишком сильно отличаются от языков программирования. Другой способ мышления, если хотите.
Mogwaika
21.12.2018 11:28А с нуля тогда что лучше изучать?
Mih-mih
21.12.2018 11:49Речь про HDL-языки? Вряд ли можно сказать, что «лучше». По ощущениям, на верилоге пишет бОльшее количество народа. С другой стороны, VHDL более структурированный, что ли, плюс есть некоторые возможности, которых нет у верилога. С третьей стороны, есть еще и SystemVerilog, с неимоверно более богатыми возможностями в плане верификации. С вменяемой литературой вот только по нему плоховато.
По остальным языкам, впрочем, тоже. В свое время мне ветка по верилогу на forum.ixbt.com помогла больше, чем все имеющиеся на тот момент книги.truebest
21.12.2018 13:26Я для себя их так классифицировал, они похож на Си другой на Паскаль. Мне паскаль с университета не нравился своими бесполезными begin и end.
Mogwaika
21.12.2018 13:52Понятное дело, про не HDL-языки, выше же обсудили, что в среднем больше за них платят…
Misaka10032
21.12.2018 11:27«разработка встраиваемых систем — это очень интересно, но не для всех»
Подписываюсь под каждым словом.
И под каждым словом автора комментария в начале ветки (кроме SQL и Java, не приходилось разрабатывать на них).
Уже несчётное число раз думал уйти нафиг из embedded. Но кайф от разработки железа, пайки, отладки удерживает. Плюс ЗП вроде вменяемая.
Надеюсь, что всё же к 30 годам гормоны улягутся и я таки уйду в чистого программиста, ибо ситуация с соотношением ЗП\навыки в эмбеде и правда удручает.truebest
21.12.2018 13:39К 30 годам станет только хуже, и желание и речь про что-то изменить сменится на какой в этом смысл.
А с кайфом по разработке железа, нужно понять какого он типа — если это доминантность (делаешь то что другие не могут или что-то уникальное что никто другой не делал), я всегда вспоминаю профессоров в институте, некоторые из них академические ветки придумали, но при этом ходят в протертых штанах, получают копейки, и за это держаться, когда зав.каф. уже давно используют по полной индексы хирша, гранты, конференции и тд в том числе для прибыли.
Наверное, в определенное время они не готовы меняться, что против логики жизни, и остаются делать то, что редко кому нужно.
Это не значит что нужно талант на деньги менять, это значит что свое реальное время жизни надо менять на реальные ресурсы.Mih-mih
21.12.2018 13:47А удовольствие от работы — это реальный ресурс? Или же реальный ресурс это всегда кэш? И как тогда быть с вещами, на которые тратишь свое реальное время и реальный кэш, взамен получая удовольствие?
Цель/смысл жизни это штука такая… У всех разная.truebest
21.12.2018 13:57Я считаю так, если ты настоящий программист, ты можешь писать на любом языке. Это подтверждают мои некоторые друзья, которые иногда шли устраиваться на backend, но собеседование было по frontend, их брали на работу, за месяц они вникали в тему, и начинали работу над проектом. И им по кайфу это стало делать.
А все железо, они на хобби оставили, коптеры собирают, ну и что там AlexGyver делает на youtube. Просто не нужно бояться перемен.Mogwaika
21.12.2018 14:02Тут вот обсудили, что с hdl на не-hdl сложно перескакивать или с асм-а на ооп…
Mih-mih
21.12.2018 14:08А что делать, если не «программист», а «инженер» (да не будет это никому в обиду сказано)? :) И тем более, если с хоббями (совершенно другими) и так нет никаких проблем? :)
Просто вот для Вас, если я правильно понимаю, «эмбеддед»===«программированию контроллеров». Написание программ для них, не больше и не меньше. Работа с собственно самой железкой скорее неприятное дополнение, обязанность, нежели чем сколь-нибудь интересный процесс. Ещё и деньги, фиктически, отнимает. В таком случае на этом «эмбеддед» сидеть нет никакого смысла, это верно.truebest
21.12.2018 14:28Я скорее сам инженер. Для меня нормально это и схемотехника и программирование.
Embedded я скорее называю разработка устройства, с процом и ОЗУ, где есть ОС, более менее полноценная типа Linux. Это сложная схема и плата, uboot, это настройка ядра, buildroot, это кросс-компиляция, ну и дальше, какой-либо твой софт.
Все что типа at91sam, stm32, nxp и тд. это микроконтроллеры, там интересные схемотехнические решение, и крайне сложный софт. Это иногда разработка DC/DC (тут недавно статья была от Nordic), иногда и трансформатор помотать руками приходится. Это про то как и чем bulk от boost отличаются, и что такое Sepic. А прошивка — вдохнуть жизнь в плату.
Я просто хочу сказать, что на берегу, где есть backend/frontend есть жизнь, она более интересная, более нужная людям и как результат более высокооплачиваемая. А драгоценное время жизни, вы можете потратить на родных и близки, на то, что действительно важно!
Misaka10032
21.12.2018 13:48ходят в протертых штанах
Посмотрел на свои ботинки, в которых вместо замка — пластиковые стяжки для проводов…
Чёрт, пора идти за новыми. Мне просто лень на другой конец города ехать.
А насчёт разработки железа — в данный момент времени я просто понимаю, что не смогу променять то, чем мне нравится заниматься, на то, от чего меня спать тянет, пусть даже за вдвое большую ЗП.
Очень надеюсь, что через несколько лет я всё же смогу найти направление в IT вне эмбеда, за которое смогу зацепиться и в которое смогу развиваться.CrashLogger
21.12.2018 14:05Я вот смотрю в сторону Китая — там сейчас востребована разработка всяких девайсов, и железячники и программеры в цене. Но эта страна на любителя конечно, не всем подойдет.
truebest
21.12.2018 14:11Дело тут не только в ботинках, а скорее в семье и воспитании. И чаще негативном. Меня например в детстве, мамка на базар таскала, купить «серенький» свитерок под горлышко. А мне с утра так это не нравилось, а меня таскали и предлагали, ну вот посмотри, а этот, а тот. В итоге в 18-20 лет я ходил в чем угодно, лишь бы не идти в магазин за вещами. Что сыграло плохую штуку, барышням, которые мне нравились, я был не очень интересен. Помню, как появились деньги, насильно себя заставлял идти в магазин идти и выбирать, мерять, снимать. Сейчас с этим вроде хорошо. Теперь я за вещами в Стамбул езжу, там она дешевле стоит, ну и там вкусная еда еще.
Я сейчас думаю что здорово быть, красивым (следить за собой, одеваться стильно и в спортзал регулярно ходить).
Вам наверное по советую сделать большой и сложный проект embedded, значимый для вашей психики. Завершить что-то. Тогда вам захочется чего-то нового.
uldashev
21.12.2018 16:40В политике самый высокий курс обмена времени на блага, в финансах, но никак не в программировании.
Whuthering
21.12.2018 11:05+1Как с языка сняли. Именно такие же мысли и ощущения. Сам ушел из embedded в бэкенд, и не жалею.
truebest
21.12.2018 13:42Все кто из embedded ушел, все не жалеют. Из всех моих знакомых это точно. Я сам следующий. Тоже бекэнд нравится, хотя если честно, мне просто нравятся разные языки. А вас, сердечно поздравляю!
truebest
21.12.2018 15:21+1Определенно последнее, что мне не понравилось в том чтобы быть таким разработчиком.
Меня перевели в новый отдел, нас стало 4 человека: схемотехник и три программиста. Знаете сколько было руководителей? 3 человека. На них весели еще обязанности, но главной конечно было драть с нас 3 шкуры. Нужно было делать то что нужно, а не то что ты хочешь, и не всегда этот проект или железка интересна. Конечно, нужно уметь работать над проектом, в независимости от того нравится или не нравится железка, но порой, когда запросов много ты просто превращается в некий обработчик чужих хотелок. А для работы того или иного устройства нужно вложить душу. Я понял, что в современном мире, имея убеждения, которые позволяют кайфовать от того что например железка заморгала как надо, более шустрые ребята будут попросту использовать вас, ваше время, мозги, меняя на ЗП в 65к (3 года назад была такая зп у меня). Таким поведением и взглядами вы заранее обрекаете себя на использование вас другими бабуинами.
Душу можно вкладывать в свой проект, в свой бизнес, что не посредственно вам эквивалент затрачено частички души, времени и сил. А не пустые поздравления старших коллег, показывающих вашу значимость, признание в коллективе, или эмоции от заработавшей платы, по сути манипулируя вами.
Как только простые люди поймут основу своего я, самоидентифицируются, управлять, т.е. манипулировать ими будет чрезвычайно тяжело».
Я уволился, сейчас получается зарабатывать в разы больше, и заниматься своими проектами. Следующий шаг — уйти из программирования под МК и стать разработчиком на высокоуровневых языках. Мк, оборудование останутся только для хобби проектов. Жизнь с годами должна становиться проще.
CrashLogger
21.12.2018 10:05+1На мой взгляд, микроконтроллеры — это одна из немногих областей, где осталось настоящее программирование, с алгоритмами и оптимизацией. В большом мире, где фреймворк на фреймворке и ты только дергаешь чужие методы и раскидываешь кнопки по форме, совсем не осталось места для творчества.
Whuthering
21.12.2018 11:08+1Лихо вы большую часть современного IT вычеркнули :)
… системное программирование, высоконагруженные сервисы, графика и геймдев, машинное зрение, обработка больших данных…
Там хардкорные алгоритмы жизненно необходимы, и тщательная оптимизация процветает во все поля.
truebest
21.12.2018 13:51+1Из-за объема, бывало и такое что делили прошивку, и писали в несколько человек.
Дело еще в том что кому-то проще читать даташиты и описывать LL функции, а кто-то, кто постоянно с абстракциями работает, он может над логикой поработать.
Как не странно, си отлично поддерживает модульность, функции заглушки и тд, и позволяет работать в команде. Так вот, те, кто работает только с логикой, уже не знают что там внизу, хоть и могут посмотреть.
«Фреймворк на фреймворке» — у меня так руководитель говорил, хотя на деле, для современных stm32 уже приходится использовать криптолибы, либы USB, и другие.
Наверное он так говорил, тк он иногда на ассемблере писал под какой-нибудь pic10f200, да и вообще asm много времени посвятил и разным процам.
Ryppka
21.12.2018 12:16А не думали попробовать в qemu эмулировать устройство? А целом вроде на английском сейчас только ленивый не пишет/докладывает про off-target test driven development…
ser-mk Автор
21.12.2018 13:19Вы про тестирование программ на эмуляторе?
Если так то у меня стояла другая задача.
Мне требовалось проверять физические устройства/платы на ошибки монтажа, корректность установленных микросхем.
А так же мне нужен был удобный инструмент для экспериментов и изучения работы с новыми устройствами.
Поэтому qemu и off-target test driven development мне тут в помощь не будут.
FForth
21.12.2018 12:28Репозиторий Mecrisp Форт кода Jeelabs
github.com/jeelabs/embello/tree/master/explore/1608-forth
ripandtear
21.12.2018 16:58+1Абсолютно похожие мысли. Начинал с программирования МК (STM32, PIC32MX), потом «перетек» в DSP (Analog Devices), сейчас докатился до того, что пишу целиком на ассемблере под DSP-ядро (вместе с оптимизацией), которые крупные вендоры встраивают в свои SoC. Производитель этого DSP-ядра не поставляет C-компилятор. Планирую в ближайшем будущем уходить в С++ или Rust, в свободное время изучаю эти языки, и наконец-то забыть весь этот фулл-таймовый ассемблер как страшный сон.
Мое личное мнение — большинство психологических неудобств вытекает из того, что при работе с железом, плохо оборудованы рабочие места, и сам рабочий процесс не очень хорошо налажен. Ну вот банальщина — один осциллограф на отдел, две или три платы на 6 и более программистов, все испытательные стенды собраны из веточек из желудей (Вместо разъемов скрутки которые вылетают и т.п.) потому что «Зачем нам нормально все собирать, все равно этот стенд потом разбирать» и так далее. «Электротехника — это наука о контактах» — вот это точное попадание. Можно до посинения отлаживать код, а потом выяснить, что кто-то где-то вместо пайки засунул провод в разъем на стенде, капнул при пайке припоем и замкнул цепь, подал вместо 24V DC 24V AC, примеры можно до бесконечности приводить…
В общем, если коротко о главном, в меньшинстве пишется сама полезная нагрузка (функционал и т.п.) а в большинстве — борьба со всем сопутствующим.
RobbieKhan
21.12.2018 18:51Белые люди тестируют проекты с помощью JTAG Boundary Scan
ser-mk Автор
21.12.2018 19:03Если вы к ним относитесь, то интересно будет узнать об этой технологии, особенно интересна цена.
truebest
22.12.2018 02:59EEVblog #499 — What is JTAG and Boundary Scan?
ser-mk Автор
22.12.2018 10:47Полно таких красивых видео и сайтов.
Но нигде почему-то не говорится про цену внедрения.RobbieKhan
22.12.2018 12:13Цена огромна, обычный человек не купит, но предприятие может себе позволить
Amomum
Ох какая классная наркомания! Круто!
По-моему, более «традиционный» подход к такому (который исповедуют всякие микропитоны и эспруино) — это интерпретатор на самом проце, с написанием кода в терминале. Не берусь судить, какой подход проще или лучше.
ser-mk Автор
Можно и так, но тут считай сравнивать теплое с мягким.
Потому как предназначения разные. Виртуальные машины / интерпретаторы на МК, могут исполнять скрипты автономно и вполне могут использоваться в продакшене. Но там мы упираемся в ограничение ресурсов МК, необходимость портирования вирутальной машины / интерпретатора, а так же еще написание библиотек переферии.
В моем подходе программы/скрипты не могут исполняться автономно, но нам доступны все ресурсы нашего хостового ПК, все виды библиотек и все виды языков программирования. При этом при использовании С/С++ можно использовать стандартные библиотеки от производителя для работы с переферией.
NetBUG
… а также в надёжность, производительность, объём и соответствие этих библиотек/интерпретаторов условиям задачи (лицензия, железо)
NetBUG
ПРошу прошения, не в ту ветку.