|
Виж темите без отговор | Виж активните теми
Дата и час: Пон Юли 27, 2026 7:46 pm
Въпрос относно собствена библиотека за pic32mx
| Автор |
Съобщение |
|
lubo_88
Ранг: Минаващ
Регистриран на: Сря Яну 09, 2019 9:13 pm Мнения: 19
|
 Въпрос относно собствена библиотека за pic32mx
Здравейте, Започнах да пиша собствена библиотека за PIC32MX. Искам да е по-универсална и да подържа повече микроконтролери от серията, но се сблъсквам с пробема, че различните модели имат различен брой модули, различните корпуси-различен брой пинове и т.н. Например pic32mx795f512h е с 6-UART модула. Но ако използвам същата библиотека на друг микроконтролер, да кажем с по-малък брой UART модули, при компилация ще хвърли грешка (поне по моя код). Давам пример с функция, която изчислява стойността, която трябва да бъде записана в BRG регистъра, при подадена стойност от вън за желан baud rate. Съответно функцията приема три параметъра: 1. Кой модул да бъде настроен (Например: UART1 или UART2 и т.н) 2. Режим (High speed or Standart speed) 3. Желаната побитова скорост. Мислех си да имам един конфигурационен хедер (config.h), в който да казвам кой UART модул да бъде включен. И след това, в сорс кода във функцията "initBaudRate()", там където са условните конструкции с препроцесорни директиви (#if, #elif, #else) да изключвам части от кода. Не знам дали това е правилния подход и въобще дали може да се направи по този начин. Ако сте се сблъсквали с подобен проблем и имате някакви идеи, как се процедира в такива ситуации, моля споделете ги.
|
| Чет Яну 30, 2020 3:03 pm |
|
 |
|
Н'бабане Гт'муан'га
Ранг: Форумен бог
Регистриран на: Сря Яну 25, 2012 9:14 am Мнения: 5298
|
 Re: Въпрос относно собствена библиотека за pic32mx
Защо не ползваш plib? Те микрочип го зарязаха заради безумието наречено хармони, обаче plib все още си остава много добра библиотека с която можеш да правиш всичко с пик32
_________________ 'просто' е технически синоним на 'красиво'
|
| Чет Яну 30, 2020 3:34 pm |
|
 |
|
gicho
Ранг: Форумен бог
Регистриран на: Пон Мар 13, 2006 1:59 pm Мнения: 3867 Местоположение: Габрово
|
 Re: Въпрос относно собствена библиотека за pic32mx
Аз как бих процедирал: - всички функции в библиотеката ти получават аргумент от тип поинтър към структурата с регистрите на тая периферия (uart както пишеш), да го наречем pBase; т.е. ако регистрите на uart_x почват от 0х1000 и са примерно 24 броя по 2 байта, то имаш typedef на структура с 24 елемента (регистъра) от тип uint16_t, да я наречем ST_PIC32MX_UART_REGS - вътре във функциите дереференцираш подадeния пойнтър, т.е. аргумента ти е ST_PIC32MX_UART_REGS* pBase и да кажем някакъв регистър контрол1 се казва Ctrl1; в инит функцията ти искаш да пишеш едно в тоя регистър и имаш: - къде и колко са uart-ите на дадения чип не е описано в библиотеката ти - твоя "драйвер" съдържа функции, които работят с една инстанция на уарт и не знае за другите. Този, който ще ползва драйвера ти, т.е. приложенията, взимат от другаде или си пишат колко уарта и на какъв base адрес има в дадения чип. Ако ще да е C файл с константа и ifdef според типа на чипа, или каквото там е удобно. Самото ползване може да е дори така - ако ползователя на библиотеката ти го иска и бърза нищо не пречи до напише така: Ако иска може да има дефайни в хедър за дадения чип, или общ хедър с ifdef според точния чип: Това би трябвало да влезе и в линкер скрипта за да не допусне разполагане на променливи в тая зона. Но това няма общо с библиотеката на драйвера - всъщност и двете (и драйвера, и описанието на чипа) ползват някакъв хедър в който е дефинирана тази вездесъща структура. Ако някоя PIC8 ползва същия тип UART (същата периферия) не е проблем да си преизползваш тоя код и там - т.е. тоя драйвер е за "майкрочип уарт тип 3" (0, 1, и 2 са примерно някакви от пик10, 16, 24, 18) и този 3 вече става за 32мх, 64ssx, 128shit и тъй нататък серии. Една от целите, които трябва да търсиш е още по време на билдване да излезе грешка ако в кода някой ползва UART2, а в този чип има само 1 уарт. Липсата на дефайн UART2 в горната постановка решава този проблем. Водещо правило е че в сорсовете на драйвера няма данни - т.е. няма адреси на регистри, само офсети в структурата (примерно чрез нея се знае че Ctrl1 е на офсет 8 от базата). Едно от важните предимства в този стил на писане (наричат се чисти функции - такива, които работят само с аргументите си и не правят side effect-и достъпвайки невидими от прототипа и викането неща) е че лесно се правят unit тестове без да има нужда от обширни mock-ове. Представяме си че сме направили някъде в рам, ако щеш глобална или в стека, променлива от типа ST_PIC32MX_UART_REGS: После насочваш драйвера да помпи в тая структура и лесно анализираш дали прави очакваното:
|
| Чет Яну 30, 2020 3:47 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
 Re: Въпрос относно собствена библиотека за pic32mx
Общото взето на това му се вика драйвер и "библиотеката" с такива концепции се нарича "ОС". Предполагам, че има съществуващи ОС-чета за тоя проц и едва ли има смисъл да се пише нов. Иначе gicho e почнал да обяснява, но това което е обяснил е само върха на айсберга. Всичко, необходимо като информация се слага в една да я нарека "info" структура. Ако драйверът има нужда от променливи, примерно състоянието му - дали е конфигуриран, дали работи и т.н. се слага в "data" структура. В зависимост от архитектурата или ОС-а, структурите може да са отделни, за да може примерно info-то да е във флаша, а данните в RAM. Може и да са една обща структура, въпрос на вкус. Ако са отделни структури, то обикновено в инфото има указател към датата. Така всичко необходимо за драйвера, може да се извлече от инфото и всички функции на драйвера им се подава такъв указател. Функциите на драйвера обикновено никога не се викат директно. Викат се от драйверната система. Демек юзера вика системна функция, тя от своя страна вика драйверни функции. По-интересни са обаче прекъсванията. Идеята, че драйверът е един, примерно UART драйвер, а инстанциите може да са 2-3-4-5-6 и т.н. Прекъсването в зависимост от архитектурата може да е едно за всички, или за всяка инстанция да си има отделно прекъсване. Когато е едно, обикновено ОС-а си го прехваща гледа откъде е вика съответния драйвер. По-точно вика драйверната му функция като й подава инфо-указателя. Когато са отделни прекъсвания се налага "wraper". При по-елементарните ртос-чета юзера си пише враперчета, колкото уарти иска, толкова врапери, инициализации и т.н. Другите решения са по-удобни, но зависят... Примерно при по-старите процове интеръпт контролера е отделен и се програмира. Стандартно се програмира с указател към интеръпт функцията, но може с всякакъв указател, включително и към инфо/драйвер. Когато пък е с отделни вектори има таблица, която нормално също се програмира с ISR-и, но с малко трикове понякога тая таблица се програмира с драйвери. Вариантът с таблица за драйверите е доста удобен, в смисъл това е единственото което трябва юзера да направи. Просто попълва таблицата с драйверите и толкоз. Всички драйвери може да се компилират, но линкера се грижи да изхвърли ония дето не се ползват. Освен това и ОС-а от таблицата знае кои драйвери трябва да се инициализират и т.н. Абе по-удобно си е. При варианта с таблица, често вместо указател към инфо се ползва индекса на драйвера в таблицата. Така че потребителя не работи с указатели (а не и работа на потребителите да имат адреси от системната част). Вместо това потребителя казва искам да работя с драйвер номер 4 (примерно). При някои още по-адванс ОС-и вместо номерца се ползва текст, примерно "/dev/tty..." или нещо от сорта. При всички случаи обаче юзера просто си вика някаква системна функция и й подава някакво параметърче за кой драйвер се отнася. Виканията може да са стандартни, т.е. да не зависят от конкретния драйвер. Може и да специфични. На специфичните викания им се вика "IO-контроли", демек искам драйвер Х да изпълни Y. Какво точно значи "Y" си знае само конкретния драйвер.. евентуално  Докато стандартните са си стандартни според вида на драйвера и други неща, но специално при микроконтролерите е желателно да има станртно отваряне/затваряне и четене/писане. Така по-лесно се прави универсален код. Примерно едно управление на дисплей не е редно да се интересува с какви жици си говори с хардуера. Дали е през SPI, дали е през UART или през нещо друго. Важното е да може да чете и пише регистрите и паметта на дисплейния контролер, а как точно става четенето и писането е подробност, която една GUI библеотека не й е работа да знае. Отварянето също е интересно. Обикновено юзера първо "отваря". При отварянето подава някакъв "режим" да кажем ако е UART, то режима ще е 9600 и т.н. Режимът е почти изцяло зависим от конкретния хардуер и драйвер. Но ако е опакован във формата на някаква структура, която се изнася навън така че даже кода, който я ползва не знае какво съдържа. Само драйверът и този който конфигурира приложението трябва да знаят. Тук ще вметна една грозна практика, която мен лично много ме дразни. Значи "режимът" в общия случай не е нищо друго освен стойности на регистри, които трябва да се попълнят на хардуера. Горещо препоръчвам да се ползват 1:1 дефинициите на хардуера, а не като някои идиоти да измислят нови. Проблемът е, че смяната на имената прави много трудно проследяването. Примерно, ако даден регистър на даден хардуер има битче "бла-бла", то трябва като търсиш в проекта "бла-бла", както и в чаршафа "бла-бла" да намериш всичко. Само идиот би ползвал 3 различни наименования, едно в чаршафа, друго в хедърите с регистрите и трето когато указва режим... Та говорехме, че се подава указател към "режим" и някаква идентификация на дравер, за да се отвори. В резултат на "отварянето" обикновено се появява "хендъл". Хендълът може да е номерче, може да е указател, зависи от ОС-а. Но общо взето на хендъла съответства една структура. В тая структура има 3 важни неща. Първо кой е собственика, т.е. клиента. Второ кой е драйвера. И трето каква е текущата заявка от клиента към драйвера (ако има такава) и нейното състояние. Тези неща са важни тъй като клиента обикновено работи в един контекст (нишка примерно), а драйвера в друг (системно извикване, прекъсване и т.н.). Затова никога един клиент не вика директно функции, а се минава през хендъли. Както и обратното, драйвера не се интересува кой е клиента и как да му върне резултата, това си е работа на кърнела - той решава дали клиента е в нишка, която трябва или не трябва да се събуди и т.н. Освен това клиентите могат да заливат драйверите със заявки, но драйверите в повечето случаи могат да работят само върху една заявка в даден момент. Затова заявките си стоят в опашки с хендълите и чакат да им дойде реда. Това е "накратко"... 
|
| Чет Яну 30, 2020 8:15 pm |
|
 |
|
gicho
Ранг: Форумен бог
Регистриран на: Пон Мар 13, 2006 1:59 pm Мнения: 3867 Местоположение: Габрово
|
 Re: Въпрос относно собствена библиотека за pic32mx
Аз си мисля че говорим за някакъв вид HAL, който после може да се закача към по-високи нива, или в по-ясните случаи да се ползва дори директно. Работата на този слой е да скрие производител или имплементатор-специфичните неща и да представи интерфейс, който е ясен за хора, запознати със самия интерфейс - т.е. ако даден програмист е чел документите на philips за i2c или на bosch за CAN то се очаква HAL-а да му предостави параметри, които са описани в съответния стандарт (baudratе, идентификатор, арбитрация, RTR, бит тайминт, error passive), да вика функции за "пращане на съобщение", а не да вижда битове и структури от имплементацията (визията) на майкрочип за контролера. Не знам как си правят библиотеките напоследък майкрочип, но преди доста години имаха един функции в които искаха да им даваш съдържанието на регистъра  Само че нЕма смисъл в такива функции. Както споменах за мен важното в подобен код, както и във всеки един код, който се опитва да се нарича "преизползваем", "библиотечен" или подобни класификации, е да не пречи на използването на статична памет (тъй де, да не изисква динамична памет), да не налага динамични API-та ако проблема (приложението) не го изисква и т.н. Работата е да се ползва компилатора да хване проблеми с типове - липсващи типове (чипът няма CAN примерно но високото API го има в ОС-а и чак когато някой пусне в Азербейджан с активиран CAN му светва лампа за грешка, дето иначе е щяла да светна още на първия билд). В конкретния случай отгоре може да има някаква абстрактна I/O, драйверна, виртуална FS или каквото и да е - може би системно регистри в което са описани наличните ресурси, после списъци и мап-ове от хендъли на отворените такива, съдържащи указатели към info структури и т.н. Слагането на тия горни слоеве не бива да е задължително, а трябва да решава определени проблеми, които ги има в даденото приложение, но може да ги няма в друго. Имам предвид избягване на banana-monkey-jungle проблема. В единия случай ще се иска да има символ за избор на чип (облечено в символ от типа на "-DMCU=P16F84") и съответния фирмуер (elf) ще става само за тоя чип. Линкерът ще ореже всички неизползваеми функции, опит за викане на несъществуваща ще гръмне моментално при билд. В другия кърнелът ще поддържа всички чипове и като тръгне ще вид дали върви на 16Ф84 или на 32МХ(добре де, да кажем 16ф628) за да избере какво да прави, т.е. дали да върне грешка ако някой повика UART_Init() (приемайки че единия има уарт, а другия не - не помня вече дреболии отпреди 20+ години). Ще го компилира и ако някой не е проверил за грешка при викане на функцията като нищо ще стигне до release тоя билд. Хайде, да кажем че има достатъчно QA, но няма файда да проверяват такива баламски грешки. Това по-скоро хипотетични проблеми, но целта е да се мисли в посоката дизайна да е минималистичен и всеки ред код вътре да е влязъл, защото е имало нужда от него и е там заради конкретно изискване точно за този проект, а не в наследство от предишния. Това е различен начин на структуриране или дизайн на кода, но е възможен и на мен ми пасва. На други хора не им допада и предпочитат други начини. Тука се стига до това всеки да си прецени и ползва което му е по-удобно и с което прави по-качествен код. Но все пак да се запознае с другите концепции и да обективно да прецени плюсовете и минусите. Едит: значи, "клиентите могат да заливат драйвера със заявки" само ако има повече от един клиент... Т.е. ако има начин някой някак да пусне нов клиент (т.е. процес) без да прекомпилира кода (монолитен фирмуер, работещ по определени изисквания, т.е. с фиксирана функционалност). Възможен е примерно случай, в който на uart на устройството може да има или модем, или принтер, или нещо друго. Т.е. дадения фирмуер поддържа конфигуриране, което показва в дадения момент дали потребителя е свързал принтер, или модем. Тогава два модула (процеса) биха имали конфликт за уарт-а, щото викат едни и същи функции. Само че дори в flash-a да има драйвер за принтер и драйвер за модем, само един от тях трябва да тръгне когато бъде "разчетена" конфигурацията. Тука има едно кардинално, ама малко драматично решение на проблема - според конфигурацията се билдва подходящия фирмуер, по-точно се линква само. Това става когато клиента поиска вариант с "принтер" и го поръча така. Ако иска по-късно да сложи модем влиза на сайта, сменя от "принтер" на "модем" и цъка "apply". Това вади оптимизиран и конфигуриран фирмуер и той съответно се зарежда през OTA ъпдейт, или се изтегля като файл в броузъра на клиента. Имам предвид че на клиента едва ли му пука като отвори някакво конфигуриращо приложение дали ще се смени целия фирмуер, или един байт в конфигурацията. Но това е доста крайно, макар и да има много бонуси. В по-близък до реалността случай този конфликт между принтер и модем ще се реши с парче код, което следи и решава кой достъпва уарт функциите - това в конкретния случай става лесно примерно през функционални пойнтъри, контролирани от бита в конфигурацията или вход с ключе. Това няма да доведе до такъв слой за ресурс контрол на SPI, таймери, I/O-та и други, които никога няма да се споделят и достъпват от два "процеса". Ако все пак се наложи и друг да го ползва, тази функционалност за контрол на достъпа трябва да може да се сложи и на тях - т.е. да е библиотечна/преизползваема. Но не и наложена без нужда, с оправданието че може да се наложи в някакъв хипотетичен момент след години. Такъв строг контрол има смисъл само в системите, в които потребителя може и пуска всякакви дивотии през минута - т.е. десктоп пц-та. И е нелогична за ембедед система, в която I/O-тата към дадената система са определени и известни към момента на пускане в експлоатация.
|
| Чет Яну 30, 2020 10:41 pm |
|
 |
|
lubo_88
Ранг: Минаващ
Регистриран на: Сря Яну 09, 2019 9:13 pm Мнения: 19
|
 Re: Въпрос относно собствена библиотека за pic32mx
Здравейте, Благодаря за изчерпателните отговори. Явно тук се навлиза в по-дълбока материя, за която нямам все още нужните познания (поне засега). По принцип не обичам да използвам чужди библиотеки от рода на harmony, plib, mla и т.н., защото от тях не можеш да научиш много за дадения микроконтролер. Донякъде пък, библиотеките са необходими, защото ако трябва всеки път да чета и да си припомням регистрите за дадена периферия, писането става много бавно. Затова реших да напиша нещо свое, което да бъде използвано единствено и само от мен, пък и по този начин си упражнявам C-то. Засега решавам частично проблема по балъшки начин (няма да се смеете). Например, за всеки UART модул, създавам собствена функция - configUART1(), configUART2()..... и т.н. Всяка функция я обграждам с #ifdef UARTx и #endif. В един главен config.h хедер дефайнвам UART модулите, които ще бъдат използвани, както и други константи за други периферии. Ясно е, че това е леко тъпо, защото налага повтарянето на код, ама засега толкова мога. Пък и не целя кода да е абсолютно универсален за всички pic микоконтролери - 8, 16, 32 битови, а само за pic32mx. Все пак, какво предлагате за да подобря уменията си в тази посока? Дали не се бъркам или нещата намирисват на учене на data structures? Знаете ли подходящи материали, книги, видео уроци, които могат да бъдат полезни?
|
| Чет Яну 30, 2020 11:55 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
 Re: Въпрос относно собствена библиотека за pic32mx
Драйверите или са драйвери или не са. Ако са драйвери няма начин да са обвързани с конкретен клиент или конкретна бройка клиенти. Това си е по дефиниция и да искаш да я прескочиш е малко трудно.. не става. Особено в по-голям ОС просто забрави, много е трудно дори да искаш. Очевидно като начало е добре да се запознаеш с наличното за тоя пик. За съжаление аз не съм в час с тоя производител така че не мога нищо конкретно да препоръчвам. Надявам се, че колегите ще са по-конкретни. Идеални неща няма, особено в чуждия код винаги може да намериш кусури. Но за да оцениш доброто трябва да минеш и през останалото.
|
| Пет Яну 31, 2020 10:12 am |
|
 |
|
gicho
Ранг: Форумен бог
Регистриран на: Пон Мар 13, 2006 1:59 pm Мнения: 3867 Местоположение: Габрово
|
 Re: Въпрос относно собствена библиотека за pic32mx
За големия ОС съм съгласен, но тук говорим за различна ситуация. И тя е различна не защото не ни се пише, а защото изискванията към ембедед системата са различни от тези към ПЦ. Наследяването на код, който е възникнал за да реши проблем в съвсем различна ситуация, може да е вредно - най-малкото защото ще изхаби ресурси на системата, без да донесе никаква полза за продукта (меко казано - реално ще навреди). Ако се погледне по-дълбоко, в ембедед система в която CAN-а се ползва от един единствен процес, наличието на слой за защита от паралелен достъп (примерно) ще бъде маркирано като dead code. Сега, дали ще успеем да завъртим кода така че анализиращите инструменти да не успеят да "хванат" това, е друга тънкост. Но при едно code review това ще ни закопае. Остава оправданието че вече е написано и проверено, та не пречи да го има. Търсим подход, който да позволи тоя слой да се включва и изключва, и то по възможност не като глобална опция на ОС-a (билдни кърнъла със "защита" или не), а като опция в съответния "процес" или клон в програмата ("да" за UART, "не" за CAN и т.н.). Това е повече мислене, но си има резон да се прави така.
|
| Пет Яну 31, 2020 12:26 pm |
|
 |
|
gicho
Ранг: Форумен бог
Регистриран на: Пон Мар 13, 2006 1:59 pm Мнения: 3867 Местоположение: Габрово
|
 Re: Въпрос относно собствена библиотека за pic32mx
Няма да се смеем, спокойно - даже ще те успокоя че има фирми, дето така си пишат драйверите, и ги продават... Тук има нещо друго, което обаче е по-дълбока тема - правейки функция configUART1() ти обединяваш по много дървен и неудобен начин функция и данни. Това му викат closure в по-свестните езици, или обект в не-дотам-развитите. В крайна сметка това ти решава проблема че в някаква точка искаш да конфигурираш точно uart1 и да пратиш точно по него. В по-общите функции (например описаните от мен чисти варианти) при всяко викане трябва да викаш общата, но и да имаш горница аргумент за кой точно уарт искаш да бъде свършена работата - дали идентификатор, хендъл, поинтър към зоната с регистрите или нещо подобно. Ако беше обектно щеше да подадеш тази информация еднократно - примерно в конструктора, и после нямаше да има нужда от нея при викане на send метода. Макар че пак ти се налага да ползваш определен, конкретен обект. В единия подход ще повикаш: В другия: С closure-ите това се решава елегантно - обща функция и променливи, които да бъдат "прихванати" (запомнени) за да имаш до достъп до тях, дори ако не си ги подал като аргумент. Нещо като улеснението да ползва глобална променлива за да си спестиш аргументи, но без недостатъците на глобалните. В C не може да се постигне това, в по-новите C++(11) има closure-и и те решават проблема - дотам че отпада нуждата от класове. Но на нашето ниво (ембедед C) това го няма.
|
| Пет Яну 31, 2020 12:57 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
 Re: Въпрос относно собствена библиотека за pic32mx
Различна, различна.. колко да е различна? Доколкото знам pic32 си е с прилично ядро и приличен набор от периферии. Сравнено с първите майнфреймове е направо... А и въпросът не само в дадения контролер, верно майкрочеп не си дават голям зор... но не са и спрели. Контролерите общо взето се роят по-бързо, отколкото софтуера за тях. Ако ти може да си позволиш един такъв, друг път инакав драйве - ОК, дерзай. Но аз пък и наблюденията ми са, че никой не прави 5 драйвера за едно и също нещо. Освен ако не е някакъв некадърник, щото тия приказки за "по-отпимизиран" код са извинявай, ама вицове от фолклора. В нито една драйверна система не съм видял някой да вика драйверни функции ей така през просото. По дефиниция драйверната система се грижи за всички синхронизации. Драйверните функции никога не са реентрант. Поне аз дотолкова калпав ОС не съм видял, верно не съм и търсил. Така че драйверите си получават заявките една по една. И обикновено си ги обслужва една по една, защото хардуерът им е такъв. Примерно заявка за пращане по UART, ами няма как да пращаш две неща едновременно, нито да получаваш... Но има и хардуери, които донякъде позволяват или поне така изглежда. Примерно при USB девайс (пък и за хост важи) за да имаш комуникация по някакъв ендпоинд трябва да си го заредил. Но реда по който се обслужват ендпоинтите е по друга логика и зависи и от отсрещната страна. По даден ендпоинт може да те халтнат/сталнат. Не може да блокираш и да чакаш един еднпоинт, защото така може да си блокираш завинаги. Искаш или не искаш трябва да може да обслужваш "паралелно" различни заявки. Та на практика броя на клиентите и начина по който драйверите обработват заявките са две различни неща. Аз споменах, че клиентите "заливат" със заявки, за да обясня смисъла и функциите на хендълите. Освен това изрично черно на бяло написах, че "драйверите в повечето случаи могат да работят само върху една заявка в даден момент". Така че колкото и да искаш да напишеш различни варианти за CAN или друг драйвер, ми просто няма как. Ех, винаги може да се напише по-добре, но това е друга тема. Многото варианти са когато си без ОС/РТОС... Спреш ли се на даден и ако той има концепции на тема драйвери - щеш не щеш трябва да ги следваш. Избор и вариантите се свеждат до минимум 
|
| Пет Яну 31, 2020 1:39 pm |
|
 |
|
Dimitar
Ранг: Форумен бог
Регистриран на: Пет Ное 12, 2004 3:38 pm Мнения: 9103 Местоположение: Chicago, IL
|
 Re: Въпрос относно собствена библиотека за pic32mx
Миро, някъде прочетох, че написахте как един драйвер за един и същи хардуер (примерно UART0) може да се ползва едновременно от няколко клиента, които да пращат и получават данни през тоя хардуер. Пращането хубаво, ама като се получат данни в прекъсването драйвера как знае тия данни за кой от клиентите са предназначени, за да му ги прати? Аз това, което съм виждал и работил с него в ембедед системите - един процес като отвори даден хардуер и хардуера бива "заключван" от драйвера и друг процес не може да отвори и ползва същия ресурс, докато предишния процес не си свърши работата и да го "отключи" отново.
|
| Пет Яну 31, 2020 4:42 pm |
|
 |
|
gicho
Ранг: Форумен бог
Регистриран на: Пон Мар 13, 2006 1:59 pm Мнения: 3867 Местоположение: Габрово
|
 Re: Въпрос относно собствена библиотека за pic32mx
Това че майкрочип са пуснали нов вариант на периферията не се решава с ОС - пак ще се пише нов драйвер за да го поддържа. Предполагам казваш че интерфейса към клиентите (приложенията) ще се запази същия - само че това не е нещо, което се случва заради ОС. Независимо от с/без ОС новата версия на драйвера може да запази същия интерфейс, без да е нужно той да е posix или друг стандарт, или да отговаря на някакво общо API за драйвери. Ако погледнеш чибито и по-точно HAL-а му (който вече е отделен от OS-а и може да се ползва с други OS-ове или без такъв) там за STM32 примерно има два драйвера за USART - водят ги 'v1' и 'v2' (по спомен). Тия драйвери се слагат и ползва в серии L0..x, F0..x, H... Т.е. тоя драйвер покрива спецификата на IP-то което е за уарт-а. Не виждам защо ще трябва да правят F4 драйвер, ако примерно F1 има същата периферия. Заливането със заявки, която примерно се решава с queue, означава че ти трябва queue някъде в кода, и възможност да го ползваш - но само когато имаш нужда от такова. Ако имаш достатъчно контексти за да свършиш работата - примерно main()-а и TX_ready прекъсване, защо да слагаш нещо повече от queue, което се източва в TX_ready прекъсването (или някой mark прекъсване)? Реално и кю не ти трябва - ако имаш 200 байта за пращане (текста "Hello, wold abcac...") какво печелиш ако имаш апи, с което да ги пратиш всичките, т.е. някой да го запомни в негов буфер (алок, ...), да затича задача да ги праща по малко, и т.н. Защо не ползваш информацията за флоу контрола, която идва от флага на TX периферията и да си работи с оригинални "Hello, world..." стринг, който сигурно е даже някъде във flash? И без това трябва да имаш някаква стейт машина, която да прати "Enter your name:" чак след като първото съобщение е заминало - иначе ако пратиш и вторите ще ти трябва втори буфер от още 200 байта, и така докато свърши рам-та. А реално това е проблем, който има само едни стабилно решение - да се ползва информацията за флоу контрола. Щото ако е уарт с хардуерен флоу контрол точно при клиента в азербейджан принтера ще каже "не давай" и всичките данни дето се бълват, ама се трупат в буферите на OS-а, ще ядат памет докато съвсем гръмне watchdog-а. И това, "за късмет", ще става само в азербейджан, или пък ще звъннат от китай да кацнем в Ухан... Имах една тема за вграждане на друг TCP/IP стек в линукса, и там целия проблем е че ми се счупва веригата на флоу контрола, която иначе си работи перфектно през TCP. Колкото и да го въртя, докато не я "възстановя" не мога да направя нищо. Просто това си е проблем на флоу контрола и на нищо друго. Когато дадена периферия има множество части, примерно многото еднпоинти на usb, или трансмит и receive частта на уарта, има резон да пазиш от едновременни достъпи - въпросът е как го имплементираш това. Много често един по-тежък драйвер при започване на запис в tx фифо ще заключи целия уарт - а всъщност нищо не пречи през това време да четеш от rx-fifo-то. В много случаи самата периферия има собствени защити, които примерно не дават да преконфигурираш тайминги извън init състояние (примерно в CAN), при което защитите стават излишни. Подходът с по дифоулт слагаме всичко, щото не искаме да се интересуваме каква е спецификата на даденото приложение, е ОК когато се пуска ОС за голямо количество потребители (примерно) и не искаш да висиш на телефона да учиш цялата пасмина потребители. При ембедед има различни изисквания, затова твърдя че има разлика - под ембедед разбирам устройство с определена функционалност, което не може да го излъжеш да прави друго, нито можеш да го объркаш да не прави това, за което производителят е поел гаранция. Т.е. работи според "договора". Не че тия изисквания не можеш да ги постигнеш и с GPOS, но вътре 90% от кода ще е мъртъв. За да се оптимизира работата се налага подхода да е по-различен - ако мога да спечеля нещо, като например да махна heap-а, или да намаля изискваната РАМ памет, или да спестя драйвер за SPI понеже пиновете на платката са NC, ще го направя. Като дойде друга платка, на която са закачени, ще има друг проект, т.е. друго приложение, т.е. друг артифакт от билда на същите сорсове. Колкото повече неща се фиксират билд тайм, толкова по-оптимизиран става фирмуера. При нас (донякъде) ползваме CI за някой от проектите. Там нещата се билдват при commit и накрая излизат артифакти (да кажем, elf/hex/bin/img) файлове - автоматично. Преди да стигнат до release тоя код трябва да мине през тестване - за момента това все още има много ръчна работа. Ако някакъв код (C файл) участва във всички фирмуери то билд сървърите ще изкарат нови бинарита за всички проекти. Ако това е примерно споменатия SPI драйвер, и половината продукти (проекти) не ползват SPI, то ще е много грубо да карам QA-то да тества продукти, които не го ползват. Това е недопустимо (според мен) и аз търся начини да го избегна. Има и други подходи, но посоката да се не се слага неизползвана функционалност помага и за това. Наскоро попаднах на една статия за екипа на HP за фирмуера на LaserJet серията и мъките покрай изкарване на нови продукти: https://itrevolution.com/the-amazing-devops-transformation-of-the-hp-laserjet-firmware-team-gary-gruver/Подходът, за който говоря, се стреми максимално рано да хваща проблеми - като се стреми колкото е възможно повече от проверките да се правят от компилатора и линкера. Това изисква да се редуцира броя на слоевете абстракция до минимално необходимите. Което е дълбоката тема - както казваха някъде (май съм го цитирал вече): Имам предвид че трябва нещо в конкретното приложение да изиска дадената функционалност - примерно контрол на достъпа до ресурс, а не да дръпна нещо с включени всякакви дрънкалки, които да се чудя как да махна.
|
| Пет Яну 31, 2020 4:50 pm |
|
 |
|
gicho
Ранг: Форумен бог
Регистриран на: Пон Мар 13, 2006 1:59 pm Мнения: 3867 Местоположение: Габрово
|
 Re: Въпрос относно собствена библиотека за pic32mx
Колко пъти в даден фирмуер ти се е случвало да отвориш уарта от 5 места и да си създадеш такъв проблем? И ако наистина го направиш (щото си copy-paste-нал и си забрави да смениш от UART0 на 1), кога би искал да бъдеш "информиран" за грешката - докато билдваш, или след като пуснеш софтуера? Едит: А за приемната страна това се случва само ако дадената периферия/шина има нещо от по-висок слой на мрежите - примерно CAN се "разпростира" почти на всичките 7 слоя и там можеш да дефинираш начин за разпределение на получените данни - примерно по идентификатора. Но това, според мен, е драйвер или модул, които работи на друго ниво и има съвсем друго API-то. Да не говорим колко невъзможно е такъв "драйвер" да се представи със същото API като UART или SPI, или най-малкото колко хемороидално е такова решение. Това, което може да направи един драйвер, е да каже "дойде съобщение - взимай го и си търси начин да разбереш на кого да го пратиш". Ако нагоре има дефиниран протокол (J1939, CANOpen) ще има правила за разпознаване какво да се прави - но това пак е част от приложението и не бива да се търси начин да влиза в "драйвера". Това е някакъв вид dispatcher, или просто таблица (статична или динамична), която работи като мултиплексор. И това, което говорех в началото беше да се търси начин мултиплексора да се слага само там, където има нужда. А въсщност писанията бяха как един драйвер за "УАРТ" може да се ползва с няколко УАРТ-а (0, 1,2,...) - за да не се пишат отделни функции за всеки. Т.е. тоя драйвер да има инстанции. Проблемът с защитата е дали конкретна инстанция не се достъпва от двама - за което обаче трябва работещ механизъм защитата да познае кой вика в дадения момент функцията. Това може да стане през хендъли от отварянето, които биха били различни за всеки клиент (всяко извикване на open() ). Другият подход е да се ползва информация от ОС кой процес в момента вика тая функция, т.е. в какъв контекст се вика. Виждал съм и варианти да се дефинира аргумент за клиент, т.е. всеки клиент да трябва да вика с различно число за да знае драйвера дали да даде или не.
|
| Пет Яну 31, 2020 4:52 pm |
|
 |
|
Dimitar
Ранг: Форумен бог
Регистриран на: Пет Ное 12, 2004 3:38 pm Мнения: 9103 Местоположение: Chicago, IL
|
 Re: Въпрос относно собствена библиотека за pic32mx
Никога не ми се е случвало да ползвам такова нещо, но ако драйвера по принцип го позволява, тогава със сигурност някой ще го ползва и бозата ще стане. CAN-а е ясен - там няма как клиента да получи и ползва данни, които не са за него, щото проверява PGN-те и сорс адресите, а ако някой го е направил без тая проверка е просто за бой. Обаче с UART-ве, АЦП-та и разни други такива, където клиента/процеса няма как да знае и да провери дали данните са точно за него ще станат яки бози ако драйвера позволява хардуера да се ползва от няколко процеса едновременно. Просто ми беше интересно, щото аз по принцип правя прости неща и не ми се налага да навлизам в такива дълбоки дебри и някак си ми се струва "опасно" драйвера да позволява такива неща. Явно стана някакво недоразумение и накрая сме на едно мнение.
|
| Пет Яну 31, 2020 5:42 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
 Re: Въпрос относно собствена библиотека за pic32mx
Да, принципно драйверите трябва да могат да се ползват от много клиенти. Иначе става като вица с флопито  Драйверната система се грижи единствено за правилното сериализиране на заявките. Демек драйверните функции няма нужда да са реентрант, нито да се заключват защото няма кой да ги извика повторно, докато не излязат. Но това не значи, че не могат (ако искат) да обработват по повече от една заявка. Въпрос на желание и както писах по-горе въпрос на конкретния хардуер. Нормалната последователност е заявка, при която драйвера пуска желязото да бачка. Когато желязото свърши имаш прекъсване и в него драйвера сигнализира заявката като приключена. Въпросът е кога точно драйвера ще поиска следваща заявка. Дали след като е приключил предишната или веднага след като е стартирал предишната. Това е. Останалото са подробности. В случая с UART-a стандартно не би трябвало да се ползва от повече от един клиент. Но на практика често се случва, защото изведените уарт-и винаги са по-малко от необходимите. По закона на Мърфи  Примерно при нас през един уарт могат да се правят 100 неща. Да се обслужват няколко протокола, кой точно - ами който поискаш. Отделно може да се управлява дисплей, може да закачиш баркод четец, може да си пуснеш конзола. За капак може и трейса да си пуснеш. Така че мераци да се ползва UART-а едновременно - колкото щеш. И други ситуации съм имал, примерно на STM-те SPI-a не поддържаше 9-битов режим, докато уарт-а си го поддържа. Та щеш не щеш, емулираш SPI през уарт. Да, ама на SPI шината имаш няколко устройства и пак стигаш до момента с много шеф, малко роб  А дори и в ситуация един клиент - един уарт пак е обичайна практика да се използват множество висящи заявки. Това е начинът, ако имаш ниско приоритетен клиент но пък не искаш да изпуска данни или да се накъсва трафика. Затова когато получи CPU време клиентът подготвя повечко заявки и ги пуска да пътуват. Драйверът е с по-висок приоритет, така че той ще си ги обработи когато им дойде времето. А може и "едновременно" да ги бачка, примерно често имаш двойно буферирани ДМА-та или ДМА–та със списъци, така че варианти има.
|
| Пет Яну 31, 2020 6:36 pm |
|
|
Кой е на линия |
Потребители разглеждащи този форум: 0 регистрирани и 3 госта |
|
Вие не можете да пускате нови теми Вие не можете да отговаряте на теми Вие не можете да променяте собственото си мнение Вие не можете да изтривате собствените си мнения Вие не можете да прикачвате файл
|
|