Skip to content
This repository has been archived by the owner on Jul 8, 2020. It is now read-only.
Brian Innes edited this page Dec 22, 2017 · 6 revisions

There is no configuration information on this page - it is provided as background on how GPIO works for TobyJnr and explains why the audio socket cannot be used.

GPIO (General Purpose Input and Output) allows you to control if the pins of the 40 pin header are high or low (on or off). Some ping have a specific purpose, such as being 5V, 3.3V or GND, whilst others can have multiple functions, such as UART, I2C and SPI, which are different communication technologies the allow the raspberry pi to communicate with other components or systems.

For TobyJnr the wiring was set by the TJBot project, and uses pins 12 and 26 for the LED data and Servo data lines.

Problems with driving GPIO from Linux

The Raspbian operating system that run the Raspberry Pi is based on Debian Linux. Part of the function of an operating system, such as Linux, is to schedule work on the processing unit (CPU).

Within the Raspberry Pi there are typically a lot of processes all trying to get time on the CPU, such as the drivers for the various hardware components (Ethernet, WiFi, Bluetooth, HDMI video output, SD Card, USB port drivers, ....) and the various software services (such as SSH, VNC servers so you can remotely connect, the many processes that drive the Graphical User Interface, services to ensure the time is correct, ...).

Along side the various system services and drivers you want to run applications, such as a Terminal window, the browser and additional background services, such as Node-RED.

To see all the different activities running on your pi run the command: ps -eL
Running the command on my Pi I see there are 236 different tasks active in the system.

The Linux Kernel tries to ensure all the competing tasks get their turn on the CPU, but this can cause issues when you want to drive GPIO, as some components, such as the LED and Servo motor require very strict timing to drive them, and you cannot directly control the Linux schedules from a user application to guarantee your application will run when required to achieve accurate timing. Timing is not always critical when driving GPIO pins, but for some components timing is critical, such as the LED and Servo used in TobyJnr, as there is only a single data wire and the protocol relies on very precise timing, I'll explain each of the device protocols below.

The Broadcom chip that drives the Raspberry Pi also has some built in hardware that implements some functionality in hardware, rather than relying on the CPU to have to drive the pins high and low, one such capability is on pin 12, which is PWM (Pulse Width Modulation). This allows software to define the required timing, then the hardware takes over and ensures accurate timing when driving the pin between high and low states.

PWM channels on the Raspberry Pi

The Raspberry Pi has 2 PWM channels, each channel can be surfaces on 1 of 2 possible pins on the 40 pin header. Out of the box the Raspberry Pi uses both PWM channels to generate an analog audio signal for the audio socket on the Pi. If you need to use PWM for other hardware, then the PWM is no longer available for audio and the audio output via the 3.5mm socket is no longer available. For TobyJnr a PWM channel is needed for the RGB LED, which is why the audio socket cannot be used to connect a speaker.

Driving the RGB LED

The LED used in TobyJnr is based on the WS2812B chip, which is embedded in the LED. This chip controls the output of 3 separate LEDs (Red, Green and Blue) but allows a very simple protocol to drive the LED, using a single data connection.

The RGB LED requires 24 bits of information (8-bits for each of the individual coloured LEDs), which sets the intensity of the Red, Green and Blue LEDs to enable any colour to be created from the RGB LED. Each bit of data relies on accurate timing between High and Low signals on the data line:

bit value of Zero(0) requires the data line to be high for 350 nanoseconds, then low for 900 nanoseconds
bit value of One(1) requires the data line to be high for 900 nanoseconds, then low for 350 nanoseconds
1 nanosecond = 1/1,000,000,000 seconds and there is a 150 nanosecond tolerance in timing.

A Raspberry Pi 3 model B usually runs a 1.2GHZ, so 1 clock pulse is 0.8 nanoseconds, so you can see why it can be difficult for an application running on a Pi to generate timing reliable to within 150 nanoseconds, when relying on the Linux scheduler to run your application along with the many other tasks needing CPU time, so the RGB LED is connected to one of the PWM channels which uses hardware to generate accurate timing.

Driving the Servo

Like the LED the servo is driven using timing between high a low signals on the data line. The angle that the servo is at is dependant on the time the signal remains high. Typically a servo runs with a 20 millisecond cycle (length of time signal is high + length of time signal is low), so every 20 milliseconds the line should become high after low, then the angle the servo motor is set to is controlled by the amount of the 20 milliseconds the data line remains hight, typical values are 0.5 milliseconds to 2.5 milliseconds.

If the timing is not maintained accurately enough then the servo becomes jittery, constant small movements around the desired angle, which is not desirable.

Often a servo is connected to a PWM hardware controlled data pin, so very accurate timing signals are used and the servo is very stable, with no jitter, but on TJBot and hence TobyJnr the servo is not connected to the seconds available PWM channel on the raspberry Pi.

It is possible to drive the servo using software, but that is not ideal as scheduling delays of the application can result in servo jitter.

On TobyJnr I use an additional service on the Raspberry Pi, which you set up earlier. Gpiod, which is a GPIO daemon. The gpiod service provides an alternative hardware assisted mechanism for providing a reliable timing signal for the servo and is supported in Node-RED using a node, which you installed in the earlier setup step.