Notice: We have migrated to GitLab launching 2024-05-01 see here: https://gitlab.rtems.org/

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


Ignore:
Timestamp:
08/18/14 20:58:40 (10 years ago)
Author:
André Marques
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • GSoC/2013/Raspberry_Pi_BSP_Peripherals

    v1 v2  
    66
    77
    8 '''Mentors:''' Alan Cudmore, Muhammad Adnan, Jennifer Averett and Amar Takhar
    9 
    10 '''Students:''' André Marques
    11 
    12 '''Status:''' This project is currently in the design phase
    13 
    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.
    15 
    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.
    17 
    18 '''Project details'''
    19  *  TBD
     8'''Mentors:''' Alan Cudmore, Muhammad Adnan, Jennifer Averett and Amar Takhar.
     9
     10'''Students:''' André Marques.
     11
     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.
    2013
    2114'''Requirements:''' This project requires some familiarity with the RTEMS codebase, low level programming in C and some hardware knowledge.
    22 
    23 '''Resources:'''
    24 
    25 [1] - [https://github.com/pficheux/raspberry_pi/tree/master/RTEMS/gpio_driver Current GPIO work for RPi by Pierre Ficheux]
    26 
    27 [2] - [http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf Broadcom BCM2835 (the RPi SOC) Peripherals Guide]
    28 
    29 '''Acknowledgements'''
    30  *  who helped and did work
     15= Project Contributions =
     16
     17= GPIO =
     18
     19
     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:
     21
     22
     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.
     25
     26
     27Through the API an application may:
     28
     29 *  Set or clear a digital output pin level;
     30
     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);
     32
     33 *  Setup a certain GPIO based interface such as SPI or I2C data buses or JTAG;
     34
     35 *  Configure a digital input GPIO pin (or several at the same time) pull-up resistor as a pull-up, pull-down or disabled;
     36
     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.
     38
     39 *  Enable/disable interrupts on digital input pins, that can call an user defined function every time that the interrupt is detected
     40
     41
     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.
     43
     44The GPIO pins to use with the API are the GPIO* labels as shown in [7].
     45
     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).
     48
     49
     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 =
     52
     53
     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).
     55
     56To use the GPIO API you must include its header
     57
     58{{{
     59#include <bsp/gpio.h>
     60}}}
     61
     62and initialize it by calling
     63
     64{{{
     65gpio_initialize()
     66}}}
     67
     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 configure.ac script. The same applies to pins 7, 8, 9, 10 and 11, which will be reserved to the SPI bus it it is enabled.
     69
     70Any further ''gpio_initialize()'' call will be silently ignored.
     71
     72With the GPIO API initialized, a pin function can be selected with:
     73
     74{{{
     75gpio_select_pin(int pin, rpi_pin type)
     76}}}
     77
     78where pin is one of the GPIO labels [7] and type must one of the following:
     79
     80 * DIGITAL_INPUT
     81 * DIGITAL_OUTPUT
     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
     89
     90In the case of an end user he will want to use the DIGITAL_* types to perform digital I/O.
     91
     92If for some reason a user wants to change a pin's function at run time it must call
     93
     94{{{
     95gpio_disable_pin(int dev_pin)
     96}}}
     97
     98with the pin's GPIO label.
     99= Using digital inputs =
     100
     101
     102When a pin is functioning as a digital input an user may get its level - or value - either by polling the pin with
     103
     104{{{
     105gpio_get_val(int pin)
     106}}}
     107
     108which will return 0 or 1 depending on the pin's current logical level, or enable interrupts on the pin with:
     109
     110{{{
     111gpio_enable_interrupt(int dev_pin, gpio_interrupt interrupt, void (*handler)(void))
     112}}}
     113
     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
     122
     123This will cause the user defined function to be called when the pin's edge or level state matches the selected interrupt type.
     124
     125Enabled interrupts may be disabled with:
     126
     127{{{
     128gpio_disable_interrupt(int dev_pin)
     129}}}
     130== Pull-up resistors ==
     131
     132
     133Each GPIO pin has a pull-up resistor, which can be configured with
     134
     135{{{
     136gpio_setup_input_mode(int *pins, int pin_count, rpi_gpio_input_mode mode)
     137}}}
     138
     139to set a number of pins to the same resistor configuration or
     140
     141{{{
     142gpio_input_mode(int pin, rpi_gpio_input_mode mode)
     143}}}
     144
     145to setup only one pin.
     146
     147mode must be one of the following:
     148
     149 * PULL_UP
     150 * PULL_DOWN
     151 * NO_PULL_RESISTOR
     152== Deboucing switch ==
     153
     154
     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:
     156
     157{{{
     158gpio_debounce_switch(int dev_pin, int ticks)
     159}}}
     160
     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 =
     163
     164
     165A digital output pin can have a high (1) level by calling
     166
     167{{{
     168gpio_set(int pin)
     169}}}
     170
     171or a low (0) level with
     172
     173{{{
     174gpio_clear(int pin)
     175}}}
     176= Sample code and test cases =
     177
     178
     179Sample code and device configurations can be seen on my [http://asuolgsoc2014.wordpress.com/2014/08/18/testing-the-project/ development blog]  and on [https://github.com/asuol/RTEMS_rpi_testing/tree/master/GPIO github].
     180= Future work =
     181
     182
     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 configure.ac option or by probing the hardware through the Mailbox interface.
     184
     185The maximum current that guarantees the desired logic level of a GPIO pin can be configured by changing a pin's drive strength (http://pt.scribd.com/doc/101830961/GPIO-Pads-Control2). '''Warning: this configuration does not limit the amount of current drawn from a GPIO pin!'''
     186= SPI/I2C =
     187
     188
     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).
     190
     191To start using any of the buses first they must be enabled on the configure.ac script (at the root of the raspberrypi BSP directory).
     192
     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.
     194
     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 =
     197
     198
     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 =
     201
     202
     203The libi2c API provides a struct which should be used by a device driver to configure the bus to a certain device:
     204
     205{{{
     206typedef struct {
     207  uint32_t baudrate;       
     208                         
     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;
     215}}}
     216
     217A SPI device driver should fill the whole structure, but an I2C device driver only need to fill the baudrate field.
     218
     219The baudrate field must contain the bus clock frequency in Hz.
     220
     221When using the bus, the device driver (either for SPI or I2C) should perform the following steps:
     222
     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)
     227
     228# rtems_libi2c_write_bytes() or rtems_libi2c_read_bytes() to write or read data to/from the bus
     229
     230# rtems_libi2c_send_stop
     231
     232# Wait another 1 millisecond to ensure the device understood the stop
     233
     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 =
     236
     237
     238Sample code and device configurations can be seen on my [http://asuolgsoc2014.wordpress.com/2014/08/18/testing-the-project/ development blog] and on [https://github.com/asuol/RTEMS_rpi_testing github].
     239= SPI future work =
     240
     241
     242 * Test bidirectional mode;
     243 * Add lossi mode support;
     244 * Add DMA access (requires DMA support on the raspberrypi BSP).
     245= I2C future work =
     246
     247
     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 =
    32252
    33 
    34 '''Acronyms'''
     253= Acronyms =
     254
    35255RPi: Raspberry Pi
    36256
     
    45265
    46266
    47  *  TBD
     267[1] - [https://github.com/pficheux/raspberry_pi/tree/master/RTEMS/gpio_driver Current GPIO work for RPi by Pierre Ficheux]
     268
     269[2] - [http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf Broadcom BCM2835 (the RPi SOC) Peripherals Guide]
     270
     271[3] - [https://github.com/asuol/rtems/tree/GPIO_API GSOC RTEMS repository]
     272
     273[4] - [https://github.com/asuol/RTEMS_rpi_testing RTEMS_rpi_testing github repository]
     274
     275[5] - [https://asuolgsoc2014.wordpress.com/ Development blog]
     276
     277[6] - http://elinux.org/RPi_Low-level_peripherals#P5_header
     278
     279[7] - http://elinux.org/RPi_Low-level_peripherals#General_Purpose_Input.2FOutput_.28GPIO.29