lilzz
Posts: 411
Joined: Sat Nov 30, 2013 5:27 pm

GPIO Code

Sun Dec 22, 2013 5:02 am

Code: Select all

// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
1)#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
2)#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
3)#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

4)#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
5)#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
I don't quite understand the above macro.
GPSET0 is at address 0x7E20 001C
GPCLR0 is at address 0x7E20 0028

why's 4 & 5 have them gpio+7, gpio+10 respectively.

Can some one explain 1, 2, 3 also to me?

User avatar
rpdom
Posts: 16104
Joined: Sun May 06, 2012 5:17 am
Location: Chelmsford, Essex, UK

Re: GPIO Code

Sun Dec 22, 2013 6:19 am

lilzz wrote:

Code: Select all

// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
1)#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
2)#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
3)#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

4)#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
5)#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
I don't quite understand the above macro.
GPSET0 is at address 0x7E20 001C
GPCLR0 is at address 0x7E20 0028

why's 4 & 5 have them gpio+7, gpio+10 respectively.

Can some one explain 1, 2, 3 also to me?
Firstly 4&5.
The gpio memory map starts at 0x7E20 0000.

The GPSET0 resgister is at ( gpio + 0x1C bytes ), which is 28 decimal bytes. C pointers are mapped to 4-byte words, so the index has to be divided by 4 to give the word number. 28/4 is 7, so GPSET0 is at 0x7E20 0000 + ( 7 * 4 ).

The same goes for GPCLR0, which is the 10th word, stored at gpio + (10 * 4).

I'll have a go at 1 next.

Code: Select all

#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
This is defining a macro that sets the mode of gpio number "g" to Input mode. It does this by clearing the relevant mode bits in words 0 to 5 of the gpio registers (the first 24 bytes). Input mode is function "0".
Each of these words hold the current mode for 10 of the 54 gpios, the first word has gpio 0 to gpio 9, the second has gpio 10 to gpio 19.

The mode uses 3 bits, so gpio 0 will be bits 0-2 of word 0, gpio 16 is bits 18-20 of word 1 etc.

So the "((g)/10)" in the code is getting the word number for the gpio "g".
Lets use gpio 16 as an example.
The "(((g)%10)*3))" is getting the low bit number for gpio "g" (16%10)*3 = 18.
The the constant "7" is shifted left by this number of bits (7<<), to get a value where all 3 bits are set. 0x001C 0000. Then it is inverted (~) to make a bitmask of bit that we don't want to clear. 0xFFE3 FFFF. Then that value is ANDed with the contents of the word and stored back in the same location.

That explains 1. It was a bit longer than I intended. From that you should be able to work out what 2 and 3 are doing. INP_GPIO should always be called before OUT_GPIO or SET_GPIO_ALT to clear the bits first, as OUT_GPIO is ORing the word with "1" shifted left the right number of bits, so the mode flags for that gpio will be 1, which is Write mode. The ALT macro sets the mode flag to the value "a".

lilzz
Posts: 411
Joined: Sat Nov 30, 2013 5:27 pm

Re: GPIO Code

Sun Dec 22, 2013 7:11 pm

rpdom wrote: #define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))

The "(((g)%10)*3))" is getting the low bit number for gpio "g" (16%10)*3 = 18.
The the constant "7" is shifted left by this number of bits (7<<), to get a value where all 3 bits are set. 0x001C 0000. Then it is inverted (~) to make a bitmask of bit that we don't want to clear. 0xFFE3 FFFF. Then that value is ANDed with the contents of the word and stored back in the same location.
hi, 000 is defining as the GPIO as input. How did you get 0x001C 0000?
for gpio 16, bit 18 to bit 20 should be zeroes right?

User avatar
rpdom
Posts: 16104
Joined: Sun May 06, 2012 5:17 am
Location: Chelmsford, Essex, UK

Re: GPIO Code

Sun Dec 22, 2013 7:55 pm

lilzz wrote:hi, 000 is defining as the GPIO as input. How did you get 0x001C 0000?
for gpio 16, bit 18 to bit 20 should be zeroes right?
Yes. But you must change/zero only those bits in GPFSEL1 (for gpio 16) and leave all the other contents as they were.

So 0x001C 0000 is just bits 18 to 20 set to ones, this is for a mask. That is then inverted (subtracted from 0xFFFF FFFF) to give 0xFFE3 FFFF. The contents of GPFSEL1 are then ANDed with that value which leaves everything as it was except bits 18 to 20 which will be zeroed.

Example:
Original contents of the word at GPFSEL1 (or gpio + 4) = 0x1234 5678 (just a made up example).
0x1234 5678 & 0xFFE3 FFFF = 0x1220 5678

In binary that would be (with bits 18 to 20 highlighted):
1111 1111 1111 1111 1111 1111 1111 1111 Minus (or XOR)
0000 0000 0001 1100 0000 0000 0000 0000
---------------------------------------------------
1111 1111 1110 0011 1111 1111 1111 1111

then

0001 0010 0011 0100 0101 0110 0111 1000 (the original contents) AND
1111 1111 1110 0011 1111 1111 1111 1111
---------------------------------------------------
0001 0010 0010 0000 0101 0110 0111 1000 (original contents with bits 18-20 set to 0)

Does that help?

If not, please ask and I'll try to help :)

lilzz
Posts: 411
Joined: Sat Nov 30, 2013 5:27 pm

Re: GPIO Code

Mon Dec 23, 2013 6:45 am

Ok, I see how it work now.
But I still have a question, for GPIO input it's 000 but for GPIO output it's 001
and it's using or operation |=.
2)#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))

or |=, or operation, how can it preserve the bit 18 to bit 21 to 001? it can changed to 111 depending on the original content.

User avatar
rpdom
Posts: 16104
Joined: Sun May 06, 2012 5:17 am
Location: Chelmsford, Essex, UK

Re: GPIO Code

Mon Dec 23, 2013 7:45 am

You are correct. It would only work to set the GPIO to output if those bits were already all zeroed.

This is why there is this comment in the code:

Code: Select all

// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
It is saying to always call the routine to set those bits to zero before using either of the two routines to set them to 001, or any other combination.

C is not my main language, but I think I would have tried to set up the macros so that the OUT and ALT ones included the INP one to automatically zero the bits.

Thank you for making me look a bit closer at this code and how it works. I hadn't bothered before, just realised it works and used it. In my ASM code I have written my own ways of handling this. :)

lilzz
Posts: 411
Joined: Sat Nov 30, 2013 5:27 pm

Re: GPIO Code

Tue Dec 24, 2013 5:06 am

rpdom your replies are very helpful, thank you.

mmi
Posts: 85
Joined: Sun Feb 24, 2013 3:53 am
Location: Bavaria-Germany

Re: GPIO Code

Sun Jan 19, 2014 12:43 am

Hello to all the GPIO direct programmers,

i'm happy with setting the GPIO outputs in C. I learnt it from Doms and Gerts example, many thanks !

What i'm missing is how i can read a value from a gpio switched to input ?

Code: Select all

INP_GPIO(gpionr);
What's the command in C to read the gpio state (high/low) after that ?

EDIT:
I took the C code from "joan" now which includes all necessary functions, thanks to joan!

Sorry for the inconvenience,
mmi

Return to “Advanced users”