Я кодирую что-то, используя прямой контроль над GPIO, для этого есть несколько хороших ресурсов, таких как http://elinux.org/RPi_Low-level_peripherals#GPIO_hardware_hacking ; процесс включает open ("/ dev / mem"), а затем операция mmap эффективно отображает нужный физический адрес в ваше виртуальное адресное пространство. Затем вы читаете раздел 6 этого http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf, чтобы узнать о том, как контролируется ввод-вывод.
Чтобы изменить функцию вывода (вход, выход или другие специальные функции), вы изменяете эти 3-битные поля в регистрах ввода-вывода GPFSELx (000 = вход, 001 = экземпляр выходного объекта). Эти операции модификации скомпилированы для операций с обычной загрузкой и сохранением (например, чтобы изменить GPIO0 на input: * (regptr) & = ~ 7; который компилируется в нечто вроде
ldr r2, [r3, #0] ; r = *ptr (load r2 from I/O register)
bic r2, r2, #7 ; r2 &= ~7
str r2, [r3, #0] ; *ptr = r2 (store r2 to I/O register)
Проблема заключается в следующем: если между загрузкой и сохранением происходит прерывание, и другой процесс или ISR изменяет тот же регистр ввода-вывода, операция сохранения (на основе устаревшего чтения в r2) будет возвращать эффекты этой другой операции. Таким образом, изменение этих регистров ввода / вывода действительно необходимо выполнить с помощью атомарной (заблокированной) операции чтения / изменения / записи. Примеры, которые я видел, не используют заблокированную операцию.
Поскольку эти регистры ввода-вывода обычно меняются только при настройке чего-либо, маловероятно, что возникнут проблемы, но «никогда» всегда лучше, чем «маловероятно». Кроме того, если у вас есть приложение, в котором вы обрабатываете биты для эмуляции вывода с открытым коллектором, то (насколько я могу судить) это включает в себя программирование выхода на 0, а затем переключение его между выходом (для низкого уровня) или входом ( для выключенного / высокого). Таким образом, в этом случае будут частые моды для этих регистров ввода / вывода, и небезопасные модификации будут с гораздо большей вероятностью вызывать проблемы.
Итак, возможно, для этого можно использовать ARM «сравнить и установить» или аналогичную операцию, может ли кто-нибудь указать мне на это, и как это сделать из кода C?
[Примечание: ничего особенного не требуется, если вы запрограммировали ввод / вывод как выход и просто изменили его с 0 на 1 или наоборот; поскольку существует регистр ввода / вывода, в который вы записываете, для установки выбранных битов на 1, а другой для сброса выбранных битов на 0. Для этой операции не требуется чтение / запись, поэтому нет опасности от прерываний].
/dev/mem
кажется, что ваш код - это код пользовательского пространства. Я не думаю, что в любой современной ОС нужно быть осторожным с прерываниями, меняющими значения регистров в коде пользовательского пространства. Я считаю, что это не будет проблемой даже в коде пространства ядра, поскольку Linux восстанавливает все регистры, когда обработчик прерываний завершает свою работу.