... | ... | @@ -3,6 +3,53 @@ A **GPIO** is a software-controllable peripheral used to configure the device IO |
|
|
GPIOs are grouped in ports and so each GPIO has an identifier.
|
|
|
The identifiers have the following format: `PXY`, where `X` is the GPIO port name and `Y` is the pin number.
|
|
|
|
|
|
## Introduction
|
|
|
GPIO ports registers are mapped to well defined memory addresses. This means that by accessing those addresses, we can access the GPIO registers.
|
|
|
Then, we can define a structure that represents the memory layout of the GPIO registers:
|
|
|
```cpp
|
|
|
typedef struct
|
|
|
{
|
|
|
volatile uint32_t MODER;
|
|
|
volatile uint32_t OTYPER;
|
|
|
volatile uint32_t OSPEEDR;
|
|
|
volatile uint32_t PUPDR;
|
|
|
volatile uint32_t IDR;
|
|
|
volatile uint32_t ODR;
|
|
|
volatile uint16_t BSRRL;
|
|
|
volatile uint16_t BSRRH;
|
|
|
volatile uint32_t LCKR;
|
|
|
volatile uint32_t AFR[2];
|
|
|
} GPIO_TypeDef;
|
|
|
```
|
|
|
Remmeber that strcut member's are allocated to consecutive addresses in memory.
|
|
|
|
|
|
In order to access a specific register (address) we need a pointer to the GPIO port.
|
|
|
Assuming we want to control the `GPIOA` port and that it can be found at `0x48000000`:
|
|
|
```cpp
|
|
|
#define GPIOA ((GPIO_TypeDef *) 0x48000000)
|
|
|
```
|
|
|
By simply changing the pointer address we can access different GPIO ports.
|
|
|
|
|
|
Via *bitwise operations* we can access the GPIO registers:
|
|
|
```cpp
|
|
|
// set 5th bit of ODR to 1
|
|
|
GPIOA->ODR |= (1 << 4);
|
|
|
|
|
|
// set 5th bit of ODR to 0
|
|
|
GPIOA->ODR &= ~(1 << 4);
|
|
|
|
|
|
// if 5th bit is set to 1
|
|
|
if (GPIOA->ODR & (1 << 4))
|
|
|
{
|
|
|
... // do stuff
|
|
|
}
|
|
|
```
|
|
|
So for example if we want to set a pin of the `GPIOA` port to the high state:
|
|
|
```cpp
|
|
|
GPIOA->ODR |= (1 << led_pin);
|
|
|
```
|
|
|
where `led_pin` is the pin number.
|
|
|
|
|
|
## Configuration
|
|
|
> :warning: **WARNING: Before using a GPIO it has to be correctly configured. A lot of times you can experience non-working code or drivers due to not initialized or configured GPIOs.**
|
|
|
|
... | ... | @@ -18,9 +65,11 @@ The available pin modes and speeds can be found in the |
|
|
|
|
|
If you want to know more about GPIOs, check out the [GPIO Tutorial - Miosix Wiki](https://miosix.org/wiki/index.php?title=GPIO_tutorial) page.
|
|
|
|
|
|
## Examples
|
|
|
## GPIO Drivers
|
|
|
|
|
|
Lukily for us, Miosix provides all the needed drivers for manipulate the GPIOs and enabling all their possible functionalities and configurations.
|
|
|
|
|
|
#### 1. Template API
|
|
|
##### 1. Template API
|
|
|
To use a pin in your board you can simply do:
|
|
|
```cpp
|
|
|
// define pin PA5 as somePin
|
... | ... | @@ -49,7 +98,7 @@ somePin::alternateFunction(5); // Specify the alternate function number |
|
|
```
|
|
|
The above method provides *optimal performance*.
|
|
|
|
|
|
#### 2. GpioPin Class
|
|
|
##### 2. GpioPin Class
|
|
|
As an alternative you can use the `GpioPin` class.
|
|
|
```cpp
|
|
|
GpioPin somePin(GPIOA_BASE, 5);
|
... | ... | |