GPIO registers and port manipulation

Post your cool example code here.
User avatar
iwalpola
Posts: 24
Joined: Tue Jun 21, 2016 1:08 pm
Location: Silchar, India
Contact:

GPIO registers and port manipulation

Postby iwalpola » Sun Jul 03, 2016 9:35 pm

Sources:
http://embedded-lab.com/blog/stm32-gpio-ports-insights/
http://hertaville.com/stm32f0-gpio-tutorial-part-1.html

The libmaple libraries, on which STM32duino is based, provides access to registers by the syntax:

Code: Select all

GPIOA->regs->REG


where REG can be one of the following:

CRH and CRL

CRH is used to set type/and or speed of pins 8-15 of the port
CRL is used to set type/and or speed of pins 0-7 of the port
Accessed as a 32 bit word, with 4 bits representing the state of each pin. Out of these 4 bits, the low 2 bits are MODE, and high 2 bits are CNF.
Image
The 4 bits for each pin can be set to:
0b0011 (binary) or 0x3 (HEX) - Corresponds to setting pin as output, same as pinMode()
0b1000 or 0x8 - Corresponds to setting pin as input, same as pinMode()

Say I want to set PORTA pins 0, 3 and 4 to OUTPUT and 1, 6, 7 to INPUT, and leave pins 2 and 5 in their original state. The code is:

Code: Select all

PORTA->regs->CRL = (PORTA->regs->CRL & 0x00F00F00) | 0x88000080 |0x00033003;
//0x00F00F00 is bitmask to retain value of pins 2 and 5 in original state
//0x88000080 is bitmask to set inputs
//0x00033003 is bitmask to set outputs


IDR - Input Data Register
Used to read input of entire 16 pins of port at once. Accessed as a 32 bit word whose lower 16 bits represent each pin.
The pins being read must be set to INPUT mode by using CRL/CRH or pinMode() before using this.

Say I want to read pins A2. The code is:

Code: Select all

bool result = GPIOA->regs->IDR & 0x0004; //returns true if A2 is HIGH
//0x0004 is 0b0000000000000100


ODR - Output Data Register
Used to write output to entire 16 pins of port at once. Accessed and written as a 32 bit word whose lower 16 bits represent each pin.
The pins being read must be set to OUTPUT mode by using CRL/CRH or pinMode() before using this.

Say I want to set pins A2, A12 and A13, and reset (clear) all other pins in the 16 pin bus. The code is:

Code: Select all

GPIOA->regs->ODR = 0b0011000000000100; //note,  binary


Now if I want to set and clear A2, A12 and A13 without altering other pins, the code is:

Code: Select all

//Set A2, A12, A13 (HIGH)
GPIOA->regs->ODR |= 0b0011000000000100;
//Clear A2, A12, A13 (LOW)
GPIOA->regs->ODR &= ~(0b0011000000000100);


but notice how, if we want to touch only some pins, we have to READ, MASK and WRITE. That's why there is BRR and BSRR

BRR - Bit Reset Register
32 bit word. Lower 16 bits have 1's where bits are to be set to "LOW". Upper 16 bits have 1's where bits are to be set "HIGH".
0's mean ignore

Now, to set and clear A2, A12, A13 while preserving the state of all other pins in the port, the code is:

Code: Select all

//Set A2, A12, A13 (HIGH)
GPIOA->regs->BRR = 0b0011000000000100 << 16; //move to upper 16 bits
//Clear A2, A12, A13 (LOW)
GPIOA->regs->BRR = 0b0011000000000100;


BSRR - Bit Set Reset Register

BSRR is like the complement of BRR. It's also a 32 bit word. Lower 16 bits have 1's where bits are to be set to "HIGH". Upper 16 bits have 1's where bits are to be set "LOW".
0's mean ignore

In this case, to set and clear A2, A12, A13 while preserving the state of all other pins in the port, the code is:

Code: Select all

//Set A2, A12, A13 (HIGH)
GPIOA->regs->BSRR = 0b0011000000000100;
//Clear A2, A12, A13 (LOW)
GPIOA->regs->BSRR = 0b0011000000000100 << 16; //move to upper 16 bits


Combination of BRR and BSRR

Since BRR and BSRR are opposite of each other, you can use both if you don't want to do the bit shift left operation .

In this case, to set and clear A2, A12, A13 while preserving the state of all other pins in the port, the code is:

Code: Select all

//Set A2, A12, A13 (HIGH)
GPIOA->regs->BSRR = 0b0011000000000100; //lower 16 bits
//Clear A2, A12, A13 (LOW)
GPIOA->regs->BRR = 0b0011000000000100; //lower 16 bits

User avatar
RogerClark
Posts: 5466
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: GPIO registers and port manipulation

Postby RogerClark » Sun Jul 03, 2016 10:42 pm

Did you see the post about individual bit access via different addresses.

( sorry I cant find the link to the thread at the moment as I am posting from my phone)

Ollie
Posts: 129
Joined: Thu Feb 25, 2016 7:27 pm

Re: GPIO registers and port manipulation

Postby Ollie » Sun Jul 03, 2016 11:01 pm

Here is the post for accessing
- individual bits of the peripheral registers
- bit fields in peripheral registers

viewtopic.php?f=3&t=1193&p=15081&hilit=bit+banding#p15081

In the first case the parameters are the register name and bit number. In the second case, the parameters are
- register name
- first bit number
- number of bits

Note: the bit number can go over 32 to make it easier to address bit fields that are stored in multiple 32 bit register words.

This method is the fastest way to access (read and write) peripheral register content. In addition, it is multi thread safe, when the mask based read-modify-write sequence is not.

Cheers, Ollie

User avatar
RogerClark
Posts: 5466
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: GPIO registers and port manipulation

Postby RogerClark » Sun Jul 03, 2016 11:25 pm

@ollie

Thanks.

I should get into the habit of trying to remember something unique in those sorts of posts, so I stand a better chance of finding them again.
In this case it would be "bit banding"

User avatar
iwalpola
Posts: 24
Joined: Tue Jun 21, 2016 1:08 pm
Location: Silchar, India
Contact:

Re: GPIO registers and port manipulation

Postby iwalpola » Sun Jul 03, 2016 11:49 pm

Sounds interesting, at this rate I won't get any sleep at all :D

smithy
Posts: 37
Joined: Sat Aug 13, 2016 7:02 pm
Location: Gießen, Germany

Re: GPIO registers and port manipulation

Postby smithy » Sun Sep 04, 2016 2:54 pm

Hmm maybe i misunderstood something but trying following did not give the results i expected:

Code: Select all

void setup() {
GPIOA->regs->CRL = (GPIOA->regs->CRL & 0x33333333) ; //set PA0-PA7 output
//Set A0-A7 (HIGH)
GPIOA->regs->ODR |= 0b0000000011111111;
}

Only PA1 is high, what is wrong ?? (using bluepill, C8 board)

Code: Select all

Serial.println(GPIOA->regs->CRL);
Serial.println(GPIOA->regs->ODR);

Results in
0
41215

The original values seem to be
0x44444444 for CLR (Input floating)
0xA000 for ODR

If i use GPIOA->regs->CRL = (GPIOA->regs->CRL | 0x33333333) ; it results to 0x77777777, still only PA1 is High
If i declare outputs like this

Code: Select all

uint8_t DPINS[] = {PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7};
  for (uint8_t i = 0; i <= sizeof(DPINS) - 1; i++)
    pinMode(DPINS[i], OUTPUT);

It is working, guess the problem is the CLR command.

Now that i can finally set GPIO´s with direct mapping i wanted to implement it in the u8g2lib in order to speed things up when using 8080 mode.
This is the original code

Code: Select all

   for( i = U8X8_MSG_GPIO_D0; i <= U8X8_MSG_GPIO_D7; i++ )
   {
     u8x8_gpio_call(u8x8, i, b&1);
     b >>= 1;
   }   

being replaced with

Code: Select all

   uint16_t bitmask;
   GPIOA->regs->ODR &= ~(0b0000000011111111); //reset dpins PA0-PA7
   bitmask = b;
   GPIOA->regs->ODR |= bitmask; //set nescessary dpins PA0-PA7 High

Now the compiler throws
C:\Users\Master\Documents\Arduino\libraries\U8g2\src\clib\u8x8_byte.c: In function 'u8x8_byte_8bit_8080mode':

C:\Users\Master\Documents\Arduino\libraries\U8g2\src\clib\u8x8_byte.c:212:2: error: 'GPIOA' undeclared (first use in this function)

GPIOA->regs->ODR &= ~(0b0000000011111111); //reset dpins PA0-PA7

^

C:\Users\Master\Documents\Arduino\libraries\U8g2\src\clib\u8x8_byte.c:212:2: note: each undeclared identifier is reported only once for each function it appears in

When searching for GPIOA with notepad++ in the Arduino_STM32-master\STM32F1 folder i get 236 hits in 27 files, i´m pretty unsure which header to include, can anyone help me a bit here ?
Arduino_STM32-master\STM32F1\system\libmaple\stm32f1\include\series\gpio.h seems to be wrong, throwing
C:\Users\Master\Documents\Arduino\libraries\U8g2\src\clib\u8x8_byte.c:213:7: error: dereferencing pointer to incomplete type

#include <wirish_types.h> throws
C:\Users\Master\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/wirish_types.h:66:1: error: unknown type name 'bool'

typedef bool boolean;


EDIT:Found the right file

Code: Select all

#include "C:\Users\Master\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\system\libmaple\include\libmaple\gpio.h"
now i´m measuring half the transmission time (from 30 down to 14 ms 128*64 display) which is quite nice :)


Return to “Code snipplets”

Who is online

Users browsing this forum: No registered users and 1 guest