Configure GPIO (Hifive1 Rev B)

Hi Folks,

I’ve read through the GPIO chapter in the FE310-G002 manual multiple times, but I’m still a little confused.

The base address for the GPIO controller is 0x10012000, the memory map for all of the GPIO control registers is 64 bytes (32 bits per register)…

Does that mean each GPIO pin has 64 bytes of control registers? So…the base address for the next GPIO pin would be (0x10012000 + 0x40), then the next pin would be (0x10012000 + (0x40 * 0x02))?

Is that the correct understanding?

My next question is regarding the Freedom Metal function, metal_gpio_enable_pinmux. Can that function be used to modify any of the GPIO control registers? Or just enable the IOF feature (SPI, PWM, etc) of the pin?

Thanks!

If anyone else is unsure about this, the metal_gpio_enable_pinmux function can be used to modify GPIO control registers. I first thought the metal_gpio_*_pinmux functions were for disabling and selecting the IOF (SPI, PWM, etc) for the pin.

I verified this by using the function to enable the internal pull up resister for a GPIO, (e.g. metal_gpio_enable_pinmux(btn, 1, METAL_SIFIVE_GPIO0_PUE)). You can find constants for the GPIO control registers inside of <metal/machine/platform.h>.

I personally think the documentation for Freedom Metal a bit lacking, things like this are not very clear, maybe it’s my lack of experience with embedded development to blame. Either way, digging through the Freedom Metal source tends to be more helpful.

Hi! Yes, it is a little confusing at first, I agree.

There are 17 words of control registers, each word being 32 bits (unsigned int, or uint32_t). Each bit corresponds to a GPIO pin, so there are 17 control registers for each pin.

When changing one of the bits of a control register it is important not to change any of the other bits that you don’t want to change. Hence, a read-modify-write paradigm such as *input_en |= (0x1UL << pin) would set the pinth bit of GPIO_INPUT_EN, where input_en = (uint32_t *) (0x10012000 + 0x04). There are some nice assembly instructions for doing this atomically. See amoand, amoor; and the conjugate pair of instructions lr and sc.

Here is a sketch below to see a graphical representation of the I/O pins:

Although some of the GPIO pins are not physically accessible, they all can be written to and read from. Thus, for example, one could use these hidden “pins” as single-bit memory locations.

The metal_gpio_enable_pinmux() basically does two things: first, it either sets or clears the appropriate bit of GPIO_IOF_SEL depending on pinmux()'s third argument; second, it sets the appropriate bit of GPIO_IOF_EN. In other words, either
GPIO_IOF_SEL &= ~(1 << pin)
or
GPIO_IOF_SEL |= (1 << pin)
and then followed by
GPIO_IOF_EN |= (1 << pin)

The metal_gpio_disable_pinmux() clears the appropriate bit of GPIO_IOF_EN, as in
GPIO_IOF_EN &= ~(1 << pin)

These functions act through enable_io() and disable_io(), their source can be found at the path freedom-e-sdk/freedom-metal/src/drivers/sifive_gpio0.c

For each of the other metal_gpio_… functions in <metal/gpio.h>,
enable_input() and disable_input() effect changes on GPIO_INPUT_EN.
enable_output() and disable_output() control GPIO_OUTPUT_EN.
get_input_pin() reads from GPIO_INPUT_VAL, while
get_output_pin() reads from GPIO_OUTPUT_VAL.
set_pin() and clear_pin() effect changes on GPIO_OUTPUT_VAL.
toggle_pin() writes to GPIO_OUTPUT_VAL.
get_interrupt_id() reads from the GPIO_…IP status register,
config_interrupt() sets the GPIO
IE control register, and
clear_interrupt() writes to the GPIO
…_IP status register.

It seems that there are no gpio_metal_… functions to access or control the registers GPIO_PUE, GPIO_DS, and GPIO_OUT_XOR.

When perusing the sources, it is helpful to note that the “common” header files are under freedom-e-sdk/freedom-metal/metal, whereas the actual source files are under freedom-e-sdk/freedom-metal/src. The “specific” header files are under, for example, freedom-e-sdk/bsp/sifive-hifive1-revb, with a “metal-” prefix on their filenames, which get built up by the makefiles during the installation process.