-
detect_GPIO_BASE.sh is broken again...
01/07/2021 at 02:38 • 0 commentsOn a Pi 3 with the 2016 script, the failure is even more burning
Why can't the RPi guys keep a consistent system or at least preserve backwards compatibility ?
A new script is required, considering the list I recently found:
#define PI_01_REG_BASE 0x20000000 // Pi Zero or 1 #define PI_23_REG_BASE 0x3F000000 // Pi 2 or 3 #define PI_4_REG_BASE 0xFE000000 // Pi 4
And don't forget that this is the base of the peripherals block, not the start address of the GPIO block. In these cases, it's:
#define PI_01_REG_BASE 0x20200000 // Pi Zero or 1 #define PI_23_REG_BASE 0x3F200000 // Pi 2 or 3 #define PI_4_REG_BASE 0xFE200000 // Pi 4
thus:
$ grep gpio /proc/iomem | grep -i -E '20200000|3F200000|FE200000' 00000000-00000000 : 3f200000.gpio gpio@7e200000
It's getting tiring to have to rewrite stuff all the time...
The latest script is :#!/bin/bash # version 20210107 export GPIO_BASE="" GPIO_LINE=$(grep gpio /proc/iomem) && { echo "$GPIO_LINE" | grep -i 20200000 && export GPIO_BASE=0x20200000 # Pi Z or 1 echo "$GPIO_LINE" | grep -i 3F200000 && export GPIO_BASE=0x3F200000 # Pi 2, 3 echo "$GPIO_LINE" | grep -i FE200000 && export GPIO_BASE=0xFE200000 # Pi4 } echo GPIO_BASE=$GPIO_BASE
Now how long is it going to work ?
-
Damned RPi3 !
02/16/2017 at 17:34 • 0 commentsTrying to turn a LED on with the lib on a RPi3 using the slim 2017-01-11-raspbian-jessie-lite.zip image.
GPIO_on.sh and GPIO_off.sh work but not the C code.
The culprit is found easily because detect_GPIO_BASE.sh doesn't return anything (despite being on RPi3).
pi@raspberrypi:~/ $ cat /proc/iomem 00000000-3affffff : System RAM 00008000-007ea673 : Kernel code 00862000-009901eb : Kernel data 3f007000-3f007eff : /soc/dma@7e007000 3f200000-3f2000b3 : /soc/gpio@7e200000 3f201000-3f201fff : /soc/uart@7e201000 3f201000-3f201fff : /soc/uart@7e201000 3f300000-3f3000ff : /soc/mmc@7e300000 ...
The expected keyword is not found ! Instead of bcm2708_gpio, I get /soc/gpio
Another thing is that I forgot to enable the device tree... But a keyword can be added:
grep -E '/soc/gpio|bcm2708_gpio' /proc/iomem
Result:
pi@raspberrypi:~/projets/files $ . detect_GPIO_BASE.sh 3f200000-3f2000b3 : /soc/gpio@7e200000 GPIO_BASE=-DGPIO_BASE=(0x3f200000) pi@raspberrypi:~/projets/files $ echo $GPIO_BASE -DGPIO_BASE=(0x3f200000)
Seems legit... But I still have to test with the device tree.
20180118 : don't forget to run the detection script as ROOT !pi@raspberrypi$ sudo detect_GPIO_BASE.sh
Raspbian now returns invalid values when run as user:
$ cat /proc/iomem 00000000-00000000 : System RAM 00000000-00000000 : Kernel code 00000000-00000000 : Kernel data 00000000-00000000 : dwc_otg ....
(I should update my files......)
-
How to support the Raspberry Pi 2
11/01/2016 at 17:39 • 2 commentsThe RPi2 swapped the venerable BCM2835 for a BCM2836. The Peripheral block is pretty much the same (or so we hope !) but the BCM2835 changed its base address. So that's the only thing that seems to matter for now.
http://elinux.org/RPi_GPIO_Code_Samples#Direct_register_access:
Note: For Raspberry Pi 2, change BCM2708_PERI_BASE to 0x3F000000 for the code to work.
My current approach is to provide the base pointer as a compile-time parameter because I write mostly "bare-metal" code for a specific board, which is then embedded somewhere for an indefinite while. I don't do "portable binary code" that gets distributed and executed here and there on all kinds of boards.
Actually, "simple is best" because the situation is pretty complicated with the current software environment. A pile of legacy code is accumulating... Some distribution provide features that allow detection of the board type and revisions, some other don't. And this depends on the kernel compile flags, as well as the distribution's bells and whistles.
Another argument in favor of a compile-time parameter is: the pointer is constant and can be optimised, which saves a bit of time and space. Nothing really important but in some cases it can do a little welcome difference.
More food for thoughts:
The following is a shameful copy-paste from http://www.airspayce.com/mikem/bcm2835/
- Physical Addresses
The functions bcm2835_peri_read(), bcm2835_peri_write() and bcm2835_peri_set_bits() are low level peripheral register access functions. They are designed to use physical addresses as described in section 1.2.3 ARM physical addresses of the BCM2835 ARM Peripherals manual. Physical addresses range from 0x20000000 to 0x20FFFFFF for peripherals. The bus addresses for peripherals are set up to map onto the peripheral bus address range starting at 0x7E000000. Thus a peripheral advertised in the manual at bus address 0x7Ennnnnn is available at physical address 0x20nnnnnn.
On RPI 2, the peripheral addresses are different and the bcm2835 library gets them from reading /proc/device-tree/soc/ranges. This is only availble with recent versions of the kernel on RPI 2.
(...)
- Raspberry Pi 2 (RPI2)
For this library to work correctly on RPI2, you MUST have the device tree support enabled in the kernel. You should also ensure you are using the latest version of Linux. The library has been tested on RPI2 with 2015-02-16-raspbian-wheezy and ArchLinuxARM-rpi-2 as of 2015-03-29.
When device tree suport is enabled, the file /proc/device-tree/soc/ranges will appear in the file system, and the bcm2835 module relies on its presence to correctly run on RPI2 (it is optional for RPI1). Without device tree support enabled and the presence of this file, it will not work on RPI2.
To enable device tree support:
sudo raspi-config under Advanced Options - enable Device Tree Reboot.
Since I don't distribute binaries, I don't care about supporting all the HW&SW combinations under the sun. I can relegate the detection to a bash script :-)
Oh and in an older Raspbian running on a B+, I get the necessary info from a different /proc/ file:
pi@pi ~/GPIO $ cat /proc/iomem 00000000-17ffffff : System RAM 00008000-005bca23 : Kernel code ... 20007000-20007fff : bcm2708_dma.0 20007000-20007fff : bcm2708_dma 20100000-201000ff : bcm2708_powerman.0 20101098-2010109a : bcm2708-i2s.0 20101098-2010109a : bcm2708-i2s.0 20200000-20200fff : bcm2708_gpio 20201000-20201fff : dev:f1 20201000-20201fff : uart-pl011 ....
The base address is obtained with the following command:
$ echo "(0x"$(grep bcm2708_gpio /proc/iomem|sed -s 's/-.*//')")" (0x20200000)
Turning this into a compile-time define is straight-forward:$ GPIO_BASE="-DGPIO_BASE=(0x"$(grep bcm2708_gpio /proc/iomem|sed -s 's/-.*//')")" $ echo $GPIO_BASE -DGPIO_BASE=(0x20200000) $ gcc $GPIO_BASE -Wall -o test_in_out test_in_out.c && sudo chown root test_in_out && sudo chmod +s test_in_out
Then all I have to do is check if the base address has already been provided:// PI_GPIO.c line 26: #ifndef GPIO_BASE #define GPIO_BASE (0x20200000) #endif
(it was only #defined before)The detection script can be run once during a session (instead of detecting each time the program starts.
If $GPIO_BASE does not exist, nothing happens and the code falls back to BCM2835. My "legacy" code works as usual and can be ported to a different version. Now it's just a matter of being sure that the script gets it right every time, but at least it's easy to control now. Look at the code of detect_GPIO_BASE.sh