Raspberry Pi 5 IoT In C - Gpio5
Written by Harry Fairhead   
Tuesday, 01 April 2025
Article Index
Raspberry Pi 5 IoT In C - Gpio5
Initializing GPIO
PAD Configuration
Examples

Using these two functions we can now create a simple function to set a single GPIO line to a value:

void gpio_put(uint32_t gpio, bool value)
{
    uint32_t mask = 1ul << gpio;
    if (value)
        gpio_set_mask(mask);
    else
        gpio_clr_mask(mask);
}

A masked version of the function is also useful:

void gpio_put_masked(uint32_t mask, uint32_t value)
{
    rioXOR->Out = (rio->Out ^ value) & mask;
}

This sets the GPIO lines specified in mask to the states defined by the corresponding bits in value.

Finally we have a simple function that reads the state of a specific GPIO line:

bool gpio_get(uint32_t gpio)
{
    return rio->In & (1u << gpio);
}

and a function to read all of the lines in one go:

uint32_t gpio_get_all(void)
{
    return rio->In;
}

PAD Configuration

Often the default setting of the PAD is good enough but occasionally we need to fine tune the settings – pull mode, skew rate. Drive strength and hysteresis. There are PAD simple configuration set/get functions that make use of the bits in the control register:

  • void gpio_set_pulls(uint32_t gpio, 
    bool up, bool down);
  • void gpio_pull_down(uint32_t gpio);
  • void gpio_pull_up(uint32_t gpio);
  • void gpio_disable_pulls(uint32_t gpio);
  • bool gpio_is_pulled_up(uint32_t gpio);
  • bool gpio_is_pulled_down(uint32_t gpio);
  • void gpio_set_input_hysteresis_enabled (
    uint32_t gpio, bool enabled);
  • bool gpio_is_input_hysteresis_enabled (
    uint32_t gpio);
  • void gpio_set_slew_rate (uint32_t gpio,
    enum gpio_slew_rate slew);
  • enum gpio_slew_rate gpio_get_slew_rate (
    uint32_t gpio);
  • void gpio_set_drive_strength (uint32_t gpio,
                      enum gpio_drive_strength drive);
  • enum gpio_drive_strength gpio_get_drive_strength (
    uint32_t gpio);

These are all easy to implement. For example:

void gpio_set_pulls(uint32_t gpio, bool up, bool down)
{
    pad[gpio] = pad[gpio] & ~0xC;
    if (up)
    {
        pad[gpio] = pad[gpio] | 0x8;
    };
    if (down)
    {
        pad[gpio] = pad[gpio] | 0x4;
    }
}

and so on. You can see the details for the other functions in the Gpio5 listing in Appendix I.

The problems of using pull-up, pull-down and open source/drain modes is discussed in Chapter 8.

Working with Gpio5

As outlined in Appendix I, the library is divided into a .c file and a .h file. If you want to use it as a stable production version then the obvious thing to do is compile the two files into a library file and include the .h file into your program and then link to the library file. This allows you to treat all of the Gpio5 functions as if they were built in and so more or less ignore them.

Of course if you are developing something novel you might want to be able to change or add to the functions in the library and a better solution is to add both files to the project and modify the tasks.json file to compile and link your main program. Assuming that Gpio5 is stored in a directory called Gpio5 same directory as the current directory. i.e. in ../Gpio5, you can add it to the build by changing the args section to read:

   "args": [
            "-fdiagnostics-color=always",
            "-g",
            "-I../Gpio5",
            "${file}",
            "../Gpio5/Gpio5.c",
            "-o",
           "${fileDirname}/${fileBasenameNoExtension}",
           ],

If you store Gpio5.c or Gpio5.h in a different folder you will need to modify the paths used.

Now when you compile the current program, Gpio5.c will be compiled and linked and if the program is correct it should run.



Last Updated ( Tuesday, 01 April 2025 )