Testing the GPIO API

As seen in the previous post, the current GPIO API can perform digital I/O on the Raspberry Pi and can setup a JTAG interface. To see these features in action, two test cases were made available: LIBGPIO_TEST and LIBGPIO_JTAG.

LIBGPIO_TEST

This test can be found at

https://github.com/asuol/rtems/blob/GPIO_API/testsuites/samples/LIBGPIO_TEST/init.c

and assumes the following configuration of the Raspberry Pi GPIO pin header:

Digital I/O test circuit.

The test case initializes the GPIO API, and sets GPIO 2 pin as a digital input (using the internal pull up resistor) and GPIO 3 pin as a digital output. The GPIO 3 pin is sent a logical 0 (so the LED starts turned off), and then the Raspberry Pi polls forever the GPIO 2 pin for a button press. Because the internal pull up resistor is enabled, when the button in not being pressed the GPIO 2 pin value, or level, is 1, and when the button is pressed the pin level is 0. The test case reads the GPIO 2 pin level, and when the level is 0 it sets GPIO 3 pin, so the LED lits up, otherwhise GPIO 3 pin is cleared (and the LED is off).

LIBGPIO_JTAG

This test can be found at

https://github.com/asuol/rtems/blob/GPIO_API/testsuites/samples/LIBGPIO_JTAG/init.c

and it just setups the Raspberry PI GPIO header for JTAG.

The Raspberry Pi GPIO header wiring setup and host computer setup to use the JTAG interface have been described by Alan Cudmore at https://github.com/alanc98/rpi-minimod.

 

 

The current GPIO API

Currently the GPIO API implementation is Raspberry Pi specific, as delivering a generic GPIO API that can be used across the hardware RTEMS supports demands more community input and care. The API design is based on the cpukit/libi2c API, which is the RTEMS API for the I2C and SPI communication buses, while trying to keep multiio in mind. Right now it is just an header file that defines the data structures and function prototypes, leaving the implementation to the Raspberry Pi BSP. This header must then by included in an application, which then calls the needed directives to operate the GPIO hardware.
The first directive to call is the rtems_gpio_initialize, which receives the total amount of GPIO pins on the target hardware. This function sets a flag indicating that the API has been initialized so further calls can silently exit the function. It then proceds to allocate memory to an array of structs (rtems_gpio_pin) which will contain info for every pin, and sets each of them as not being used. The access to a pin is done through the array index. For instance, to get info on the first pin on the board (pin 1), the corresponding array index will be 0. This numbering conversion is done on the directives and not the application, so the application uses the board pin number.

At this point the application must setup the GPIO pins it wants to use. This requires a pin number to identify the pin and a pin type or function, such as:

  • digital output;
  • digital input;
  • one of 6 alternative functions, which are hardware specific and managed by the BSP implementation of the API. The API only provides these generic types that can be used by a BSP to use some specific non-standard function to a GPIO pin, such as configuring a GPIO pin to behave as a general purpose clock, or as a receiver for an UART interface;
  • not used.

To select a pin to be used two directives can be called:

rtems_gpio_select_pin -> receives a pin number (its number on the board hardware) and the pin function. The function takes this information to get the pin select memory address and proceds to select the specified function to that pin on the hardware, while updating the GPIO pin array with the information that the said pin is no longer available to selection because it is now in use.

rtems_gpio_setup_input_mode -> this function receives an array of structures (rtems_gpio_configuration) that define a number of pins and their corresponding function, and calls rtems_gpio_select_pin for each of them. This allows a BSP to define specific GPIO configurations that are useful to that target than can then be easily used by an application.

The Raspberry Pi BSP defines a structure on include/gpio.h to setup a JTAG interface using GPIO pins (https://github.com/asuol/rtems/blob/GPIO_API/c/src/lib/libbsp/arm/raspberrypi/include/gpio.h).

The API also allows a pin to be disabled, using:

rtems_gpio_disable_pin -> This directive marks a pin as not used, so it can be selected to another function.

The API only provides directives to operate digital I/O pins.

Digital Output:

rtems_gpio_set -> Writes a logical 1 to an output pin

rtems_gpio_clear -> Writes a logical 0 to an output pin

The API further provides the following functions, which may not apply to the Raspberry Pi:

rtems_gpio_set_mb and rtems_gpio_clear_mb -> Sets and clears multiple output pins in a GPIO port. A GPIO port is a group of pins that can be operated as one entity, so this function allows to operate a GPIO port as such. While this is useful for targets that organize their GPIO pins in groups, the Raspberry Pi does not, so it was not implemented.

rtems_gpio_output_mode -> Defines the output pin operating mode. This can range from:

  • push-pull – Defines that the pin can both source and sink current;
  • open drain – Defines that the pin can only sink current;
  • neutral – No drive mode defined.

Because the Raspberry Pi documentation [1] does not refer any of these modes, this function was not implemented for the Raspberry Pi, but can be useful to other targets.

Digital Input:

rtems_gpio_get_val -> Reads an input pin logic value, or level.

rtems_gpio_input_mode -> Sets an input drive mode, which means to operate the internal pull resistor.

A pull resistor “pulls” the pin voltage either up (to 3.3v) to create a logical 1, or down (to 0v) to create a logical 0. If a pull resistor is not used the pin voltage can float, due to a number of random factors [2], which would cause unexpected behaviour, as logical ones and zeros could be randomly generated.

The input drive modes available on the API are:

  • Pull up – Enables the internal pull up resistor;
  • Pull down – Enables the internal pull down resistor;
  • No pull resistor – Disables the internal pull resistors. This can be the case where an external one is used.

rtems_gpio_setup_input_mode -> This function allows to set the drive mode of a number of GPIO input pins.

References:

[1] – http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf

[2] – http://raspi.tv/2013/rpi-gpio-basics-6-using-inputs-and-outputs-together-with-rpi-gpio-pull-ups-and-pull-downs

 

The implementation of the above can be found on:

The GPIO API  ->https://github.com/asuol/rtems/blob/GPIO_API/cpukit/libgpio/libgpio.h

The Raspberry Pi implementation of the API -> https://github.com/asuol/rtems/blob/GPIO_API/c/src/lib/libbsp/arm/raspberrypi/gpio/libgpio.c

RTEMS GPIO API design (start)

This blog post will explain the logic behind the code currently at the GPIO_API github branch, and what the next steps may be.

Currently the code only focus on the discrete I/O part, but ADC and DAC pin types can be merged from multiio. The next image is a simple diagram of the data structures that hold each pin type information.

GPIO API data structs

Where:

  • DIN – Discrete/digital input
  • DOUT – Discrete/gigital output
  • ADC – Analog to digital converter
  • DAC – Digital to analog converter
  • GPIO – General Purpose I/O, which here means a pin that can be configured to behave either as a DIN or a DOUT

The API defines that each type of pin (DIN, DOUT, ADC or DAC) has a structure type with all the information that may be relevant about the pin. The GPIO box on the diagram is another structure that defines the pin physical address, the pin type and an union structure that allows to use either a DIN or DOUT pin data structure. The API would enforce a pin data structure based on the pin type field.

There would be an array for each type of pin (GPIO (which may be a DIN or DOUT), ADC or DAC), where the access to an individual pin would be made through the index. The size of these arrays would be based on a BSP defined macro, for instance RTEMS_GPIO_COUNT, which if undefined would disable the GPIO part of the library. The access to these arrays would be syncronized by the library, so that multiple drivers can operate at the same time, and each pin would have a major and minor number so that a driver cannot access pins operated by other drivers.

The advantage of the array approach is direct access to a pin, as it could be easily reached through the array index, and easy management of the diferent drivers that may be accessing the GPIO pins (ensuring that no two drivers are operating the same pin at the same time).

GPIO peripheral interfaces

All the interfaces using a GPIO configuration can go on this API, like UART, I2C, SPI, JTAG or others. For instance, the API can define a function prototype like:

int rtems_gpio_set_UART(void)

That each BSP with this interface could implement to enable UART. This would mean that the pins used for UART would be accessible only for the UART driver.

More design notes on the GPIO API should appear soon.

The current API code can be found at: https://github.com/asuol/rtems/tree/GPIO_API/cpukit/libgpio

With draft implementation on the Raspberry Pi BSP: https://github.com/asuol/rtems/tree/GPIO_API/c/src/lib/libbsp/arm/raspberrypi/gpio

And a small test case that lits a LED connected to the Raspberry Pi GPIO pin 25: https://github.com/asuol/rtems/tree/GPIO_API/testsuites/samples/LIBGPIO_TEST