[PATCH] Add GPIO, I2C and SPI support for the RPi BSP

Joel Sherrill joel.sherrill at oarcorp.com
Tue Nov 4 23:29:15 UTC 2014



On November 4, 2014 5:27:51 PM CST, Andre Marques <andre.lousa.marques at gmail.com> wrote:
>On 11/04/14 23:16, Joel Sherrill wrote:
>> On 11/4/2014 5:01 PM, Andre Marques wrote:
>>> Hi gedare,
>>>
>>> will send a new version of this patch in the next few days.
>>>
>>> Replies to your comments below.
>>>
>> I am too overwhelmed to remember but are there example
>> and/or test programs for the IO pins?
>
>Yes I have put the test cases and the device drivers I used during
>development in github:
>
>https://github.com/asuol/RTEMS_rpi_testing

Gedare.. Any suggestions for a home on git.rtems.org? The best idea I have is a subdirectory in examples

>>
>> FWIW I have a Pinewood Derby application that uses 3 discrete
>> inputs to time two wooden cars on a race track. I need to move
>> it to my personal git repo. It was developed to use a parallel
>> port on a PC as input but moving to a Raspberry Pi for it would
>> be cool!
>>
>> --joel
>>> --André Marques.
>>>
>>> On 10/31/14 14:25, Gedare Bloom wrote:
>>>> Thanks, I'll leave detailed comments to the experts but noticed a
>few things.
>>>>
>>>> On Fri, Oct 31, 2014 at 7:56 AM, Andre Marques
>>>> <andre.lousa.marques at gmail.com> wrote:
>>>>> Aditional documentation can be found in the RTEMS wiki
>>>>>
>>>>> http://www.rtems.org/wiki/index.php/Raspberry_Pi_BSP_Peripherals
>>>>>
>>>>> and on my GSOC development blog
>>>>>
>>>>> http://asuolgsoc2014.wordpress.com/2014/08/18/testing-the-project/
>>>>>
>>>>> Device drivers and test cases used to test this work were moved to
>a github repository
>>>>>
>>>>> https://github.com/asuol/RTEMS_rpi_testing
>>>>> ---
>>>>>    c/src/lib/libbsp/arm/raspberrypi/Makefile.am       |  11 +-
>>>>>    c/src/lib/libbsp/arm/raspberrypi/configure.ac      |  12 +
>>>>>    c/src/lib/libbsp/arm/raspberrypi/gpio/gpio.c       | 745
>+++++++++++++++++++++
>>>>>    c/src/lib/libbsp/arm/raspberrypi/i2c/i2c.c         | 427
>++++++++++++
>>>>>    c/src/lib/libbsp/arm/raspberrypi/i2c/i2c_init.c    |  78 +++
>>>>>    c/src/lib/libbsp/arm/raspberrypi/i2c/spi.c         | 564
>++++++++++++++++
>>>>>    c/src/lib/libbsp/arm/raspberrypi/i2c/spi_init.c    |  83 +++
>>>>>    c/src/lib/libbsp/arm/raspberrypi/include/gpio.h    | 198 ++++++
>>>>>    c/src/lib/libbsp/arm/raspberrypi/include/i2c.h     | 166 +++++
>>>>>    c/src/lib/libbsp/arm/raspberrypi/include/irq.h     |   6 +-
>>>>>    .../libbsp/arm/raspberrypi/include/raspberrypi.h   |  79 ++-
>>>>>    c/src/lib/libbsp/arm/raspberrypi/irq/irq.c         | 103 ++-
>>>>>    c/src/lib/libbsp/arm/raspberrypi/preinstall.am     |   8 +
>>>>>    .../lib/libbsp/arm/raspberrypi/startup/bspstart.c  |  17 +-
>>>>>    14 files changed, 2475 insertions(+), 22 deletions(-)
>>>>>    create mode 100644 c/src/lib/libbsp/arm/raspberrypi/gpio/gpio.c
>>>>>    create mode 100644 c/src/lib/libbsp/arm/raspberrypi/i2c/i2c.c
>>>>>    create mode 100644
>c/src/lib/libbsp/arm/raspberrypi/i2c/i2c_init.c
>>>>>    create mode 100644 c/src/lib/libbsp/arm/raspberrypi/i2c/spi.c
>>>>>    create mode 100644
>c/src/lib/libbsp/arm/raspberrypi/i2c/spi_init.c
>>>>>    create mode 100644
>c/src/lib/libbsp/arm/raspberrypi/include/gpio.h
>>>>>    create mode 100644
>c/src/lib/libbsp/arm/raspberrypi/include/i2c.h
>>>>>
>>>>> diff --git a/c/src/lib/libbsp/arm/raspberrypi/Makefile.am
>b/c/src/lib/libbsp/arm/raspberrypi/Makefile.am
>>>>> index 839c8de..81dc196 100644
>>>>> --- a/c/src/lib/libbsp/arm/raspberrypi/Makefile.am
>>>>> +++ b/c/src/lib/libbsp/arm/raspberrypi/Makefile.am
>>>>> @@ -44,6 +44,8 @@ include_bsp_HEADERS += include/irq.h
>>>>>    include_bsp_HEADERS += include/mmu.h
>>>>>    include_bsp_HEADERS += include/usart.h
>>>>>    include_bsp_HEADERS += include/raspberrypi.h
>>>>> +include_bsp_HEADERS += include/gpio.h
>>>>> +include_bsp_HEADERS += include/i2c.h
>>>>>
>>>>>    include_libcpu_HEADERS =
>../../../libcpu/arm/shared/include/cache_.h \
>>>>>        ../../../libcpu/arm/shared/include/arm-cp15.h
>>>>> @@ -79,7 +81,6 @@ libbsp_a_SOURCES += ../../shared/bspclean.c
>>>>>    libbsp_a_SOURCES += ../../shared/bspgetworkarea.c
>>>>>    libbsp_a_SOURCES += ../../shared/bsplibc.c
>>>>>    libbsp_a_SOURCES += ../../shared/bsppost.c
>>>>> -libbsp_a_SOURCES += ../../shared/bsppredriverhook.c
>>>>>    libbsp_a_SOURCES += ../../shared/bsppretaskinghook.c
>>>>>    libbsp_a_SOURCES += ../../shared/cpucounterread.c
>>>>>    libbsp_a_SOURCES += ../../shared/cpucounterdiff.c
>>>>> @@ -119,11 +120,19 @@ libbsp_a_SOURCES += clock/clockdrv.c
>../../../shared/clockdrv_shell.h
>>>>>    # Timer
>>>>>    libbsp_a_SOURCES += misc/timer.c
>>>>>
>>>>> +# GPIO
>>>>> +
>>>>> +libbsp_a_SOURCES += gpio/gpio.c
>>>>> +
>>>>>    # RTC
>>>>>
>>>>>    # SSP
>>>>>
>>>>>    # I2C
>>>>> +libbsp_a_SOURCES += i2c/i2c.c
>>>>> +libbsp_a_SOURCES += i2c/i2c_init.c
>>>>> +libbsp_a_SOURCES += i2c/spi.c
>>>>> +libbsp_a_SOURCES += i2c/spi_init.c
>>>>>
>>>>>    # Cache
>>>>>    libbsp_a_SOURCES += ../../../libcpu/shared/src/cache_manager.c
>>>>> diff --git a/c/src/lib/libbsp/arm/raspberrypi/configure.ac
>b/c/src/lib/libbsp/arm/raspberrypi/configure.ac
>>>>> index 9bd6883..ef83c9d 100644
>>>>> --- a/c/src/lib/libbsp/arm/raspberrypi/configure.ac
>>>>> +++ b/c/src/lib/libbsp/arm/raspberrypi/configure.ac
>>>>> @@ -24,6 +24,18 @@ AM_CONDITIONAL(HAS_NETWORKING,test
>"$HAS_NETWORKING" = "yes")
>>>>>    RTEMS_BSPOPTS_SET([BSP_START_RESET_VECTOR],[*],[])
>>>>>    RTEMS_BSPOPTS_HELP([BSP_START_RESET_VECTOR],[reset vector
>address for BSP start])
>>>>>
>>>>> +RTEMS_BSPOPTS_SET([I2C_IO_MODE],[*],[1])
>>>>> +RTEMS_BSPOPTS_HELP([I2C_IO_MODE],[Define to 1 to use
>interrupt-driven I/O with the Raspberry Pi I2C bus. If defined to other
>value the access will be polled-driven.])
>>>>> +
>>>>> +RTEMS_BSPOPTS_SET([SPI_IO_MODE],[*],[1])
>>>>> +RTEMS_BSPOPTS_HELP([SPI_IO_MODE],[Define to 1 to use
>interrupt-driven I/O with the Raspberry Pi SPI bus. If defined to other
>value the access will be polled-driven.])
>>>>> +
>>>>> +RTEMS_BSPOPTS_SET([BSP_ENABLE_SPI],[*],[0])
>>>>> +RTEMS_BSPOPTS_HELP([BSP_ENABLE_SPI],[Define to 1 to use the SPI
>bus. This will register the bus in /dev/spi and also any device driver
>mentioned in i2c/spi_init.c .])
>>>>> +
>>>>> +RTEMS_BSPOPTS_SET([BSP_ENABLE_I2C],[*],[1])
>>>>> +RTEMS_BSPOPTS_HELP([BSP_ENABLE_I2C],[Define to 1 to use the I2C
>bus. This will register the bus in /dev/i2c and also any device driver
>mentioned in i2c/i2c_init.c .])
>>>>> +
>>>>>    RTEMS_BSP_CLEANUP_OPTIONS(0, 0)
>>>>>    RTEMS_BSP_LINKCMDS
>>>>>
>>>>> diff --git a/c/src/lib/libbsp/arm/raspberrypi/gpio/gpio.c
>b/c/src/lib/libbsp/arm/raspberrypi/gpio/gpio.c
>>>>> new file mode 100644
>>>>> index 0000000..d245339
>>>>> --- /dev/null
>>>>> +++ b/c/src/lib/libbsp/arm/raspberrypi/gpio/gpio.c
>>>>> @@ -0,0 +1,745 @@
>>>>> +/**
>>>>> + * @file gpio.c
>>>>> + *
>>>>> + * @ingroup raspberrypi_gpio
>>>>> + *
>>>>> + * @brief Support for the Raspberry PI GPIO.
>>>>> + *
>>>>> + */
>>>>> +
>>>>> +/*
>>>>> + *  Copyright (c) 2014 Andre Marques <andre.lousa.marques at
>gmail.com>
>>>>> + *
>>>>> + *  The license and distribution terms for this file may be
>>>>> + *  found in the file LICENSE in this distribution or at
>>>>> + *  http://www.rtems.org/license/LICENSE.
>>>>> + */
>>>>> +
>>>>> +#include <bsp/raspberrypi.h>
>>>>> +#include <bsp/irq.h>
>>>>> +#include <bsp/gpio.h>
>>>>> +
>>>>> +#include <stdlib.h>
>>>>> +
>>>>> +/* Calculates a bitmask to assign an alternate function to a
>given pin. */
>>>>> +#define SELECT_PIN_FUNCTION(fn, pn) (fn << ((pn % 10) * 3))
>>>>> +
>>>>> +static bool is_initialized = false;
>>>>> +
>>>>> +rpi_gpio_pin *gpio_pin;
>>>>> +
>>>>> +/**
>>>>> + * @brief Waits a number of CPU cycles.
>>>>> + *
>>>>> + * @param[in] cycles The number of CPU cycles to wait.
>>>>> + *
>>>>> + */
>>>>> +static void arm_delay (int cycles)
>>>>> +{
>>>>> +  int i;
>>>>> +
>>>>> +  for (i = 0; i < cycles; i++)
>>>>> +    asm volatile ("nop");
>>>> We prefer to see nested scopes within a function (even with just
>one
>>>> line) have explicit braces { }.
>>> Will review the code against the coding conventions. On a side note
>the
>>> explicit braces convention does not seem to be in the wiki page (I
>am
>>> looking it through the google cache since the wiki is down).
>>>
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * @brief Initializes the GPIO API.
>>>>> + *        Allocates space to the gpio_pin array and sets every
>pin as NOT_USED.
>>>>> + *        If the API has already been initialized silently exits.
>>>>> + */
>>>>> +void gpio_initialize(void)
>>>>> +{
>>>>> +  int i;
>>>>> +
>>>>> +  if ( is_initialized )
>>>>> +    return;
>>>>> +
>>>>> +  is_initialized = true;
>>>>> +
>>>>> +  gpio_pin = (rpi_gpio_pin *) malloc(GPIO_PIN_COUNT *
>sizeof(rpi_gpio_pin));
>>>>> +
>>>>> +  for ( i = 0; i < GPIO_PIN_COUNT; i++ ) {
>>>>> +    gpio_pin[i].pin_type = NOT_USED;
>>>>> +    gpio_pin[i].enabled_interrupt = NONE;
>>>>> +
>>>>> +    gpio_pin[i].h_args.debouncing_tick_count = 0;
>>>>> +  }
>>>> This entire function can be eliminated, dynamic allocation and
>>>> initialization are unnecessary since you know the size and initial
>>>> values to use.
>>>>
>>> The allocation can indeed become static. As for the initialization
>of
>>> the array this function is to be called by any application that
>intends
>>> to use digital I/O capabilities. The alternative is to have this
>>> initialization on startup/bspstart.c (as I2C/SPI which are activated
>>> through configure.ac).
>>>
>>> When changing the alocation from dynamic to static I found that some
>>> pins were not getting the pull-up resistors to work, which I traced
>to
>>> the rpi_gpio_input_mode enumerator in include/gpio.h (for some
>reason if
>>> PULL_UP is 0 the resistor is not activated when the gpio_pin array
>is
>>> staticly-allocated):
>>>
>>> typedef enum
>>> {
>>>     PULL_UP,
>>>     PULL_DOWN,
>>>     NO_PULL_RESISTOR
>>> } rpi_gpio_input_mode;
>>>
>>> Will initialize every first value on the enumerators there to 1.
>>>
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * @brief Gives an output GPIO pin the logical value of 1.
>>>>> + *
>>>>> + * @param[in] pin The Raspberry Pi GPIO pin label number (not is
>position
>>>>> + *            on the header).
>>>>> + *
>>>>> + * @retval 0 Pin was set successfully.
>>>>> + * @retval -1 The received pin is not configured as an digital
>output.
>>>>> + */
>>>>> +int gpio_set(int pin)
>>>>> +{
>>>> I'd add some asserts here and in other places that use 'pin',
>like..
>>>> assert(pin > 0);
>>>> assert(pin < =PIN_COUNT);
>>>> Or whatever is sensible.
>>> Will do.
>>>
>>>>> +  if (gpio_pin[pin-1].pin_type != DIGITAL_OUTPUT)
>>>>> +    return -1;
>>>>> +
>>>>> +  BCM2835_REG(BCM2835_GPIO_GPSET0) = (1 << pin);
>>>>> +
>>>>> +  return 0;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * @brief Gives an output GPIO pin the logical value of 0.
>>>>> + *
>>>>> + * @param[in] pin The Raspberry Pi GPIO pin label number (not is
>position
>>>>> + *            on the header).
>>>>> + *
>>>>> + * @retval 0 Pin was cleared successfully.
>>>>> + * @retval -1 The received pin is not configured as an digital
>output.
>>>>> + */
>>>>> +int gpio_clear(int pin)
>>>>> +{
>>>>> +  if (gpio_pin[pin-1].pin_type != DIGITAL_OUTPUT)
>>>>> +    return -1;
>>>>> +
>>>>> +  BCM2835_REG(BCM2835_GPIO_GPCLR0) = (1 << pin);
>>>>> +
>>>>> +  return 0;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * @brief Gets the value (level) of a GPIO input pin.
>>>>> + *
>>>>> + * @param[in] pin The Raspberry Pi GPIO pin label number (not is
>position
>>>>> + *            on the header).
>>>>> + *
>>>>> + * @retval The function returns 0 or 1 depending on the pin
>current
>>>>> + *         logical value.
>>>>> + */
>>>>> +int gpio_get_val(int pin)
>>>> avoid abbreviations
>>> This one should become gpio_get_value or gpio_read.
>>>
>>>>> +{
>>>>> +  return BCM2835_REG(BCM2835_GPIO_GPLEV0) &= (1 << (pin));
>>>> Do you intend for the assignment as a side-effect? If so, it should
>be
>>>> documented.
>>> Actually the assignment is not needed. There is also too many
>parenthesis.
>>>
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * @brief Configures a GPIO pin to perform a certain function.
>>>>> + *
>>>>> + * @param[in] pin The Raspberry Pi GPIO pin label number (not is
>position
>>>>> + *            on the header).
>>>>> + * @param[in] type The new function of the pin.
>>>>> + *
>>>>> + * @retval 0 Pin was configured successfully.
>>>>> + * @retval -1 The received pin is already being used, or unknown
>function.
>>>>> + */
>>>>> +int gpio_select_pin(int pin, rpi_pin type)
>>>>> +{
>>>>> +  /* Calculate the pin function select register address. */
>>>>> +  volatile unsigned int *pin_addr = (unsigned int
>*)BCM2835_GPIO_REGS_BASE + (pin / 10);
>>>>> +
>>>>> +  /* If the pin is already being used returns with an error. */
>>>>> +  if ( gpio_pin[pin-1].pin_type != NOT_USED )
>>>>> +    return -1;
>>>>> +
>>>> You could simplify the following by defining the enum rpi_pin
>like...
>>>> DIGITAL_OUTPUT = 1,
>>>> ALT_FUNC_5,
>>>> ALT_FUNC_4,
>>>> ALT_FUNC_0,
>>>> ...
>>>>
>>>> Then use
>>>>    *(pin_addr) |= SELECT_PIN_FUNCTION(type, pin);
>>>>
>>>>
>>>> Also, is ALT_FUNC_3 identical to DIGITAL_INPUT?
>>> DIGITAL_INPUT uses the &~ operators instead of |, but the switch may
>be
>>> simplified through the enumerator.
>>>
>>>>> +  /* Sets pin function select bits as zero (DIGITAL_INPUT).*/
>>>>> +  *(pin_addr) &= ~SELECT_PIN_FUNCTION(7, pin);
>>>>> +
>>>>> +  switch ( type ) {
>>>>> +    case DIGITAL_INPUT:
>>>>> +
>>>>> +      /* Digital input is set by default before this switch. */
>>>>> +
>>>>> +      break;
>>>>> +
>>>>> +    case DIGITAL_OUTPUT:
>>>>> +
>>>>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(1, pin);
>>>>> +
>>>>> +      break;
>>>>> +
>>>>> +    case ALT_FUNC_0:
>>>>> +
>>>>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(4, pin);
>>>>> +
>>>>> +      break;
>>>>> +
>>>>> +    case ALT_FUNC_1:
>>>>> +
>>>>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(5, pin);
>>>>> +
>>>>> +      break;
>>>>> +
>>>>> +    case ALT_FUNC_2:
>>>>> +
>>>>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(6, pin);
>>>>> +
>>>>> +      break;
>>>>> +
>>>>> +    case ALT_FUNC_3:
>>>>> +
>>>>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(7, pin);
>>>>> +
>>>>> +      break;
>>>>> +
>>>>> +    case ALT_FUNC_4:
>>>>> +
>>>>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(3, pin);
>>>>> +
>>>>> +      break;
>>>>> +
>>>>> +    case ALT_FUNC_5:
>>>>> +
>>>>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(2, pin);
>>>>> +
>>>>> +      break;
>>>>> +
>>>>> +    default:
>>>>> +      return -1;
>>>>> +  }
>>>>> +
>>>>> +  /* If the alternate function was successfuly assigned to the
>pin,
>>>>> +   * record that information on the gpio_pin structure. */
>>>>> +  gpio_pin[pin-1].pin_type = type;
>>>>> +
>>>>> +  return 0;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * @brief Configures the pull resistor setting of an array of
>GPIO pins.
>>>>> + *
>>>>> + * @param[in] pins Array of Raspberry Pi GPIO pin label numbers
>(not their position
>>>>> + *            on the header).
>>>>> + * @param[in] pin_count Number of pins on the @var pins array.
>>>>> + * @param[in] mode The pull resistor mode.
>>>>> + *
>>>>> + * @retval 0 Pull resistor successfully configured.
>>>>> + * @retval -1 Unknown pull resistor mode.
>>>>> + */
>>>>> +static int
>>>>> +set_input_mode(int *pins, int pin_count, int pin_mask,
>rpi_gpio_input_mode mode)
>>>>> +{
>>>>> +  int i;
>>>>> +
>>>>> +  /* Set control signal. */
>>>>> +  switch ( mode ) {
>>>>> +    case PULL_UP:
>>>>> +      BCM2835_REG(BCM2835_GPIO_GPPUD) = (1 << 1);
>>>>> +      break;
>>>>> +
>>>>> +    case PULL_DOWN:
>>>>> +      BCM2835_REG(BCM2835_GPIO_GPPUD) = (1 << 0);
>>>>> +      break;
>>>>> +
>>>>> +    case NO_PULL_RESISTOR:
>>>>> +      BCM2835_REG(BCM2835_GPIO_GPPUD) = 0;
>>>>> +      break;
>>>>> +
>>>>> +    default:
>>>>> +      return -1;
>>>>> +  }
>>>>> +
>>>>> +  /* Wait 150 cyles, as per BCM2835 documentation. */
>>>>> +  arm_delay(150);
>>>>> +
>>>>> +  /* Setup clock for the control signal. */
>>>>> +  BCM2835_REG(BCM2835_GPIO_GPPUDCLK0) = pin_mask;
>>>>> +
>>>>> +  arm_delay(150);
>>>>> +
>>>>> +  /* Remove the control signal. */
>>>>> +  BCM2835_REG(BCM2835_GPIO_GPPUD) = 0;
>>>>> +
>>>>> +  /* Remove the clock. */
>>>>> +  BCM2835_REG(BCM2835_GPIO_GPPUDCLK0) = 0;
>>>>> +
>>>>> +  /* If the operation was successful, record that information
>>>>> +   * on the gpio_pin structure so it can be recalled later. */
>>>>> +  for ( i = 0; i < pin_count; i++ )
>>>>> +    gpio_pin[pins[i]-1].input_mode = mode;
>>>>> +
>>>>> +  return 0;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * @brief Configures a single GPIO pin pull resistor.
>>>>> + *
>>>>> + * @param[in] pin Raspberry Pi GPIO pin label number (not its
>position
>>>>> + *            on the header).
>>>>> + * @param[in] mode The pull resistor mode.
>>>>> + *
>>>>> + * @retval 0 Pull resistor successfully configured.
>>>>> + * @retval -1 @see set_input_mode().
>>>>> + */
>>>>> +int gpio_input_mode(int pin, rpi_gpio_input_mode mode)
>>>>> +{
>>>>> +  int pin_mask = (1 << pin);
>>>>> +  int pins[1];
>>>>> +
>>>>> +  /* If the desired actuation mode is already set, silently
>exits. */
>>>>> +  if ( gpio_pin[pin-1].input_mode == mode )
>>>>> +    return 0;
>>>>> +
>>>>> +  pins[0] = pin;
>>>>> +
>>>>> +  return set_input_mode(pins, 1, pin_mask, mode);
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * @brief Sets the same pull-up/down resistors actuation mode to
>multiple GPIO input pins.
>>>>> + *        There is a maximum number of 32 pins per call, which is
>enough for
>>>>> + *        Raspberry Pi models A and B (17 GPIOs on P1 GPIO
>header)
>>>>> + *        and also model B+ (28 GPIOs on J8 GPIO header).
>>>>> + *
>>>>> + * @param[in] pins Array of Raspberry Pi GPIO pin label numbers
>(not their position
>>>>> + *            on the header).
>>>>> + * @param[in] pin_count Number of pins on the @var pins array.
>>>>> + * @param[in] mode The pull resistor mode.
>>>>> + *
>>>>> + * @retval 0 Pull resistor successfully configured.
>>>>> + * @retval -1 Unknown pull resistor mode.
>>>>> + */
>>>>> +int gpio_setup_input_mode(int *pins, int pin_count,
>rpi_gpio_input_mode mode)
>>>>> +{
>>>>> +  uint32_t pin_mask = 0;
>>>>> +  int diff_mode_counter = 0;
>>>>> +  int i;
>>>>> +
>>>>> +  if ( pin_count > 32 )
>>>> Use the max macro instead of literal 32
>>> Will create a macro for it.
>>>
>>>>> +    return -1;
>>>> Consider using more informative error codes.
>>> Should I print something before the return?
>>>
>>>>> +
>>>>> +  /* Cycle through the given pins to check if this operation will
>have an effect
>>>>> +   * on the resistor actuation mode of any one of the pins.
>>>>> +   * Every pin that currently uses a different pull resistor mode
>sets a bit
>>>>> +   * in its corresponding place on a bitmask. If the mode for a
>pin will not change
>>>>> +   * then the diff_mode_counter variable is increased. */
>>>>> +  for ( i = 0; i < pin_count; i++ ) {
>>>>> +    if ( gpio_pin[pins[i] - 1].input_mode != mode )
>>>>> +      pin_mask |= (1 << pins[i]);
>>>>> +
>>>>> +    else
>>>>> +      diff_mode_counter++;
>>>>> +  }
>>>>> +
>>>>> +  /* If no pin will have its resistor mode changed silently
>exits, avoiding an
>>>>> +   * unnecessary access to the Rasberry Pi memory registers. */
>>>>> +  if ( diff_mode_counter == 0 )
>>>>> +    return 0;
>>>>> +
>>>>> +  return set_input_mode(pins, pin_count, pin_mask, mode);
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * @brief Disables a GPIO pin on the APiI, making it available to
>be used
>>>>> + *        by anyone on the system.
>>>>> + *
>>>>> + * @param[in] dev_pin Raspberry Pi GPIO pin label number (not its
>position
>>>>> + *            on the header).
>>>>> + *
>>>>> + * @retval 0 Pin successfully disabled on the API.
>>>>> + * @retval -1 Could not disable an ative interrupt on this pin.
>>>>> + */
>>>>> +int gpio_disable_pin(int dev_pin)
>>>>> +{
>>>>> +  rtems_status_code sc;
>>>>> +  rpi_gpio_pin *pin;
>>>>> +
>>>>> +  pin = &gpio_pin[dev_pin-1];
>>>>> +
>>>>> +  pin->pin_type = NOT_USED;
>>>>> +
>>>>> +  /* If the pin has an enabled interrupt then remove the handler.
>*/
>>>>> +  if ( pin->enabled_interrupt != NONE ) {
>>>>> +    sc = gpio_disable_interrupt(dev_pin);
>>>>> +
>>>>> +    if ( sc != RTEMS_SUCCESSFUL )
>>>>> +      return -1;
>>>>> +  }
>>>>> +
>>>>> +  return sc;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * @brief Setups a JTAG interface using the P1 GPIO pin header
>>>>> + *        for the models A/B and J8 header on the B+.
>>>>> + *        The following pins should be unused before calling this
>function:
>>>>> + *        GPIO 4, 22, 24, 25 and 27.
>>>>> + *
>>>>> + * @param[in] dev_pin Raspberry Pi GPIO pin label number (not its
>position
>>>>> + *            on the header).
>>>>> + *
>>>>> + * @retval 0 JTAG interface successfully configured.
>>>>> + * @retval -1 At least one of the required pins is currently
>occupied.
>>>>> + */
>>>>> +int gpio_select_jtag(void)
>>>>> +{
>>>>> +  /* Setup gpio 4 alt5 ARM_TDI. */
>>>>> +  if ( gpio_select_pin(4, ALT_FUNC_5) < 0 )
>>>>> +      return -1;
>>>>> +
>>>>> +  /* Setup gpio 22 alt4 ARM_TRST. */
>>>>> +  if ( gpio_select_pin(22, ALT_FUNC_4) < 0 )
>>>>> +      return -1;
>>>>> +
>>>>> +  /* Setup gpio 24 alt4 ARM_TDO. */
>>>>> +  if ( gpio_select_pin(24, ALT_FUNC_4) < 0 )
>>>>> +      return -1;
>>>>> +
>>>>> +  /* Setup gpio 25 alt4 ARM_TCK. */
>>>>> +  if ( gpio_select_pin(25, ALT_FUNC_4) < 0 )
>>>>> +      return -1;
>>>>> +
>>>>> +  /* Setup gpio 27 alt4 ARM_TMS. */
>>>>> +  if ( gpio_select_pin(27, ALT_FUNC_4) < 0 )
>>>>> +      return -1;
>>>>> +
>>>>> +  return 0;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * @brief Setups a SPI interface using the P1 GPIO pin header
>>>>> + *        for the models A/B and J8 header on the B+.
>>>>> + *        The following pins should be unused before calling this
>function:
>>>>> + *        GPIO 7, 8, 9, 10 and 11.
>>>>> + *
>>>>> + * @param[in] dev_pin Raspberry Pi GPIO pin label number (not its
>position
>>>>> + *            on the header).
>>>>> + *
>>>>> + * @retval 0 SPI interface successfully configured.
>>>>> + * @retval -1 At least one of the required pins is currently
>occupied.
>>>>> + */
>>>>> +int gpio_select_spi_p1(void)
>>>>> +{
>>>>> +  /* SPI master 0 MISO data line. */
>>>>> +  if ( gpio_select_pin(9, ALT_FUNC_0) < 0 )
>>>>> +      return -1;
>>>>> +
>>>>> +  /* SPI master 0 MOSI data line. */
>>>>> +  if ( gpio_select_pin(10, ALT_FUNC_0) < 0 )
>>>>> +      return -1;
>>>>> +
>>>>> +  /* SPI master 0 SCLK clock line. */
>>>>> +  if ( gpio_select_pin(11, ALT_FUNC_0) < 0 )
>>>>> +      return -1;
>>>>> +
>>>>> +  /* SPI master 0 CE_0 chip enable line. */
>>>>> +  if ( gpio_select_pin(8, ALT_FUNC_0) < 0 )
>>>>> +      return -1;
>>>>> +
>>>>> +  /* SPI master 0 CE_1 chip enable line. */
>>>>> +  if ( gpio_select_pin(7, ALT_FUNC_0) < 0 )
>>>>> +      return -1;
>>>>> +
>>>>> +  return 0;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * @brief Setups a I2C interface using the P1 GPIO pin header
>>>>> + *        for the models A/B and J8 header on the B+.
>>>>> + *        The following pins should be unused before calling this
>function:
>>>>> + *        GPIO 2 and 3.
>>>>> + *
>>>>> + * @param[in] dev_pin Raspberry Pi GPIO pin label number (not its
>position
>>>>> + *            on the header).
>>>>> + *
>>>>> + * @retval 0 JTAG interface successfully configured.
>>>>> + * @retval -1 At least one of the required pins is currently
>occupied.
>>>>> + */
>>>>> +int gpio_select_i2c_p1_rev2(void)
>>>>> +{
>>>>> +  int pins[] = {2,3};
>>>>> +
>>>>> +  /* I2C BSC1 SDA data line. */
>>>>> +  if ( gpio_select_pin(2, ALT_FUNC_0) < 0 )
>>>>> +      return -1;
>>>>> +
>>>>> +  /* I2C BSC1 SCL clock line. */
>>>>> +  if ( gpio_select_pin(3, ALT_FUNC_0) < 0 )
>>>>> +      return -1;
>>>>> +
>>>> Does it make sense to have gpio_select_pins(int[], type[])?
>>> It may make sense in some scenarios, but probably is easier to read
>if
>>> each call assigns a type to all pins on a given array instead of
>having
>>> to visually match each pin with a type.
>>>
>>>>> +  /* Enable pins 2 and 3 pull-up resistors. */
>>>>> +  if ( gpio_setup_input_mode(pins, 2, PULL_UP) < 0 )
>>>>> +    return -1;
>>>>> +
>>>>> +  return 0;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> 



More information about the devel mailing list