LINUX.ORG.RU

Интерфейс /dev/mem забагован?

 , ,


0

1

В общем, стоит задача программно реализовать (в userspace) один аппаратный интерфейс через дерганье gpio-выводами. Вариант через sysfs даже не рассматривался - медленно до безобразия (взять хотя бы то, что у интерфейса есть параллельная двунаправленная шина, и придётся побитово загонять в неё данные и побитово же переключать направление). Напрашивается прямой доступ к регистрам контроллера через /dev/mem.

Уж сколько дней ломаю голову, ситуация следующая. Через sysfs все 11 нужных пинов работают (во всех режимах). И если предварительно через sysfs настроить пин на выход (испробовал на трёх), то и через /dev/mem получается им помигать/прочитать. А вот переключить направление пина (вход или выход) прямой записью в регистр не удаётся никак - значение записывается, но как будто не в регистр, а в какой-то кэш. И остаётся в этом кэше даже после переоткрытия memory mapping и даже при следующем запуске программки. Но стоит поменять направление порта через sysfs, как значение в этом регистре обновляется тем, что туда записалось через sysfs.

Думал, может, я чего-то не так делаю с этим отображением. Поставил из репозиториев утилиту devmem2. С ней всё то же самое. Далее предположил, что, быть может, направление пина не так просто переключается. Или подумал, вдруг направление порта хранится в поле структуры и не синхронизируется со значением регистра. Но нет, в структурах только указатели на функции, которые обращаются к этим регистрам через readl/writel.

А теперь самое главное. Решил пока вырубить полностью gpio controller через device tree на всём порту, с которым работаю. Пробую опять помигать через devmem2. Теперь получается и мигнуть, и попереключать направление… но только младшими 8-ю битами. В остальные 24 бита значения пишутся (и считываются), но нужного действия не оказывают. Пока такое подозрение, что запись uint32 в отображение инициирует побайтовое копирование, регистры же могут быть перезаписаны только целиком по 4 байта.

Кто что может посоветовать, кроме как свой модуль ядра писать? Куда копать, как быть?

P. S. Платформа freescale imx6dl, ядро 3.14.



Последнее исправление: SVG (всего исправлений: 1)

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

Если тебе религия не позволяет делать закрытый драйвер, сделай прослойку, которая будет делать claim на нужные gpio и принимать нечто из userspace и дёргать в нужном порядке gpio плюс слушать что там валится из шины.

Dark_SavanT ★★★★★
()
Ответ на: комментарий от Dark_SavanT

Так ведь я уже отключил драйвер (через device tree), ответственный за нужный мне порт, и регистры конкретно этого порта теперь никем не управляются (смотрю по /proc/iomem). И всё равно ничего не работает.

SVG
() автор топика
Ответ на: комментарий от SVG

Значит кумарь даташит ещё раз, ты что-то делаешь не так.

Dark_SavanT ★★★★★
()

bit-banging в юзерспейсе ИМХО очень плохая идея, пригодная разве что для микроскопических объемов данных на инерфейсе, некритичном к таймингам (т.к. юзерспейс процесс вполне может уйти поспать на несколько сот миллисекунд скажем, никого не предупредив - ну, там, своппинг случится, или еще какое-то сверхважное мероприятие у ядра).

NiTr0 ★★★★★
()

По поводу младших 8-и бит был неправ, как оказалось. И через devmem2 всё работает. И ещё прояснилось, что дело действительно в кэшировании. Записываемое в регистр направления порта (вход-выход) значение записывалось в некий кэш и вообще не попадало в регистр, даже после закрытия memory mapping и завершения процесса (WTF?). Зато если сразу после записи в этот регистр вызвать msync с параметром MS_ASYNC (пробовал ранее с параметром MS_SYNC - возвращало EINVAL), то всё работает. Как это понимать? Неоднократно встречались наставления, что в случае отображения в /dev/mem msync вообще не нужно вызывать. И почему кэшируется именно регистр направления порта, а стоящие впритык по соседним адресам регистры данных (их два по обе стороны, второй показывает фактическое значение сигнала на пинах) - никогда?

SVG
() автор топика
Ответ на: комментарий от SVG

Совершенно непонятные вещи происходят. Как оказалось, msync помогает далеко не всегда, закономерность мне так и не удалось выявить. Не давал покоя тот факт, что ручное манипулирование портами через утилиту devmem2 работало стабильно. Взял её исходники, поковырял, и оказалось, что совершенно по-разному себя ведёт обращение к типизированному (volatile uint32_t * ) и нетипизированному, но динамически кастуемому (volatile void * ) указателю. В первом случае ничего не работает (запись в регистр не происходит, но изменённое извне значение (допустим, путём вызова system("devmem2 <…>") ) читается), во втором - работает. WTF?

Причём полученные ключом -s ассемблерные листинги идентичны. Компилятор arm-linux-gnueabihf-gcc v4.9.3.

SVG
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.