Pull to refresh
4
Кривенков Роман@qwerty19106

Embedded

3
Subscribers
Send message

А от тех, кто писал на нем прод, и ушел в другие языки, претензии принимаются?)

Разве то, что они пишут новый код на Rust, и не пишут его на С++, не доказывает первоначальный тезис?

А легаси был, есть и будет. И его нет смысла переписывать с языка Х на язык Y.

Любая программа на С собирается компилятором С++.

Это распространенное заблуждение. В C++ нет restrict, массивов переменной длины:

struct X { int m; int n; char bytes[]; };

Неявный typedef в С++, из-за которого этот код на С не скомпилируется в С++:

enum Bool { FALSE = 0, TRUE = 1 }; typedef int Bool;

Полный список из 23 пунктов можно прочитать здесь.

Проблема во многом преувеличена.

Текущий проект на 37cloc, компиляция после изменения нескольких строк кода: 1-2 секунды компиляция, 5 сек линковка. Долгая линковка из-за LTO, без него 1 сек.

Компиляция с нуля: ~35 секунд, 5 сек линковка. Но с нуля я запускаю раз в месяц наверное.
Вот для CI/CD в некоторых случаях нужна компиляция с нуля, там немного напрягает.

Асссемблерные вставки.

FFI, но чтобы в нем разобраться, нужно прочитать весь Rustonomicon, т.к. модель памяти отличается от С.

Я не знаю, какие именно прерывания вы имеете ввиду. Но на микроконтроллерах прерывания реализуются библиотеками рантайма, например cortex-m-rt.

Гарантировать - никак. Предотвратить опасные последствия - правильным использованием watchdog и учитывая в коде, что мой поток может не успевать за DMA и у меня будут пропуски сэмплов.

Ну вот мы и вернулись к началу. Это не возможно написать надежно на любом языке, даже на ассемблере.
И watchdog вам не поможет, он только добавит вероятность, что чип перезагрузится при ошибке, но гарантий нет.

Впрочем, необходимость увеличения кольцевого буфера DMA или производительности потока чтения, обычно, выявляется ещё при отладке и стресс-тестах.

И вы только подтвердили мои слова: все-равно придется взять чип помощнее или ПЛИС.

А я вообще не вижу Вашего ответа про чипы на ядре Cortex-M со встроенным WiFi и BLE. Так что давайте двигаться последовательно )

Много, 7 семейств МК на Cortex-M3 или M4.
Выбор зависит от задачи, а вы сейчас пытаетесь меня убедить, что если нужен WiFi, то только ESP32.

Только если Вы компенсируете возросшую в три раза себестоимость готового изделия из собственного кармана.

Или Вы только чужими деньгами так вольно распоряжаться готовы?

Внезапно себестоимость состоит только из чипа МК? А стоимость разработки уже не надо учитывать? Которая будет гораздо выше, пока вы пытаетесь впихнуть в чип невпихуемое.

Кстати, а почему в 3 раза? Даже в STM32F0 не один порт GPIO, и стоят они 77 руб на элитане.

На таймере оно и есть, под управлением FreeRTOS. Но дополнительные задержки в синхронизации между потоками тут явно не позволят уложиться в +-150ns. А DMA тут вообще не при чём: There is no connection at all between the GPIO module and the DMA subsystem

Пишете через DMA в порт GPIO, события для DMA выдает таймер. Кстати ваша ссылка не открывается.

Смотря с чем сравнивать. В одной и той же ценовой категории я заметной разницы не вижу. Вы бы более конкретно высказывались.


Один порт GPIO, мало ножек, в большинстве чипов нет FPU, мало UART, только один SPI и т.д.
https://en.wikipedia.org/wiki/ESP32

Кстати, какую цену вы для них считаете?

Для SPSC кольцевого буфера AtomicPtr и правильный подбор Ordering позволяют это сделать быстро и безопасно, и без циклов CAS.

Даже между прерыванием и главным циклом. API примерно такой, как писал mayorovp выше. В понедельник доберусь до работы, могу вам скинуть код, если интересно.

Не надеяться на компилятор, а воспользоваться собственной головой. В общем случае, при работе с bare metall компилятор не помощник для получения безопасного кода.

Это не ответ, а отписка.
Мне интересно, как вы будете гарантировать, что DMA не перезапишет еще не прочитанные данные, в тот самый момент, когда вы с ними работаете (без копирования).

что если на GPIO нужен параллельный 8-битный интерфейс

Выше мы обсуждали 3-битный интерфейс, и мой ответ был про него.

Для 8-битного интерфейса ответ прежний: взять другой МК, в котором больше 1 порта GPIO. Просто не вместо, а в дополнение к ESP32. И SPI между ними.

Тоже приводил пример выше с управлением более, чем одной матрицей WS2812.

Так в этой задаче вам нужно только 2 ножки GPIO, но достаточно быстро. На таймерах и DMA не вариант?

P.S. Я совсем не против ESP32, для WiFi и BLE ничего лучше нету. Но обычная периферия МК у них бедная, согласитесь.

Не я хочу без копирования, а жесткие ограничения на доступную память и производительность при разработке для встроенных систем требуют избегать копирования.

Тогда объясните, как это сделать без копирования и безопасно. На любом языке.

При чем тут количество "ножек", если речь идет о портах? Мне даже интересно стало, что же Вы предложите вместо ESP32-C2/C3/H2/C6, у которых всего один порт? Вообще отказаться от них, если нужно управлять более, чем одним пином GPIO? А если нужно управлять тремя пинами GPIO, то вообще отказаться от продукции Espressif, так как я не знаю у них ни одного МК, имеющего более двух портов?

Взять любой чип на ядре Cortex-M3 или M4, и использовать аппаратный bit-banding.

И вообще, это очень узкая задача. Обычный цикл выкл. прерывания - read-copy-update регистра - вкл. прерывания займет около 20 тактов, зависит от архитектуры. Это достаточно быстро для абсолютного большинства задач.

Если не секрет, что за проект, который жестко завязан на Espressif, и одновременно такие жесткие требования к GPIO?

Мы обсуждали кольцевой буфер, в который пишет DMA без остановок. Перечитайте тред выше.

Особенность DMA в том, что он не будет проверять указатель чтения, только смещает указатель записи. Если же обе стороны - программы, то можно проверять оба указателя, чтобы не перезаписать еще не прочитанные данные.

Я и указываю, что это написать "безопасно" не получится. Особенно, если это существенный поток, например, на уровне 100К SPS с ADC.

Вы точно открывали мою ссылку? Там конкретный пример, как это можно написать безопасно.

Если же вы хотите без копирования, то тут не получится безопасно на чем угодно, хоть на ассемблере.

Чаще всего это невозможно. Даже на 8-битных МК, не говоря уже о 32-битных.

Это очень специфическая задача, и под нее можно выбрать МК с большим количеством ножек, и не решать неразрешимые проблемы в коде.

Он не потокобезопасный не смотря на Send и Sync. Смотрите API RingBuffer, который требует &mut self, и комментарий в исходниках:

// SAFETY: all methods that require mutable access take &mut,
// being send and sync was the old behavior but broke when we switched to *mut T.

И, как верно заметили ниже, в реализации нет AtomicUsize либо AtomicPtr. Но язык и не позволит его использовать из разных потоков.

Вот например настоящий потокобезопасный кольцевой буфер, я его регулярно использую на микроконтроллерах. В теории можно и под ОС использовать.

Туда вообще не CPU может писать, а DMA. Но исключить при этом ошибку, когда оттуда читается до записи нельзя. Вот и приходится верифицировать весь код.

Практика показывает, что в Rust можно написать чтение из кольцевого буфера DMA, внутри MaybeUninit. Минус такого подхода - копирование байт при чтении. Но без копирования я не вижу, как это написать безопасно даже в С.

Например, изменять значения пинов у MK на конкретном порту из разных потоков безопасно никак не получится, потому что значение конкретного пина изменяется накладыванием маски на весь порт.

Похоже это невозможно сделать безопасно на любом языке программирования. Единственное решение - разнести логически связанные пины по разным портам GPIO.

Прошу ссылку на сайт языка или его документацию, где это утверждают.

Есть большая разница между "невозможны принципиально" и "возможны при каких то условиях".

там нет ни одной НЕ unsafe функции))

Если для вас неприемлем любой код, который внутри содержит unsafe, то как тогда пользоваться стандартной библиотекой в любом языке?
Её реализация, как и любое FFI, по определению unsafe.

Возможны. Есть и другие библиотеки.

Может вы имели ввиду "невозможны без unsafe"?

Как раз для зонда продолжает работать с "отравленными" данными может привести к печальным последствиям. Например он перестанет отвечать на внешние команды и будет потерян.

В коде для зондов стараются обработать все возможные ошибки. Но если пропустили, то лучше бы упасть чем UB.

Причем тут "развернуть и против вас"? Я опираюсь на факты, а не риторическими утверждения.

В таком случае вам нужно было под той статьей написать дополнение, например что "вы имели ввиду оптимальную реализацию". Но что-то вам помешало принять факты, например вера)

Этот код ничем от отличается от кода на С++ и не дает гарантий безопасного управления памятью, о чем я и писал выше.

Ну да, слабые ссылки в std Rust такие же как в std С++. Но и применяются они крайне редко (я вот ни разу не видел). Вместо них применяют готовые алгоритмы с множественным владением. Как и в С++.

А вот о чем вы умалчиваете: другие виды утечек памяти не возможны, как и use after free. Если вы не используете слабые ссылки, никогда память не утечет.

Лучше какая-то (и очень неплохая) защита на уровне языка, чем никакой.

Такой подход можно развернуть и против вас.

Например, вот в этом комментарии вам прямо пишут, что написать двусвязный список можно без unsafe (с помощью счетчиков ссылок и слабых ссылок). Но нельзя написать оптимальную реализацию без unsafe. Аналогично можно написать и более сложные алгоритмы (например деревья).

Но вы и тогда, и сейчас говорите что это не возможно. А, между тем, больше половины вашей статьи опирается на этот тезис, который очевидно ошибочный. Так кто из нас обратился к религии?

От того что аргументы уже озвучены, они стали менее актуальными? Ведь вы привели свои аргументы еще раз, почему я не могу?

P.S. Клонов у меня нет.

1
23 ...

Information

Rating
5,773-rd
Location
Ижевск, Удмуртия, Россия
Date of birth
Registered
Activity