GPIO in the kernel: an introduction
GPIO in the kernel: an introduction
Posted Jan 18, 2013 8:44 UTC (Fri) by russell (guest, #10458)Parent article: GPIO in the kernel: an introduction
1. GPIO can be both output and input at the same time. Yep you may want to read back the value of an output. MCUs I've used in the past offered this. After all output are really just stronger versions of the pull up/down :)
2. GPIO have pull up/down resistors.
3. And this is the BIG one. GPIO has state BEFORE the kernel boots. Bootstrap code can set the state of GPIO during the first few cycles of operation. This can eliminate the need for extra external hardware. However, the kernel blows this away and you have to wait for userspace to boot before you get control!!!! This behaviour on for example RPi required extra hardware to be added to the circuit to prevent this kind of transient boot behaviour from glitching relays.
Posted Jan 18, 2013 11:50 UTC (Fri)
by etienne (guest, #25256)
[Link] (2 responses)
Reading back output GPIO is described in Documentation/gpio.txt
Posted Jan 19, 2013 0:33 UTC (Sat)
by jimparis (guest, #38647)
[Link] (1 responses)
The volatile should ensure that both writes occur in that case.
I agree, and I do the same in embedded development, but it's not perfect. The three biggest problems:
Posted Jan 21, 2013 11:36 UTC (Mon)
by etienne (guest, #25256)
[Link]
Last time I tried few days ago it did not work, you have to do:
> You lose control over the access size
Yes, I would also like to have bitfields accessed like they are declared, i.e. "char abit : 2;" accessed as a byte and "unsigned abit :2;" accessed as a 32 bits, because it is usual to have devices which cannot do short word access (lots of system on chip).
> [... using "(struct my_IO_s) {}" extension ...]
My system is more complex than Arduino, I have arrays of structures containing other arrays in these I/O areas, and all those #define blessed by software-quality people drive me mad.
Posted Jan 18, 2013 14:42 UTC (Fri)
by dougg (guest, #1894)
[Link]
Things are moving so fast in the device tree/pinctrl area that it might be worth LWN writing another article on the subject.
Posted Jan 28, 2013 21:27 UTC (Mon)
by BenHutchings (subscriber, #37955)
[Link]
Indeed this is an absolute requirement for a GPIO used as an I2C SCL line.
GPIO in the kernel: an introduction
My main problem is that people (even software manager responsible of software "quality") do think it is clean to use the C preprocessor, either in C or C++.
That leads to massive amount of #define, to define the address, the value when active, the value when inactive, the shift position for each GPIO and the mask for that GPIO (you never know if the mask is shifted or not).
Then you have a set of GPIO to represent a 3 bit value, and the preprocessor will never tell you that you are trying to write 0x15 in this 3 bit value.
Also those quality specialists tell you to use the macro:
#define IOWRITE32BYTE(addr, val) *((volatile unsigned *)(addr)) = (val)
(Hint: try to write the same addr twice with a newer compiler).
Anyway on newer architecture, those are memory mapped and IHMO it is a lot cleaner to use C to declare them:
volatile struct my_IO_s {
#ifdef BIG_ENDIAN
enum { healthy, fail } power_state : 1;
unsigned power_active : 1;
#else
unsigned power_active : 1;
enum { healthy, fail } power_state : 1;
#endif
} * const my_IO = (volatile struct my_IO_s *)0xDC002000;
Instead of pages and pages of #define.
GPIO in the kernel: an introduction
Also those quality specialists tell you to use the macro:
#define IOWRITE32BYTE(addr, val) *((volatile unsigned *)(addr)) = (val)
(Hint: try to write the same addr twice with a newer compiler).
Anyway on newer architecture, those are memory mapped and IHMO it is a lot cleaner to use C to declare them:
volatile struct my_IO_s {
enum { healthy, fail } power_state : 1;
unsigned power_active : 1;
} * const my_IO = (volatile struct my_IO_s *)0xDC002000;
Instead of pages and pages of #define.
Really it's one of the more annoying parts of C when doing embedded development on a constrained system, as it's hard to avoid without adding some layer of performance-killing indirection (like Arduino does).
read 0: interrupt has not occurred
read 1: interrupt has occurred
write 0: no action
write 1: clear interrupt flag
To clear a flag, you can't just do:
my_IO->timer_interrupt = 1;
because this can become
tmp = *my_IO_addr | (1 << TIMER_INTERRUPT_SHIFT);
*my_IO_addr = tmp;
Instead, you'd need to use something like:
*my_IO = (struct my_IO_s) {
.timer_interrupt = 1
};
which is not much better than the equivalent:
*my_IO_addr = (1 << TIMER_INTERRUPT_SHIFT);
*my_IO_addr |= (1 << PIN0_SHIFT) | (1 << PIN1_SHIFT);
without something like:
struct my_IO_s tmp = *my_IO;
tmp.pin0 = 1;
tmp.pin1 = 1;
*my_IO = tmp;
GPIO in the kernel: an introduction
> The volatile should ensure that both writes occur in that case.
#define IOWRITE32BITS(addr, val) do { \
volatile unsigned *ptr = (volatile unsigned *)(addr); \
*ptr = (val); \
} while (0)
#define FPGA1_FILTER_2_PARAMETER_4_ACTIVE 1
How to do a loop for each filters?
In short, in C or C++, unlike BASIC, the linker is made to manage addresses, the compiler manages offsets into these addresses; the C pre-processor has nothing to do there.
IHMO even GPIO in the kernel shall be identified with an address, not a #define.
GPIO in the kernel: an introduction
GPIO in the kernel: an introduction
1. GPIO can be both output and input at the same time. Yep you may want to read back the value of an output.