|
Драйвер, написать самому |
|
|
|
Nov 12 2012, 11:20
|
Местный
  
Группа: Участник
Сообщений: 351
Регистрация: 5-04-05
Пользователь №: 3 874

|
Цитата(Dubov @ Nov 12 2012, 14:21)  Просто ранее я писал только standalone приложения и смущает отсутствие в Linux процедур прямого обращения к регистрам (здесь всё через обёртки какие то мудрёные). Это не так, именно через прямое обращение к регистрам SoC в адресном пространстве и происходит взаимодействие с железом. Цитата(Dubov @ Nov 12 2012, 14:21)  В линукс смущает то что нету так привычных мне *.h файлов где через дефайны описаны адреса всех регистров (по мануалу). Они как правило есть, но не всегда на _все_ регистры. Для написания драйвера _устройства_ подключённого через spi слейвом, обращаться напрямую к железу не надо - это делает драйвер spi контроллера (мастера).
|
|
|
|
|
Nov 12 2012, 12:46
|
Местный
  
Группа: Участник
Сообщений: 408
Регистрация: 28-05-12
Пользователь №: 72 052

|
Цитата(Idle @ Nov 12 2012, 15:20)  Это не так, именно через прямое обращение к регистрам SoC в адресном пространстве и происходит взаимодействие с железом.
Они как правило есть, но не всегда на _все_ регистры.
Для написания драйвера _устройства_ подключённого через spi слейвом, обращаться напрямую к железу не надо - это делает драйвер spi контроллера (мастера). так вот этот драйвер мастера, насколько я могу понять, не может складывать данные в буфер произвольной длины, а только работает через read() или write(). Таким образом считать данные из ацп в пространстве пользователя нельзя, точнее можно, но данные будут не нерпрерывные, а спотреями, ввиду латентности операционки. Выход: написать драйвер "с нуля" на уровне ядра. как? пока сложно себе представляю... увидеть бы пример работы с SPI через DMA в драйвере. Цитата(xor.kruger @ Nov 12 2012, 15:54)  Сначала ознакомьтесь с принципами функционирования подсистемы SPI в ОС GNU/Linux. Инфа есть в каталоге Documentation/spi исходников ядра или например в книге Essential Linux Device Drivers. Также для примера можете подсмотреть как соведуют делать для семейства чипов AT91SAM9X link подсистема iio - мутная вещь. По моему намного проще обращаться к регистрам как в standalone приложении. Как раз для SAM9260 писал именно "напрямую" через SPI DMA, взяв пример кода из проекта плейера (тоже без ос). Получилось просто и быстро: standalone процедура превратилась в драйвер уровня ядра. Тем более, в книге Linux Device drivers написано что на уровне ядра к регистрам можно обращаться напрямую. IIO выдумали якобы для унифицирования, но мне показалось там слишком всё усложнено.Тем более из общения с разработчиками драйверов из AD я так и не смог выяснить зачем они написали софтовое тактирование АЦП из юзерспейс. Это же идиотизм: тактировать промышленный АЦП клоком с непредсказуемым джиттером. Отвлёкся от темы.
|
|
|
|
|
Nov 12 2012, 13:24
|
Местный
  
Группа: Участник
Сообщений: 351
Регистрация: 5-04-05
Пользователь №: 3 874

|
Цитата(Dubov @ Nov 12 2012, 16:46)  так вот этот драйвер мастера, насколько я могу понять, не может складывать данные в буфер произвольной длины, а только работает через read() или write() а как должно происходить чтение? вот есть, например, spi_w8r16 два байта читает - почему она не подходит?
Сообщение отредактировал Idle - Nov 12 2012, 13:25
|
|
|
|
|
Nov 12 2012, 13:39
|
Местный
  
Группа: Участник
Сообщений: 408
Регистрация: 28-05-12
Пользователь №: 72 052

|
Цитата(Idle @ Nov 12 2012, 17:24)  а как должно происходить чтение? вот есть, например, spi_w8r16 два байта читает - почему она не подходит? Вообще планировалось сделать так: завести на уровне ядра большущий буфер(около 1 МБ), а чтение происходит в самом драйвере, пусть по 2 байта, но складываться всё должно тоже в буфер на уровне ядра (в тот самый большой буфер). В приложении же отобразить буфер в юзерспейс и читать указатель, который возвращает драйвер. Иными словами: User mode SPI device driver support - не подходит. P.S. Возможно я чего-то не понимаю. Все реализации что я до этого видел предлагают править файл борды и активировать User mode SPI device driver support. Но это не подходит. Цитата(Idle @ Nov 12 2012, 17:24)  а как должно происходить чтение? вот есть, например, spi_w8r16 два байта читает - почему она не подходит? и это как я понял, не DMA чтение
|
|
|
|
|
Nov 12 2012, 14:04
|
Местный
  
Группа: Участник
Сообщений: 351
Регистрация: 5-04-05
Пользователь №: 3 874

|
Цитата(Dubov @ Nov 12 2012, 17:39)  Вообще планировалось сделать так: завести на уровне ядра большущий буфер(около 1 МБ), а чтение происходит в самом драйвере, пусть по 2 байта, но складываться всё должно тоже в буфер на уровне ядра (в тот самый большой буфер). тогда можно выделить в драйвере буфер, периодически дёргать (через таймер, например) чтение по spi, складывать полученные данные в буфер создать в драйвере chardev и отдавать буфер при чтении из созданного файла как такой вариант?
|
|
|
|
|
Nov 12 2012, 15:25
|
Местный
  
Группа: Участник
Сообщений: 351
Регистрация: 5-04-05
Пользователь №: 3 874

|
Цитата(Dubov @ Nov 12 2012, 18:56)  Насколько я понял мне все пытаются объяснить что линукс предоставляет независимость от платформы даже в таких задачах (чтиение зSPI по DMA в модуле ядра). нет, пишу как я бы это делал Цитата(Dubov @ Nov 12 2012, 18:56)  А мне нужно потоковое накопление в буфере и периодическая отдача в юзерспейс. ну вот и накапливайте в буфере периодически читая при помощи дравера мастера, а в чём разница при чтении из полностю своего кода и при использовании драйвера? updя понял - вы хотите зарядить dma на чтение по spi  тогда линуксовая подсистема spi тут не нужна совсем, смотрите на реализацию мастера для своего SoC и пишите что нужно работа с регистрами происходит так же как и на bare metal - они в памяти работа с dma - через линуксовый api, с ним мне работать не приходилось
Сообщение отредактировал Idle - Nov 12 2012, 15:26
|
|
|
|
|
Nov 12 2012, 19:17
|
Местный
  
Группа: Участник
Сообщений: 408
Регистрация: 28-05-12
Пользователь №: 72 052

|
Цитата(Idle @ Nov 12 2012, 19:25)  ну вот и накапливайте в буфере периодически читая при помощи дравера мастера, а в чём разница при чтении из полностю своего кода и при использовании Я думал всегда что в скорости. Если считывать из юзерспейс то можно пропустить данные. Частота дисркетизации АЦП 100kSps. В модуле же ядра, если считывать по DMA можно напихать большой буфер без пропусков и потом из юзерспеейс потихонечку грести. Как вариант, можно на ПЛИС сделать буфер, чтобы просто из юзерспейс забирать даные, но это за рамками топика. Вот и пытаюсь: 1) найти примеры для OMAP DMA SPI без ОС (standalone), чтобы оформить как модуль ядра. либо 2) какие-то средства линукса (api для DMA на уровне ядра) Цитата(Idle @ Nov 12 2012, 19:25)  работа с регистрами происходит так же как и на bare metal - они в памяти я пока даже *.h-файл описания регистров для OMAP не нашёл. Настолько всё запутано в исходниках. Эх, у Atmela в этом было много проще и нагляднее (AT91SAM9260.h - и всё)
Сообщение отредактировал Dubov - Nov 13 2012, 10:26
|
|
|
|
|
Nov 13 2012, 12:03
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(Dubov @ Nov 13 2012, 00:17)  Я думал всегда что в скорости. Если считывать из юзерспейс то можно пропустить данные. Частота дисркетизации АЦП 100kSps. В модуле же ядра, если считывать по DMA можно напихать большой буфер без пропусков и потом из юзерспеейс потихонечку грести. Вам Idle так и предлагает - создать большой ядерный буфер и пихать туда данные непрерывно без пропусков. А потом из юзерспейса через read() накопленные в ядерном буфере данные выгребать. Вы говорили, что Вам не нравится получать данные путем чтения файла устройства. Почему? Фактически, такое чтение - просто копирование данных из одного участка памяти в другой...
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Nov 13 2012, 12:08
|
Местный
  
Группа: Участник
Сообщений: 408
Регистрация: 28-05-12
Пользователь №: 72 052

|
Цитата(alx2 @ Nov 13 2012, 16:03)  Вам Idle так и предлагает - создать большой ядерный буфер и пихать туда данные непрерывно без пропусков. А потом из юзерспейса через read() накопленные в ядерном буфере данные выгребать. Вы говорили, что Вам не нравится получать данные путем чтения файла устройства. Почему? Фактически, такое чтение - просто копирование данных из одного участка памяти в другой... хорошо, чтение - это просто метод забрать данные. Мне нужен метод положить данные в буфер. Причём в большой буфер. пока нашёл вот что: spi-omap2-mcspi.c как настроить на приём по DMA ума не приложу(
Сообщение отредактировал Dubov - Nov 13 2012, 12:09
|
|
|
|
|
Nov 13 2012, 16:14
|
Местный
  
Группа: Участник
Сообщений: 351
Регистрация: 5-04-05
Пользователь №: 3 874

|
Цитата(alx2 @ Nov 13 2012, 16:03)  Вам Idle так и предлагает - создать большой ядерный буфер и пихать туда данные непрерывно без пропусков. А потом из юзерспейса через read() накопленные в ядерном буфере данные выгребать. Вы говорили, что Вам не нравится получать данные путем чтения файла устройства. Почему? Фактически, такое чтение - просто копирование данных из одного участка памяти в другой... ему надо опрашивать ацп со скоростью 100KS/s т.е. каждые 10 мкс программно через таймеры или delayed work это не получится т.к. слишком часто вопрос тут - как написать свой драйвер spi мастера для конкретного железа под эти нужды
|
|
|
|
|
Nov 13 2012, 17:59
|
Местный
  
Группа: Участник
Сообщений: 408
Регистрация: 28-05-12
Пользователь №: 72 052

|
Цитата(Idle @ Nov 13 2012, 20:14)  ему надо опрашивать ацп со скоростью 100KS/s т.е. каждые 10 мкс программно через таймеры или delayed work это не получится т.к. слишком часто вопрос тут - как написать свой драйвер spi мастера для конкретного железа под эти нужды Именно так. Например подобное делал для SAM9, взяв пример из проекта wav-плейера. Там по DMA с флешки по SPI считывание происходило. CODE //------------------------------------------------------------------------------ /// Use PDC for SPI data transfer. /// Return 0 if no error, otherwise return error status. /// \param pSdSpi Pointer to a SdSpi instance. /// \param pData Data pointer. /// \param size Data transfer byte count. //------------------------------------------------------------------------------ unsigned char SDSPI_PDC_read(SdSpi *pSdSpi, unsigned char *pData, unsigned int size) { AT91PS_SPI pSpiHw = pSdSpi->pSpiHw; unsigned int spiIer;
// Enable the SPI clock AT91C_BASE_PMC->PMC_PCER = (1 << pSdSpi->spiId);
// Disable transmitter and receiver pSpiHw->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
// Receive Pointer Register pSpiHw->SPI_RPR = (unsigned long)pData; // Receive Counter Register pSpiHw->SPI_RCR = size; // Transmit Pointer Register pSpiHw->SPI_TPR = (unsigned long)dummy_ff_block; // Transmit Counter Register pSpiHw->SPI_TCR = size;
// spiIer = AT91C_SPI_RXBUFF;
// Enable transmitter and receiver pSpiHw->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN; while(! (pSpiHw->AT91C_SPI_SR & AT91C_SPI_ENDRX)); pSpiHw->AT91C_SPI_PTCR = AT91C_PDC_RXTDIS; pSpiHw->AT91C_SPI_PTCR = AT91C_PDC_TXTDIS; // Interrupt enable shall be done after PDC TXTEN and RXTEN // pSpiHw->SPI_IER = spiIer;
return 0; } вобщем там свелось всё к умелому обращение с регистрами SPI_RPR, SPI_RCR, SPI_TPR, SPI_TCR. Для OMAP не думаю что сложнее, но, зараза, не могу понять... Другой вопрос: почему в Linux драйверах всё так сложно? никогда не увидишь имён регистров прямых, всё через структуры структур структур и т.д. ? безопасность? универсальность?
Сообщение отредактировал Dubov - Nov 13 2012, 18:01
|
|
|
|
|
Nov 13 2012, 20:00
|
Частый гость
 
Группа: Участник
Сообщений: 167
Регистрация: 15-08-07
Пользователь №: 29 803

|
Простейший способ "в лоб" - это char device, внутри которого 2 буфера, в один пишем, другой готов к чтению из приложения через read(). При заполнении одного буфера DMA перезапускается на другой буфер. Либо "дмашить" в кольцевой буфер. Как сделать лучше - см. спеки на железо. Есть нюансы  Во-первых, вам нужно перезапустить DMA за 10мкс (по прерыванию, например). Не факт, что вы успеете, т.к. если обращение к регистру занимает (к примеру) 1мкс, а вам нужно перезаписать 5шт - это уже 10мкс. Некоторые DMA умны настолько, что могут сами брать дескрипторы из памяти и закольцовываться по их списку. В этом случае перезапускать DMA нет необходимости. Если это не так и терять данные нельзя вообще - то вы близки к теоретическому пределу железа - опять же, см. спеки на железо. Во-вторых, при использовании своего char dev нужно убедиться, что никто через линуксовый SPI-фреймворк не обращается к SPI контроллеру (и через DMA фреймворк тоже). Что касается "сложности" драйверов в linux - это нормально  На самом деле там все довольно просто - почти все разбито на слои и фреймворки для облегчения портируемости и расширения. Фактически, там используется ООП подход, со всеми вытекающими. В итоге вход в это хозяйство усложняется (и кажется странным для людей работавших до этого с МК осями/bare metal), но иначе никак. Вообще, такой подход характерен для всех не-tiny мультиплатформенных ОС. P.S. Есть фреймворк comedi, все еще стандарт де-факто для data acquisition. Но 100К семплов/с - немалая величина, и с ней оверхед фреймворка может стать неприемлемым.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|