Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: libopencm3
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2, 3, 4
demiurg_spb
https://github.com/libopencm3/libopencm3

ИМХО хорошая альтернатива стандартной библиотеке от ST и не только.
zhevak
Цитата(demiurg_spb @ Mar 15 2013, 12:35) *
https://github.com/libopencm3/libopencm3

ИМХО хорошая альтернатива стандартной библиотеки от ST и не только.

TNX!
Посмотрю потом, но все равно спасибо!
esaulenka
Тут есть пользователи этой библиотеки?

Первое впечатление - написано заметно приятнее, чем Cube/SPL. Можно читать и не плеваться каждые 15 секунд.
Склонность, правда, авторов к созданию своих велосипедов (почему бы не использовать родные определения регистров?..) несколько удивляет. Ну да ладно...

Собственно, у меня задача - сделать USB-Device.
Что-то как-то работает, однако мне сильно не нравится реализация USB без прерываний, опросом. Попытка запихать usbd_poll() в прерывание с разрешением такового пока к результатам не привела...
AlexandrY
Цитата(demiurg_spb @ Mar 15 2013, 09:35) *
https://github.com/libopencm3/libopencm3

ИМХО хорошая альтернатива стандартной библиотеке от ST и не только.


Детская поделка.
А остальная половина файлов просто пустые.
Аккуратней надо быть с такими ссылками.
demiurg_spb
Цитата(esaulenka @ Apr 3 2015, 11:06) *
Тут есть пользователи этой библиотеки?
Нет пользоваться не стал, т.к. у них тогда сильно менялись интерфейсы библиотеки.
Цитата
Первое впечатление - написано заметно приятнее, чем Cube/SPL. Можно читать и не плеваться каждые 15 секунд.
Склонность, правда, авторов к созданию своих велосипедов (почему бы не использовать родные определения регистров?..) несколько удивляет. Ну да ладно...
Абсолютно такое же впечатление и у меня осталось.

Цитата(AlexandrY @ Apr 3 2015, 13:38) *
Детская поделка.
А остальная половина файлов просто пустые.
Аккуратней надо быть с такими ссылками.
Не понял вашего юмора. Да эта либа пока не претендует на полноту. Да есть что пилить. Но уже сейчас глазу гораздо приятнее смотреть на неё нежели на творения ST (SPL).
klen
голосую за libcm3
Spl еще както было похоже на чтото , со скидкой что первый раз в первый класс.... но куб извините это говнокод. перевожу все проекты на куб а в результате поцесса получается что перевожу на регистры... при попытке воткнуть FreeRTOS обнаружил что куб использует системный таймер - пришлось перекостыливать куб, куда не плюнеш -ПЕРЕКОСТЫЛИВАТЬ.... а че они творят в яко бы дефолтных обработчиках прерываний... за каждый if else не по делу растреливать нада. куб это либа для школоты. единственное что понравилост - включение выключение переферии, макрос через регисты rcc

да libcm3 не полная, но... лучше я в этот проект комитить буду то чо недоделано
вобщем каждому по вкусу..
_Pasha
Цитата(esaulenka @ Apr 3 2015, 11:06) *
Собственно, у меня задача - сделать USB-Device.
Что-то как-то работает, однако мне сильно не нравится реализация USB без прерываний, опросом. Попытка запихать usbd_poll() в прерывание с разрешением такового пока к результатам не привела...

у меня та же задача, msc. но поллинг пока устраивает.
уже моск выкипел, определяется стабильно с 3 раза, это секунд 40, затыкается на отдаче scsi готов/неготов... хз как его отловить.

Цитата(demiurg_spb @ Apr 3 2015, 16:24) *
Не понял вашего юмора. Да эта либа пока не претендует на полноту. Да есть что пилить. Но уже сейчас глазу гораздо приятнее смотреть на неё нежели на творения ST (SPL).

че там за полнота дожна быть? f3 f4 и хватит. в мелких вообще неясно нахрена эти обертки.

Цитата(klen @ Apr 4 2015, 10:36) *
голосую за libcm3

да libcm3 не полная, но... лучше я в этот проект комитить буду то чо недоделано
вобщем каждому по вкусу..

+100500
там тоже иногда аццки хочется показать, шо так не делают, но в целом нормально.
Только мне непонятно, чего они автогенерированные части, которые инклюдятся, с расширением *.c оставили - это ж бардак..надо каждый файлик перебирать и смотреть что включать в проект а что нет.
Цитата
куда не плюнеш -ПЕРЕКОСТЫЛИВАТЬ

меняю клок инит через куб на регистры - минимум 2 кб кода уходит. Мама миа!
esaulenka
Цитата(_Pasha @ Apr 6 2015, 17:49) *
у меня та же задача, msc. но поллинг пока устраивает.
уже моск выкипел, определяется стабильно с 3 раза


Определяется стабильно.
Прерывание тоже нормально работает вот с таким нехитрым кодом:
Код
extern "C"
void OTG_FS_IRQHandler (void)
{
    usbd_poll(usbd_dev);
}

Почему не взлетело сразу, я так и не понял...

Сейчас борюсь с граблей - некорректно работает прием по control endpoint.
kan35
Цитата(klen @ Apr 4 2015, 10:36) *
голосую за libcm3
Spl еще както было похоже на чтото , со скидкой что первый раз в первый класс.... но куб извините это говнокод. перевожу все проекты на куб а в результате поцесса получается что перевожу на регистры... при попытке воткнуть FreeRTOS обнаружил что куб использует системный таймер - пришлось перекостыливать куб, куда не плюнеш -ПЕРЕКОСТЫЛИВАТЬ.... а че они творят в яко бы дефолтных обработчиках прерываний... за каждый if else не по делу растреливать нада. куб это либа для школоты. единственное что понравилост - включение выключение переферии, макрос через регисты rcc

да libcm3 не полная, но... лучше я в этот проект комитить буду то чо недоделано
вобщем каждому по вкусу..

Запускаю свой первый проект на HAL через CubeMX, не соглашусь, что это говнокод. Косяков, конечно, еще довольно много, но в целом все это собирается более менее небольшими усилиями и с FreeRTOS состыкуется хорошо, прерывания с обработкой всех флагов - if else меня не сильно напугали, понятно, что за универсальность приходится платить. На SPL код был оптимальнее, на какую то долю % быстрее и на какие то единицы % копактнее, но делал я его на порядок дольше, а памяти и мегагерцев и так некуда девать.
Dr.Alex
Цитата(kan35 @ Apr 12 2015, 18:50) *
Запускаю свой первый проект на HAL через CubeMX, не соглашусь, что это говнокод. Косяков, конечно, еще довольно много, но в целом все это собирается более менее небольшими усилиями и с FreeRTOS состыкуется хорошо, прерывания с обработкой всех флагов - if else меня не сильно напугали, понятно, что за универсальность приходится платить. На SPL код был оптимальнее, на какую то долю % быстрее и на какие то единицы % копактнее, но делал я его на порядок дольше, а памяти и мегагерцев и так некуда девать.

В этом HALе куда ни плюнь while (какой-то бит); то есть затачивать реально подо РТОС они это будут ещё как минимум очень долго.
Golikov A.
А какая связь наличие или отсутствия while (бит) и долготы затачивания под РТОС?

В обычном супер лупе - это 100% зло которое заблокирует всю программу. Под РТОС еще есть шансы что задачу вытеснит более приоритетная, если конечно семафор никакой не заткнут. Но с другой стороны если этот бит должен появиться и не появляется - это же нарушение работы железа, с которым может и благо повиснуть и по вочдогу вылететь?

Но это мои рассуждения, а что вы хотели сказать? я без стеба, мне интересно.
Dr.Alex
Цитата(Golikov A. @ Apr 13 2015, 09:45) *
А какая связь наличие или отсутствия while (бит) и долготы затачивания под РТОС?

Под Винду вы тоже пишете с while (bit) ?
Golikov A.
строго говоря я не под что не пишу while(условие). У меня все ожидания с таймаутами.

Но пока я все равно не понял. Хотите сказать что при while(bit) не будет переключаться задачи?
Dr.Alex
Цитата(Golikov A. @ Apr 13 2015, 12:28) *
строго говоря я не под что не пишу while(условие). У меня все ожидания с таймаутами.

Но пока я все равно не понял. Хотите сказать что при while(bit) не будет переключаться задачи?

Я хотел сказать ровно то, что сказал. Считать такой стиль годным для РТОС так же странно, как и годным для Винды. Если никто не пишет так даже под Винду, то странно писать так подо РТОС.
AlexandrY
Цитата(Golikov A. @ Apr 13 2015, 12:28) *
строго говоря я не под что не пишу while(условие). У меня все ожидания с таймаутами.

Но пока я все равно не понял. Хотите сказать что при while(bit) не будет переключаться задачи?


Да, не будут.
Но к вашему случаю с двумя задачами это не относится.

Реальная проблема возникнет когда будет несколько десятков задач и вы перестанете всех их помнить. Хотя думаю и семи хватит.
Тогда while приведут к полному краху всей системы приоритезации.
Скажем во всех задачах есть диагностика. Она пишет лог. А тот лог в свою очередь пишет в файл. А в драйвере файловой системы стоит while да хоть и с таймаутом.
И все, кранты вашей риалтаймности.
Golikov A.
понятно, спасибо...
SasaVitebsk
Вы знаете, но честно говоря меня напрягают оценки результатов труда одного программиста, другим. Прога это такая субъективная вещь ...
Я правда тоже тут с одним образчиком творчества работаю .... Тоже разговариваю одними междометиями и нецензурными словами, но всё же ...
Можно понять и тех кто делал тот же stdlib или куб. Когда я последний проект начинал был только stdlib - посмотрел, что он для меня обладает избыточной функциональностью. И отказался от него.
Особенно меня напрягла работа с портами. Для инициализации порта требуется ввести три енума потом три массива и работать через процедуры. Короче на первый взгляд значительный и неоправданный оверхед. Особенно в сравнении с тем как я привык писать. Но когда потом смотрел некоторые части понимаешь смысл написанного. Так как у меня написано - не стандартизуешь. Мы разные цели ставим перед собой. Они изначально закладывают избыточность и пишут библиотеки, чтобы максимально перекрыть все возможные применения. А я строю реальное приложение, устраняю избыточность, нацелен на локальное использование.
В общем объёме приложения - объём драйверов у меня составляет единицы процентов. Учитывая что я их пишу в 2 - 3 уровня, то получается драйвера камнезависимые вообще копейки. Поэтому я могу себе позволить их написать. Хоть каждый раз. А стандартными воспользоваться как примером в каких то случаях.
Это общие моменты, а конкретно ... Я вижу что куб был рассчитан на применение в составе ОСи. Причём обкатывался с разными. Приведу пример.
Я использовал драйвер Ethernet из куба. Поскольку у меня не было заведено прерывания на обрыв линии, как это реализовано в кубе, то мне пришлось это сделать опросом в другой задаче...
Я посмотрел их код и вижу например heth->State ...
Это для чего написано? Для разруливания работы с устройством из под разных задач. И некоторые другие вещи.
И как результат подключение не вызвало никаких проблем. У меня всё заработало устойчиво.
Наверняка там тоже есть что оптимизировать. Так этим никто не запрещает заниматься.
Даже механизм блокировки вы можете привести в соответствие с применяемой осью.
mantech
Цитата(SasaVitebsk @ Apr 13 2015, 13:00) *
Особенно меня напрягла работа с портами. Для инициализации порта требуется ввести три енума потом три массива и работать через процедуры. Короче на первый взгляд значительный и неоправданный оверхед.


Мне вот тоже не всегда понятна логика программеров на разных процах при работе с портами. Вот сам пишу процедуры таким образом:
Настройка порта на вывод, с параметрами ножки(там 0 или 1) на ввод(пуллап, даун, 3е сост.) и процедуры опроса линии, BitIsSet() BitIsClear()
Вот что еще надо для работы с ними? А как ни посмотришь, в творения от СТ, фрискала и пр ... жуть какая-то crying.gif
Golikov A.
А вот теперь я задумался, а как с учетом заточености под RTOS правильно делать передачу данных, допустим по SPI в режиме мастера, допустим с какой-нибудь FRAM? Ведь там есть послать данные, подождать бита готовности памяти и принять их. Как бита ждать?

AHTOXA
Тут всё просто. Если ждать долго, то надо на окончение ожидания настраивать прерывание, и ждать флага. Если недолго, то ждать, опрашивая в цикле.
В частности, FRAM работает быстро, поэтому есть вероятность, что от попыток переноса ожидания в прерывания будут только дополнительные тормоза.
Естественно, ожидание в цикле опроса желательно производить в менее приоритетной задаче, чтобы более важные задачи могли этот цикл прервать.
Dr.Alex
Цитата(AHTOXA @ Apr 14 2015, 17:21) *
Если ждать долго, то надо на окончение ожидания настраивать прерывание, и ждать флага.

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

Цитата(AHTOXA @ Apr 14 2015, 17:21) *
Если недолго, то ждать, опрашивая в цикле.

Это ничего в принципе не меняет. Просто вечный while переходит из HALа в вашу программу.
Можно сделать while (нет бита) шедьюлинг();
правда тогда период опроса будет много миллисекунд, что может быть долго.
mantech
Цитата(Golikov A. @ Apr 14 2015, 14:16) *
А вот теперь я задумался, а как с учетом заточености под RTOS правильно делать передачу данных, допустим по SPI в режиме мастера, допустим с какой-нибудь FRAM? Ведь там есть послать данные, подождать бита готовности памяти и принять их. Как бита ждать?


Вообще-то для этого под оси и пишутся драйвера, они висят на прерываниях железа, более высокого уровня, чем переключатель контента у оси, и работают через стандартные потоки, как драйвер ком-порта под виндой, например...
Ну или ждите в вечном цикле, если это устройство монопольно используется.
AHTOXA
Цитата(Dr.Alex @ Apr 14 2015, 19:35) *
Кто вам создаст это прерывание? А "флаг" как ждать? Чем его ожидание отличается от ожидания бита?

Прерывание мне никто не создаст, придётся самому :-)
Под флагом я имел в виду какой-нибудь объект синхронизации операционной системы (event, mutex). Соответственно, ожидание такого флага -- усыпляет ожидающий процесс.
Цитата(Dr.Alex @ Apr 14 2015, 19:35) *
Это ничего в принципе не меняет. Просто вечный while переходит из HALа в вашу программу.
Можно сделать while (нет бита) шедьюлинг();

Ну зачем же вечный? Можно с тайм-аутом. Мысль моя была о том, что если период ожидания бита ожидается короткий (например, гарантирован в даташите на FRAM), то такое ожидание ничем не отличается от просто небольшого цикла по ходу выполнения. Поэтому принимать специальные меры для перевода процесса в сон на время этого ожидания вряд ли целесообразно. Например, я не усыпляю процессор на время передачи пары байт по SPI. А вот на время передачи блока из 512 байт в SD-карту - уже усыпляю, ибо уже успею за это время сделать что-нибудь ещё полезное.
ЗЫ. В вытесняющей оси "while (нет бита) шедьюлинг();" ничего не даст, потому что вернёт управление тому же самому процессу. Лучше тогда while (нет бита) sleep(1);
Dr.Alex
Цитата(AHTOXA @ Apr 14 2015, 20:01) *
Ну зачем же вечный? Можно с тайм-аутом.

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

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

Осёвый "sleep" это и есть функция, вызывающая шедьюлинг..
AHTOXA
Цитата(Dr.Alex @ Apr 14 2015, 22:04) *
С тайм-аутом или без не важно, всё равно это "вечный цикл" с точки зрения операционки.

Нет. С тайм-аутом цикл не вечный. Это просто несколько шагов выполнения алгоритма. То, что они оформлены в цикл - ничего не меняет. Так можно договориться до того, что и вычисление математических функций тоже придётся признать "вечным циклом", неприменимым в программировании с ОС. А что, какой-нибудь atan2() - вон как долго вычисляется! Значительно дольше, чем я буду ожидать флага опустошения передатчика SPI перед отправкой туда символа.
Цитата(Dr.Alex @ Apr 14 2015, 22:04) *
Осёвый "sleep" это и есть функция, вызывающая шедьюлинг..

Нет. Осёвый "sleep" не просто вызывает шедулинг, он ещё перед этим переводит текущий процесс в состояние ожидания.
Golikov A.
Цитата
Вообще-то для этого под оси и пишутся драйвера, они висят на прерываниях железа, более высокого уровня, чем переключатель контента у оси, и работают через стандартные потоки, как драйвер ком-порта под виндой, например...
Ну или ждите в вечном цикле, если это устройство монопольно используется.

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

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

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

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

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

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

Не понятно как это решить в универсальной библиотеке
AlexandrY
Цитата(Golikov A. @ Apr 14 2015, 21:16) *
Мне как-то внутренне кажется устраивать заопарк прерываний в ОС не верно.


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

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

Работа с быстрой периферией по прежнему пишется в стиле автоматов состояний.
Задержки делаются аппаратными таймерами. Переключение состояний автоматов производится в процедурах обслуживания прерываний по цепочке от разных источников включая DMA.
Сами прерывания это прерывания уровня ядра.
Прерывание RTOS вызывается только когда уже готов блок данных для обработки. И вот там-то взводится объект синхронизации о готовности данных.
jcxz
Цитата(AlexandrY @ Apr 15 2015, 00:40) *
Работа с быстрой периферией по прежнему пишется в стиле автоматов состояний.
Задержки делаются аппаратными таймерами. Переключение состояний автоматов производится в процедурах обслуживания прерываний по цепочке от разных источников включая DMA.

Иногда (при необходимости быстрой работы со сложной периферией) получаются очень сложные автоматы состояний со множеством состояний (десятками) и сложными переходами между ними.
Код становится трудночитаем, ведь программирование в стиле автоматов состояний гораздо хуже читается чем линейный код.
В таких случаях я иногда применяю подход "а-ля ISR-псевдозадача":
создаю отдельный контекст (стек), при завершении очередной транзакции с периферией (получении прерывания от неё, от DMA или от таймера), внутри ISR переключаюсь на этот контекст, выполняю
участок кода до след. запроса к периферии (после которого следует обратное переключение контекста на исходный стек ISR с выходом из ISR). И по завершении этого запроса - опять вход в
ISR-псевдозадачу.
Получается простой хорошо читаемый линейный код вместо леса автомата состояний.
Надо только не забывать про уровни приоритетов ISR, участвующих в этом (на NVIC). Можно просто сделать все одного уровня.

Цитата(AlexandrY @ Apr 15 2015, 00:40) *
Прерывание RTOS вызывается только когда уже готов блок данных для обработки. И вот там-то взводится объект синхронизации о готовности данных.

О готовности данных, или освобождении какого-то ресурса (занятого буфера или флага в API доступа к драйверу, работающему на уровне прерываний) и т.п..
AHTOXA
Цитата(Golikov A. @ Apr 14 2015, 23:16) *
Имеется ввиду, запускаем ДМА, а задачу в sleep, то есть ОС будет к ней возвращаться с каким то своим достаточно большим интервалом, так?

Не в sleep, а в wait(). В ожидание объекта синхронизации (event, mutex, ...). А объект синхронизации взводится в прерывании по окончании передачи. В этом случае ОС не будет возвращаться к ожидающей задаче с каким-бы то ни было интервалом - задача будет спать чётко до момента окончания передачи. И затем практически сразу проснётся.
AlexandrY
Цитата(jcxz @ Apr 15 2015, 06:04) *
Иногда (при необходимости быстрой работы со сложной периферией) получаются очень сложные автоматы состояний со множеством состояний (десятками) и сложными переходами между ними.
Код становится трудночитаем, ведь программирование в стиле автоматов состояний гораздо хуже читается чем линейный код.
В таких случаях я иногда применяю подход "а-ля ISR-псевдозадача":
создаю отдельный контекст (стек), при завершении очередной транзакции с периферией (получении прерывания от неё, от DMA или от таймера), внутри ISR переключаюсь на этот контекст, выполняю
участок кода до след. запроса к периферии (после которого следует обратное переключение контекста на исходный стек ISR с выходом из ISR). И по завершении этого запроса - опять вход в
ISR-псевдозадачу.
Получается простой хорошо читаемый линейный код вместо леса автомата состояний.
Надо только не забывать про уровни приоритетов ISR, участвующих в этом (на NVIC). Можно просто сделать все одного уровня.


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


В принципе не возражаю, только вот это - "хорошо читаемый" напрягает. Субъективизм же.
Во первых в скоростной периферии важнее хорошая отлаживаемость
Во вторых хорошо читаемый только короткий код.
Расположите все ISR связанные с одним автоматом в одном месте и получите короткий код, понятно откоментируйте и отформатируйте и получите отличную читаемость.
mantech
Цитата(AlexandrY @ Apr 14 2015, 21:40) *
Работа с быстрой периферией по прежнему пишется в стиле автоматов состояний.
Задержки делаются аппаратными таймерами. Переключение состояний автоматов производится в процедурах обслуживания прерываний по цепочке от разных источников включая DMA.
Сами прерывания это прерывания уровня ядра.
Прерывание RTOS вызывается только когда уже готов блок данных для обработки. И вот там-то взводится объект синхронизации о готовности данных.


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

конкретный пример SPI обмен:
опустить CS
послать запрос - 6 байт
дождаться ответа (ножки ОК, Есть данные, Ошибка) или таймаут
в случае наличия данных принять их - 4 байта
поднять CS

Хорошо звучит написать драйвер, без блокировок, без ожиданий циклами и так далее...
А на деле что?
Прерывания принят - отправлен байт по SPI - нет, единственный способ это проверять флаг что передатчик закончил. ДМА настраивать на обмен 6 байтами - глупо, а 2 ДМА для приема 4 еще глупее. Если нет FIFO как в STM все байты сразу не запихаешь. Растянуть цикл обмена на несколько миллисекунд - глупо.

Вот и получается что "надо драйвер написать чтобы все в прерывании делал и не тормозил" - не о чем...
AlexandrY
Цитата(Golikov A. @ Apr 15 2015, 08:12) *
ДМА настраивать на обмен 6 байтами - глупо, а 2 ДМА для приема 4 еще глупее.


Да, если недальновидно выбран микроконтроллер.

Я например сразу планирую сколько скоростных последовательных каналов будет в системе и прикидываю сколько каналов DMA понадобится.

Чем больше каналов DMA тем лучше чип заточен под RTOS.

Лучше всего здесь дела обстоять у Kinetis (32 канала), похуже у STM32F4 (16 каналов), еще хуже у LPC17xx (8 каналов)
jcxz
Цитата(AlexandrY @ Apr 15 2015, 10:46) *
В принципе не возражаю, только вот это - "хорошо читаемый" напрягает. Субъективизм же.
Во первых в скоростной периферии важнее хорошая отлаживаемость
Во вторых хорошо читаемый только короткий код.
Расположите все ISR связанные с одним автоматом в одном месте и получите короткий код, понятно откоментируйте и отформатируйте и получите отличную читаемость.

Вот такая работа с SPI (вполне хорошо читаемая и короткая при построении драйвера на уровне OS-задачи или как я описывал - псевдозадачей (выглядит так же как с OS)):
Код
FlashRead();
n = N_PAGES;
do FlashWrite();
while (--n);

при описывании state-машиной превращается в дикий лес, из нескольких десятков шагов с вермишельной логикой ветвлений:
(учтите что здесь ещё надо расписать шаги внутри FlashRead()/FlashWrite(), с реализацией стека вызовов (стека state-переменных))
Код
while (1) {
  switch (state) {
    case STATE_0:
      StartActionRead(...);
      state = STATE_1;
      break;
    case STATE_1:
      n = N_PAGES;
    case STATE_2:
      StartActionWrite(...);
      state = STATE_3;
      break;
    case STATE_3:
      state = STATE_ERROR;
      if (!result) continue;
      state = STATE_2;
      if (--n) continue;
     ...
    case STATE_ERROR:
     ...
  ...
  }
break;
}

Особенно если учесть, что надо реализовать цикл(циклы), что внутри FlashWrite(), FlashRead() может быть несколько транзакций по SPI-шине с несколькими входами в ISR, могут быть циклы с проверкой условий и т.п.). Вообще если нужно сделать простейшую функцию (набор часто повторяемых действий) на базе state-машины.
Если взять любой код драйвера, работающий на базе задачи ОС с использованием её объектов синхронизации (для уведомления о завершениях транзакций от ISR), и попытаться его развернуть в
state-машину, то сразу видно какой получается малочитаемый код.

State-машиной ещё вполне нормально реализуются простые линейные последовательности шагов алгоритма, без ветвлений и вызовов функций. Не более того.
scifi
Цитата(jcxz @ Apr 15 2015, 09:55) *
при описывании state-машиной превращается в дикий лес

Для этого существует protothreads. Никакого дикого леса.
Dr.Alex
Цитата(AlexandrY @ Apr 15 2015, 08:47) *
Лучше всего здесь дела обстоять у Kinetis (32 канала), похуже у STM32F4 (16 каналов), еще хуже у LPC17xx (8 каналов)

Тут дело даже не в "канальности".
У STM32F4 например к каждому каналу (точнее, стриму) привязано до 8 определённых источников/приёмников данных.
Поэтому если вы хотите использовать ДМА для 2-3-4 источников, привязанных к одному стриму, то вас может ждать облом.
Точнее, облом был бы неминуем, но один и тот же источних часто (но не всегда) привязан к двум стримам (а в целом они распределены хаотично), но всё же облом вероятен (я — уже). Нет и речи о том чтобы использовать хотя бы половину стримов.

А к примеру в "тупике эволюции" блэкфине каналы ДМА не привязаны к конкретной периферии.
При этом забавно, что там каналов чуть ли не больше чем источников данных :-)))
Golikov A.
еще матрица шин, а потом доступ проца и каналы кроют друг друга, и к шине не достучишься...
ДМА - хорошо, но все же использовать надо с осторожностью.

Опять же иногда ДМА настроить дольше чем перепихать данные... LPC кстати имеет фифо - что здорово облегчает иногда дело, но все равно проблемы имеются...
mantech
Цитата(Golikov A. @ Apr 15 2015, 08:12) *
Вот и получается что "надо драйвер написать чтобы все в прерывании делал и не тормозил" - не о чем...


Ну вот зачем такие голословные утверждения?

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

Прием - запускаю дма и счетчик таймаута, жду событий и генерю софтинт, что сложного? И не надо ждать в циклах и ступорить ось. Все работает по прерываниям в режиме полного автомата.
jcxz
Цитата(Dr.Alex @ Apr 15 2015, 13:37) *
Поэтому если вы хотите использовать ДМА для 2-3-4 источников, привязанных к одному стриму, то вас может ждать облом.
Точнее, облом был бы неминуем, но один и тот же источних часто (но не всегда) привязан к двум стримам (а в целом они распределены хаотично), но всё же облом вероятен (я — уже). Нет и речи о том чтобы использовать хотя бы половину стримов.

Это одна из главных причин из-за которой недавно, при выборе МК для новой железки, мы отказались от STM32F4. Очень убого реализована периферия в нём - ни буферизации (FIFO) ни достаточного числа DMA-каналов для решения проблемы без FIFO. sad.gif

Цитата(Golikov A. @ Apr 15 2015, 13:44) *
Опять же иногда ДМА настроить дольше чем перепихать данные... LPC кстати имеет фифо - что здорово облегчает иногда дело, но все равно проблемы имеются...

LPC, Tiva имеют нормальные FIFO (UARTы, SPI, etc). STM32 экономит на пуговицах непонятно зачем, значительно ухудшая характеристики МК.
Golikov A.
Цитата
Прием - запускаю дма и счетчик таймаута, жду событий и генерю софтинт, что сложного?

ничего сложного нет, особенно если для примера взят интерфейс который сам работает...
SasaVitebsk
Когда у человека появляется красивый инструмент, возникает непреодолимое желание его использовать. Иногда вопреки здравому смыслу. И старый тут же объявляется вне закона.
Смотрю различные драйвера обработки SPI - просто убивает. Порой визуально видно, что будет менее эффективно чем простой while.
При частоте проца 168МГц и работе SPI 22, байт вылетает за 61 такт. Обработчик прерывания на SPI это не 2 строки. Плюс вход/ выход. В чём прелесть?
Применение DMA порой ещё более натянуто. Я попробовал реализовать работу с флэшкой at45db. Правда у меня там разные режимы включая потоковую запись через разные буфера. Применение DMA существенно усложняет драйвер. Оценить выигрыш в производительности не представляется возможным. Оценить надёжность такой работы ... Да это надо целое исследование производить. При этом не надо забывать, что Ваше приложение не винда!!! Вам не нужно обеспечивать максимальную производительность. Вам надо обеспечить достаточную производительность. Как правило. Ну если не рассматривать вопросы потребления.
Применение автомата в некоторых случаях конечно оправдано и наиболее удобно.
А в целом нет универсального способа написания драйвера. Чего бы то ни было. Надо исходить из поставленной задачи.
Кидайте в меня палками, на SPI я применяю while. Не блокирующий. Кроме того у меня есть один поток на диагностику, где я пытаюсь контролировать в том числе зависание потока, а также анализирую зависание периферии. Там кстати автомат, так как я там всякие мелкие задачи в один поток собираю чтобы не плодить.
jcxz
Цитата(SasaVitebsk @ Apr 15 2015, 15:59) *
Смотрю различные драйвера обработки SPI - просто убивает. Порой визуально видно, что будет менее эффективно чем простой while.
При частоте проца 168МГц и работе SPI 22, байт вылетает за 61 такт. Обработчик прерывания на SPI это не 2 строки. Плюс вход/ выход. В чём прелесть?

Прелесть в том, что по SPI обычно не по одному байту пересылают, а десятки и сотни за транзакцию.

Цитата(SasaVitebsk @ Apr 15 2015, 15:59) *
Применение DMA существенно усложняет драйвер. Оценить выигрыш в производительности не представляется возможным. Оценить надёжность такой работы ... Да это надо целое исследование производить.

Ошибаетесь. Всего ПЛЮС несколько дополнительных строк на инициализацию, и МИНУС некоторое кол-во строк на цикл опроса состояний/программной пересылки и т.п.
В простых случаях по коду одинаково, но несравнимо быстрее с DMA.

Цитата(SasaVitebsk @ Apr 15 2015, 15:59) *
Кидайте в меня палками, на SPI я применяю while. Не блокирующий. Кроме того у меня есть один поток на диагностику, где я пытаюсь контролировать в том числе зависание потока, а также анализирую зависание периферии. Там кстати автомат, так как я там всякие мелкие задачи в один поток собираю чтобы не плодить.

Ваш while убъёт все нижележащие по приоритету задачи. Особенно если там надо не один-два байта переслать.
Для многозадачной среды - это зло.
mantech
Цитата(jcxz @ Apr 15 2015, 12:07) *
Это одна из главных причин из-за которой недавно, при выборе МК для новой железки, мы отказались от STM32F4. Очень убого реализована периферия в нём - ни буферизации (FIFO) ни достаточного числа DMA-каналов для решения проблемы без FIFO.


Че-то не пойму, или все пытаются использовать стм для ЦОС, с несколькими стримами по 100 мегабайт\сек или используют сразу всю периферию, что каналов дма нехватает или что еще...
Вот никогда эти фифо не использовал, муторно с ними, работал с 5 уартами и 2 спи одновременно, по 100мег не передавал, конечно, ибо для таких задач существуют коммуникационные процы или плис. Никаких проблем не испытывал, либо, принимал по прерываниям, либо дма, для больших пакетов.

Тут, по моему, искусственно создают бурю в стакане воды...
den_po
Цитата(mantech @ Apr 15 2015, 22:41) *
Вот никогда эти фифо не использовал, муторно с ними

Да нет же, практически то же самое, что и без фифо, только в обработчиках прерываний не по одному байту бросается, а сколько влезло
Dr.Alex
Цитата(mantech @ Apr 15 2015, 20:41) *
Че-то не пойму, или все пытаются использовать стм для ЦОС, с несколькими стримами по 100 мегабайт\сек или используют сразу всю периферию, что каналов дма нехватает или что еще...

Достаточно неудачно выбрать 3-4 периферийных блока чтобы стримы ДМА пересеклись.
А для ЦОС - да, уже пытаюсь использовать.

Цитата(mantech @ Apr 15 2015, 20:41) *
по 100мег не передавал, конечно, ибо для таких задач существуют коммуникационные процы или плис.

Для ПЛИС 100 МБпс это ничто. Отличный способ сделать совершенно неоптимальное устройство.
Можно мне показать такой "коммуникационный процессор"? Чтобы 1-2МБ флеши, 256КБ срамы, корпус 10х10х0.6?
Задача ещё и в том чтобы обрабатывать эти потоки на минимальной частоте ядра. Для моей текущей задачи разница в потреблении на частоте 168 и 84 очень существенна. Надеюсь вообще уложиться в 42.
jcxz
Цитата(mantech @ Apr 15 2015, 23:41) *
Че-то не пойму, или все пытаются использовать стм для ЦОС, с несколькими стримами по 100 мегабайт\сек или используют сразу всю периферию, что каналов дма нехватает или что еще...
Вот никогда эти фифо не использовал, муторно с ними, работал с 5 уартами и 2 спи одновременно, по 100мег не передавал, конечно, ибо для таких задач существуют коммуникационные процы или плис.

Не для ЦОС (хотя и она там возможно в каком-то количестве будет чуть позже), но в устройстве нужно 5-6 UART (одновременно работающих и при этом желательно - не перегружающих систему прерываниями в десятки кГц) + 2 одновременно работающих SPI (20-40МГц). Это как минимум то, что в STM32 придётся делать с DMA. В старых устройствах на LPC17x примерно то же самое работает занимая всего 4 DMA-канала (2 SPI), а UART-ы без DMA нормально работают, так как имеют FIFO. Да и SPI-каналы имеют FIFO, так что, как я понимаю, меньше занимают шину блочными пересылками.
А в новом устройстве планируется более интенсивный поток по SPI-каналам (к тому-же - реалтаймовый). По этой причине в основном и отказались от STM32.
Как тут уже написали - работать с FIFO - то же самое что и без, практически никакой разницы, только частота обслуживания может быть в 16 раз меньше.
mantech
Цитата(jcxz @ Apr 16 2015, 05:16) *
Как тут уже написали - работать с FIFO - то же самое что и без, практически никакой разницы, только частота обслуживания может быть в 16 раз меньше.


Это только в "тепличных" условиях. В моем случае была поддержка протоколов с пакетами разной длины от 6 до 1000 байт, причем длина указывается в первых байтах, без таймаутов, там же и ИД-пакета, которые нужно парсить "на лету", тут все фифы только вредят, и работа уартов на 115200 не сильно замедляет систему, если конечно, не нагружать прерывания чем-то еще, кроме приема...
SasaVitebsk
Цитата(jcxz @ Apr 15 2015, 13:29) *
Прелесть в том, что по SPI обычно не по одному байту пересылают, а десятки и сотни за транзакцию.

У меня по SPI 2 устройства: at45db и АЦП.
1. Во втором случае надо передавать 2 байта и получать 4.
2. В случае работы с флэшкой то же не всё шикарно. Если не выравнивать флэшку на границу страницы, то надо выполнять кучу работы. Грузить страницу, заполнять, записывать. Для всего этого требуется разные команды. У меня идёт в основном запись архивов и ошибок. Как правило требуется забота с малыми объёмами данных.
Я прикидывал, вариант драйвера с DMA. Для меня это очень значительное усложнение.

Плюс поясните мне пожалуйста. Вот я записываю информацию во флэшку. Потом мне надо ждать готовности флэшки. Как это обойти с помощью DMA?
jcxz
Цитата(mantech @ Apr 16 2015, 10:59) *
Это только в "тепличных" условиях. В моем случае была поддержка протоколов с пакетами разной длины от 6 до 1000 байт, причем длина указывается в первых байтах, без таймаутов, там же и ИД-пакета, которые нужно парсить "на лету", тут все фифы только вредят, и работа уартов на 115200 не сильно замедляет систему, если конечно, не нагружать прерывания чем-то еще, кроме приема...

Ну да... 11520*6UART*2(TX/RX) итого частота прерываний ==138240Гц, т.е. - прерывания с периодом 7.2мкс конечно не нагружают никак систему wink.gif
Про случай когда надо работать всего с одним UART-ом - тут нет вопросов.
А ведь бывают ещё и бОльшие скорости по UART.
У нас тоже по всем UART-каналам идёт обмен по протоколам с размером кадров переменной длины. FIFO не мешает этому никак.

Цитата(SasaVitebsk @ Apr 16 2015, 11:05) *
Плюс поясните мне пожалуйста. Вот я записываю информацию во флэшку. Потом мне надо ждать готовности флэшки. Как это обойти с помощью DMA?

Когда нужно всего пару байт - никто не мешает использовать обмен по прерываниям: записать в FIFO сразу все 1...8 слов, а потом получить 1..N прерываний и вычитать.
Можно комбинировать (я так делаю при малых размерах транзакции по SPI, полностью влезающей в размер FIFO): настраиваю DMA только на приёмный канал, записываю в TX.FIFO сразу все байты (программно), а потом по окончании приёма всего пакета получаю ОДНО прерывание завершения DMA (без ожидания таймаута по завершению).
Готовность AT45DB никак не надо обходить. Считывать регистр состояния согласно документации. Хоть программно, хоть с DMA.
Никто не мешает смешивать работу через DMA с программным обменом, хоть одновременно, хоть поочередно.
В зависимости от SCLK и её соотношения с частотой CPU, можно хоть программно записать в SPI необходимую команду чтения статуса и ждать поллингом завершения приёма
(допустимо при большой SCLK, когда такое ожидание приёма занимает мало тактов и выигрыш от освобождения процессора на время передачи невелик или нету его),
хоть записать программно, настроив DMA на приём ответа и генерацию прерывания по завершению (если SCLK много меньше частоты CPU и если ждать поллингом, то
надолго займёшь CPU впустую).
На МК без FIFO всё гораздо хуже, так как нельзя записать целиком посылку в FIFO, настроив только RX.DMA.

Мы много используем AT45DB. Передача данных в драйверах идёт через DMA, опрос состояния - как я описал (у нас SCLK=25...30МГц).
Под рукой сейчас нет исходника с AT45DB, но вот подобная операция с nRF24L01+ (чтение регистра nRF24L01+ - короткая SPI-транзакция):
CODE
static void ActSSP(int cmd, int len, int stepNew)
{
Pclr(PIN_NRF_CS); //CS=low
isrStep = stepNew;
volatile HwRegsSSP *ssp = &concatAB(SSP, nSSP_nrf);
HwRegsDMA::T_CH volatile *ch = &DMA.CH[DMA_CH_nrf_RX];
//DMA-канал DMA_CH_nrf_RX статически привязан к данному SPI (nSSP_nrf), так что адрес источника (ch->SRC) и ch->LLI устанавливаются в инит-коде и каждый раз их писать не надо.
//Всё программирование DMA для запуска транзакции занимает 3 строчки кода ниже, настройка регистров: ch->DST, ch->CTL и старт RX.DMA: ch->CFG.
ch->DST = &sh.regIO.status;
ch->CTL = len + sizeof(sh.regIO.status) | 1 << 12 | B27 | B31;
ch->CFG = B0 | (DMA_REQ_nrf_RX >> 4) << 1 | 2 << 11 | B14 | B15;
ssp->CR[1] = B1; //включаем SPI-канал
__DMB();
ssp->DR = cmd; //старт передачи (и приёма)
}

static uint RegRead(REG reg)
{
ActSSP((int)reg + CMD_R_REGISTER, 1, IS_GAP);
concatAB(SSP, nSSP_nrf).DR = 0; //запись хвоста (для приёма значения регистра)
NrfCtxSw(); //переключение контекста в фоновую задачу с ожиданием завершающего DMA-IRQ, который делает CS=high
return sh.regIO.val[0];
}

Код
#define concatAB_(a, b) a##b
#define concatAB(a, b) concatAB_(a, b)


Это код для LPC17xx.
Golikov A.
Цитата
которые нужно парсить "на лету", тут все фифы только вредят,

Это не верно!
Они вредят только в одном случае, при неожиданном разрыве обмена их надо очищать от старых пакетов... И в LPC для уарта они сделали очистку, а для SSP нет, приходиться 8 слов читать чтобы точно передатчик был пусть, в случае слейва это ложиться на внешнее устройство...

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

FIFO - благо

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