blob: 25e5e4b02698814860b7ab250ca9a1588b966fb5 [file] [log] [blame]
#pragma once
#include <cdefs.h>
#include <stdint.h>
/**
* The Arty A7 configuration has two LEDs (LD5 and LD6), four buttons, and four
* switches, exposed over GPIO.
*
* This provides a simple driver for them.
*/
struct GPIO
{
/**
* Input register. This is unused for the LEDs.
*/
uint32_t read;
/**
* The output register. This is a bitmap of GPIO lines to set.
*/
uint32_t write;
/**
* Write enable. This sets the pins that should be controlled by `write`.
*/
uint32_t writeEnable;
/**
* The index of the first GPIO pin connected to a LED.
*/
static constexpr uint32_t FirstLED = 14;
/**
* The index of the last GPIO pin connected to a LED.
*/
static constexpr uint32_t LastLED = 15;
/**
* The number of GPIO pins used for LEDs.
*/
static constexpr uint32_t LEDCount = LastLED - FirstLED + 1;
/**
* Helper that defines a set of bits in a GPIO input word used for a
* specific purpose.
*/
struct InputBits
{
/**
* The number of bits.
*/
const uint32_t Count;
/**
* The offset of the lowest bit in the GPIO input word.
*/
const uint32_t Shift;
/**
* The mask used to extract the bits.
*/
[[nodiscard]] constexpr uint32_t mask() const
{
return (1 << Count) - 1;
}
/**
* Extract the bits for this range.
*/
[[nodiscard]] __always_inline uint32_t extract(uint32_t value) const
{
return (value >> Shift) & mask();
}
};
/**
* The buttons zero to three are in the low four bits.
*/
static constexpr InputBits Buttons = {4, 4};
/**
* Switches zero to three are in the next four bits.
*/
static constexpr InputBits Switches = {4, 0};
/**
* Helper to read all of the bits defined by an `InputBits` instance.
*/
template<InputBits Bits>
__always_inline uint32_t bits() volatile
{
return Bits.extract(read);
}
/**
* Helper to read a single bit defined by an `InputBits` instance.
*/
template<InputBits Bits>
__always_inline uint32_t bit(uint32_t index) volatile
{
return (Bits.extract(read) >> index) & 1;
}
/**
* Read the value of all of the buttons.
*/
uint32_t buttons() volatile
{
return bits<Buttons>();
}
/**
* Read the value of all of the switches.
*/
uint32_t switches() volatile
{
return bits<Switches>();
}
/**
* Read the value of one of the buttons, indicated by index.
*/
uint32_t button(uint32_t index) volatile
{
return bit<Buttons>(index);
}
/**
* Read the value of one of the switches, indicated by index.
*
* This should be called `switch`, but that's a keyword in C/C++.
*/
uint32_t switch_value(uint32_t index) volatile
{
return bit<Switches>(index);
}
/**
* Helper that maps from an LED index to a bit to set / clear to control
* that LED. Returns 0 for out-of-bounds LED values and so can be safely
* masked.
*/
constexpr static uint32_t led_bit(uint32_t index)
{
if (index >= LEDCount)
{
return 0;
}
return 1 << (index + FirstLED);
}
/**
* Enable all of the LED GPIO pins.
*
* This must be called before `led_on` or `led_off`.
*/
void enable_all() volatile
{
uint32_t bitmap = 0;
for (uint32_t i = 0; i < LEDCount; i++)
{
bitmap |= led_bit(i);
}
writeEnable = bitmap;
}
/**
* Turn on the LED specified by `index`.
*/
void led_on(uint32_t index) volatile
{
write = write | led_bit(index);
}
/**
* Turn off the LED specified by `index`.
*/
void led_off(uint32_t index) volatile
{
write = write & ~led_bit(index);
}
};