
Комментарии 62
Когда управляешь инвертором двигателя, real time измеряется 10-30мкс.
Что же вы самое интересное пропустили? Откуда у вас взялись такие цифры 10-30мкс?
Я правда делал управление коллекторным двигателем, там слот времени принятия решения определялся полупериодом сетевого напряжения (50 Гц, 220В) это
1000 миллисекунд / 50Гц / 2 полупериода = 10 миллисекунд.
Семистр открывается до следующего пересечения нуля сетевым напряжением. Но некоторые вещи тем не менее требуют почти абсолютной точности расчетов по времени, это правда, как говорится "это real time детка!" :). Причем проблема не только минимальное разрешение, есть еще проблема больших интервалов для которых должна поддерживаться точность, например однажды выставленные 10мс должны колебаться вокруг именно 10 мс, а не 9.9 мс(например) на протяжении потенциально бесконечного времени работы драйвера двигателя...
В этом случае разработчики начинают использовать прерывания, и распихивать код по ним. После определенного количества прерываний, можно получить ситуацию, что одно будет мешать другому в непредсказуемых комбинациях которые отладить бывает очень трудно.
Эта задача решается не в языках программирования! В языках программирования нет такого понятия: "прерывания", ни в одном! Надо построить схему или диаграмму прерываний - то есть надо придумать как(!) конкретную схему нарисовать, для определенного набора прерываний и необходимого времени на их обработку так, чтобы они не накладывались непредсказуемым образом, а в коде надо просто контролировать что схема работает, то есть не происходит не продуманных наложений. Это проверяется на этапе отладки-тестирования, когда схема проверена это превращается в простую математическую задачу уровня 5-7 класса. А вот придумать как грамотно изобразить-начертить схему и как ее проверить - это действительно сложно.
Если интересно я могу подробно, с примерами, рассказать как создавать такие, поддающиеся проверке, схемы прерываний. Я думаю на эту тему можно даже написать диссертацию, если руководитель найдется, который не постесняется руководить изучением такого нестандартного вопроса в нашей научной традиции.
Что же вы самое интересное пропустили? Откуда у вас взялись такие цифры 10-30мкс?
Я правда делал управление коллекторным двигателем, там слот времени принятия решения определялся полупериодом сетевого напряжения (50 Гц, 220В) это
1000 миллисекунд / 50Гц / 2 полупериода = 10 миллисекунд.
Неверное у вас двигатель был подключен к электрораспределительной сети, а у него в мобильной сети.
Ну например BLDC покрутить. Им надо 2кГц. Защитный контур по транзисторам как раз 10-30мкс, иначе они успеют надежно сгореть. А симистором управлять, на современных МК как угодно можно, все равно хорошо будет.
2 кГц - это пол миллисекунды и это действительно уже практически на пределе возможностей процессора который работает на частоте до 100МГц, ну как на пределе - если заниматься ручной оптимизацией то запас есть, но он счетный, скажем пара тысяч тиков = примерно тысяча инструкций ассемблера запаса - это можно посчитать, но почему вы ориентируетесь на 10-30мкс все равно не понятно!
Защитный контур это наверняка какая-то схема, пока эта схема не сработала с нее, ну может идет какой то дежурный сигнал, но вряд ли каждые 30 мкс! Сделать счетным время реакции на аварийное прерывание не так уж и сложно (если догадаться сделать аварийный сигнал прерыванием высшего приоритета). Это конечно еще вопрос насколько грамотно (тоже оптимально) сделана обвязка процессора. Это другой сложный вопрос, что сигналы должны грамотно распределяться по типам и по задержкам друг относительно друга. В обвязке это тоже нужно контролировать, а лучше спланировать.
@audisergзаказ принял! К сожалению теперь я не работаю с механикой или с ПИД регулировками, месяца два понадобится, на фоне основной работы, чтобы воспроизвести что-то по памяти, думаю. Но я в принципе давно хотел - не мог определиться с темой, спасибо автору этой статьи, у меня сформировалось что-то вроде той печки от которой надо плясать формулировать, а еще, недавно правленые драйвера Линукса теперь помогают мне сопоставить то, что я делал на голом железе с тем, что можно найти в ядре Линукса.
Интересно! Рассказывайте! )
Ковырялся (года 4 назад) в коде для 32 кГц BLDC + CAN и оно норм работает на stm32f4, можно быстрее, но уже в АЦП упирается - надо брать stm32g4 - на 64кГц целились
Контроллер с хорошей периферией позволяет решить задачу фазового управления аппаратно. (dsPIC33EP...).
// Задержка в мс
async me_delay(struct async *pt, uint32_t ticks)
{
async_begin(pt);
static uint32_t timer_delay; // <<<--- если забыть static будут прикольно
timer_delay = timer + ticks;
while(!LoopCmp(timer, timer_delay)) {
...
У себя использовал похожую схему. Я использовал - "постепенно исполняемые функции" (afn - async fn). Вообще любая такая функция просто набор 3х указателей: 1-состояние асинхронной функции (ctx), 2-обработчик сигналов (setup), 3-обработчик итерации (loop)
afn.h
typedef struct afn_t {
void *ctx;
int (*setup)(void *ctx,int sev);
int (*loop)(void *ctx);
} afn_t;
enum SetupEvents { sevInit, sevDone };
Если функция loop вернула 0 то она закончила, если 1-еще рабоает, остальные коды прерывания можно использовать для запросов. Функция setup тоже 0=ok. Фунция гарантируется что если вызвали setup(sevInit) то обязательно будет вызван setup(sevDone). И то что функция loop быполняет итерацию за конечное время. И самое главное предача кванта управления выполняется явно.
А вот для реализации итераций в обработчике loop была такая же схема как и тут на switch-е. Но не на LINE а на COUNTER. И все переменные которые использует асинхронная функция она явно описывает в своём состоянии. Примерно так:
example.c
/* example.c */
#include <stdio.h>
#include "afn.h"
#include "loop-fn.h"
typedef struct fn1_ctx {
loop_t loop;
int i;
} fn1_ctx;
int fn1_setup(fn1_ctx *my,int sev) {
if (sev==sevInit) LOOP_RESET(my->loop);
return 0;
}
int fn1_loop(fn1_ctx *my) {
LOOP_BEGIN(my->loop)
printf(" fn1.begin");
LOOP_POINT
printf(" fn1.step1");
LOOP_POINT
for(my->i=0;my->i<3;my->i++) {
printf(" fn1.i=%d",my->i);
LOOP_POINT
}
printf(" fn1.end");
LOOP_END
}
int main(int argc,char** argv) {
fn1_ctx fn1[1]; int it,rc;
fn1_setup(fn1,sevInit);
for(it=0;it<10;it++) {
printf("it=%2d fn1=%2d",it,fn1->loop);
rc=fn1_loop(fn1);
if (!rc) printf(" [fn1 is done]");
printf("\n");
if (!rc) break;
}
fn1_setup(fn1,sevDone);
return 0;
}
output:
it= 0 fn1= 0 fn1.begin
it= 1 fn1= 1 fn1.step1
it= 2 fn1= 2 fn1.i=0
it= 3 fn1= 3 fn1.i=1
it= 4 fn1= 3 fn1.i=2
it= 5 fn1= 3 fn1.end [fn1 is done]
loop-fn.h
/* loop-fn.h - sequential execution function */
#ifndef __LOOP_FN_H__
#define __LOOP_FN_H__
typedef int loop_t;
#define LOOP_RESET(loop) { loop=0; }
#if defined(__COUNTER__) && __COUNTER__!=__COUNTER__
#define LOOP_BEGIN(loop) { enum { __loop_base=__COUNTER__ }; \
loop_t *__loop=&(loop); __loop_switch: int __loop_rv=1; \
switch(*__loop) { default: *__loop=0; case 0: {
#define LOOP_POINT { enum { __loop_case=__COUNTER__-__loop_base }; \
*__loop=__loop_case; goto __loop_leave; case __loop_case:{} }
#else
#define LOOP_BEGIN(loop) {loop_t*__loop=&(loop);__loop_switch:int __loop_rv=1;\
switch(*__loop){ default: case 0: *__loop=__LINE__; case __LINE__:{
#define LOOP_POINT { *__loop=__LINE__; goto __loop_leave; case __LINE__:{} }
#endif
#define LOOP_END { __loop_end: *__loop=-1; case -1: return 0; \
{ goto __loop_end; goto __loop_switch; } } \
}} __loop_leave: return __loop_rv; }
#define LOOP_SET_RV(rv) { __loop_rv=(rv); } /* rv must be non zero */
#define LOOP_INT(n) { __loop_rv=(n); LOOP_POINT } /* interrupt n */
#define LOOP_POINT_(name) { *__loop=name; goto __loop_leave; case name:{} }
#define LOOP_INT_(n,name) { __loop_rv=(n); LOOP_POINT_(name) }
#endif /* __LOOP_FN_H__ */
Такие функции могут итерироваться супервизорорами. Они очень удобно отслеживают и реагируют на аварийные ситуации и итерируют подопечную функцию. А для выполнения множеста таких функций используются планировщики. Они довольно разнообразны и это целая отдельная тема.
Мне одному это сильно напоминает Protothreads от Адама нашего Дакнкелса?
Когда управляешь инвертором двигателя, real time измеряется 10-30мкс.
Хорошо живете, столько времени иметь в запасе
Однако чтобы прицизионно контроллером измерить напряжения и токи во всех фазах и еще внутренности разные измерить, делая это синхронно с шимом, то останется всего пара микросекунд. Это половинное время минимального пульса ШИМ.
Потому что уложиться надо от середины пульса и пока не возникнет фронт или спад на какой либо фазе. На это, кстати, указывается во всех мануалах по управлению двигателями на однокристальных SoC.
Поэтому всяческие коооперативные переключатели, как в этой статье, никак уже не подходят.
Приходится применять вложенные прерывания с приоритетностью, и обычную RTOS типа FreeRTOS.
Ничего лучшего человечество пока не придумало.
Да основные вычисления делаются в прерывании. По другому никак. Но скрещивать RTOS с управлением мотором это я еще нигде не видел ))). по поводу переключателей, есть куча доп интерфейсов, интерактивность для человека, меню, кнопки, сигналы внешние, все это надо фильтровать и обрабатывать перед принятием решением. Медленные сигналы в виде напряжения DC звена управления контактором. Там переключатели очень даже хорошо. внутри самой математики у меня лично есть ветвления и там применяется указанный подход. В целом соглашусь с одним из комментариев, что построение реал тайм мастерство. А у каждого мастера может быть свой подход.
Но скрещивать RTOS с управлением мотором это я еще нигде не видел ))).
Есть известный/успешный в своих кругах проект VESC, управляющий 1-2 моторами. Построен на ChibiOS.
Да основные вычисления делаются в прерывании. По другому никак.
Это прям беда! Я такое как раз переделывал в том числе. По другому гораздо лучше, надежнее и все такое. В ядре Линукса есть такой термин bottom half, примерно та же идея замечательно работает для любых прерываний в любой системе. Ядро Линукса это, в общем то, тоже эмбеддед программа, наверно самая известная.
Интересный подход! По названию, я подумал, что вы будете говорить о реализации асинхронный логики путем использования аппаратных контроллеров периферии и памяти. Но тут настоящий python/js async :) Выглядит впечатляюще!
Хотя я бы так не писал. Во многих задачах, где мне доводилось применять микроконтроллеры, нужно так или иначе реальное время - а том смысле, что время реакции системы на входные сигналы должно быть однозначно предсказуемо. Применение async этому препятствует - очень трудно однозначно сказать, будет в конкретном месте когда yield или не будет, и не получится ли, что при каком-то редком сочетании факторов время реакции будет неожиданно сильно большим, чем в остальных случаях.
Ну и к preprocessor hell это уже очень близко. :) Напоминает труды Александреску по C++, очень красиво, но лучше не применять в реальной жизни)
И несправедливости, что возит, поит, греет творение М.О. Доливо-Добровольского, а поминают Н. Тесла. Причем АД второго, невероятно плох. Двухфазный (привет асимметрии линий электропередачи), концентрированная обмотка на полюсах (прощай КПД), ну и низкий пусковой момент. А вот Михаила Осиповича творение с первого включения показало КПД в районе 90 и двойной пусковой момент, что и стало стандартом де-факто с 1891г. и по сей день.
Михаи́л О́сипович Доли́во-Доброво́льский внес существенное усовершенствование в переменный ток добавив еще одну третью фазу. Сместив фазы одна относительно другой на 120°. Вообще чем фаз больше тем лучше штук так сем вообще было бы замечательно. Жаль только ЛЭП располагать трудно, а выгода "мизерная". Тесла предложил только 2 фазы их было мало третья же фаза оказалась решением проблемы оставшейся после Теслы. Тоесть не следует противопоставлять, они скорее коллеги чем соперники.
Они были жесткими конкурентами. Тесла - это американский Westinghouse, у американцев Тесла не взлетел и они подтянули патенты Феррариса, Добровольский - это немецкий AEG. Где то в 1900ых они даже соглашение заключили о разделе "мира" по районам продаж. После первой мировой, немцев осадили, но AEG существует и по ныне. Основная проблема двух фаз проводов ЛЭП там три тоже, но они разного сечения. Единственная электростанция двухфазная была на Ниагаре, и то ее преобразовывали на 3 фазы трансформаторами Скотта в итоге.
Причина несправедливости в том же, почему у них закон всемирного тяготения называют законом Ньютона, а таблицу Менделеева называют просто периодической таблицей элементов.
Вообще построение систем реального времени (то есть систем с гарантированно малым временем реакции на событие) требует определённого мастерства. Надо понимать что на некоторые события реакция должна быть побыстрее на другие и более медленная подойдет. Поэтому проверки событий вставляются в циклы и/или прерывания и в зависимости от режима опрашиваются либо не опрашиваются, на предмет того произошло ли событие.Не лишним бывает совокупность условий, и импровизированный интерпретатор логического программирования. Сам предпочитаю использовать длинные последовательности else if и с условиями режимов и событий на предмет необходимых реакций. Но так чтобы универсального решения то на мой взгляд нету.
Имхо, понятие "реальное время", распространимо только на один, самый приоритетный процесс.
Все остальные будут - мягкого реального времени, т.к. в любой момент могут быть прерваны тем, самым приоритетным процессом.
Есть только одно определение систем реального времени. Это системы с адекватной реакцией на событие за гарантированно достаточно малое время.
Обычно один какой-то процесс либо как либо иначе обособленную составляющую задачи труднее всего реализовать, но это не значит что другие не подчинены тому же принципу.
Если например прерывание может обеспечивать скажем считывание обработку АЦП и выдает какой-то адекватный сигнал управления по полученному сигналу АЦП. И такой обработчик скажем программу которая настраивает режим работы для этого же обработчика. То если режим работы для такого фильтра который меняется гораздо реже, не будет изменен пускай с большей допустимой задержкой но все таки вовремя, то какой смысл тогда в таком обработчике.
Немного не соглашусь с вами.
Реакция на событие может быть не за такое уж и малое время, оно может быть и достаточно большим. Но оно гарантировано.
Т.е. мы гарантируем, что если в момент времени T0 у нас наступило событие, то в момент времени T0+Tevent будет получена реакция на события.
Где Tevent - время реакции, оно документировано и гарантировано.
Плюс системы РВ делятся на системы жесткого и мягкого РВ. В первых Treact должно быть точно выдержано, вплоть до такта процессора. Во вторых допускается некоторое отклонение от точного Treact, но оно так же документировано и не должно превышаться.
Так вот я имел в виду, что в однопроцессорной системе мы можем обеспечить точную выдержку времени (то есть режим жесткого реального времени) только для одного события. Для всех остальных будет задержка реакции, в случае поступления двух событий одновременно.
Как "Гарантированное малое" я имел в виду в том смысле что не более чем некоторое достаточно малое значение. например где-то 100 пикосекунд много, а где-то и пару дней немного.
Определение жесткого мягкого реального времени измерения в тактах процессора вызовах прерывания таймера еще либо в какие единицах относятся к практической реализации фундаментальной теории.
Обеспечение приоритетов, расчет гарантированно малого времени реакции, тоже интересная задача, не имеющая общего лучшего решения. Нахождение частного решения иногда позволяет очень экономить. Конечно не возможно обеспечить гарантированно малое время на одном ядре процессора если такое малое время в каждом случае требует заход в прерывание в произвольный момент для одного процесса по отношению к другому, опять же но есть частности.
В принципе прикладной разработчик видит задачу с точки зрения прикладной науки, фундаментальная выглядит как демагогия оторванная от практики, но иногда именно фундаментальный подход позволяет исправить ошибки прикладного.
"Условно вызов printf в разных задачах может привести к непредсказуемым последствиям." - под управлением RTOS каждая задача кладёт свои сообщения в LOGGER FIFO, откуда оно уже выгребается постепенно (или записывается куда-то). Суть в том, что форматирование строки - относительно медленная операция и её можно прерывать, а вот копирование из локального буфера сообщений в общий - быстрая, и прерывать её нельзя.
Касательно BLDC и FreeRTOS - в том же MCSDK - это стандартное решение. Более того, и без RTOS там кооперативно сосуществуют несколько тасков, и обмен есть.
в FOC петли (момента, скорости, позиции) имеют предсказуемое и примерно постоянное время вычисления, они просто на прерываниях сидят. А в RTOS уже всё остальное вешается.
В своё время в профильных сообществах интересовался, почему живы RTOS, если для задач, специфичных для них гораздо лучше походят ПЛИС? Не являются ли RTOS и аналогичные сущности попыткой "искать не там где потерял, а там, где светло"?
"Вы шшшштооо! Как вы можете?! Это настолько оскорбительно, что мы даже обсуждать это не будем!" был наиболее частый ответ :))))
Сложно конструктивно обсуждать сравнение теплого с мягким
Сложно конструктивно обсуждать сравнение теплого с мягким
...зато легко вставлять не по месту комментарии про "сравнение тёплого с мягким" :)))
Ну потому что это реально теплое с мягким. FPGA и кремний это про парралельное исполнение кучи простой логики, RTOS это про жонглирование высокоуровнемым кодом, чтобы он весь исполнялся более-менее равномерно. Если надо датчик считать, на экранчик вывести и моторчиком подрыгать, то FPGA тут лишний.
А вот если надо поток видео пережевать в реальном времени, да еще и в память его писать, то процессор способный на это будет дорогим и жирным. А на FPGA оно реализуетс вполне себе несложно.
Ну и наоборот — попытка написать программу с кучей ветвлений и сложной логики с какой-нибудь математикой или wifi-http на FPGA будет очень больно, хотя на RTOS это пишется на изи. Но да, то что вы напишете на FPGA будет работать ОЧЕНЬ БЫСТРО. А стоит ли оно того? Надо ли в 99% задач?
Ну потому что это реально теплое с мягким
Пока единственное, что реально - это бросание заезженым лозунгом.
Если надо <...> моторчиком подрыгать, то FPGA тут лишний.
попытка написать программу с кучей ветвлений <...> FPGA будет очень больно...
...для человека ничего не писавшего на FPGA. В реальности программа, написанная, например в парадигме автоматного программирования будет что на процессорной архитектуре, что на FPGA даже по синтаксису очень похожей.
с какой-нибудь математикой
Приведите, пожалуйста конкретный пример, чтобы я вам наглядно продемонстрировал, что FPGA за ту же цену, что и MCU насчитает всё гораздо быстрее.
То, что вы изложили - набор матёрых мифов. Единственное ключевое преимущество процессорных архитектур перед FPGA - армия людей, умеющих писать на Си и не умеющих на Верилоге.
Эм. Вы или не понимаете концепта FPGA или троллите.
Пока единственное, что реально - это бросание заезженым лозунгом.
Каким лозунгом-то?
Ну вы бы хоть почитали по ссылке-то, что там говорится. Low latency, 100,000 RPM for sensorless Field Oriented Control (FOC), Surgical Robots, Actuator Control in Avionics, Heart Lung Machines и так далее. Это хардкорные применения, а не "подрыгать моторчиком". Ну и как бы пример не в тему, софистика какая-то: я говорю что для подрыгать моторчиком достаточно МК, а вы мне показываете что это задачу можно решить на FPGA. Ну можно-можно, я обратного не утверждал, только нафига, если этот моторчик не в "Surgical Robots, Actuator Control in Avionics, Heart Lung Machines" и так далее, а в штуке, которая шторы закрывает дома.
В реальности программа, написанная, например в парадигме автоматного программирования будет что на процессорной архитектуре, что на FPGA даже по синтаксису очень похожей.
Ага-ага. В индустрии уже которое десятилетие пытаются придумать что-нибудь, чтобы можно было из привычных императивных языков (или хотя бы из чего-нибудь с похожим подходом) синтезировать логику. Ну придумали разных HLS, DSL всякие, даже из логики на питоне чет можно синтезировать, но чет все до сих пор сидя на VHDL и Verilog, а все эти штуки применяются для отдельных применений или в крайнем случае для синтеза отдельных IP-блоков. Потому что если бездумно писать на си, а потом из этого синтезировать — часто получится неоптимальная фигня
Приведите, пожалуйста конкретный пример, чтобы я вам наглядно продемонстрировал, что FPGA за ту же цену, что и MCU насчитает всё гораздо быстрее.
Ну, какой-нибудь PADAUK PFC161-U06 за эээм $0.07 в розницу? Он мелкий и тупенький, но все же. Ближайшее что можно найти в стоке это SLG46108V за $0.34, но это даже не fpga, а так, cpld.
Ну или ок, ESP32-C3. $2. 4 MB флеша, 400kb RAM (правда часть под кеш), поэтому 200кб, wifi+ble. Чо там, по какому курсу будем обменивать 4 MB асма под RISC-V на LUT-ы? Wifi+ble можно пока опустить.
Вы или не понимаете концепта FPGA или троллите.
Вы допускаете, что этот концепт не понимаете вы?
я говорю что для подрыгать моторчиком
В ваш мозг у меня лаза нет и что вы понимаете под "подрыгать моторчиком" без вашего уточнение - вопрос интерпретации.
Если речь про "штуку, которая закрывает шторы", то с этим и что-нибудь на NE555 и 74 логике справится. Кстати, любопытный вызов.
PADAUK PFC161-U06
И какую же RTOS вы на нём развернёте?
Вы допускаете, что этот концепт не понимаете вы?
Допускаю, конечно. Но пока что-то никто аргументы привести не смог.
И какую же RTOS вы на ней развернёте?
Внезапно, для мультизадачности не нужна ртос.
Ну и вот на ESP32 замечательно FreeRTOS работает.
Должен признаться, статья перекликается с задачей которая у меня на столе.
Суть в чем со старых принтеров определенных годов можно добыть шаговые моторчики и применить для различных задач. Часть моторчиков 2-фазные, но еще часть 3-фазные. Мало того 3-фазные и моторы шпинделей жестких дисков. и приводы больших копировальных аппаратов с внешним ротором.
Для 2-фазных доступно великое множество драйверов а для 3-фазных увы начинаются в основном от профессиональных, попытки приспособить интегральные микросхемы 3-фазных драйверов разбиваются о отличную таблицу дробления фаз.
Микроконтроллеры не обладает достаточным быстродействием для реализации токового драйвера. Где реакция на событие должна составлять ну хотя бы эдак 100нС (и то это очень долго). Исключение составляют stm32f3* у которого есть подходящая автоматика но и они и самые быстродействующие микроконтроллеры и FPGA обходятся дороже чем если бы купить готовые 2-фазные шаговые моторчики и драйверы.
Вот возникла идея использовать дешевые микроконтроллеры и простейшую автоматику на *тм2 (*ls74). Реализовать драйвера сразу нескольких двигателей и в микроконтроллере расположить хотя бы часть контроллера самого устройства (например тот же интерпретатор g-кода). В таком случае получается некоторая выгода решается сразу несколько проблем. Не последней выгодой будет факт наличия обратной связи с детектором пропусков шагов которого в дешевых драйверах обычно не бывает.
В какую цену цифровой части вы хотите уложиться?
Планируете ли вы, что у вас 1 цифровая микросхема может управлять сразу несколькими моторами? Или у вас "1 мотор - 1 микросхема"?
Хочу чтобы кучка дешевых микросхем несколько моторов и получить контроллер с драйверами причем как 2-фазных так и 3-фазных шаговых двигателей.Чтобы сразу g-код выполнял. (кстати 2-фазный можно та же через 3 полу-моста включить как и 3-фазный)
Причем чтобы еще и повторяемой была конструкция. Чтобы посреди радиолюбителей ее распространить.
Сейчас напаяно 1 stm8s105k? 2 74?ls74 3 драйвера с транзисторами и 1 компаратор на общий шунт. и там еще пару стабилизаторов разъемов...


В некоторых задачах тёплое и мягкое комбинируют - FPGA для time-critical вещей, где счёт идёт на нано- и микросекунды, а RTOS - там где десятки микросекунд и миллисекунды и сложная логика. Жирные плисины или плисины с интегрированным hard-processor (типичные примеры из недорогих - Xilinx Zynq, Ultrascale, Cyclone V SE) позволяют делать и то, и другое. Один из известных примеров - проект machinekit: в линуксе preempt-rt крутится парсер g-code и ядро линукса, на логической части - генераторы шагов, обработчики энкодеров, ШИМ и прочая реалтаймовая логика, типа развёртки изображения для гальванического сканера. Так же и в SDR поступают: базовые станции, начиная с 3G - тоже пример такого симбиоза. Радиочасть в плиске крутится - многоканальный модем и DDC/DUC, а процессор обрабатывает протокольную часть. Высокопроизводительные коммутаторы/маршрутизаторы - тоже реализуют эту схему. Процессор управляет записью правил в ПЛИС или ASIC, а пакеты (в труху) перемалывает конфигурируемая логика.
Да в любом осцилле так делается. FPGA быстро семплирует, кладет в память, а мк читает и рисует на экране. МК не умеет быстро, тратить дорогой FPGA на рисование на экранчике жалко, да и писать долго.
Ну, не в любом. Например, свежеиспеченный отечественный осциллограф OSA103 сделан полностью на Спартане, без МК: https://www.osa103.ru/ru/hardware-ru/
Все работает, но… Недостаток у данного подхода — ужасная читаемость кода.
Под "читаемостью кода" подразумевается понятность логики работы программы? Когда реализуется сложная логика, то возникает конфликт между скоростью работы и "читаемостью кода". Разработчик старается писать текст программы так, чтобы хорошо была видна логика работы, а потом уговаривает компилятор оптимизировать это для максимальной скорости. Или наоборот, он сам оптимизирует, но из-за этого разобраться в логике работы программы становится очень сложно, и соответственно искать логические ошибки становиться очень сложно.
Об этом идет речь?
Когда реализуется сложная логика, то возникает конфликт между скоростью работы и "читаемостью кода".
нет, обычно сложная логика это когда есть, в самом простом (как это ни странно звучит) случае две логики и есть некоторая логика взаимодействия этих логик, тогда проблема как раз в попытке построить какую-то объединенную супер-логику, которая игнорирует это разделение и как раз и становится не адекватно сложной. Сложная бывает математика (дифференциальное исчисление, например, в реальном времени, бывает)! Математика должна быть как-то обособлена от логики, когда логику мешают и перемешивают с математикой (даже с простой!) логика становится просто невозможно сложной. Если вы внутри, например, какого-то вычисления БПФ или фильтра какого-то замешаете какую-то логику - это будет убийство здравого смысла, но так к сожалению бывает.
Дано: сложная логика.
Задача: реализовать эту логику в коде.
Требование: код должен быть одновременно эффективным и "читаемым".
Вопрос: Должен ли программист концентрироваться на читаемости кода, а не эффективности, и надеяться на то, что компилятор сделает любой код эффективным за счет оптимизации.
На проблему "читаемости" указал автор. Это заставило его переписывать уже готовый и рабочий код.
Дано: сложная логика.
надо бы разобраться что вы здесь имеете ввиду сначала, потому что дальше у вас на этом все основано, вдруг это неверная посылка? Можете привести пример сложной логики, причем обоснованно сложной?
надо бы разобраться что вы здесь имеете ввиду сначала, потому что дальше у вас на этом все основано
В основе лежит факт из этой статьи - автор переделывает готовый работающий код, потому что этот код недостаточно "читаемый". Я пытаюсь понять - зачем. Если плохая "читаемость" затрудняет понимание логики работы, то это можно компенсировать дополнительными комментариями и документацией с блок-схемами.
По идее, акцент при разработке встроенного ПО должен быть на эффективности программы по основным техническим параметрам - скорость, объем, надежность. Плохая "читаемость" может быть побочным эффектом, из-за сложности реализуемой логики. Но стоит ли переделывать программу в угоду "читаемости"? Плохая "читаемость" конечно повышает требование к программисту. Но может это нормально.
Можете привести пример сложной логики, причем обоснованно сложной?
Сложной конкретно для Вас? Нет разумеется. Сложность это субъективный параметр. У кого-то в голове умещается логика описанная на тысячах страниц с сотнями диаграмм и таблиц соответствия. И он элементарно способен разглядеть эту логику в коде. Для такого человека, "сложность" это вымышленное понятие, несуществующее в природе.
Не знаю, может это, действительно, только для меня сложно. Вот вы видите логику в таком изложении принципа (некоторой идеи):
Общий принцип таков. Контекст не переключается, нужен delay или событие, проверь счетчик или наличие событие и jump на другой участок кода.
Я не вижу. А как я понял код пытается реализовать именно этот принцип. Внимание вопрос, если мы пытаемся реализовать в коде некую идею, которая не имеет смысла (пусть здесь я жестко ошибаюсь по поводу наличия смысла, но просто для примера), какова будет читаемость такого кода?
Прежде чем рассуждать о читаемости кода неплохо бы выяснить, а есть ли какое-то содержание у этого кода, которое можно прочитать. Дело в том что в данном случае у нас есть человеческое изложение принцыпа, который пытались реализовать в коде, поэтому после анализа принципа код можно не читать, в общем-то. К сожалению это практически исключительный случай, обычно к коду нет никакого изложения идеи реализованной в коде, поэтому приходится доказывать, что в коде нет содержания, или этого содержания совершенно не достаточно чтобы служить решением конкретной задачи. Я к тому что прежде чем рассуждать о читаемости какого-то кода надо выяснить, а стоит ли этот код читать.
Вот вы видите логику в таком изложении принципа (некоторой идеи):
Общий принцип таков. Контекст не переключается, нужен delay или событие, проверь счетчик или наличие событие и jump на другой участок кода.
Это отрывок из потока мыслей автора. Естественно что в отрыве от контекста он не понятен.
Я попробую изложить его мысли по своему, но не факт что это будет более понятным:
Программа разбита на задачи (подпрограммы). Задачи выполняются последовательно в цикле main.
Есть задачи, которые содержат циклы ожидания события (wait event), или задержки времени (delay). Когда такая задача доходит до точки wait event или delay, у нее есть два варианта действия:
1. Зависнуть в ожидании, затормозив выполнение всей программы.
2. Поставить флаг "Условие не выполнено", и перепрыгнуть к началу следующей задачи.
Первый вариант приводит к подвисанию и потере производительности.
Второй вариант усложняет логику, уменьшает точность delay, и скорость реакции на events.
А ещё в темы про ассемблер для Cortex-M, ведение микроконтроллера на ARM в каждый такт, устройство внутренних шин и гарантии реакции на то или иное событие, по опыту прибегает 10⁶ типов, рассказывающих в лучших традициях:
"Не, а зачем вам? Вы расскажите конкретно какая у вас задача? Сейчас так не делают, сейчас не считают такты, сейчас у микроконтроллеров есть прерывания, таймеры и фигаймеры, всем всего всегда хватает".
Визитной карточкой таких спецов это сравнение жигулей с мерседесом - видимо люди душой ещё в 90х :)
Я думал, эта специфика и эти метафоры - отличительная черта профессиональных сообществ из СНГ, но нет! :) На electronics.stackexchange в теме про подсчёт тактов на Cortex-M мне тип начал говорить, что это всё равно, что после Кадилака 1950-х годов спрашивать как завести с крюка Фольксваген Гольф.
Он очень был доволен собой ровно до момента, пока я не кинул ссылку на Sitara AM437x, у которого есть центральное высокопроизводительное ядро на ARM с частотой за ГГц и два дополнительных ядра с частотами по 200МГц и гарантией, что каждая ассемблерная инструкция на них выполняется ровно за 1 такт. Причём сам TI и говорит, что эти два ядра нужны для Ensuring real‑time predictability.
Меня всегда настораживает, когда периферийным RISC модулям или примитивным FPGA присваивают способность к некоей точности или универсальности.
Откуда у них точность-то с их целочисленной арифметикой. Скорее всего они расчитывают на свои оптимизированные для целочисленной арифметики и закрытые IP блоки. Все заточенные на традиционный FOC с PID-ами.
Но кому они нужны теперь, когда есть Cloude?
А если нужно эстиматоры посложнее и именно для того чтобы повысить точность регулирования, то там уже не так радужно.
Тотже STM32N6 уделает эту ситару вместе с ее PRU как нечего делать. Потому как PRU не умеют в AI. А управлять STM32N6 может теми же двумя моторами и еще быстрее потому как 240 МГц на мотор. Но к этому он еще и видеть может чем управляет.
Потому как PRU не умеют в AI
RPU, конечно, не умеет в AI. Только сама парадигма AI не подразумевает использования тех приёмов, про которые говорится в статье.
Тут либо мы доверяем AI рулить реалтаймом - и тогда что RTOS, что RPU, что ПЛИС остаются не у дел в контексте задач реалтайма. Либо мы не доверяем AI и тогда STM32N остаётся не у дел - именно в нашем реалтайме.
Не исключаю, что весь драматургический конфликт в статье и обсуждении - это потасовка в отцепленном вагоне истории. Но тем не менее, этот вагон един и для RTOS, крутящихся на одном ядре, и для Ситары и для какого-нибудь MAX-10.
Ок. Я выше немного запутал понятие AI.
Речь идет о нейросетевых алгоритмах типа NN-PID, PID + NN-feedforward, NN-Inverse и т.д. Их масса. Это самые что ни на есть риалтаймовые алгоритмы.
И это самый писк моды. Прям локомотив истории. Cмотрим тот же Cortex-M55.
Я даже не знаю как FPGA и доморощенные PRU с этим могут конкурировать.
Речь идет о нейросетевых алгоритмах типа NN-PID
NN-PID - это в некотором смысле чёрный ящик. Сомнительно, чтобы для него была актуальна ручная экономия тактов.
Повторюсь, либо у нас NN-PID (на оптимизированном под это железе), которому мы верим. И тогда "руками ничего не трогать!".
Или мы не верим NN-PID (ну или STM32N в контексте нашего проекта слишком дорог). Тогда мы выносим его за скобки дискуссии.
интересно почему сложилось такое предвзятое отношение к rtos? на современных не очень быстрых (400мгц) микропроцессорах арм время реакции ртос на событие примерно 0.6-1.3мкс. причем наихудшее время показывает популярная freertos.
Отвечу на один из вопросов. Почему до сих пор уделяется вниманием затраченным тактам. Когда надо сделать что то разовое или мелкосерийное - проблем нет. Затраты до +10долл за мощное железо в единицу продукции, это намного меньше чем придется заплатить программисту. Можно ставить все что угодно. При тиражах от 1000 шт так уже не получится. От 10000 борьба будет за каждый цент. В принципе это справедливо в вопросе, а почему избегаете FPGA. Для серии это дороже.
Логика немного хромает.
Смотрим на айфоны и видим что туда вставляют все самое дорогое.
И не трясутся за копейки. В современном обществе, где спрос воспитывают, копейки не имеют значения.
Фишка в том что если что-то реально выгодное на FPGA делают, то это сразу превращается в SoC.
От 10000 борьба будет за каждый цент. В принципе это справедливо в вопросе, а почему избегаете FPGA.
На каком микроконтроллере (ну плюс-минус, чтоб NDA не раскрывать) вы реализуете управление двигателем?
Асинхронность в микроконтроллерах