Перейти к содержанию
    

Вы знаете, но честно говоря меня напрягают оценки результатов труда одного программиста, другим. Прога это такая субъективная вещь ...

Я правда тоже тут с одним образчиком творчества работаю .... Тоже разговариваю одними междометиями и нецензурными словами, но всё же ...

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

Особенно меня напрягла работа с портами. Для инициализации порта требуется ввести три енума потом три массива и работать через процедуры. Короче на первый взгляд значительный и неоправданный оверхед. Особенно в сравнении с тем как я привык писать. Но когда потом смотрел некоторые части понимаешь смысл написанного. Так как у меня написано - не стандартизуешь. Мы разные цели ставим перед собой. Они изначально закладывают избыточность и пишут библиотеки, чтобы максимально перекрыть все возможные применения. А я строю реальное приложение, устраняю избыточность, нацелен на локальное использование.

В общем объёме приложения - объём драйверов у меня составляет единицы процентов. Учитывая что я их пишу в 2 - 3 уровня, то получается драйвера камнезависимые вообще копейки. Поэтому я могу себе позволить их написать. Хоть каждый раз. А стандартными воспользоваться как примером в каких то случаях.

Это общие моменты, а конкретно ... Я вижу что куб был рассчитан на применение в составе ОСи. Причём обкатывался с разными. Приведу пример.

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

Я посмотрел их код и вижу например heth->State ...

Это для чего написано? Для разруливания работы с устройством из под разных задач. И некоторые другие вещи.

И как результат подключение не вызвало никаких проблем. У меня всё заработало устойчиво.

Наверняка там тоже есть что оптимизировать. Так этим никто не запрещает заниматься.

Даже механизм блокировки вы можете привести в соответствие с применяемой осью.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Особенно меня напрягла работа с портами. Для инициализации порта требуется ввести три енума потом три массива и работать через процедуры. Короче на первый взгляд значительный и неоправданный оверхед.

 

Мне вот тоже не всегда понятна логика программеров на разных процах при работе с портами. Вот сам пишу процедуры таким образом:

Настройка порта на вывод, с параметрами ножки(там 0 или 1) на ввод(пуллап, даун, 3е сост.) и процедуры опроса линии, BitIsSet() BitIsClear()

Вот что еще надо для работы с ними? А как ни посмотришь, в творения от СТ, фрискала и пр ... жуть какая-то :crying:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тут всё просто. Если ждать долго, то надо на окончение ожидания настраивать прерывание, и ждать флага. Если недолго, то ждать, опрашивая в цикле.

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если ждать долго, то надо на окончение ожидания настраивать прерывание, и ждать флага.

Кто вам создаст это прерывание? А "флаг" как ждать? Чем его ожидание отличается от ожидания бита?

 

Если недолго, то ждать, опрашивая в цикле.

Это ничего в принципе не меняет. Просто вечный while переходит из HALа в вашу программу.

Можно сделать while (нет бита) шедьюлинг();

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Ну или ждите в вечном цикле, если это устройство монопольно используется.

Изменено пользователем mantech

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кто вам создаст это прерывание? А "флаг" как ждать? Чем его ожидание отличается от ожидания бита?

Прерывание мне никто не создаст, придётся самому :-)

Под флагом я имел в виду какой-нибудь объект синхронизации операционной системы (event, mutex). Соответственно, ожидание такого флага -- усыпляет ожидающий процесс.

Это ничего в принципе не меняет. Просто вечный while переходит из HALа в вашу программу.

Можно сделать while (нет бита) шедьюлинг();

Ну зачем же вечный? Можно с тайм-аутом. Мысль моя была о том, что если период ожидания бита ожидается короткий (например, гарантирован в даташите на FRAM), то такое ожидание ничем не отличается от просто небольшого цикла по ходу выполнения. Поэтому принимать специальные меры для перевода процесса в сон на время этого ожидания вряд ли целесообразно. Например, я не усыпляю процессор на время передачи пары байт по SPI. А вот на время передачи блока из 512 байт в SD-карту - уже усыпляю, ибо уже успею за это время сделать что-нибудь ещё полезное.

ЗЫ. В вытесняющей оси "while (нет бита) шедьюлинг();" ничего не даст, потому что вернёт управление тому же самому процессу. Лучше тогда while (нет бита) sleep(1);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну зачем же вечный? Можно с тайм-аутом.

С тайм-аутом или без не важно, всё равно это "вечный цикл" с точки зрения операционки.

 

ЗЫ. В вытесняющей оси "while (нет бита) шедьюлинг();" ничего не даст, потому что вернёт управление тому же самому процессу. Лучше тогда while (нет бита) sleep(1);

Осёвый "sleep" это и есть функция, вызывающая шедьюлинг..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С тайм-аутом или без не важно, всё равно это "вечный цикл" с точки зрения операционки.

Нет. С тайм-аутом цикл не вечный. Это просто несколько шагов выполнения алгоритма. То, что они оформлены в цикл - ничего не меняет. Так можно договориться до того, что и вычисление математических функций тоже придётся признать "вечным циклом", неприменимым в программировании с ОС. А что, какой-нибудь atan2() - вон как долго вычисляется! Значительно дольше, чем я буду ожидать флага опустошения передатчика SPI перед отправкой туда символа.

Осёвый "sleep" это и есть функция, вызывающая шедьюлинг..

Нет. Осёвый "sleep" не просто вызывает шедулинг, он ещё перед этим переводит текущий процесс в состояние ожидания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Ну или ждите в вечном цикле, если это устройство монопольно используется.

это плохой ответ, не о чем...

 

А вот на время передачи блока из 512 байт в SD-карту - уже усыпляю,

Имеется ввиду, запускаем ДМА, а задачу в sleep, то есть ОС будет к ней возвращаться с каким то своим достаточно большим интервалом, так?

 

Подытожим, у нас есть варианты:

1. усыпление процесса и возврат к нему с долгими интервалами для проверки дождались или нет (ожидание чего-то очень долгого)

2. это прерывание на окончание ожидания и в нем какой-то симафор, что позволяет ожидающую задачу усыпить до появления симафора. (если надо подождать среднюю длительность)

3. это долбим проверку интервала прямо в задаче циклом. В некоторых ОС будут переключать задачи по временным интервалам, если ожидание затянется, а в некоторых все задачи будут ждать эту. (ожидаем чего-то очень короткого)

 

правильные варианты?

 

Мне как-то внутренне кажется устраивать заопарк прерываний в ОС не верно.

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

 

Не понятно как это решить в универсальной библиотеке

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мне как-то внутренне кажется устраивать заопарк прерываний в ОС не верно.

 

Именно, о чем я вам и говорил. В драйверах доступа к всяческой памяти никаких вытеснений и семафоров RTOS.

Кто так делает убивает RTOS и получает просто примитивную многозадачность.

 

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

Наоборот она их усложняет.

 

Работа с быстрой периферией по прежнему пишется в стиле автоматов состояний.

Задержки делаются аппаратными таймерами. Переключение состояний автоматов производится в процедурах обслуживания прерываний по цепочке от разных источников включая DMA.

Сами прерывания это прерывания уровня ядра.

Прерывание RTOS вызывается только когда уже готов блок данных для обработки. И вот там-то взводится объект синхронизации о готовности данных.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Работа с быстрой периферией по прежнему пишется в стиле автоматов состояний.

Задержки делаются аппаратными таймерами. Переключение состояний автоматов производится в процедурах обслуживания прерываний по цепочке от разных источников включая DMA.

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

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

В таких случаях я иногда применяю подход "а-ля ISR-псевдозадача":

создаю отдельный контекст (стек), при завершении очередной транзакции с периферией (получении прерывания от неё, от DMA или от таймера), внутри ISR переключаюсь на этот контекст, выполняю

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

ISR-псевдозадачу.

Получается простой хорошо читаемый линейный код вместо леса автомата состояний.

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

 

Прерывание RTOS вызывается только когда уже готов блок данных для обработки. И вот там-то взводится объект синхронизации о готовности данных.

О готовности данных, или освобождении какого-то ресурса (занятого буфера или флага в API доступа к драйверу, работающему на уровне прерываний) и т.п..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Имеется ввиду, запускаем ДМА, а задачу в sleep, то есть ОС будет к ней возвращаться с каким то своим достаточно большим интервалом, так?

Не в sleep, а в wait(). В ожидание объекта синхронизации (event, mutex, ...). А объект синхронизации взводится в прерывании по окончании передачи. В этом случае ОС не будет возвращаться к ожидающей задаче с каким-бы то ни было интервалом - задача будет спать чётко до момента окончания передачи. И затем практически сразу проснётся.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

В таких случаях я иногда применяю подход "а-ля ISR-псевдозадача":

создаю отдельный контекст (стек), при завершении очередной транзакции с периферией (получении прерывания от неё, от DMA или от таймера), внутри ISR переключаюсь на этот контекст, выполняю

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

ISR-псевдозадачу.

Получается простой хорошо читаемый линейный код вместо леса автомата состояний.

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

 

 

О готовности данных, или освобождении какого-то ресурса (занятого буфера или флага в API доступа к драйверу, работающему на уровне прерываний) и т.п..

 

В принципе не возражаю, только вот это - "хорошо читаемый" напрягает. Субъективизм же.

Во первых в скоростной периферии важнее хорошая отлаживаемость

Во вторых хорошо читаемый только короткий код.

Расположите все ISR связанные с одним автоматом в одном месте и получите короткий код, понятно откоментируйте и отформатируйте и получите отличную читаемость.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...