Changes between Version 1 and Version 2 of GSoC/2013/Raspberry_Pi_BSP_Peripherals

Aug 18, 2014, 8:58:40 PM (6 years ago)
André Marques


  • GSoC/2013/Raspberry_Pi_BSP_Peripherals

    v1 v2  
    8 '''Mentors:''' Alan Cudmore, Muhammad Adnan, Jennifer Averett and Amar Takhar
    10 '''Students:''' André Marques
    12 '''Status:''' This project is currently in the design phase
    14 '''Introduction:''' This project will improve the Raspberry Pi BSP support for peripherals, namely: GPIO driver, I2C and SPI Bus drivers and Frame Buffer graphics driver support.
    16 '''Goal:''' The GPIO driver should have a "generic" interface, so that other BSP's only need to provide the low level part of the driver. The I2C and SPI Bus drivers should use the cpukit/libi2c API library, while the FrameBuffer driver should use the rtems framebuffer API. Each of these drivers will be tested with real hardware wired to a Raspberry Pi. The debug environment will also be looked during this project.
    18 '''Project details'''
    19  *  TBD
     8'''Mentors:''' Alan Cudmore, Muhammad Adnan, Jennifer Averett and Amar Takhar.
     10'''Students:''' André Marques.
     12'''Introduction:''' This project has provided the Raspberry Pi BSP with support for more peripherals, namely: GPIO driver, I2C and SPI Bus drivers. Unfortunately the Frame Buffer graphics driver support was left out.
    2114'''Requirements:''' This project requires some familiarity with the RTEMS codebase, low level programming in C and some hardware knowledge.
    23 '''Resources:'''
    25 [1] - [ Current GPIO work for RPi by Pierre Ficheux]
    27 [2] - [ Broadcom BCM2835 (the RPi SOC) Peripherals Guide]
    29 '''Acknowledgements'''
    30  *  who helped and did work
     15= Project Contributions =
     17= GPIO =
     20The access to the GPIO hardware is done through an API. It operates the total of 54 GPIOs, which include pins reserved for Raspberry Pi own peripherals (such as the EMMC interface for the SD card) hence not all of these 54 GPIOs are usable to connect to external peripheral devices. Currently only GPIOs 0-31 of these 54 pins can be directly controlled by an API user, which is enough to control all the external GPIO pins on all Raspberry Pi models:
     23 *  Models A and B P1 GPIO header. Note: the P5 GPIO header should also work with the API but it was not tested mainly because the header is unpopulated by default on the Raspberry Pi hardware [6];
     24 *  Model B+ J8 GPIO header. It was not confirmed yet but the raspberrypi BSP was already tested on the B+ by Alan Cudmore, and since it just expands the model A/B P1 header the GPIO API should work as well.
     27Through the API an application may:
     29 *  Set or clear a digital output pin level;
     31 *  Select a GPIO pin function, such as digital input or output or one of the 5 possible alternative functions (each pin has a different set of possible alternate functions);
     33 *  Setup a certain GPIO based interface such as SPI or I2C data buses or JTAG;
     35 *  Configure a digital input GPIO pin (or several at the same time) pull-up resistor as a pull-up, pull-down or disabled;
     37 *  Debounce a switch connected to a gpio input pin. This ignores interrupts generated on a digital input GPIO caused by a bouncing switch through software by requiring a certain number of clock ticks (defined by the user) to pass between interrupts to guarantee that the actual source of an interrupt comes from a real user button press.
     39 *  Enable/disable interrupts on digital input pins, that can call an user defined function every time that the interrupt is detected
     42Although the GPIO API tracks every GPIO pin, it only directly controls GPIO pins configured as digital inputs or outputs. Any pin configured to perform any other function should be operated by another API or driver.
     44The GPIO pins to use with the API are the GPIO* labels as shown in [7].
     46The GPIO API keeps track of which GPIO pins are being used and their current function. Trying to select a pin which the API knows is being used somewhere else will result on an error, which may also happen if one of the GPIO based interfaces (JTAG or the SPI or I2C buses) is enabled and an application uses one of the pins reserved for those interfaces.
     47This feature can help prevent some bugs such as unknowingly setting the same pin for different functions or several times in a row, and also prevents setting up GPIO based interfaces when the pins they require are being used as digital inputs or outputs (in the case of the SPI/I2C buses the error will come from the digital I/O pins setup, since the buses are enabled before the application starts to execute).
     50'''Warning: When using the GPIO pins care should be taken on the current drawn by the devices. Each pin can safely provide 16mA of current, and the total current drawn from all GPIO pins on a GPIO header should not surpass the 50mA mark (the maximum current the header 3v3 pin can provide). Since the GPIOs are directly connected to the arm, too much current can permanently damage the Raspberry Pi as it also does not feature any current protection mechanisms.'''
     51= Using the GPIO API with an application =
     54The GPIO API functions are to be used by both end users (to use GPIO pins as digital inputs or outputs) and device drivers (using the available GPIO based interfaces).
     56To use the GPIO API you must include its header
     59#include <bsp/gpio.h>
     62and initialize it by calling
     68This will initialize the pin's data structure and set all pins as unused, the exception being the pins used for the SPI or I2C buses if any of them are enabled. If you want to use pins 2 and/or 3 as digital I/O pins you must first disable the I2C bus on the raspberrypi BSP script. The same applies to pins 7, 8, 9, 10 and 11, which will be reserved to the SPI bus it it is enabled.
     70Any further ''gpio_initialize()'' call will be silently ignored.
     72With the GPIO API initialized, a pin function can be selected with:
     75gpio_select_pin(int pin, rpi_pin type)
     78where pin is one of the GPIO labels [7] and type must one of the following:
     82 * ALT_FUNC_0
     83 * ALT_FUNC_1
     84 * ALT_FUNC_2
     85 * ALT_FUNC_3
     86 * ALT_FUNC_4
     87 * ALT_FUNC_5
     88 * NOT_USED
     90In the case of an end user he will want to use the DIGITAL_* types to perform digital I/O.
     92If for some reason a user wants to change a pin's function at run time it must call
     95gpio_disable_pin(int dev_pin)
     98with the pin's GPIO label.
     99= Using digital inputs =
     102When a pin is functioning as a digital input an user may get its level - or value - either by polling the pin with
     105gpio_get_val(int pin)
     108which will return 0 or 1 depending on the pin's current logical level, or enable interrupts on the pin with:
     111gpio_enable_interrupt(int dev_pin, gpio_interrupt interrupt, void (*handler)(void))
     114where dev_pin is the pin's GPIO lavel and the handler may be a user defined function (must return void and receive no parameters and perform no blocking or wait calls. Print calls will slow the function execution). The interrupt parameter can be one of the following:
     115 * FALLING_EDGE
     116 * RISING_EDGE
     117 * BOTH_EDGES
     118 * LOW_LEVEL
     119 * HIGH_LEVEL
     120 * BOTH_LEVELS
     121 * NONE
     123This will cause the user defined function to be called when the pin's edge or level state matches the selected interrupt type.
     125Enabled interrupts may be disabled with:
     128gpio_disable_interrupt(int dev_pin)
     130== Pull-up resistors ==
     133Each GPIO pin has a pull-up resistor, which can be configured with
     136gpio_setup_input_mode(int *pins, int pin_count, rpi_gpio_input_mode mode)
     139to set a number of pins to the same resistor configuration or
     142gpio_input_mode(int pin, rpi_gpio_input_mode mode)
     145to setup only one pin.
     147mode must be one of the following:
     149 * PULL_UP
     150 * PULL_DOWN
     152== Deboucing switch ==
     155Since a digital input pin is usually connected to switches and buttons problems may arise when the pin is interrupt-driven, as a button may bounce when released and generate a number of unintended interrupts. To solve this the GPIO API provides a software solution by allowing to attach a deboucing function to an input pin with:
     158gpio_debounce_switch(int dev_pin, int ticks)
     161This functions receives a number of clock ticks which the API will wait to pass between interrupts before processing a new one. Any interrupt generated less than ticks clock ticks have passed since the last processed interrupt will be ignored.
     162= Using digital outputs =
     165A digital output pin can have a high (1) level by calling
     168gpio_set(int pin)
     171or a low (0) level with
     174gpio_clear(int pin)
     176= Sample code and test cases =
     179Sample code and device configurations can be seen on my [ development blog]  and on [ github].
     180= Future work =
     183The GPIO API does not know which Raspberry Pi model it is running on, so when setting up the I2C bus on the GPIO header it assumes to be running on a rev 2 board. This means that currently it is not possible for the API to setup the I2C bus on a rev 1 board. This can be either solved by a option or by probing the hardware through the Mailbox interface.
     185The maximum current that guarantees the desired logic level of a GPIO pin can be configured by changing a pin's drive strength ( '''Warning: this configuration does not limit the amount of current drawn from a GPIO pin!'''
     186= SPI/I2C =
     189The access to the two buses is done through the cpukit/libi2c API, which uses the Raspberry Pi buses through a set of low level functions which this GSOC project provides (refer to cpukit_libi2c/README_libi2c for documentation on the libi2c API).
     191To start using any of the buses first they must be enabled on the script (at the root of the raspberrypi BSP directory).
     193This will cause the BSP_spi_init (for SPI) or BSP_i2c_init (for I2C) function to be called, which setups the bus interface on the GPIO header, registers the bus on "/dev/spi" or "/dev/i2c" and registers any needed device driver which requires the bus.
     195To use a device that requires one of the buses its device driver must be registered on the function BSP_spi_register_drivers or BSP_i2c_register_drivers using the libi2c function rtems_libi2c_register_drv.
     196= Creating a new device driver =
     199Because the SPI and I2C buses uses the libi2c API, device drivers will use libi2c functions to operate the bus so any existing libi2c device driver should also work with the raspberrypi BSP. This also means that a device driver may be located either on the raspberrypi BSP directory or in libchip.
     200= Configuring the bus =
     203The libi2c API provides a struct which should be used by a device driver to configure the bus to a certain device:
     206typedef struct {
     207  uint32_t baudrate;       
     209  uint8_t  bits_per_char;
     210  bool     lsb_first;     
     211  bool     clock_inv;     
     212  bool     clock_phs;     
     213  uint32_t  idle_char;     
     214} rtems_libi2c_tfr_mode_t;
     217A SPI device driver should fill the whole structure, but an I2C device driver only need to fill the baudrate field.
     219The baudrate field must contain the bus clock frequency in Hz.
     221When using the bus, the device driver (either for SPI or I2C) should perform the following steps:
     223# rtems_libi2c_send_start()
     224# rtems_libi2c_ioctl() with the RTEMS_LIBI2C_IOCTL_SET_TFRMODE request and the rtems_libi2c_tfr_mode_t structure
     225# rtems_libi2c_send_addr (rtems_device_minor_number minor, int rw). For SPI the rw parameter is not used, so any value is valid. For I2C rw should be FALSE when going to write to the bus and TRUE when reading from the bus. Doing a write followed by a read (such as sending a request command to the device and read its response) on the I2C bus both should perform this entire sequence (step 2 only needs to be performed once) and change the rw parameter accordingly.
     226# A 1 millisecond wait can be made here, just to ensure that the device has time setup its registers (the raspberry pi SPI and I2C buses implementation both wait for the transfer on the bus to complete before returning)
     228# rtems_libi2c_write_bytes() or rtems_libi2c_read_bytes() to write or read data to/from the bus
     230# rtems_libi2c_send_stop
     232# Wait another 1 millisecond to ensure the device understood the stop
     234To use the device an application must open its device file, which will be in the format "/dev/spi.<device_name>" or "/dev/i2c.<device_name>", and operate it through the device file.
     235= Sample code and test cases =
     238Sample code and device configurations can be seen on my [ development blog] and on [ github].
     239= SPI future work =
     242 * Test bidirectional mode;
     243 * Add lossi mode support;
     244 * Add DMA access (requires DMA support on the raspberrypi BSP).
     245= I2C future work =
     248 * Clock stretching (although there is a known bug on the raspberry pi itself with this feature);
     249 * 10 bit addressing;
     250 * Clock edge delays.
    31251= Miscellaneous Sections =
    34 '''Acronyms'''
     253= Acronyms =
    35255RPi: Raspberry Pi
    47  *  TBD
     267[1] - [ Current GPIO work for RPi by Pierre Ficheux]
     269[2] - [ Broadcom BCM2835 (the RPi SOC) Peripherals Guide]
     271[3] - [ GSOC RTEMS repository]
     273[4] - [ RTEMS_rpi_testing github repository]
     275[5] - [ Development blog]
     277[6] -
     279[7] -