Raspberry Pi – Programming BCM2835 GPIO

Picture Credit score: RasPi.television

That is the sixth article in a collection that explores GPIO programming on a Raspberry Pi 3B+. It’s an introduction to controlling GPIO peripheral gadgets by immediately interacting with the suitable registers on the BCM2835 SoC (System on a chip). It’s an introduction in that it solely covers one of many capabilities, utilizing the essential GPIO functionality as described in Section 6 of the BCM2835 ARM Peripherals guide. This excludes BCM2835 help for protocols comparable to Serial Peripheral Interface (SPI), Pulse Width Modulation (PWM), and Inter-integrated-circuit (IC2) which overlay particular protocol functionality by using the underlying pins mapped to a given protocol (e.g., GPIO pins 8–11 are related to the SPI protocol and have behaviors that may be enabled which can be particular to that protocol). That stated, utilizing the essential pin stage performance covers the identical ideas wanted to make the most of superior protocol capabilites comparable to SPI. This text, coupled with the BCM2835 ARM Peripherals guide, ought to present sufficient background to drive gadgets which can be managed through these capabilities.

After all, there are a number of libraries such because the C BCM2835 and WiringPi libraries, the Python pgpio, and RPi.GPIO libraries, and the Go go-rpio library makes this a lot simpler. And whereas these libraries are normally extra applicable for many initiatives, it may be useful to grasp how the BCM2835 SoC works and the way these libraries work together with the BCM2835. This background can also be useful if you end up studying library code and/or wish to contribute to those initiatives, and even write your individual library.

This text assumes you have already got some familiarity with the BCM2835 and GPIO programming on the Raspberry Pi. If you happen to don’t chances are you’ll wish to take into account attempting the initiatives coated in a few of my other GPIO articles. The only article within the collection is Raspberry Pi GPIO in Go and C — Blinking LED. It demonstrates the identical functionality as this text does, blinking an LED, however it additionally demonstrates the utilization of the WiringPi and the Go go-rpio libraries. It’s a good introduction to utilizing GPIO on the Raspberry Pi, however it solely covers fundamental GPIO ideas and how you can wire a breadboard to a Raspberry Pi’s GPIO outputs.

The next subjects will likely be coated:

  1. Stipulations — describes the {hardware} and libraries you’ll want for this text.
  2. An introduction to BCM2835 GPIO Peripherals — offers an summary the BCM2835’s structure and capabililites.
  3. Utilizing the BCM2835 board to regulate an LED through the GPIO pins — offers the small print, together with code, for controlling an LED utilizing the BCM2835 GPIO registers.
  4. Abstract — summarizes the essential ideas coated on this article.
  5. References — offers an inventory of references I discovered useful, a few of which have been used within the creation of this text.

If you happen to don’t have one, you’ll want a Raspberry Pi. I used a Raspberry Pi 3B+ with the ‘stretch’ model of the Raspbian OS. See How to setup a new Raspberry Pi from scratch in the event you don’t have already got a Raspberry Pi and need assistance setting one up.

Subsequent you’ll want is a breadboard, some jumper wires, a 220 Ohm resistor, and an LED. You must also take into account getting a 40 pin female to female with a T-Type adapter to connect the GPIO outputs to the breadboard. You need to use solely jumper wires, however the adapter will make issues simpler and can assist forestall injury to the GPIO pins on the Raspberry Pi. If you happen to elect to not purchase the 40 pin cable with T-Kind adapter you’ll want to purchase male-to-female jumper wires. Shopping for all this stuff individually will price greater than a equipment, nonetheless. Here’s a simple kit that has all of the above. If you happen to count on to observe this collection I like to recommend shopping for the Sunfounder Raspberry Pi Ultimate Starter Kit.

Picture Credit score: Sunfounder Final Starter/Raphael equipment

Lastly, you’ll want some fundamental C programming information in addition to familiarity with logging on to a Raspberry Pi terminal, or into the desktop GUI that comes with some OS variations. Relying on the method you are taking, chances are you’ll want to attach a keyboard and monitor to the Raspberry Pi. I merely SSH into the Pi. You’ll additionally want familiarity with how you can use an editor like Vi or nano. Lastly, you’ll want fundamental familiarity with the Linux command line.

This part offers an summary of the BCM2835 peripherals. It begins with an summary of the capabilities of the varied kinds of peripherals. It then strikes to an summary of BCM2835 addressing. Understanding addressing is key to understanding the remainder of the article. It concludes with a extra detailed dialogue about how registers are used to entry the peripherals and their related I/O capabilities.

This isn’t an exhaustive description of the BCM2835. The one functionality that will likely be coated in any element, and is the main focus of this text, is interacting with the GPIO I/O capabilities, specifically defining the perform of a pin and setting and clearing the worth of the pin (e.g., setting it to HIGH and LOW), particularly programming BCM2835 GPIO to blink an LED.

There are a number of pin numbering schemes. The Raspberry Pi has bodily pin numbers, i.e., the numbers printed on the Pi board. BCM2835 has a numbering scheme known as GPIO numbering. It’s totally different than, and incompatible with, the Pi’s bodily numbering scheme. Lastly, some libraries such because the C WiringPi library have their very own numbering schemes that are incompatible with the Pi and BCM2835 schemes. This text makes use of the BCM2835 numbering scheme solely. There’s a good pin out diagram obtainable that maps between these 3 numbering schemes. The place a pin helps a specific I/O perform, as described under, can also be known as out on this pin out diagram.

A fast observe on terminology… The time period “peripherals” is used within the title and in some elements of this text. To me, the time period peripherals are one thing of a misnomer. Let me clarify. At its most elementary the GPIO functionality of the BCM2835 is made obtainable by way of a set of bodily pins on the machine. A few of these pins present the ability and floor wanted to drive exterior gadgets like LEDs, sensors, and motors. Different pins may be managed programmatically to take enter from, or output to, these exterior gadgets. At a better stage, subsets of the GPIO pins present help for full protocols that implement extra refined capabilities like controlling the pace and route of a motor and controlling LED shows that show textual content like these in freeway indicators. These fundamental and extra refined capabilities are managed by setting the perform of a pin. Enter and output are 2 capabilities that may be set. There are a selection of others that will likely be coated. Setting the perform of a pin describes how the BCM2835 interacts with a tool or peripheral. Due to this, I want to make use of the time period I/O Perform. I believe that extra precisely describes the idea than the time period “peripherals” does. To me “peripherals” are exterior gadgets. The primary use of the time period I/O Features is the title of the following part.

The BCM2835 helps a wide range of I/O capabilities. These are the topic of the BCM2835 ARM Peripherals guide. This part will solely describe a number of of those capabilities intimately. There are different sources like Wikipedia that may present details about the others.

The principle I/O capabilities supported by the BCM2835 are:

  • GPIO
  • SPI
  • PWM
  • AUX
  • BSC
  • DMA
  • Exterior Mass Media Controller
  • Interrupts
  • Audio (PCM/I2s Audio)
  • System Timer
  • UART

As I’ve direct expertise with the primary 3 I/O capabilities, GPIO, SPI, and PWM, this part will give attention to these. This can present sufficient context to be able to get a fundamental understanding of the sorts of issues the BCM2835 is able to in addition to leveraging the data within the Addressing and Registers sections under to be able to study and use the remaining I/O capabilities.

GPIO (Basic Goal Enter/Output)

GPIO stands for Basic Goal Enter Output. Within the BCM2835 ARM Peripherals information the time period GPIO refers back to the most normal, or fundamental, stage of management of a bodily pin. That is what’s used to regulate the perform of a pin, comparable to setting it as an enter or output pin, or extra superior I/O capabilities comparable to SPI and PWM. It’s additionally used to set or get the worth of a pin. Values are conceptually known as HIGH and LOW, however they’re represented by voltage, or lack thereof, passing throughout the pin. There are different kinds of settings for pins. Certainly one of these settings is used to regulate whether or not to detect a state change on the rising or falling fringe of a pin’s voltage change. One other setting controls what known as pull-up/pull-down resistors hooked up to every pin. These resistors are used to explicitly management the worth of a pin, 1 or 0, when a pin’s voltage is in an indeterminate state. This tutorial has a fairly good clarification for why pull-up and pull-down resistors are wanted.

The code related to this text causes an LED to blink. Undertaking this entails the next steps:

  1. Set the perform of the pin to output, i.e., it’s going to be written to to be able to ship a sign to the LED.
  2. Write LOW to the pin to trigger the LED to activate.
  3. Pause
  4. Write HIGH to the pin to trigger the LED to show off.
  5. Repeat steps 2 by way of 4.

Undertaking this makes use of the GPIO I/O capabilities. Extra precisely it makes use of the GPIO registers to set the pin’s perform (e.g., output) and to regulate the conduct of the peripheral, an LED on this case.

SPI (Serial Peripheral Interface)

SPI is used to ship knowledge serially to a peripheral that may settle for or requires knowledge in parallel. That is useful as a result of a comparatively massive set of parallel inputs may be written to utilizing simply 3 GPIO pins, not together with energy (VCC) and floor (GND). If SPI wasn’t used, one GPIO pin can be required for every parallel enter. This might simply be prohibitive since pins are a restricted useful resource. Let’s see how this works with an instance.

Picture credit score: Creator

The diagram above exhibits the MAX7219 LED Dot Matrix Show. It’s generally used to show arbitrary shapes comparable to letters, numbers, and smiley faces. It controls an 8×8 matrix of LEDs. Controlling an LED requires 1 pin excluding energy or floor. An 8×8 LED matrix has 64 LEDs. This quantity is effectively in extra of the 26 or 40 GPIO pins obtainable on a typical Raspberry Pis. You’ll discover the MAX7219 has the next enter pins:

  1. DIN — that is the serial knowledge enter pin.
  2. CS — That is generally known as a chip choose (CS) or chip allow (CE) pin.
  3. CLK — This pin connects to a clock pin on the Raspberry Pi that synchronizes knowledge transfers between the Raspberry Pi and the MAX7219.

There are 2 extra pins that aren’t used to regulate the MAX7219.

  1. VCC — That is the power-in pin. It connects to an influence supply on the Raspberry Pi, normally a 3.3v supply.
  2. GND — That is the bottom pin. It connects to a floor pin of the Raspberry Pi.

Utilizing a mixture of three GPIO pins to attach from the Raspberry Pi to the DIN, CS, and CLK pins permits the Raspberry Pi to regulate 64 LEDs in a price (pin-wise) environment friendly method. Using the pins related to the SPI protocol on the Raspberry Pi to drive the Max7219 is the popular method to carrying out this.

The SPI functionality on the Raspberry Pi requires at most 5 GPIO pins. One of many pins, MOSI, sends knowledge to a peripheral. MOSI stands for Grasp Out Slave In. The second pin, MISO (Grasp In Slave Out) accepts enter.

I reluctantly use the phrases “grasp” and “slave”. Nevertheless these phrases are utilized in all the paperwork I’ve learn on SPI. I’ll proceed to make use of them to be able to keep away from confusion.

The third pin is a clock that controls the info transmission between the grasp and slave. The 4th pin known as the chip choose (CS) or chip allow (CE) pin. It’s used to organize the slave machine to interface with the BCM2835. An extra slave machine may be accessed by utilizing a fifth pin, the second CE/CS pin. The two CE/CS pins are used to allow every of the slave gadgets, however just one machine may be enabled at a time. The article Using Multiple SPI Slave Devices with the Raspberry Pi offers extra details about how the two CE/CS pins are used. It’s doable to get by utilizing 3 GPIO pins (not together with energy and floor) if just one slave machine is used and there’s no must obtain knowledge from the slave. On this case, the pins used are the MOSI pin, the clock pin, and one CE/CS pin.

The first SPI interface on the BCM2835, SPIO, is carried out on GPIO pins 7–11. Pins 7 & 8 are the two CE/CS pins obtainable on the BCM2835. Pin 9 is MISO, 10 is MOSI, and 11 is the clock (SCLK). The BCM2835 has 2 auxiliary SPI interfaces, SPI1 (AKA AUX_SPI0) and SPI2 (AKA AUX_SPI1). From the BCM2835 ARM Peripherals Information, SPI1 is obtainable on pins 16–21 and SPI2 on pins 35–39. These auxiliary interfaces can be found through the AUX I/O perform.

Along with LED matrix shows, SPI can be utilized to regulate a wide range of peripherals to show photographs, take enter from touchscreens, and work together with varied sensors. Wikipedia has a good article describing SPI in additional element.

I’ve an upcoming article dedicated to SPI. I’ll replace this doc by including a reference when it turns into obtainable.

PWM (Pulse Width Modulation)

PWM is used to transform a digital sign, like that produced by the BCM2835, right into a simulated analog sign. It’s simulated within the sense that it’s not a real analog sign. It’s nonetheless a digital sign however it cycles so quick that, very similar to a video, it seems to be an analog sign. Many peripherals like electrical motors, dimmable LEDs, and shade LEDs require an analog sign. As with SPI, there are devoted pins that may be enabled to make the most of the PWM I/O perform. These are GPIO pins 12, 13, 18, and 19. With these pins, the BCM2835 helps one thing known as {hardware} PWM. The PWM performance is embedded into the BCM2835. It implements a hardware-based clock loop that controls the frequency of the simulated analog sign. It’s doable to make use of different GPIO pins for PWM, that is known as software program PWM. Nevertheless, in software program PWM the clock loop is written within the code that runs on the Raspberry Pi CPU. Since that CPU is doing many different issues it isn’t doable to create a dependable clock sign. This can lead to some undesirable unintended effects comparable to a flickering LED instead of a dim LED. See my articles Raspberry Pi GPIO in Go and C — RGB LED and Pulse Width Modulation for Dummies for extra details about PWM in addition to examples of PWM in use.

All GPIO I/O capabilities are accessed through registers. These registers are situated at varied offsets within the onboard reminiscence. Accessing the registers requires information of how addressing works on the BCM2835 was effectively as on the Raspberry Pi. Right here’s a diagram from the BCM2835 ARM Peripherals guide, part 1.2.1, exhibiting how reminiscence is mapped from Pi’s bodily deal with to the BCM2835 addresses.

BCM2835 Addressing: Picture Credit score BCM2835 ARM Peripherals Information

The Raspberry Pi maps the BCM2835 reminiscence to the Pi’s bodily deal with of 0x2000 0000. That is proven within the center column labeled “ARM Bodily Addresses”. The grey shaded space labeled I/0 peripherals is the Pi’s bodily reminiscence location of the BCM2835’s peripherals (e.g., GPIO pins). Shifting in the direction of the left you’ll see a gold field labeled “VC/ARM MMU”. That is the Memory Management Unit that’s answerable for mapping the Pi’s bodily reminiscence to the BCM2835 reminiscence. Following the road from the center column’s “I/O Peripherals” partition, by way of the VC/ARM MMU, to the far left column titled “VC CPU Bus Addresses” results in the “I/O Peripherals” partition on the BCM2835’s CPU deal with bus. Its deal with is 0x7E00 0000.

The I/O peripheral addresses may be made obtainable to the appliance by way of one in all 2 methods. The standard manner is through the /dev/memmachine mounted on the file system. Accessing this machine requires root privileges. A more moderen technique grew to become obtainable beginning with the Raspberry Pi 2. This technique accesses the I/O peripheral addresses through /dev/gpio. A bonus of utilizing this technique is that it doesn’t require root entry. A drawback to utilizing this technique is that solely the GPIO I/O performance of the BCM2835 may be accessed. This implies superior capabilities like PWM and SPI will not be obtainable. Accessing the I/O peripherals utilizing /dev/mem additionally requires somewhat extra work, specifically mapping the bodily reminiscence from /dev/mem to the appliance’s digital reminiscence. This will likely be coated in additional element later.

There may be third method to interface with GPIO registers. Within the case of SPI, there are 2 gadgets (typically obtainable on many Raspberry Pi fashions), /dev/spidev0.0 and /dev/spidev0.1 through ioctl(). This technique gained’t be coated on this article.

As talked about above, specifying the I/O perform of a pin or set of pins is completed by way of registers on the BCM2835. Every I/O perform has an related register set situated at an offset throughout the BCM2835’s I/O peripheral deal with house. For instance, the GPIO register set begins on the CPU bus deal with 0x7E20 0000. The SPI register set begins at CPU bus deal with offset 0x7E20 4000. The PWM register set begins at offset 0x7E20 C000. And so forth, every I/O perform has it’s personal set of registers to handle its conduct. That stated, all of them work on the identical rules. Specifically, discover the offset of the start of every I/O perform’s register set after which set (or get) the suitable bits on the applicable offsets to regulate the conduct. To make this instance extra express, and to spotlight extra particulars, let’s do a excessive stage walkthrough of how you can management a GPIO pin to blink an LED.

As talked about beforehand the GPIO register begins at bus deal with 0x7e2000 0000. Part 6.1 of the BCM2835 ARM Peripherals guide beginning on web page 90 offers the small print in regards to the GPIO registers. To blink an LED we’ll first must specify the pin’s perform, output on this case, after which toggle the worth of the LED between HIGH and LOW.

Specify a pin’s perform

First, the I/O perform of the pin must be set. A pin’s performance is outlined through one in all 8 different capabilities. Encoding every perform requires 3 bits, 000–111. These bits are contained inside what known as a GPIO Perform Choose Register. Every register is 32 bits lengthy. Due to this fact every 32-bit register can management 10 pins with 2 bits left over. So as to management all the GPIO pins, there are 6 perform choose registers. The BCM2835 has the potential to regulate as much as 54 pins, if supported, through perform choose registers (on the Raspberry Pi 3B+ solely 40 pins can be found). Supporting 54 pins, with 10 pins/register, requires 6 registers. The primary perform choose register is situated at 0x7E20 0000, zero-offset from the beginning of the GPIO register set. The sixth perform choose register begins at offset 0x7E20 0014. The 8 different capabilities are:

  • Enter — represented by the bit sample 000
  • Output — represented by the bit sample 001
  • and Alternate capabilities 0 by way of 5 represented by bit patterns 010 by way of 111 respectively.

On this instance let’s use pin 17 as an output pin. Inspecting the BCM2835 ARM Peripherals information we see that pin 17 is in perform choose register 1, AKA GPFSEL1. GPFSEL1 is at offset 0x7E20 0004. Pin 17’s perform choose offset throughout the register is at bits 21-23. Recall that the output bit sample is 001 so we’ll must put that bit sample in bits 21-23. Within the part on coding under we’ll see how that is truly completed.

Set the pin worth

This text assumes that pin 17 is hooked up to the bottom terminal of the LED (the cathode). Because of this we’ll must set the pin to LOW to ensure that present to move from the ability enter to the anode by way of to the LED floor on pin 17 and light-weight the LED. Setting the pin to HIGH will trigger the LED to show off. Switching between LOW and HIGH will trigger the LED to blink, which is what we’re in search of.

GPIO pin values are managed through the GPIO Pin Output Set register. There are 2 GPIO Pin Output Set registers. Pin 17 is within the first register, GPIO Pin Output Set 0, AKA GPSET0, at GPIO register offset 0x7E20 002C. Pin 17 is at bit offset 17 inside GPSET0. Setting bit 17 to 1 units the register to HIGH. GPIO Pin Output Set registers can solely set a pin to HIGH, setting a pin to 0 has no impact. However recall we have to set the pin to LOW. Since setting a pin in GPSET0 gained’t consequence within the pin being set to LOW how can we accomplish this? It seems there’s one other set of GPIO registers known as GPIO Pin Output Clear registers. These are used to set a pin’s worth to LOW. Pin 17 is in GPIO Pin Output Clear register 0, AKA GPCLR0, beginning at offset 0x7E20 0028. It’s place throughout the register can also be at bit 17. Setting bit 17 to 1 will set the pin to LOW. So we’ll must left shift a 1 into bit 17 to be able to activate the LED. We’ll use GPSET0 to show the LED off. As with specifying a pin’s perform, how that is completed will likely be coated later on this article. By utilizing the GPCLR0 and GPSET0 registers in flip we will trigger the LED to blink.

Different GPIO settings

The GPIO register set can be utilized to regulate many different capabilities of a GPIO pin along with choosing the perform and setting/clearing a pin’s worth. It will also be used to learn the worth of a pin. As mentioned within the I/O capabilities part above different issues that may be managed embody specifying how state modifications are to be detected (rising/falling edge detection) and how you can set the voltage of a pin when it’s in an indeterminate state (pull-up/down resistors). Discussing these different registers is a sophisticated subject and is past the scope of this text.

This part begins with a program that causes an LED to blink. It’s pretty easy and can present the essential steps wanted to program the BCM2835. The subsequent a part of this part will cowl the BCM2835 programming in additional element. However earlier than all that, right here’s how you can wire the breadboard to work with the blinking LED instance.

Picture credit score: Sunfounder

The breadboard ought to be wired as illustrated within the above diagram. Word that the (bent) lengthy lead of the LED, the anode, is linked to the three.3 volt energy pin through the resister and the cathode, or floor, is linked to GPIO pin 17. If you happen to’re unfamiliar with breadboards and breadboard diagrams this breadboard tutorial ought to be useful.

This part will first describe the primary program that blinks an LED. After that, it goes into element about how the code that interacts with the BCM2835 works to regulate the I/O capabilities.

All code on this article may be present in my gpio repository, within the ledblink listing.

The code for the file that comprises this code may be discovered at gpio/ledblink/blinkinglednolib.c.

This primary code snippet exhibits a few essential issues:

  1. Line 1 provides the command to compile and hyperlink this system.
  2. Line 3 offers the included directive wanted to import the BCM2835 capabilities that immediately work together with the BCM2835.
  3. Line 8 defines the BCM GPIO pin that’s used to regulate the LED. It matches the wiring diagram above.

This snippet declares an interrupt handler for use to gracefully exit this system. This ensures that the pin, and the LED, are left in a identified state. The definition of the interrupt handler will likely be proven later.

This snippet exhibits the start of the primary perform.

Line 3 registers the interrupt handler for the SIGINT sign (i.e., ctrl-C).

Traces 5–10 initialize the BCM2835 GPIO performance. Briefly, it finds the GPIO peripherals offset and size inside important reminiscence and maps it to /dev/mem so it may be safely accessed throughout the program. It then units variables to the offsets of the varied functionality registers (e.g., GPIO or SPI). If initialization fails this system exits. The bcm_init() perform will likely be described in additional element under.

Line 13 units LEDPIN to the GPIO output perform. This permits this system to write down values, HIGH or LOW, to the pin. The bcm_gpio_fsel() perform will likely be described in additional element under.

This snippet implements the first performance of this system. Traces 2–10 blink the LED on and off.

Traces 5 and eight set the worth of the LEDPIN by calling bcm_gpio_write() and setting the worth of the pin to both LOW to show the LED on, or HIGH to show the LED off. LOW turns the LED off as a result of the lead connecting BCM GPIO pin 17 to the LED is linked to the LED’s floor pin. To get present to move the pin have to be set to 0 volts. Likewise, HIGH turns the LED off. bcm_gpio_write() will likely be described in additional element under.

Traces 6 and 9 trigger this system to sleep for 500 milliseconds so the LED may be noticed blinking.

Because the remark states, line 13 releases the GPIO sources obtained by bcm_init(). This may even set the GPIO system again to a identified state. bcm_close() will likely be described in additional element under.

This snippet defines the interrupt handler perform. Traces 3 and 4 first flip the LED off, then launch the GPIO sources obtained by bcm_init().

This part describes how the code interacts with and controls the GPIO peripherals, particularly setting the values of the varied registers related to the I/O performance of the BCM2835. Setting register values is used to regulate GPIO peripherals and studying register values enable the present state of the related GPIO peripherals to be accessed.

The code for this part may be present in bcmfuncs.c in my gpio repository. The header file can be found in bcmfuncs.h.

bcm_init()

The above part on Registers mentions that each one operations on BCM2835 peripherals are completed by manipulating the registers related to that kind of peripheral. The aim of bcm_init() is to find out the deal with offsets for all of the kinds of registers, e.g., GPIO, PWM, SPI, and so on. in order that their related peripherals may be managed.

This snippet exhibits the start of the bcm_init() perform.

Line 10 opens the BCM_RPI2_DT_FILENAME. As indicated within the remark, the rb within the fopen() name opens a binary file for studying. BCM_RPI2_DT_FILENAME is outlined within the related bcmfuncs.h header file. It’s worth is /proc/device-tree/soc/ranges. As said in Linux and the Devicetree,

An working system used the Machine Tree to find the topology of the {hardware} at runtime, and thereby help a majority of accessible {hardware} with out onerous coded info (assuming drivers have been obtainable for all gadgets).

One of many items of data the machine tree holds, and is essential for our functions, is the placement and size of the I/O Peripherals partition within the BCM2835’s bodily deal with house. Right here’s a hex dump of the contents of /proc/device-tree/soc/ranges on a Raspberry Pi 3B+:

pi@pi-node1:/ $ hexdump -C /proc/device-tree/soc/ranges
00000000 7e 00 00 00 3f 00 00 00 01 00 00 00 40 00 00 00 |~...?.......@...|
00000010 40 00 00 00 00 00 10 00 |@.......|
00000018

We’ll refer again to this on this subsequent code snippet. Per devicetree.org, in v0.4-rc1 of the Devicetree Specification, the soc/ranges property is outlined as follows:

The ranges property offers a way of defining a mapping or translation between the deal with house of the bus (the kid deal with house) and the deal with house of the bus node’s guardian (the guardian deal with house). The format of the worth of the ranges property is an arbitrary variety of triplets of (child-bus-address, parent-bus-address, size)

Within the case of the I/O Peripherals deal with block, as described within the Addressing section above, the “child-bus-address” refers back to the “I/O Peripherals” deal with block within the “VC CPU Bus Addresses” reminiscence house. The “parent-bus-address” refers back to the the “I/O Peripherals” deal with block within the “ARM Bodily Addresses” block. And the “size” refers back to the precise size of the “I/O Peripherals” deal with block. The Raspberry Pi 3B+ has a 32 bit deal with house so every of the values within the triple are 32 bits or 4 bytes.

This subsequent code snippet finds the parent-bus-address and size of the I/O peripherals block utilizing the info from /proc/device-tree/soc/ranges. Recall that the guardian bus deal with is the second entry within the triplet that additionally defines the kid bus deal with and size. Traces 1 through 4 shift the contents of the parent-bus-address, bytes at buf offsets 4 through 7, into base_address. 3F is shifted into the excessive order byte of base_address. The remaining buf cells are likewise shifted into base_address from left (most important) to proper (least vital byte). After shifting is full base_address will likely be set to 0x3F000000. Trying again on the diagram within the Addressing section above you’ll discover it doesn’t match the bottom deal with of 0x20000000 within the I/O Peripherals deal with block in ARM Bodily Addresses. It is because the diagram within the Addressing part is for the Raspberry Pi 1. This offset is totally different within the Raspberry Pi fashions 2 & 3. And it’s totally different but once more within the Raspberry Pi 4 mannequin.

Shifting on, in the same method to base_address, traces 6 to 9 get the size by shifting from buf offsets 8 through 11 into peri-size. For the Raspberry Pi 3B+, 0x01000000 is the anticipated size of the deal with block.

This subsequent code snippet completes acquiring the addressing info from /proc/device-tree/soc/ranges. Particularly it validates that the “child-bus-address” and “parent-bus-address” have the anticipated values. Recall that the “child-bus-address” is the primary worth within the addresses/size triplet, buf offsets 0 through 3. Traces 1 by way of 6 do the next:

  1. Traces 1 through 4 confirm that the primary 4 bytes of buf, the child-bus-address, is 0x7E000000 as outlined by the “I/O Peripherals”deal with block within the “VC CPU Bus Addresses” reminiscence house.
  2. Line 5 verifies that the parent-bus-address, base_address, matches one of many anticipated base addresses for Raspberry Pi fashions 1 through 4.

Traces 7 and eight then set the bottom deal with and size of the I/O Peripherals deal with block to the variables that will likely be utilized in the remainder of this system. The essential factor about this line is that it casts the supply variables to the categories anticipated by the goal variables.

This subsequent snippet maps the BCM2835’s “I/O Peripherals” deal with block within the “ARM Bodily Addresses” reminiscence house from /dev/memin order that it may be safely utilized in this system.

Line 1 first checks to see if the person working this system is working as root (both root person or sudo). If not, the /dev/mem machine can’t be used. /dev/mem offers unrestricted entry to the CPU’s reminiscence. As that is clearly a harmful factor to do its use is restricted to root. As chances are you’ll recall from the Addressing section, there’s an alternative choice to /dev/mem, /dev/gpio. This will likely be proven later on this part.

Line 4 opens /dev/mem in preparation to the mapping operation.

Line 13 assigns the bcm_peripherals variable to the offset and size, bcm_peripherals_base and bcm-peripherals_size, of the I/O Peripherals deal with block. This mapping successfully restricts this system’s entry to the I/O Peripherals deal with block of bodily reminiscence.

This subsequent code snippet calculates the offsets for the varied kinds of registers (e.g., GPIO, PWM, SPI, and so on). Every offset is relative to the worth of bcm_peripherals which was the results of a mapmem() operation within the earlier snippet. So to get the deal with of a register set just like the GPIO register set we might add BCM_GPIO_BASE to the bcm_peripherals base deal with. However you’ll have observed the code divides these offsets by 4 previous to including them to bcm_peripherals. These offsets, e.g., BCM_GPIO_BASE, that are specified as integers, level to particular byte addresses, i.e., at 8 bit boundaries. bcm_peripherals is specified as a uint32_t*, a pointer. You’ll be able to’t simply naively add an integer to a pointer. You might recall that pointer arithmetic operates on a pointer variable based mostly on the scale of the kind of the related variable. For unint32_t‘s their measurement is 32 bits or 4 bytes. Including 1 to a uint32_t pointer will end in that pointer pointing to the following uint32_t, which begins 4 bytes from the present place. Naively including offsets like BCM_GPIO_BASE to bcm_peripherals will end in bcm_peripherals pointing to a place in reminiscence that’s 4 uint32_ts previous the present place, not 1 uint32_t previous the present place which is what we would like. Which is why every register kind offset like BCM_GPIO_BASE is split by 4 previous to including it to bcm_peripherals.

If you happen to’re new to C you might not be conscious that pointer arithmetic is inherently harmful. It may be onerous to know precisely what a pointer will reference on account of pointer arithmetic. The pointer might be an sudden kind or have an sudden worth. This will result in sudden conduct which may be very tough to debug. In some instances, for instance performing division, pointing to an sudden place that comprises the worth zero will result in this system abruptly ending (with a segmentation fault). That is good, this fashion you understand one thing is fallacious and also you even know the place it went fallacious. A pointer could even level exterior this system’s deal with house this system which can result in system crashes. In our case nonetheless the register areas and related sorts are very well-known and utilizing pointers is comparatively protected. That’s, so long as we carry out pointer arithmetic appropriately…

bcm_fsel()

bcm_fsel is answerable for setting the I/O perform related for a given pin. There are a complete of 8 capabilities obtainable. One defines that the related pin is to be set as an enter pin that means that it is going to be learn from. One other perform defines the related pin as an output pin that means the pin will likely be written to. The remaining 6 are known as “alternate capabilities” and are given names like “alternate perform 0”. The I/O perform that’s assigned for the varied alternate capabilities is totally different for the varied GPIO pins. For instance, setting BCM GPIO pin 17 to alternate perform 4 defines its I/O perform to be SPI. It truly defines the pin to be a selected subset of SPI performance known as chip allow or chip choose, however that may be a subject for a later article. Recall that in important() above the perform is being set to BCM_GPIO_FSEL_OUTP which defines pin 17 to be an output pin.

There’s fairly a bit happening on this perform though it’s fairly quick.

Line 1 defines the perform as taking two parameters, pin and mode. It’s pretty apparent that pin the pin whose perform is to be assigned. mode is the I/O perform to affiliate with pin. mode is definitely a bit sample to be assigned to a specific register offset. The bit sample assignments are outlined within the The BCM2835 I/O Peripherals datasheet in part 6, GPIO. The patterns are outlined as follows:

000 = GPIO Pin X is an enter
001 = GPIO Pin X is an output
100 = GPIO Pin X takes alternate perform 0
101 = GPIO Pin X takes alternate perform 1
110 = GPIO Pin X takes alternate perform 2
111 = GPIO Pin X takes alternate perform 3
011 = GPIO Pin X takes alternate perform 4
010 = GPIO Pin X takes alternate perform 5

There may be some extra background wanted to grasp the remainder of the perform. First, The BCM2835 I/O Peripherals datasheet, part 6, exhibits {that a} complete of 54 GPIO pins are addressable through the perform choose registers (GPFSEL0-GPFSEL5). Every perform choose register is 32 bits lengthy. Since every of the perform choose patterns above is 3 bits lengthy every perform choose register can specify the I/O perform for 10 pins with 2 bits left over. Ten pins per register and a complete of 54 pins explains why there are 6 perform choose registers numbered 0 through 5. The maths that follows is derived from this info.

Line 3 defines the register offset, paddr, of the bits that will likely be set in response to mode. BCM_GPFSEL0 is the bottom offset, in bytes, of the perform choose registers. Right here’s an evidence of the arithmetic carried out on this line.

  1. Discover that pointer arithmetic is being carried out. Recall that the results of pointer arithmetic is predicated on the kind of the goal variable (see the bcm_init() part above). Since uint32_t‘s are 4 bytes lengthy BCM_GPFSEL0 must be divided by 4 for the calculation to return out appropriately. Therefore ... paddr = bcm_gpio + BCM_GPFSEL0/4 ....
  2. Additionally, recall that every register holds the perform choose info for 10 pins. For a given pin we have to decide which perform choose register, GPFSEL0 through GPFSEL5, specifies the I/O perform for a given pin. In C, the results of integer division that leads to a fraction will likely be rounded down. So if we divide the pin quantity by 10, (pin/10), we’ll get the offset to the right perform choose register. So pin 9 will end in 9/10 which equals 0, that means pin 9’s perform choose location is in GPFSEL0. Likewise, pin 17’s, 17/10 = 1, perform choose register is GPFSEL1. And so forth.

Taken collectively, the equation paddr = bcm_gpio + BCM_GPFSEL0/4 + (pin/10) leads to the perform choose register offset applicable for a given pin. For pin 17 this may end in paddr logically pointing to GPFSEL1 at deal with 0x7E20 0004, 7E being the bus deal with, 20004 being the offset of the GPIO registers plus the offset of GPFSEL1, 4, from the start of the GPIO register set. I say logically as a result of bcm_gpio is an offset from an deal with returned as the results of a mmap() operation. mmap() returns a pointer into the method’s digital reminiscence whereas 0x7E20 0004 is an deal with within the BCM2835’s VC CPU Bus Addresses house.

Line 4 calculates the placement throughout the perform choose register for given pin’s perform choose worth. Since we’ll use bit shifting to set the pin’s perform choose worth this location turns into the variety of bits to SHIFT the pin’s perform choose worth as supplied within the modeparameter. Constructing the calculation up we first want to search out the pin’s logical location, that’s, which 3 bit cell throughout the perform choose register (recall that every perform choose worth is 3 bits lengthy). The calculation for that is given by shift = (pin % 10) .... For pin 17 (pin % 17) = 7. So pin 17’s 3 bit cell is situated on the seventh 3-bit offset. Subsequent we’ve got to search out the precise bit offset throughout the register. Since every perform choose worth is 3 bits lengthy every pin’s boundary is a a number of of three, therefore the entire calculation of shift = (pin % 10) * 3. For pin 17 this leads to (17percent10)*3 which equals 7*3 which ends up in an absolute bit offset of 21. Consulting the BCM2835 I/O Peripherals datasheet, section 6, on web page 92, we will verify that pin 17’s offset throughout the GPFSEL0 register is in bit positions 21 through 23.

Now let’s take a look at line 5. When setting a subset of bits to a given worth we wish to protect the values of the encircling bits. A masks is used to perform this. The masks comprises a bit(s) that’s within the place of the bit within the goal worth that we wish to change. For instance, within the bit sample 0101 1111, if we wish to set bit 6’s worth from 1 to 0 we solely must outline a bit sequence with 1 bit set. To create probably the most normal resolution we might simply set the least vital bit(s). Since we solely want a single bit set we might outline the masks as hex quantity 0x1, which specifies the bit sample 0000 0001. Subsequent we have to shift this bit sample as required in order that the 1 bit is moved to the right place. In our instance, since we wish to change bit 6, we might left shift the masks sample 6 bits to the left, e.g., newMask = 0000 0001 << 6. This leads to newMask equaling 0100 00000, which is places the 1 bit in place 6 as we want. It’s doable that we may have outlined the masks as 0100 0000 outright, however this is able to not end in a normal resolution that may work for any masks wanted to set a bit(s) in an arbitrary bit place, comparable to bits 21-23.

As given in bcmfuncs.h the worth of BCM_GPIO_FSEL_MASK is 0x7 or 0000 0111, it’s because every GPIO perform choose sample is 3 bits lengthy. So it is a helpful bit sample for masking 3 bit sequences. If we shift this sample by the SHIFT of 21 as calculated in line 4 above we’ll get a 32 bit sample that appears like this, 0000 0000 1110 0000 0000 0000 0000 0000. The masks is now in bit areas 21-23, which is the placement of pin 17’s perform choose sample within the GPFSEL1 perform choose register.

In abstract, line 5 creates the masks wanted to set the three bit perform choose sample as specified within the mode parameter on the supplied pin parameter.

Line 6 creates the brand new 3 bit worth that will likely be positioned into the GPFSEL1 register. Recall that GPFSEL1 is a 32 bit register. To make use of a 3 bit worth comparable to mode to set a 3 bit sequence at an arbitrary place, e.g., bits 21-23, we create a price masks that units the bits within the desired place to the specified worth. As with the masks above, probably the most normal resolution specifies that these bits be set beginning within the least vital place. Let’s say in our instance we would like pin 17 to be set to alternate perform 1. Trying on the bit patterns above we will see that the three bit worth for alternate perform 1 is 101. The mode parameter will include this worth. To set pin 17 to alternate perform 1 we have to shift mode‘s bit sample of 0000 0101 21 bits to the left. As with line 5, line 6 does this in a normal manner, worth = mode << shift. Given our worth of mode and the calculated worth of shift we get the 32 bit worth of 0000 0000 1010 0000 0000 0000 0000 0000.

So we now have the 4 variables wanted to calculate the brand new worth of the GPFSEL1 register, paddr, mode, masks, and worth.

Line 7 calls the perform bcm_peri_set_bits() to finish this operation. This operation is completed in a separate perform since there are different register values that require setting as we are going to see later.

bcm_peri_set_bits()

bcm_peri_set_bits() is the perform that units a 32 bit sequence, v, to a brand new worth, worth, at place paddr, utilizing a masks as mentioned above. As with bcm_fsel(), this perform does fairly a bit in only a few traces of code.

Line 3 makes use of bcm_peri_read() to learn the 32 bit worth v situated at paddr. Extra on this later.

Line 4 units the v to its new worth. Recall that when a masks is used a subset of bits may be set whereas leaving the remaining bits unchanged. Line 4 does this in 3 steps. First it does a bitwise-AND operation, &, between the present worth v with the complement of masks. Taking the instance within the earlier part for BCM_GPIO_FSEL_MASK, it’s bit worth, for brevity simply bit positions 16 and 23, is reversed from ... 1110 0000 ... to ... 0001 1111 .... When the bitwise-AND happens between the the complemented masks and vas in (v & ~masks), solely the bits 21-23 of the unique worth v are modified and bits 21-23 are reset to 0s. The remaining bits are unchanged. If bits 16-23 of v have been initially set to ... 0100 1010 ..., the brand new worth of bits 16-23 will now appear to be ... 0000 1010 .... In our instance for pin 17 its perform choose bits have been reset to zeros. Word the bits in positions 16 through 20 are unchanged.

The subsequent operation, (worth & masks) solely retains the values of the bits at positions 21-23 of the brand new worth, worth, setting the remaining bits to 0. Bits 16-23 of worth are ... 1010 0000 ... which specifies pin 17 is is to be set to alternate perform 1. The results of the operation ... 1010 0000 ... & ... 1110 0000 ... is ... 1010 0000 ..., which is predicted. The operation is specified as (worth & masks)as a result of we will’t say forward of time that solely bits 21-23 are to be reset to worth. Each worth and masks may have bits set at different positions.

Placing this all collectively, the third and remaining step, (v & ~masks) | (worth & masks) will OR the two outcomes, ... 0000 1010 ... | ... 1010 0000 ... which ends up in v being reset to ... 1010 1010 .... Do not forget that solely bits 21-23 have been modified. That is proven right here by bits 16-20 retaining their earlier values. Likewise, the opposite bits of v will stay unchanged.

Line 5 the units the 32 bits at paddr to v through bcm_peri_write(). Extra on this later as effectively.

bcm_peri_read()

bcm_peri_read() will learn the 32 bits beginning at paddr and return them to the caller as a 32 bit worth. In contrast to bcm_fsel() and bcm_peri_set_bits() this perform is kind of easy.

Traces 4 and 6 synchronize entry to reminiscence in order that the learn can’t be interrupted.

Line 5 merely units the return worth, ret, to the contents situated at paddr.

bcm_peri_write()

bcm_peri_write() will write the 32 bits beginning at paddr to the worth contained in worth. Like bcm_peri_read() this perform is kind of easy.

Traces 3 and 5 synchronize entry (lock) to the 32 bits beginning at paddr.

Line 4 units the 32 bits situated at paddr to worth.

bcm_gpio_write()

bcm_gpio_write() writes the 32 bit worth to the required pin. It makes use of 2 helper capabilities, bcm_gpio_set() and bcm_gpio_clr(). The parameter on is used to specify if the worth for pin ought to be set or cleared. There are a set of 4 GPIO registers, GPSET0 and GPSET1, and GPCLR0 and GPCLR1, which specify if the worth of a pin is HIGH or LOW. HIGH corresponds to GPSETn. LOW corresponds to GPCLRn. When the worth of on is 1 the GPSETn register related to the worth of pin is about to 1. If on is about to 0 then the GPCLRn register related to the worth of pin is about to 1. GPSETn’s values are solely used when a pin’s I/O perform is about to OUTPUT. GPCLRn’s values are likewise solely used when a pin’s I/O perform is about to OUTPUT. Values of 0 in these registers are ignored. Recall that the BCM2835 permits GPIO capabilities to be specified for 54 pins (vs. the anticipated 40). Since every pin requires 1 bit to specify whether or not it’s to be set or cleared a complete of 54 bits is required. This explains why two 32 bit registers are wanted for set and clear.

Using these registers is additional described in part 6, web page 95, of the BCM2835 I/O Peripherals datasheet.

bcm_gpio_set() and bcm_gpio_clr()

bcm_gpio_set() and bcm_gpio_clr() are twins by way of their performance. They solely differ wherein registers they function on. *set() operates on the GPSETn registers and *clr() operates on the GPCLRn registers. They’re answerable for setting the suitable bit offset within the applicable register for the supplied pin argument. This part will solely describe bcm_gpio_set(). Aside from the register set operated on their implementations are similar. In actual fact, with the addition of one other parameter to specify the beginning offset they might be collapsed right into a single perform.

In bcm_gpio_set() line 3 calculates the deal with, paddr, of the goal register. bcm_gpio is the beginning offset of the GPIO registers. BCM_GPSET0 is the beginning offset of the set and clear registers. Recall from the dialogue within the bcm_init() part above that pointer arithmetic is used to find out the reminiscence offset to make use of for a given operation. This is the reason BCM_GPSET0 is split by 4 on this operation. pin/32 is used to calculate which of the GP*n registers is for use for the given pin. Recall that integer division at all times rounds down. So the results of pin 17/32 is 0 which specifies that the primary GP*n register will likely be used. That is per the BCM2835 ARM Peripherals information. And 0 is right within the calculation of the paddr due to the usage of integer arithmetic.

Line 4 calculates how massive of a shift is required to set the right bit related to pin within the GP*n register. Taking our instance of pin 17, 17percent32 is 17, which corresponds to bit 17 in GPSET0. Once more, per the BCM2835 ARM Peripherals information, that is the right offset throughout the right register.

Line 5 then makes use of bcm_peri_write() to shift 1, shift bits to the left, to be able to write to the right offset within the right register. From the calculation on line 4, 1 is shifted 17 bits to the left.

bcm_close()

bcm_close deallocates all sources and resets all GPIO offsets to their authentic values, MAP_FAILED on this case. With reference to MAP_FAILED, this worth prevents any extra operations on the BCM2835 peripheral registers.

Line 3 releases the reminiscence reserved by the mapmem() operation in bcm_init().

Traces 4–14 reset all of the register offsets to their default settings.

This text has supplied an in depth take a look at how you can work together immediately with the BCM2835’s peripherals registers, with out utilizing a third social gathering library, to make an LED blink. It first supplied an summary of the BCM2835’s ARM peripherals important ideas together with the kinds of I/O capabilities that function on exterior gadgets/peripherals, how the BCM2835 addressing works as a prerequiste for describing how you can work together with the BCM2835 registers to regulate exterior gadgets (like an LED). It then described the lab setup wanted to regulate an LED. Subsequent, it introduced the code, together with explanations of what the code is doing, utilized by the primary program. It completed up by presenting the code, with explanations, that interacts immediately with the BCM2835’s registers which can be related to varied kinds of peripherals.

At this level, you need to have a very good understanding of how you can immediately program the BCM2835 to regulate a wide range of peripheral sorts utilizing the varied I/O capabilities supported by the BCM2835. Whereas the low-level particulars for a selected I/O perform, e.g., SPI, could differ, the mechanics for programming the BCM2835 are the identical.

Preserve a watch out for my upcoming article titled “Raspberry Pi GPIO — Utilizing SPI to show alphanumeric characters on a MAX7219 Dot Matrix Show Module” which, amongst different issues, will display how you can management a dot matrix LED show utilizing solely low-level entry to the BCM2835 registers. It makes a pleasant companion to this text as it would introduce a brand new set of peripheral registers used to program the SPI I/O perform.

Feedbacks about this text are welcome.

More Posts