Pull to refresh
88
0
Вадим Дерябкин @Vadimatorikda

Инженер-программист

Send message
Да. Авионика. Конечно же, статика, защиты от зависания, стеки в несколько раз больше, чем нужно и прочие штуки по стандартам. Но если есть аппаратная возможность, почему бы еще и ей не воспользоваться? А уронить самому, понятное дело… Начиная с тестов алгоритмов в симуляции (как-нибудь напишу про это), заканчивая тестами на длительное выполнение.
У меня зачастую работа с устройствами, в которых «нужно выжить любой ценой и не уронить аппарат». Так что там как правило задается с очень сильным запасом все. Тут скорее имею ввиду, что не получится ситуации, когда перешедший за пределы выделенного стек задачи не перетрет данные, с которыми работает программа. То есть это дает возможность избежать ситуации, когда код продолжает работать, но уже с битыми данными. И начинаются приключения типа «в конфиге же было задание шим от 0.1 до 0.7 держать (скважность), почему вдруг резко начал выдавать 0.9? (то есть значение момент обновилось в таймере, а там уже было битое значение из-за того, что стек соседней задачи был поблизости и перетер данные, с которыми работает другой поток.
Да. И это тоже. Вообще, по опыту, CCMRAM идеальное место для хранения стеков/внутренних структур объектов FreeRTOS (если используется в проекте). Позволяет решить вопрос с тем, когда переполнение стека задачи затрагивает данные, с которыми работает прошивки в основной RAM.
Да. Был опыт работы над устройством измерения частот с 8 каналов. Каждый импульс приходило прерывание. Из него я узнавал на каком канале произошел импульс и его длительность (ведется статистика отклонений (наибольшее, наименьшее) и прочие штуки по тех заданию). И вот. Параметры, которые следует фиксировать задаются пользователем. Для того, чтобы удовлетворить требованиям пришлось разместить методы обработчики в RAM, как и саму таблицу векторов прерываний. И каждый раз дергать данные из FLASH, выполняя обработчик из RAM оказалось очень накладно. Конкретных цифр привести не могу. Со временем пришло понимание, что именно настройки даже лучше размещать не в RAM, а в CCRAM. Чтобы разгрузить шину (код выполняется из RAM, а данные берутся параллельно из CCRAM). Про CCRAM справедливо только для F405 (с которым работал). Возможно и для других мк/серий тоже.
Задумайтесь, как по-вашему начальные значения попадают (или как должны) в переменные в озу и чем это отличается от вашего случая?

При старте МК попадаю в обработчик по reset. Там копирую из области data (во flash) в область data в ram. Область bss, noinit заполняю 0-ми. Но причем здесь это? Тут ведь речь про данные, которые должны быть в отрыве от прошивки МК. Они должны быть в строго определенных местах, чтобы в случае чего можно было снять dump памяти и посмотреть, с какими последними параметрами стартовало устройство.
У вас и так для каждой секции линкер поддерживает два адреса — адрес в образе и адрес времени исполнения

А нужно 4 по ТЗ. Резервирование. Надежность.
чем это отличается от вашего случая?

Тем, что то, что попадет в RAM зависит от того, целостны ли данные в момент подачи питание или после перезагрузки в резервированных блоках или их стоит заменить начальными из текущей актуальной прошивки.
RTFM, же!

Читал. Нигде нет возможности указать явное дублирование в N копий. Вот пример.
Есть ощущение, что дети стали забывать румынского диктатора

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

Но ведь я тут про дополнение linker-скрипта распинался…
И это хорошо ;) т.к. конкуренция меньше, но все же!

Людей, умеющих адекватно работать с ld и прочими низкоуровневыми штуками и так мало… Не надо уменьшать.
И не нужно делать макрос отдельно для массивов. Нужен просто макрос, задающий имя секции. И ставить его в коде при определении массивов, структур, переменных и прочего.

Полагаю, вы невнимательно читали статью. Поправьте, если я не прав. Мне нужно, чтобы каждая сущность была продублирована в 4 местах. ТЗ такое. При вашем подходе мне придется явно задавать одну и ту же сущность 4 раза, просто указывая в макросе, в какую секцию стоит положить ее.
И выравнивание компилятор сам умеет задавать, в зависимости от типа данных и контроллера — вам там точно это нужно в макросе?

У нас обычно структуры задаются с атрибутом упаковки. Так что внутри них может и не быть адекватного выравнивания. Код к этому готов. А вот сами структуры/массивы и прочие в отдельности обязаны быть выравнены на 4. По-умолчанию компоновщик пытается все объявленные переменные через макрос выше складывать подряд. Без выравнивания. Тут атрибут выравнивания скорее дополнительная гарантия, что этого не произойдет. Уже сталкивался на практике с ситуацией, когда переменные лежали без выравнивания, а обращение к ним шло с использованием взятия ассемблерной команды по кратному 4 адресу. И падение в соответствующий обработчик гарантировано.
И таблицы секций тоже можно и нужно делать через скрипт ликера.

Но ведь я там их и объявил…
Вместе с указателями размерами, флагами и чем хотите — всё необходимое в лимонное есть.

Я получаю из ld скрипта размеры, указатели, чтобы мой собственный модуль произвел инициализацию области RAM валидными данными и далее в процессе работы мог актуальными данными перезаписывать резервируемые блоки, если пользователь захочет изменить настройки при включении.
И место для crc тоже должно с через смените ликера резеовироваться в вашем случае.

Не понял смысла предложения. Поясните пожалуйста, что вас не устроило. Я в mem.ld резервирую место под CRC в областях памяти, реализующих резервирование настроек пользователя.
Платите, но ваш велосипед ужасен и вреден.

Кому платить? Подводя итог, что именно ужасно? Выше аргументировал каждый пункт вашего недовольства.
Тут есть несколько вариантов. Не так давно сталкивался с этим снова. На новом arm-none-eabi (9-я версия. Последняя на момент написания комментария).
Убедитесь, что:
  1. Стека задачи достаточно (тут я так понял вы используете snprintf. Пишете в буфер и потом буфер отсылаете. Ради интереса можно задать буфер сильно больше нужного.
  2. В прерываниях не происходит переполнения стека. Как стека задачи, в которой произошло прерывание, так и соседних задач. Может у вас есть задача, которая сбрасывает wdt, а в ней стек на 128 элементов. Появляется прерывание. Пишет 4 килобайна, вы возвращаетесь в задачу wdt, планировщик меняет задачу на другую и тут все падает.
  3. У вас достаточно места в «куче». Имею ввиду не freertos кучу, а та, что «не занятое место» между буферной зоной стека и bss областью. Ее пользует функция _sbrk. Она считает, что место от конца bss области до начала зарезервированного стека (физический конец оперативной памяти) принадлежит ей (функции _sbrk). Тут надо оставить хотя бы 1 кб. Реально используется около 500 байт, когда вы устанавливаете например единый буфер.
  4. Можно явно задать буфер, с которым будет работать printf/scanf. setvbuf функцией (помните, что когда вы их вызовите, случится еще дерганье sbrk функции, которая сохъст 500 байт в «куче» (та что не принадлежит freertos). Кстати. Устанавливать буферы надо до запуска планировщика.

Если это соблюдено, то можно попробовать:
Ничего себе какая прелесть. Пошел читать про это!)
Похоже имеют ввиду, что даже CubeMX научился генерировать define по имени пина, чтобы не было этих безымянных MODEX_Y.
А, и самое главное. Проверять перед отправкой, а не после. Чтобы по-максимуму использовать SPI время.
Тут (на хабре) некоторое время назад была статья про то, как достигать максимальной скорости из SPI (даже без DMA). Сколько помню, все свелось к тому, что нужно проверять флаг того, что данные передались из DR во внутренний сдвиговый и сам DR сейчас «пуст» (в него можно писать). И, по сути, за счет этого достигается эффект непрерывной передачи. Типа данные еще передаются, а мы уже заготовили в DR следующую пачку. Ну а вообще лучше DMA конечно. Но это чуть усложнит пример (ИМХО).
Ну так ведь «отладка перепрошивкой» — это достаточно распространенная проблема у 8-ми биток. Я вот только у atmega16+ видел jtag и 1-wire у attiny2313 (говорят что с недавнего времени и у младших появились). Ту же atmega8a отлаживаешь по принципу «зашил и смотришь». Вроде у stm8 есть какое-то подобие отладки. Но тут уже не удалось поработать.
Лично мне из названия было ничего не понятно до тех пор, пока я не открыл статью и не дочитал до примера кода на C#. В заголовке и тегах об этом ни слова.
Ну в целом впечатления смешанные. Но безусловно стоит продолжать. Пока еще не совсем ясно, что и зачем. Да, интересно. Да, на вид круто. Но что и куда — не ясно. К тому же не ясно, как даже попробовать это все (тут многие используют Linux...).
Что-то меня это сообщение задело и я даже пошел, проверил. Да, вот. Как раз в это время разбираться с constexpr. Тогда же примерно задавал вопросы по этой теме. Потому что тогда переходил с C++11 на C++14.
Спрашивал. Не соглашусь правда что за основы (можно ссылки, пожалуйста? Помню что не так давно спрашивал про constexpr. Даже потом статью запилил. Но там, ИМХО, были не очень очевидные вещи с неявным cast-ом объектов к структурам). А что смешного в том, что я относительно рано начал изучать эту предметную область (ну и нашел работу, потому что уже имел некоторый опыт)?
В embedded сталкивался. Когда cmake не верно передавал g++ параметры linker-а. В 3.10.1 кажется. В 3.14 уже поправили.
Не понимал ModbusTCP и FTP на МК. Для остального:
LWIP — сам по себе отжирает 1 поток в «стандартной поставке».
ModbusRTU — у меня живет в прерываниях + 1 поток для ответов (на каждого клиента, понятное дело)
HTTP — т.к. это по сути TCP, то 1 поток. Суммарно я смогу даже с учетом 4-х клиентов выделить около 10.
Удачно было бы привести пример, когда пихают под сотню потоков на решение задачи, которая без кучи уровней абстракции решалась бы в пару десятков строк внутри нескольких прерываний (подобный пример был написан здесь).
Ну а так же, что «не бесплатная». Именно поэтому нужно понимать, когда стоит их включать, а когда нет. В конечном продукте (в идеале) они бесполезны и их можно отключать. Само собой, если просчитаны всевозможные случаи и гарантируется, что стек не будет переполнен ни при каких обстоятельствах.
Вот только нужны ли в микроконтроллере «под сотню» задач — вопрос отдельный.
Ну и из-за того, что у нас «отвалился кварц» надо произвести инициализацию по другому алгоритму. Например, без этого кварца уже нельзя использовать ETH, но можно технологический UART и т.д.

Information

Rating
Does not participate
Location
Красноярск, Красноярский край, Россия
Date of birth
Registered
Activity

Specialization

Software Developer, Embedded Software Engineer
Lead
From 250,000 ₽
C++
STM32
Linux
Circuitry
Python
Assembler
Programming microcontrollers
Embedded system
Software development
Object-oriented design