Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F407: Ethernet, HAL + Lwip
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
k000858
Всем привет.

Кто изучал драйвер Ethernet'а, идущий с HAL библиотеками (вариант для FreeRTOS: ETHERNET прерывание релизит семафору, которая парсится в отдельной realtime задаче ОС)? Что будет при переполнении указанного количества приёмных буферов? Ошибка DMA обработается, но не будет ли DMA записывать данные дальше (портить память) или это исключено т.к. указывается в размер буферов в настройках DMA?

Имею следующую ситуацию: устройство с Ethernet в параллельной задаче (с меньшим приоритетом чем Ethernet) копирует данные (memcpy функцией) с внутренней FLASH контроллера. При шторме устройства Ethernet трафиком, в какой то раз данные копируются неправильно (временно нарушается адресация флэш - откуда копировать, но до конца процесса восстанавливается), в результате часть данных получается битыми.

Пока подозрения на ошибку в Ethernet драйверах либо LwIP стеке (v1.4.1).

То есть многократное срабатывание прерывания Ethernet + работа задачи по сохранению принятого по Ethernet пакету приводит к сбою работы memcpy

Нехватка памяти для RTOS и его задач контролируется соответствующими отладочными функция FreeRTOS

Может у кого то будут умные мысли, как можно сузить круг поиска бага?
Как еще подиагностировать. Повторить ситуацию непросто, получается ни каждый раз.
pitt
Цитата(k000858 @ Jan 12 2017, 02:11) *
Пока подозрения на ошибку в Ethernet драйверах...


Есть убеждение, что HAL от STM использовать можно только как референс. Использовать его в собственных приложениях - тоже пожалуйста, но тогда или молиться или смириться.
Извините за ответ, которого Вы не спрашивали.

Мур
Сам долго мучился с HAL, пока не скачал книгу
Mastering STM32
Carmine Noviello
""A step-by-step guide to the most complete ARM Cortex-M
platform, using a free and powerful development
environment based on Eclipse and GCC
""
k000858
спасибо за советы. определенный смысл в них конечно есть, но задача стоит несколько другая. необходимо в существующем проекте найти источник утечки памяти или другую причину такого поведения. явно проблемы на стеке.
pitt
Цитата(k000858 @ Jan 12 2017, 22:43) *
спасибо за советы. определенный смысл в них конечно есть, но задача стоит несколько другая. необходимо в существующем проекте найти источник утечки памяти или другую причину такого поведения. явно проблемы на стеке.

Можно искать пропавшие вещи под фонарем - там светлее, но все-таки, наверное, лучше там, где утеряны. У меня давно нет никаких проблем с Ethernet, но у меня собственный HAL.
Насколько я помню, STM HAL в принципе не годится(не годился, так как несколько лет в него не заглядывал, а индусы пишут быстро, а переписывают еще быстрее).
SasaVitebsk
Насколько вы описали проблему, мне кажется, что проблема не в дровах и не в стеке. Ничего там не переполнится.
Судя по всему, у вас проблемы с синхронизацией между задачами. Либо второй вариант - где-то используется глобальная переменная, доступная на запись из нескольких задач. Туда ройте.
k000858
Цитата(SasaVitebsk @ Jan 13 2017, 21:12) *
где-то используется глобальная переменная, доступная на запись из нескольких задач. Туда ройте.

такое есть. чем это чревато?
SasaVitebsk
В зависимости от текста... Как правило непредсказуемыми последствиями...
Здесь давече была тема про атомарный доступ к таким переменным. Не хочу вступать в полемику, так как в программировании, одну и туже задачу можно десятком способов решить...
Я обычно решаю так:
Есть задачи А, Б, С. Например задача А выставляет какой то запрос флагом фА. Задачи Б и С могут его прочитать, но не сбросить! Задача Б по флагу фА подтверждает запрос выставив флаг фБ. По флагу фБ задача А сбрасывает флаг фА.
То есть Одна задача только читает, вторая только пишет. Найболее яркий пример реализации в протоколе centronix.
Если всё же не избежать взаимных колизий, то использую защищённую секцию, либо средства самой ОС. Ну в зависимости, от частоты события...
===
Ну приведу классическую работу с кольцевым буфером:
1. При поступлении символа либо пакета, в прерывании двигается хвост очереди tail.
2. В задаче, после обработки пакета - двигается голова очереди head.
Вроде всё класс. Но вам требуется определить размер доступных данных... Ну типа так..
len = tail - head;
if(len <0) len += sizebuf;
....
И здесь видно, что во время операции len = tail - head, значение tail может измениться в прерывании (например пришёл пакет, и указатель сдвинулся по кольцу). В результате вы можете получить значение совершенно неверное. Дабы это предотвратить, вы должны например запретить прерывание на эту операцию. Либо приостановить планировщик, если речь не о прерывании, а о задачах.

Для FreeRTOS:
taskENTER_CRITICAL() — вход в критическую секцию
taskEXIT_CRITICAL() — выход из критической секции
vTaskSuspendAll() - Приостановка планировщика
xTaskResumeAll() - возобновления работы планировщика

Если приложение написано верно, то таких мест будет крайне мало... У меня их единицы. Но всё же они есть.


Forger
Цитата(k000858 @ Jan 16 2017, 07:44) *
такое есть. чем это чревато?

Курим интернеты, думаем, делаем соотв. выводы sm.gif
Лично рекомендую нафик уходить с голого C на C++ и использовать вместо глобальных объектов синглтоны.
Особенно для толстых проектов.
pitt
Цитата(k000858 @ Jan 15 2017, 23:44) *
такое есть. чем это чревато?

No comments... wacko.gif
SasaVitebsk
Цитата(Forger @ Jan 16 2017, 17:24) *
Лично рекомендую нафик уходить с голого C на C++ и использовать вместо глобальных объектов синглтоны

Ещё раз обращаю внимание, что это не конструкция языка... Это не оператор, не тип данных ... Это одна из реализаций задачи средствами языка...
Таких куча. И в Си тоже. Вот ребята обсуждали https://electronix.ru/forum/index.php?showtopic=139522
В теме есть законченные, грамотные решения. Причём весьма лаконичные.
IAR, например, предлагает typedef i-type sig_atomic_t; в библиотеке <signal.h>
Цитата
The type is the integer type i-type for objects whose stored value is altered by an assigning operator as an atomic operation (an operation that never has its execution suspended while partially completed). You declare such objects to communicate between signal handlers and the rest of the program.
.
А переходить на другой язык, только потому что не знаешь как решить задачу в рамках этого ... ну извините.

Aner
QUOTE (Forger @ Jan 16 2017, 18:24) *
Курим интернеты, думаем, делаем соотв. выводы sm.gif
Лично рекомендую нафик уходить с голого C на C++ и использовать вместо глобальных объектов синглтоны.
Особенно для толстых проектов.

С++ и его достоинства перед С, ... думаю не для STM c его осами и ограниченностью памяти. C++ даст только увеличение объема кода, подъест ресурсы которые и так ограничены. Хотя если задачка простенькая то пофигу на чем писать под STM хоть на С#.

Правильно pitt пишет в STM HAL в принципе не годится, у меня тоже свой. Все отлажено и работает в серийном изделии. А тот что выложен, у всех глючит и будет глючить по понятным причинам. Он для начинающих и лентяев.

И что ещё за шторм устройства Ethernet трафиком? Дураку, понятно что простых DoS атак STMы никак не потянут, даже старшие.
Сергей Борщ
QUOTE (Aner @ Jan 16 2017, 23:51) *
С++ и его достоинства перед С, ... думаю не для STM c его осами и ограниченностью памяти. C++ даст только увеличение объема кода, подъест ресурсы которые и так ограничены.
Опять двадцать пять. Снова повторение одних и тех же мантр. Вы можете свои слова подтвердить хоть одним примером, когда хоть какое-то действие, алгоритм и т.д. даст "увеличение объема кода, подъест ресурсы" только потому, что написана на плюсах вместо голых сей? Криворукость программиста не рассматриваем, мы знаем, что "настоящие программисты пишут на Паскале на любом языке". Уже много лет как перешел на плюсы не только на STM32 "c его осами и ограниченностью памяти" но и, страшно сказать, на AVR(!) и не вижу описываемых вами ужасов. Вот совсем не вижу. А преимущества плюсов вижу и постоянно использую.
SasaVitebsk
Цитата(Сергей Борщ @ Jan 17 2017, 09:50) *
А преимущества плюсов вижу и постоянно использую.

Сергей, но по сабжу применение синглтонов, явно не то преимущество, согласитесь.
Forger
Синглтон я указал как самый популярный способ избежать глобальных переменных и отучить себя раз и навсегда от этой дурной привычки.
Я давно уже перевел все свои активные проекты на модульную структуру (на чистом C невозможно это сделать вменяемо, читаемо и легко переносимо).

Размер кода хоть и больше, но и быстродействие выше за счет более разумного построения проекта.
На размер кода мне покласть - щас даже самый убогий и нищий ARM контроллер имеет на борту хотя бы 16к памяти.

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

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

А недавно за пару вечеров сделал туже обертку под FreeRTOS, благо они наконец-то сделали возможность создавать сервисы и задачи статически (v 9.0.0).
Подтолкнуло к этому еще и то, что под FreeRTOS есть уже готовая сборка Segger System View (крайне рекомендую).
Segger заранее все сделал под эту ось, допиливать ничего не пришлось, все заработало с полпинка
При отладке толстых проектов очень полезная и удобная. Я в восторге!

Так все мои существующие проекты собрались под эту (новую для меня) RTOS, при этом во всех этих проектах не было изменено не единой строчки кода!
Это - как пример модульного подхода к построению проектов: сначала проектируем, потом кодируем.

Важное дополнение, категорически не использую нигде динамическую память: malloc, free (и т. п. штатное зло) перегружено во всех проектах пустыми функциями с соотв. ассертами.
Не использую исключения C++ (принудительно заблокированы опциями компилятора).

Но без применения виртуальных функций и других крайне полезных вещей C++ уже никогда не откажусь.

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

Для примера хочу показать, как выглядит содержимое Application.cpp (заместо тупого main.c):

Код
#include "Application.hpp"

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main(void)
{
    Kernel::getInstance().initialize(CORE_FREQUENCY_HZ, RTOS_SYSTEM_TIMER_FREQUENCY_HZ);
    Kernel::getInstance().run();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Kernel::initializeModules(void)
{
    WatchDog::getInstance().initialize();
    Communication::getInstance().initialize();
    Inputs::getInstance().initialize();
    MotionControl::getInstance().initialize();
    Leds::getInstance().initialize();
    Settings::getInstance().initialize();

    WatchDog::getInstance().setPriority(30);
    MotionControl::getInstance().setPriority(1);
    Inputs::getInstance().setPriority(2);
    Communication::getInstance().setPriority(3);
    Settings::getInstance().setPriority(6);
    Leds::getInstance().setPriority(10);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Kernel::runModules(void)
{
    WatchDog::getInstance().run();
    Communication::getInstance().run();
    Inputs::getInstance().run();
    MotionControl::getInstance().run();
    Leds::getInstance().run();
    Settings::getInstance().run();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Kernel::initializeHardware(void)
{
// здесь инциализируется только таблица векторов и тактовый генератор, не более того!
}


Каждый из модулей (в данном случае они все - синглтоны), может иметь внутри себя одну или несколько задач (потоков) или вовсе их не иметь.
Взаимодействуют модули друг с другом исключительно через соотв. открытые методы.
В этих методах уже используются сервисы RTOS или другие способы синхронизации.
Такой подход ПОЛНОСТЬЮ исключает существование глобальных объектов и тем более глобальных переменных.
Очень легко переносить модули из одного проекта в другой или создавать новый проект на базе существующих.
Одинаковые или похожие модули из разных проектов постепенно унифицируются тем самым эволюционируют.
Постепенно, некоторые неизменные модули выносятся в отдельные заранее скомпилированные библиотеки (например, RTOS).

Сергей Борщ
QUOTE (SasaVitebsk @ Jan 17 2017, 09:19) *
Сергей, но по сабжу применение синглтонов, явно не то преимущество, согласитесь.
Про синглтон как таковой ничего пока сказать не могу, не проникся им пока. Но спорю на ящик пива, что та же функциональность, написанная на голых сях, будет занимать не меньше памяти и "ограниченных ресурсов", а исходный текст при этом выглядеть будет куда более чудовищно. К тому же оставит программисту кучу возможностей натворить ошибок в процессе использования этого готового и безусловно рабочего кода.
pitt
Цитата(Сергей Борщ @ Jan 17 2017, 01:50) *
Опять двадцать пять. Снова повторение одних и тех же мантр....и не вижу описываемых вами ужасов. Вот совсем не вижу. А преимущества плюсов вижу и постоянно использую.

На вкус и цвет...

Цитата(Forger @ Jan 17 2017, 03:29) *
Помню, что в чистом С я проклял все на свете при поисках багов, связанных с глобальными ресурсами (да и не только).

Что там мешает плохому танцору?
Forger
Цитата(Сергей Борщ @ Jan 17 2017, 15:12) *
Про синглтон как таковой ничего пока сказать не могу, не проникся им пока.

А мне пришлось их использовать, т. к. в противном случае просто нереально контроллировать порядок вызова конструкторов статически создаваемых классов.

Например:
есть класс Hardware, где инициализируется и используется железо МК,
есть класс RTOS, инициализация которой должна пройти сразу после инициализации тактового генератора,
но до всех остальных инциализаций, в т. ч. и до создания задач и других объектов.

Если размещать объявление этих классов экземпляров в одном файле, то их конструкторы вызываются соотв. в порядке их размещения в файле (обычно их кладут в начале cpp файла),
а если файлов много и в каждом есть статические объекты (само собой все с квалификатором static), то в каком порядке будут вызываться конструкторы статически объявленных классов, одному богу известно.
Все зависит от пристрастий линкера и фазы луны. Я наступал на эти грабли, вдоволь накушался (((

Конечно, отложенная инициализация - неплохое решение (перенос содержимого конструктора в отдельный метод initialize(), который уже вызывается в определенном месте).
Но все равно возникает проблема видимости статически созданных классов в других файлах.
Можно пойти дальше - объявлять некоторые поля таких классов со словом static.
Но это по-сути выраждается в коряво имитируемый синглтон ))

В итоге все равно приходишь к полноценному готовому шаблону - синглтону ))

К слову, под синглтон идеально ложится класс RTOS, класс железа или чего-то, что в проекте ВСЕГДА будет существовать в единственном экземпляре.
Синглтон позволяет сам контроллировать вызов своей инциализации, причем делать это лишь один раз.
Например, инициализаця класса RTOS должно проводится всего один раз и всегда ДО создания объектов классов задач/потоков, семафоров, мьютексов и др. сервисов RTOS.
Достаточно лишь в конструкторе каждого такого объекта вызывать соотв. метод отложенной инициализации класса RTOS, где уже внутри него проверятся - была проведена инициализация или нет.
Вся эта "тряхомуть" сложена в одном файле, один раз отлажена, собрана в библиотеки под разные виды платформ и забыта до тех пор, пока не потребуется расширить ее функционал или поменять ядро RTOS.

Снаружи любого проекта это выглядить очень просто и лаконично - задачи, сервисы RTOS можно объявлять где угодно:
статически (в начале файле cpp), динамически, размещать их в закрытой секции (private) соотв. класса, да хоть локально в соотв. функции ))
Голова никогда не болит где и в каком поредке они будут созданы, но будут проинициализированы и запущены в строго отведенных местах в заданном порядке (см. код из предыдущего моего поста).

Впрочем, прелесть сигнлтона есть и в другом - он легко позволяет перестать быть синглтоном, а сам код класса при этом почти не меняется.
Т.е. можно при желании создать несколько экзэмпляров RTOS, и переписать порт под многоядерную систему, где будут крутиться более одной оси .... wink.gif
На данный момент это пока что абсурд, но тем не менее!

Цитата(pitt @ Jan 17 2017, 17:18) *
Что там мешает плохому танцору?

Рукастый слесарь со стажем, который работал только стамеской и молотком, может сотворить настоящее чудо.
Когда потребуется сделать что-то подобное, то все по новой - долго, муторно, трудоемко sad.gif
В этот раз чуда может не получится - скажем, отколется часть детали и все по-новой....

Другой же слесарь, который смотрит дальше того, что умеет, поступит иначе:
нарисует 3D модель (придется освоить соотв. инструменты), отдаст ее в деревообрабатывающий цех (придется научится правильно рисовать модели под особенности технологии),
ему на ЧПУ станке по дереву вырежут ему десяток таких чудесных деталей.
Когда ему потребуется еще десяток таких же деталек или подобных, но отличающихся, скажем, лишь положением крепежных отверстий,
его задача - потратить 10 минут на исправление уже созданной им ранее модели, далее процедура знакомая и быстрая.
ЧПУ станок нарежет столько деталей, сколько нужно. В этом время этот слесарь занят следующей моделью.

Конечно, никто не мешает до конца жизни стучать молотком по стамеске biggrin.gif
SasaVitebsk
Цитата(Forger @ Jan 17 2017, 17:32) *
Конечно, никто не мешает до конца жизни стучать молотком по стамеске biggrin.gif

Завидую я вам. А у меня практически каждый проект - новый проект. А идей ещё больше. Заимствуются крохи. Причём то что заимствуется, как то без особых проблем.
Я ничего не говорил, по С++. Я им пользуюсь. Какие-то проекты, обслуживания прибора пишу на QT. Но как то всё равно язык не стал своим...
Я - убей - не пойму, что мне даёт класс Hardware... Выглядит несколько надуманно. Я не утверждаю, что так и есть. Просто представить себе не очень могу...
Типа базовый класс? Далее от него класс SPI?
А что вы за ось пользуете?
Forger
Цитата(SasaVitebsk @ Jan 17 2017, 18:42) *
Я - убей - не пойму, что мне даёт класс Hardware... Выглядит несколько надуманно.

В текущих проектах у меня давно нет такого отдельного класса (выше указал для примера), а все периферийные вещи, привязывающие код к железу, рассованы по разных низкоуровым методам в соотв. модулях.
Некоторые вынесены в отдельные классы, например, драйвер для общения по сети CAN, экземпляр класса просто "подключается" библиотеке, которая требует CAN driver для своей работы.
Общая система взаимодействия формируется постепенно - от проекта к проекту.
Например, общие для всех проектов библиотеки я размещаю отдельно (разумеется, все под контролем SVN) в отдельном каталоге, где все разложено по своим местам.
Там же библиотеки RTOS, драйверы на некоторую периферию.
Это позволяет избежать ненужного копирования уже готовых отлаженных библиотек (кода) из предыдущего проекта в новый - общие библиотеки потому и называются общими, что они общие )))
Более того, они заранее скомпилированы и собраны в либы, чтобы в самих проектах компиляция проходила быстрее и меньше файлов болталось в дереве файлов. Только самое необходимое.


Цитата
Типа базовый класс? Далее от него класс SPI?

Есть готовые открытые С++ либы под периферию разных процов. Погуглите ))

Цитата
А что вы за ось пользуете?

Разные: https://electronix.ru/forum/index.php?s=&am...t&p=1475072
SasaVitebsk
Стиль написания, конструирование программы и язык всё же параллельны. А стабильность работы вообще к языку никакого отношения не имеет.
Не в плане спора, но как известно С++ ни в одном источнике, как ясный прозрачный и без проблемный не рассматривается. Ну это же объективно. Просто почитайте мнение специалистов.
В предпоследнем проекте у меня было 411 объектных файлов и более 50 тыс строк текста. Это прибор коммерческого учёта. Я не видел случаев его падения.
Там Си + FreeRTOS + LwIP. Драйвера в несколько уровней.
Например, обращение к флэшке SPI из различных задач - на ура. Мало того, использовались 2 аппаратных буфера поочерёдно для ускорения. В некоторых случаях заливка производилась потоковым способом. Всё работало как часики. При падении напряжения возникало прерывание, сохранялся контекст, сохранялись указатели архивов... Сделал - положить нельзя прибор. Только контрольный выстрел. ))
Меню там экранов штук сто - объектно построено.
Вот подумываю один проект замутить на плюсах. Там просто графика будет приличная. Должно окупиться.
А что вы так взъелись на динамическое выделение памяти? Тоже пробовал в проектах. В одном проете вообще на нём всё построено было. Причём там у меня дырки появлялись. Так я свой сборщик мусора сделал. Тоже претензий не было. Если всё продумать, то всё работает.
Forger
Цитата(SasaVitebsk @ Jan 18 2017, 01:21) *
В предпоследнем проекте у меня было 411 объектных файлов и более 50 тыс строк текста.

По статистике, среди программистов самый популярный способ продемонстрировать крутизну проекта - указать число строк и файлов )))
И совершенно до лампочки тот факт, что из них львиная доля - сторонние чужие библиотеки ...

Цитата
Вот подумываю один проект замутить на плюсах.

В чем смысл переходить на плюсы, коли уже выработалась стойкая привычка применять объектные фишки на голом С?
Неужели и вас тоже утомило работать "молотком по стамеске"? biggrin.gif

Цитата
А что вы так взъелись на динамическое выделение памяти?

Все просто - категорически не люблю мотаться по командировкам sm.gif

Есть у меня испытанный в тестах неплохой диспетчер динамической памяти (TLFS), но пока нет ни одного проекта, где понадобилось применять динамическую память.
Поэтому пока что предпочитаю заложить в проект камень с достаточным объемом памяти (или прикрутить внешнюю), вместо того, чтобы мотаться по командировкам, вылавливая баги.
В моем случае такой подход выгоднее ))

з.ы. На ум приходит такая старая фраза (формулировка по памяти): "идеальна не та конструкция, к которой уже нечего добавить, а та, от которой уже нечего убрать"....
SasaVitebsk
Посмотрите с чего начиналась тема. Начали гнать на HAL от ST. Что по своей сути это такое? По сути это попытка создания универсальной библиотеки. Более того, в купе с генератором, это попытка создания универсального подхода. С моей точки зрения - он провалился. Хотя куча его использует и счастливы.
Что предлагаете вы? Вы пытаетесь создать туже универсальную библиотеку, с универсальным подходом. Только 2 отличия. 1 - на С++. 2 - вы не ST.
Простите - я лучше стамеской поработаю.
Любая универсальная библиотека будет избыточна. И должна быть избыточна. Потому что универсальность и избыточность это одно и тоже. Меня не напрягает избыточность сама по себе. Камни сейчас обеспечивают - я не парюсь. Но весь мой опыт написания универсальных вещей, говорит что они не нужны. В принципе не нужны. Посмотрите HAL от ST на USART. Пипец. Я даже не представляю приложение куда это можно воткнуть!!! Получается, что для применения этой универсальной вещи потребуется обёртка большая по объёму, чем если бы я с нуля написал неуниверсальный драйвер. Я уже писал по этому поводу. Я делаю 2 уровня дров. Железозависимая часть и железонезависимая. Ну например SPI и ADC. Этот же SPI и DATAFLASH.
USART -> MODBUS. Нижняя часть - это десяток строк. Дрова у меня в проекте занимают 2% по объёму и ещё меньше по времени. Отлаживаются на раз и к ним никогда не возвращаешься.
А остальная часть проекта это как раз то, что я постоянно меняю. Даже если прибор аналогичный.
Я видел несколько попыток создания универсальных платформ. В том числе на плюсах. Ни одна меня не впечатлила.
Возможно вы от своей без ума. Но это не значит, что я был бы счастлив ей пользоваться. Или кто-то другой.

Теперь по поводу динамической памяти. В том проекте, о котором я писал примерно такое построение было... Поступают данные с внешнего интерфейса. Данные поступают в виде команд. Команды разной длины и разного времени жизни. Устройство выполняет команду и удаляет её. Получается, что одна команда могла выполниться и сразу удалялась, а другая выполнялась в течении длительного времени. В результате память дифрагментировалась. Поток команд был очень интенсивный. Объём памяти тогда на контроллере был 64к всего. Под кучу килобайт 30 было отведено. Уже не помню. Были бы проблемы это бы вылезло достаточно быстро. Устройство не выключалось. Работало круглосуточно. Не скажу что мы их много сделали. Ну несколько десятков было.
А вот на плюсах как раз трудноустранимые утечки случаются. Парень писал для нас OPC сервер. На QT4 + VS. Была утечка памяти. Устранил только когда свой QSerialPort написал. Хотя я с той же версией QT+GCC писал прогу удалённого управления прибором и проблем не было. При этом для связи использовали те же классы. Вот такой вот пример.
Forger
Цитата(SasaVitebsk @ Jan 18 2017, 02:48) *
Что предлагаете вы? Вы пытаетесь создать туже универсальную библиотеку, с универсальным подходом. Только 2 отличия. 1 - на С++. 2 - вы не ST.
Вы нифига ничего не поняли ))

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

Нету у меня единой обертки под все железные дела, есть лишь заранее скомпилированные либы на базе индусской PeriphLib под разные ST-процы (сижу плотно на них).
Правда, все же есть у меня один класс - Pin, он реализован под каждое семество, т. к. библиотечный код для управления пинами от ST в данном случае слишком тяжелый.
Все остальное - по максимому чужое. Изобретать велосипед - уже не тот возраст ))
Так как поддержка PeriphLib прекращена, похоже, придется переключаться на HAL, но по возможности по максимому буду использовать только объявления регистров и ессно cmsis.
Но вся эта тряхомуть с железов закопана глубоко и при переноски модулей из одного проекта в другой почти ничего переписывать уже не нужно, кроме функционала самого модуля под конкретный проект.

Цитата
Любая универсальная библиотека будет избыточна.
Еще раз - речь не об этом ))
Я ни сколько не призываю использовать мой код (попросите, не дам),
Я лишь продемонстрировал как применяется на примере класс синглтон и самое главное пример модульного построения проекта на основе одного из моих проектов.

Есть у меня также самописный Iterator (изумительная вешь, я в восторге от ее простоты и функциональности!),
Queue для управления списками (самописный простой),
набор разных цифровых фильтров (шаблоны, т.е. не привязаны к типам данных)
есть само собой Singleton, от которого наследуются все синглтоны (модули проекта)....
Все это - шаблоны классов, т.к. просто hpp файлы. Вообще не зависят ни от какого железа.

Готовые чужие реализации мне не понравились - слишком толстые и перегруженные всякой ненужной трухой.
Впрочем, такого добра у каждого программиста полно. У каждого - свой ))
SasaVitebsk
На счёт грамотного проектирования - ктож с вами спорит. Только по моему опыту - это приходит с годами. Самые тяжёлые - ошибки в проектировании, так как они обнаруживаются на поздних этапах разработки и влекут за собой значительную переработку проекта... Ну или костыли,которых не любят все.
На счёт того, что плюсы дают преимущество в проектировании - возможно. Так как более высокоуровневый язык, проще позволяет описать именно верхний уровень. Но это справедливо будет только при хорошем владении инструментом. Иными словами - вот человек неверно спроектировал проект. И что? При переходе на С++ ошибки исчезнут? Думаю их добавится.
На плюсах даже подход меняется..
Сергей Борщ
QUOTE (Forger @ Jan 17 2017, 16:32) *
Синглтон позволяет сам контроллировать вызов своей инциализации, причем делать это лишь один раз.
Вот на реализации этого и страдает мое чувство прекрасного. Он каждый раз проверяет - создан ли объект, и если не создан - то создает. То есть программа может годами работать после запуска, все инициализации давно прошли, а он продолжает тратить время на ставшие уже ненужными проверки при каждом обращении к каждой сущности. Я понимаю, что это тяжелое наследие моего ассемблерного прошлого, что ресурсов у современных МК завались, но побороть себя пока не могу. Хотя с проблемами порядка инициализации сталкиваюсь постоянно, да. Пока я думаю о запихивании всего в один класс Application - там порядок вызова конструкторов однозначно определен порядком объявления, а уж наличие в программе одного объекта Application я как-нибудь вручную обеспечу.
Forger
Цитата(Сергей Борщ @ Jan 18 2017, 12:18) *
Вот на реализации этого и страдает мое чувство прекрасного. Он каждый раз проверяет - создан ли объект, и если не создан - то создает. То есть программа может годами работать после запуска, все инициализации давно прошли, а он продолжает тратить время на ставшие уже ненужными проверки при каждом обращении к каждой сущности.

Редкая проверка битового флага отнимает совсем немного времени sm.gif

К тому же далеко не везде и не так уж часто нужно проверять факт существования некоторых сущностей.

Вот пример: синглтон rtos - класс Kernel.
При создании мьютекса в конструкторе вызывается инициализация Kernel.
Т.е. проверка только на этапе запуска системы (я динамически практически никогда не создаю объекты rtos).
По сути в данном случае все эти проверки производятся только при подаче питания.

Код
void Kernel::initialize(void)
{
    if (!isInitialized)
    {
        __disable_irq();
        initializeHardware();
        initializeModules();
        isInitialized = true;
    }
}


Код
class Mutex
{
public:
    Mutex(void)
    {
        Kernel::getInstance().initialize();
        handle = xSemaphoreCreateMutexStatic(&controlBlock);
    }
....



Цитата(Сергей Борщ @ Jan 18 2017, 12:18) *
Пока я думаю о запихивании всего в один класс Application - там порядок вызова конструкторов однозначно определен порядком объявления, а уж наличие в программе одного объекта Application я как-нибудь вручную обеспечу.
В начале так делал, но еще на этапе проектирования возникли проблемы с областями видимости одних модулей с другими - ведь они ничего друг о друге не знают.
Костыли с дополнительными методами решали проблему (передача в модули ссылок на другие объекты), но такие костыли лучше сразу выкинуть, ибо они еще хуже, чем все это ваять на голом С.
Синглтоны, имхо, тут оказались самым уместным решением.
И обязательно - возможность отложенной инициализации, у меня каждый модуль имеет метод initialize(), пусть пустой, но он должен быть.
(в будущем это даст возможность запихать их в container и инициализировать все скопом через foreach).






Цитата(SasaVitebsk @ Jan 18 2017, 11:32) *
Самые тяжёлые - ошибки в проектировании, так как они обнаруживаются на поздних этапах разработки и влекут за собой значительную переработку проекта...

Ну, "не так страшен черт, как его малюют" sm.gif

Цитата(SasaVitebsk @ Jan 18 2017, 11:32) *
Ну или костыли,которых не любят все.
Никто не любит костыли, просто, многие ленятся отказаться от них wink.gif

Цитата(SasaVitebsk @ Jan 18 2017, 11:32) *
На счёт того, что плюсы дают преимущество в проектировании - возможно. Так как более высокоуровневый язык, проще позволяет описать именно верхний уровень. Но это справедливо будет только при хорошем владении инструментом.
Хорошее владение инструментом возникает только в процессе пользования инструментом, по щелчку пальца такие навыки не приходят.
Не стоит бояться новых инструментов, уверяю вас - привыкание приходит быстро sm.gif

Цитата(SasaVitebsk @ Jan 18 2017, 11:32) *
Иными словами - вот человек неверно спроектировал проект. И что? При переходе на С++ ошибки исчезнут? Думаю их добавится.

Разумеется! Тупой переход с C на C++ в лоб ничего полезного не даст, а даже наоборот.
Потребность в новом инструменте возникает тогда, когда накопленный опыт + старый инструмент уже не дают нужного результата.
Но, чтобы опыт рос, нужно развивать соотв. навыки, самое простое - делать много разных проектов.
Но делать с таким расчетом, что накопленные навыки (библиотеки) могут пригодится в других проектах.

Цитата(SasaVitebsk @ Jan 18 2017, 11:32) *
На плюсах даже подход меняется..
Именно! Думать начинаешь иначе, поэтому ошибок проектирования возникает в разы меньше (разумеется, нужно почитывать книжки умных дядек).
pitt
Цитата(Forger @ Jan 17 2017, 19:13) *
На С++ это сделать проще и нагляднее, чем городить огород из С-костылей (сужу исключительно по своему опыту).

Опыт у всех разный и, соответственно, результаты и выводы. Вообще, универсально-идеального подхода/решения нет и не будет. Suum cuique.
Forger
Цитата(pitt @ Jan 18 2017, 16:43) *
Вообще, универсально-идеального подхода/решения нет и не будет. Suum cuique.

На самом деле есть идеально-универсальные решения, но они всегда основываются на новых более функциональных инструментах sm.gif
pitt
Цитата(Forger @ Jan 18 2017, 14:31) *
На самом деле есть идеально-универсальные решения, но они всегда основываются на новых более функциональных инструментах sm.gif

Блажен, кто верует, тепло ему на свете!
Forger
Цитата(pitt @ Jan 19 2017, 07:35) *
Блажен, кто верует, тепло ему на свете!

А другой долбил молотком по стамеске до конца дней своих ... biggrin.gif
SasaVitebsk
Цитата(Forger @ Jan 18 2017, 02:00) *
По статистике, среди программистов самый популярный способ продемонстрировать крутизну проекта - указать число строк и файлов )))
И совершенно до лампочки тот факт, что из них львиная доля - сторонние чужие библиотеки ...

Из сторонних библиотек только LwIP и FreeRTOS. Больше ничего нет. Я HAL не пользуюсь. Из HAL использовал только инициализацию CPU и шин переписанную и Ethernet подправленный.
Строки, естественно считал по своим файлам. Нафига чужое считать.
Проект реально большой. Я 2 года писал. Понятно, что попутно куча другой работы была. Поддержка старых приборов, всякие там сертификации, поездки .. ))

Насчёт плюсов я так скажу. Это надо бы взять какой-нибудь камень ясный... Ну типа того же AVR. Ну чтобы ассемблер был такой, чтобы читался как роман... ))
После чего наваять несколько простых проектов. Компильнуть и посмотреть чё получилось. Поиграться. Ну чтобы ясная картина появилась, во что превращается та хрень, что ты написал. biggrin.gif
Вот где на это время взять?
scifi
Цитата(SasaVitebsk @ Jan 19 2017, 15:47) *
Насчёт плюсов я так скажу. Это надо бы взять какой-нибудь камень ясный... Ну типа того же AVR. Ну чтобы ассемблер был такой, чтобы читался как роман... ))
После чего наваять несколько простых проектов. Компильнуть и посмотреть чё получилось. Поиграться. Ну чтобы ясная картина появилась, во что превращается та хрень, что ты написал. biggrin.gif

Это ассемблер головного мозга. Его надо лечить электрошоком.
В машинный код нужно смотреть тогда, когда реально не хватает памяти и/или скорости, то есть раз в год biggrin.gif
А иначе не останется времени на отдых. Ну и программы будут писАться по два года smile3009.gif
Forger
Цитата(SasaVitebsk @ Jan 19 2017, 15:47) *
Ну чтобы ассемблер был такой, чтобы читался как роман... ))


Искренне сочувствую и .. желаю удачи!
pitt
Цитата(Forger @ Jan 19 2017, 01:52) *
А другой долбил молотком по стамеске до конца дней своих ... biggrin.gif

Продолжайте набор...
Увы, не все на этом свете излечимо...
Forger
Классика жанра: вопрос -> холивар -> срач -> закрытие темы.

Прихожу к выводу, что стойкая потребность в сраче зашита в генетический код человека. Вот это действительно неизлечимо!
k000858
не соглашусь

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

проблема не простая, баг найти нелегко, пытаюсь зайти с разных сторон. проект вполне рабочий, содержит в себе ни мало функционала, все работает исправно, не считая описанного в посте-1 эффекта

дам немного конкретики: устройство помимо ethernet интерфейса имеет на борту радио-интерфейс, который обслуживает 6lowPAN протокол (само устройство - координатор, общается с конечными устройствами через ре-трансляторы). По радио-интерфейсу конечные устройства скидывают данные, а так же обновляются прошивки. Прошивка конечных устройств закачивается в координатор через вэб-интерфейс. Один из этапов обновления ПО конечных устройств - передача частей ПО по радио-интерфейсу, для этого каждая часть по очереди копируется с FLASH и упаковывается в DataPacket. эффект наступает именно на этом этапе. Спровоцировать эффект можно повысив нагрузку на ethernet-интерфейс. под штормом трафика подразумивал банальный UDP спам
Forger
Цитата(k000858 @ Jan 19 2017, 19:24) *
не соглашусь

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

Все идет хорошо, пока не дошло до срача ...

Цитата
проблема не простая, баг найти нелегко, пытаюсь зайти с разных сторон. проект вполне рабочий, содержит в себе ни мало функционала, все работает исправно, не считая описанного в посте-1 эффекта

Я бы попытался искать косяк точно так же, как и поиск неисправности в любой технике - сузить круг поиска.
В данном случае предлагаю поэтапно отключать куски проекта.
Если построение модульное, то это сделать очень просто, если нет, придется "разрезать" и изолировать блоки друг от друга.

Но есть другой - более радикальный способ (однажды именно так я и сделал, о чем не жалею).
Заново перепроектировать проект, постепенно набивая ее функционалом из существующего.
Конечно, это потребует несколько дней кропотливой работы, но потом только спасибо себе скажите )))
Для этого не обязательно сразу перескакивать на С++, для начала нужно просто спроектировать проект.
Я очень часто пользую такую прогу - XMind и не только для этого.
Главное - не спешить набивать проект кодом, это мелочи, главное - разумно и однозначно спроектировать связи между модулями.
Для уже существующего проекта это делать намного проще. "Глаза боятся, а руки делают" )))

Забыл добавит - нельзя забывать о тестовом коде, который должен "проверять на прочность" каждый модуль.
SasaVitebsk
Цитата(k000858 @ Jan 19 2017, 19:31) *
проблема не простая, баг найти нелегко, пытаюсь зайти с разных сторон. проект вполне рабочий, содержит в себе ни мало функционала, все работает исправно, не считая описанного в посте-1 эффекта
...
Спровоцировать эффект можно повысив нагрузку на ethernet-интерфейс. под штормом трафика подразумивал банальный UDP спам

Очень очень давно разрабатывал модем. Появлялись сбои непонятные. Очень редкие... Примерно 1 сбой на 2 Мб передаваемых данных. Отладчика тогда не было как класса. По вероятности вычислил что ошибка возникает если приходит прерывание в каком-то месте головы. Осей тогда тоже не было. Сделал синхронный вывод инфы. Ну и обнаружил переменную. Дальнейшее было делом техники.
На вашем месте я попробовал бы
1. добиться повторяемости ошибки
2. Выводил бы отладочную инфу по прерываниям и задачам (для локализации)
3. дальше - глубже залазил.

k000858
Цитата(SasaVitebsk @ Jan 19 2017, 23:19) *
Очень очень давно разрабатывал модем. Появлялись сбои непонятные. Очень редкие... Примерно 1 сбой на 2 Мб передаваемых данных. Отладчика тогда не было как класса. По вероятности вычислил что ошибка возникает если приходит прерывание в каком-то месте головы. Осей тогда тоже не было. Сделал синхронный вывод инфы. Ну и обнаружил переменную. Дальнейшее было делом техники.
На вашем месте я попробовал бы
1. добиться повторяемости ошибки
2. Выводил бы отладочную инфу по прерываниям и задачам (для локализации)
3. дальше - глубже залазил.

В принципе именно такую методику и применяю
Выяснил что именно и при каких условиях портится: вот есть буфер со скопированной часть ПО, вот он же но уже битый. За время порчи молотил езернет (именно им провоцирую баг). Не удается пока выяснить почему происходит эта порча в буфере (а может происходит порча указателей на буферы ака указатели типа хедер?).
Пока кручусь вокруг одного места, добавляю отладочной инфы, меняю условия, проверяю адреса...но пока безрезультатно.
Forger
Цитата(k000858 @ Jan 20 2017, 08:54) *
В принципе именно такую методику и применяю ... ...но пока безрезультатно.

.
SasaVitebsk
Ну в принципе, здесь возможны 4 ошибки.
1. классическая, то есть глобальная переменная которая модифицируется в разных задачах или прерываниях при этом не предусмотрены средства контроля за этим.
2. неверная работа с указателем.
3. более сложная. Какой либо буфер выходит за пределы и портит указатель или переменную, а эта переменная уже начинает косячить..
4. стек задачи выходит за пределы.
Исходя из того, что порча происходит кратковременно, и потом ситуация восстанавливается, две последних маловероятны.
А портится один и тот же участок?
Forger
Если проектировать код похожим образом (на C++ без глобальных объектов), т.е. как я указывать в самом начале этой темы, то:

Цитата(SasaVitebsk @ Jan 20 2017, 11:08) *
1. классическая, то есть глобальная переменная которая модифицируется в разных задачах или прерываниях при этом не предусмотрены средства контроля за этим.

Этого никогда не произойдет, т. к. нет ни одного глобального объекта.

Цитата
2. неверная работа с указателем.

Указатели не используется, лишь ссылки на объекты, и то очень многие с квалификатором const. Нужно изрядно постараться, чтобы навредить ))
Т.к. нет указателей, то приведение типов НИГДЕ не используется, а это - тоже очень частая причина неконтроллируемых сбоев.

Цитата
3. более сложная. Какой либо буфер выходит за пределы и портит указатель или переменную, а эта переменная уже начинает косячить..

Самодельных буферов нет, есть давно отлаженные и вылизанные классы, которые реализуют работу буферов.

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

Цитата
4. стек задачи выходит за пределы.

Контроль стека средствами RTOS с соотв. отладочной информацией. Это уже встроено во всех нормальных RTOS.

Эти все сущности однажды написаны и отлажены, поэтому нет никакой нужды в каждом проекте лечить подобный "анальный зуд"!
Впрочем, у каждого свои предпочтения biggrin.gif biggrin.gif


зы. Речь идет лишь о коде приложения, а не о коде сторонних библиотек, где наверняка используются указатели, самодельные буферы и т. п. наследия голого С
SasaVitebsk
Уважаемый Forger. Мы вас уже поняли. Надо проект обязательно переписать на C++. Обязательно использовать синглтоны. И, конечно, тогда никаких ошибок не будет. Потому что у программистов пишущих на С++ не бывает ошибок. Особенно у программистов пишущих на С++ и включающих в проект FreeRTOS и LwIP на Си. Понятно, что надо использовать статическое выделение памяти, так как динамическое это смерть.
Хотелось бы спросить, а как быть с LwIP? Вы там тоже статическое выделение используете?
Понятно что надо использовать стороннюю библиотеку.. Лучше брать PeriphLib или переключиться на HAL...
Мы услышали. Спасибо.
Не понятно, с кем вы здесь спорите? Со мной? Так у меня нет таких ошибок. По крайней мере на данном этапе. Надеюсь это понятно?
А у топикстартера есть. И я пытаюсь ему помочь.
Я не знаю в каком коллективе вы работаете, но иногда проект переписать нельзя. И этому может быть сто причин, как правило, все они лежат вне программирования... Например сроки, финансирование, малая вероятность того, что в новом проекте не будет других ошибок, или как минимум, отсутствие веры в это руководства. И так далее...
Я просто не хочу вступать в полемику с вами. Я не всегда писал проекты по 2 года. Например был проект с экспортным автобусом маз. Дисплей 480x272 + светодиодные столбики + стрелки + 2 CAN и два проца в жёсткой связке LPC2478 + stm32f103 был написан за 2 месяца. Потому что законченное решение. А крупный проект - там проблема в том, что сотни параметров исходных, и в зависимости от этого работа прибора полностью меняется. Там объективно много работы. А писал я его в одиночку, попутно занимаясь другой работой.
Может не стоит хаить человека, не зная реальной ситуации?
Асмом я не пользуюсь. На плюсах пишу, но пока незначительный объём.
Но мы сейчас не обо мне говорим. Надеюсь это понятно?
Я прекрасно знаю о контроле стека и прочей ерунде... У меня, на лету определяется вылет если он происходит, диагностируется задаче и место откуда это происходит. Всё это запоминается происходит рестарт проца и информация записывается в виде ошибки с точным указанием времени.
Поэтому... Давайте по делу. Есть что сказать топикстартеру, пожалуйста скажите. А тему про грамотный переход из С в С++ начните с чистого топика и поделитесь своим опытом построения. Многие с удовольствием это почитают. И я в том числе..
pitt
Цитата(SasaVitebsk @ Jan 20 2017, 07:22) *
Уважаемый Forger. Мы вас уже поняли. Надо проект обязательно переписать на C++. Обязательно использовать синглтоны. И, конечно, тогда никаких ошибок не будет. Потому что у программистов пишущих на С++ не бывает ошибок. Особенно у программистов пишущих на С++ и включающих в проект FreeRTOS и LwIP на Си. Понятно, что надо использовать статическое выделение памяти, так как динамическое это смерть.
Хотелось бы спросить...

Что можно спрашивать у того, у кого есть единственный готовый ответ на все случаи жизни?! Вопрос, конечно, риторический, потому что все идут не в ногу, а по сему нас посылают в Ж, хотя весьма почтительно...
Forger
Навеяло (ничего личного) ...

pitt
Цитата(Forger @ Jan 20 2017, 12:38) *
Навеяло (ничего личного) ...


По-видимому, музыкой. Попробуйте сменить репертуар, хотя, как известно, С++ решает все проблемы на все случаи жизни.
Forger
Цитата(pitt @ Jan 21 2017, 01:11) *
По-видимому, музыкой. Попробуйте сменить репертуар...

Не стоит всерьез воспринимать эту картинку и на свой счет, это - шутка, не более того ))

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

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

Сильно сомневаюсь, что и вам придется кодить на голом С до глубокой старости (долбить "молотком по стамеске"), на это способны лишь избранные (фанатики)!
Придет время и ваше мнение изменится, т.к. к тому времени скорее всего появятся новые, более совершенные и более удобные инструменты.
Скажем, Keil станет поддерживать С# ...
pitt
Цитата(Forger @ Jan 20 2017, 17:19) *
Не стоит всерьез воспринимать эту картинку и на свой счет, это - шутка, не более того ))

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

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

Сильно сомневаюсь, что и вам придется кодить на голом С до глубокой старости (долбить "молотком по стамеске"), на это способны лишь избранные (фанатики)!
Придет время и ваше мнение изменится, т.к. к тому времени скорее всего появятся новые, более совершенные и более удобные инструменты.
Скажем, Keil станет поддерживать С# ...

Не вижу смысла повторять сказанное.
Товарищ не понимает...
k000858
все оказалось проще: в одной задаче действительно использовались данные, которые подготавливаются другой задачей, при этом в некоторых случаях происходила коллизия, при которой использовались недоподготовленные данные. Причем возможность такой ситуации я учитывал и, еще не приступив к глубокой отладке, несколько раз проверил наличие такой возможности. Говоря простым языком, пялился в конкретные строчки кода много раз, подозревая что дело в них, не знаю, почему не обнаружил, видимо "глаз замылил".

Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.