rework #4
87
drivers/gpio.c
Normal file
87
drivers/gpio.c
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/** @file gpio.c
|
||||||
|
* Module handling General Purpose Input/Output (GPIO) pins
|
||||||
|
*
|
||||||
|
* The module provides functions to configure the gpio pins and read from/
|
||||||
|
* write to them
|
||||||
|
*/
|
||||||
|
|
||||||
|
//--includes--------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "gpio_regs.h"
|
||||||
|
|
||||||
|
#include "rcc.h"
|
||||||
|
|
||||||
|
|
||||||
|
//--local definitions-----------------------------------------------------------
|
||||||
|
|
||||||
|
static volatile struct GPIO* regs = (struct GPIO*)GPIO_BASE_ADDRESS;
|
||||||
|
|
||||||
|
|
||||||
|
//--local variables-------------------------------------------------------------
|
||||||
|
|
||||||
|
//--public functions------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the provided mask to generate its equivalent with 3 bits of padding
|
||||||
|
* between each initial bit. This new mask matches the registers layout and
|
||||||
|
* allow for direct application of the mode and config. Outputs are disabled
|
||||||
|
* prior to confiiguration to avoid any glitches. The relevant clocks are
|
||||||
|
* automatically enabled for the ports used
|
||||||
|
*/
|
||||||
|
void gpio_configure(enum GpioPort port, enum GpioPin pin_mask,
|
||||||
|
enum GpioMode mode, enum GpioConfig config)
|
||||||
|
{
|
||||||
|
//ensure gpio port is enabled
|
||||||
|
rcc_enable(RCC_AHB_NONE, RCC_APB1_NONE, RCC_APB2_IOPA << port);
|
||||||
|
|
||||||
|
//reset outputs before configuring anything
|
||||||
|
regs->PORTS[port].BRR.word |= pin_mask;
|
||||||
|
|
||||||
|
//clear config for selected port, then apply new config, 8 first pins
|
||||||
|
uint32_t mask = 0;
|
||||||
|
for (uint8_t i=0; i<8; ++i)
|
||||||
|
{
|
||||||
|
if (pin_mask & (0x1 << i))
|
||||||
|
{
|
||||||
|
mask |= 0x1 << (i * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
regs->PORTS[port].CRL.word &= ~(0xF * mask);
|
||||||
|
regs->PORTS[port].CRL.word |= (config << 2) | (mode << 0) * mask;
|
||||||
|
|
||||||
|
//clear config for selected port, then apply new config, 8 last pins
|
||||||
|
mask = 0;
|
||||||
|
pin_mask = pin_mask >> 8;
|
||||||
|
for (uint8_t i=0; i<8; ++i)
|
||||||
|
{
|
||||||
|
if (pin_mask & (0x1 << i))
|
||||||
|
{
|
||||||
|
mask |= 0x1 << (i * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
regs->PORTS[port].CRH.word &= ~(0xF * mask);
|
||||||
|
regs->PORTS[port].CRH.word |= (config << 2) | (mode << 0) * mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_reset(enum GpioPort port, enum GpioPin pin_mask)
|
||||||
|
{
|
||||||
|
gpio_configure(port, pin_mask, GPIO_MODE_INPUT, GPIO_CONFIG_IN_FLOATING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_write(enum GpioPort port, enum GpioPin pin_mask, bool value)
|
||||||
|
{
|
||||||
|
if (value) {
|
||||||
|
regs->PORTS[port].BSRR.word |= pin_mask;
|
||||||
|
} else {
|
||||||
|
regs->PORTS[port].BRR.word |= pin_mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gpio_read(enum GpioPort port, enum GpioPin pin_mask)
|
||||||
|
{
|
||||||
|
return (regs->PORTS[port].IDR.word & pin_mask) == pin_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//--local functions-------------------------------------------------------------
|
||||||
116
drivers/gpio.h
Normal file
116
drivers/gpio.h
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/** @file gpio.h
|
||||||
|
* Module handling General Purpose Input/Output (GPIO) pins
|
||||||
|
*
|
||||||
|
* The module provides functions to configure the gpio pins and read from/
|
||||||
|
* write to them
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GPIO_H_
|
||||||
|
#define _GPIO_H_
|
||||||
|
|
||||||
|
//--includes--------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "stdbool.h"
|
||||||
|
|
||||||
|
|
||||||
|
//--type definitions------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Available GPIO ports. Note that not all ports may be available for a
|
||||||
|
* particular chip
|
||||||
|
*/
|
||||||
|
enum GpioPort {
|
||||||
|
GPIO_PORT_A = 0,
|
||||||
|
GPIO_PORT_B,
|
||||||
|
GPIO_PORT_C,
|
||||||
|
GPIO_PORT_D,
|
||||||
|
GPIO_PORT_E,
|
||||||
|
GPIO_PORT_F,
|
||||||
|
GPIO_PORT_G,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Availables pin for a particular port. Note that all ports available may not
|
||||||
|
* have all the pins listed here and that some pins may be used by defaut (jtag,
|
||||||
|
* ...)
|
||||||
|
*/
|
||||||
|
enum GpioPin {
|
||||||
|
GPIO_PIN_0 = (0x1 << 0),
|
||||||
|
GPIO_PIN_1 = (0x1 << 1),
|
||||||
|
GPIO_PIN_2 = (0x1 << 2),
|
||||||
|
GPIO_PIN_3 = (0x1 << 3),
|
||||||
|
GPIO_PIN_4 = (0x1 << 4),
|
||||||
|
GPIO_PIN_5 = (0x1 << 5),
|
||||||
|
GPIO_PIN_6 = (0x1 << 6),
|
||||||
|
GPIO_PIN_7 = (0x1 << 7),
|
||||||
|
GPIO_PIN_8 = (0x1 << 8),
|
||||||
|
GPIO_PIN_9 = (0x1 << 9),
|
||||||
|
GPIO_PIN_10 = (0x1 << 10),
|
||||||
|
GPIO_PIN_11 = (0x1 << 11),
|
||||||
|
GPIO_PIN_12 = (0x1 << 12),
|
||||||
|
GPIO_PIN_13 = (0x1 << 13),
|
||||||
|
GPIO_PIN_14 = (0x1 << 14),
|
||||||
|
GPIO_PIN_15 = (0x1 << 15),
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Available modes for a pin. To have a pin in both modes simultaneously, see
|
||||||
|
* push-pull configuration in input mode
|
||||||
|
*/
|
||||||
|
enum GpioMode {
|
||||||
|
GPIO_MODE_INPUT = 0,
|
||||||
|
GPIO_MODE_OUTPUT, //10MHz max
|
||||||
|
GPIO_MODE_OUTPUT_SLOW, //2MHz max
|
||||||
|
GPIO_MODE_OUTPUT_FAST, //50MHz max
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Available configurations for a pin. Some configurations onlly apply in input
|
||||||
|
* mode (denoted "IN") while others only apply in output mode (denoted "OUT")
|
||||||
|
*/
|
||||||
|
enum GpioConfig {
|
||||||
|
GPIO_CONFIG_IN_ANALOG = 0,
|
||||||
|
GPIO_CONFIG_IN_FLOATING,
|
||||||
|
GPIO_CONFIG_IN_PUSH_PULL, //use gpio_write() to configure pull_up/down
|
||||||
|
GPIO_CONFIG_OUT_PUSH_PULL = 0,
|
||||||
|
GPIO_CONFIG_OUT_OPEN_DRAIN,
|
||||||
|
GPIO_CONFIG_OUT_ALT_PUSH_PULL,
|
||||||
|
GPIO_CONFIG_OUT_ALT_OPEN_DRAIN,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//--functions-------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures gpio pins on a single port. The GpioPin enum can be used as mask
|
||||||
|
* to configure multiple pins at the same time. Before configuring a pin, make
|
||||||
|
* sure it isn't used somewhere else (peripherals, jtag, ...). After
|
||||||
|
* configuration, the selected output pins are set to output 0V
|
||||||
|
*/
|
||||||
|
void gpio_configure(enum GpioPort port, enum GpioPin pin_mask,
|
||||||
|
enum GpioMode mode, enum GpioConfig config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets gpio pins on a single port. The GpioPin enum can be used as mask
|
||||||
|
* to reset multiple pins at the same time. This is a simple wrapper over
|
||||||
|
* gpio_configure(), setting the selected ports as floating input
|
||||||
|
*/
|
||||||
|
void gpio_reset(enum GpioPort port, enum GpioPin pin_mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a value to output gpios on a single port. The GpioPin enum can be used
|
||||||
|
* as mask to reset multiple pins at the same time. In push-pull input mode,
|
||||||
|
* configure the pull up/down. Has no effect otherwise
|
||||||
|
*/
|
||||||
|
void gpio_write(enum GpioPort port, enum GpioPin pin_mask, bool value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the value of gpios on a single port. The GpioPin enum can be used
|
||||||
|
* as mask to read multiple pins at the same time. For output pins, reads the
|
||||||
|
* pin state. Returns true if all selected ports are high
|
||||||
|
*/
|
||||||
|
bool gpio_read(enum GpioPort port, enum GpioPin pin_mask);
|
||||||
|
|
||||||
|
|
||||||
|
#endif //_RCC_H_
|
||||||
Loading…
Reference in New Issue
Block a user