Article Index

There is no doubt that input is more difficult than output. When you need to drive a line high or low you are in command of when it happens but input is in the hands of the outside world. If your program isn't ready to read the input or if it reads it at the wrong time then things just don't work. What is worse is that you have no idea what your program was doing relative to the event you are trying to capture - welcome to the world of input.

 

 

 

Now On Sale!

You can now buy a print or ebook edition of Raspberry Pi IoT in C from Amazon.

 

For Errata and Listings Visit: IO Press

 

 

This our ebook on using the Raspberry Pi to implement IoT devices using the C programming language. The full contents can be seen below. Notice this is a first draft and a work in progress. 

Chapter List

  1. Introducing Pi (paper book only)

  2. Getting Started With NetBeans In this chapter we look at why C is a good language to work in when you are creating programs for the IoT and how to get started using NetBeans. Of course this is where Hello C World makes an appearance.

  3. First Steps With The GPIO
    The bcm2835C library is the easiest way to get in touch with the Pi's GPIO lines. In this chapter we take a look at the basic operations involved in using the GPIO lines with an emphasis on output. How fast can you change a GPIO line, how do you generate pulses of a given duration and how can you change multiple lines in sync with each other? 

  4. GPIO The SYSFS Way
    There is a Linux-based approach to working with GPIO lines and serial buses that is worth knowing about because it provides an alternative to using the bcm2835 library. Sometimes you need this because you are working in a language for which direct access to memory isn't available. It is also the only way to make interrupts available in a C program.

  5. Input and Interrupts
    There is no doubt that input is more difficult than output. When you need to drive a line high or low you are in command of when it happens but input is in the hands of the outside world. If your program isn't ready to read the input or if it reads it at the wrong time then things just don't work. What is worse is that you have no idea what your program was doing relative to the event you are trying to capture - welcome to the world of input.

  6. Memory Mapped I/O
    The bcm2835 library uses direct memory access to the GPIO and other peripherals. In this chapter we look at how this works. You don't need to know this but if you need to modify the library or access features that the library doesn't expose this is the way to go. 

  7. Near Realtime Linux
    You can write real time programs using standard Linux as long as you know how to control scheduling. In fact it turns out to be relatively easy and it enables the Raspberry Pi to do things you might not think it capable of. There are also some surprising differences between the one and quad core Pis that make you think again about real time Linux programming.

  8. PWM
    One way around the problem of getting a fast response from a microcontroller is to move the problem away from the processor. In the case of the Pi's processor there are some builtin devices that can use GPIO lines to implement protocols without the CPU being involved. In this chapter we take a close look at pulse width modulation PWM including, sound, driving LEDs and servos.

  9. I2C Temperature Measurement
    The I2C bus is one of the most useful ways of connecting moderately sophisticated sensors and peripherals to the any processor. The only problem is that it can seem like a nightmare confusion of hardware, low level interaction and high level software. There are few general introductions to the subject because at first sight every I2C device is different, but here we present one.

  10. A Custom Protocol - The DHT11/22
    In this chapter we make use of all of the ideas introduced in earlier chapters to create a raw interface with the low cost DHT11/22 temperature and humidity sensor. It is an exercise in implementing a custom protocol directly in C. 

  11. One Wire Bus Basics
    The Raspberry Pi is fast enough to be used to directly interface to 1-Wire bus without the need for drivers. The advantages of programming our own 1-wire bus protocol is that it doesn't depend on the uncertainties of a Linux driver.

  12. iButtons
    If you haven't discovered iButtons then you are going to find of lots of uses for them. At its simples an iButton is an electronic key providing a unique coce stored in its ROM which can be used to unlock or simply record the presence of a particular button. What is good news is that they are easy to interface to a Pi. 

  13. The DS18B20
    Using the software developed in previous chapters we show how to connect and use the very popular DS18B20 temperature sensor without the need for external drivers. 

  14. The Multidrop 1-wire bus
    Some times it it just easier from the point of view of hardware to connect a set of 1-wire devices to the same GPIO line but this makes the software more complex. Find out how to discover what devices are present on a multi-drop bus and how to select the one you want to work with.

  15. SPI Bus
    The SPI bus can be something of a problem because it doesn't have a well defined standard that every device conforms to. Even so if you only want to work with one specific device it is usually easy to find a configuration that works - as long as you understand what the possibilities are. 

  16. SPI MCP3008/4 AtoD  (paper book only)

  17. Serial (paper book only)

  18. Getting On The Web - After All It Is The IoT (paper book only)

  19. WiFi (paper book only)

 

GPIO Input

GPIO input is be a much more difficult problem than output from the point of view of measurement and verification. At least for output you can see the change in the signal on a logic analyzer and know the exact time that it occurred. This makes if possible to track down timing problems and fine tune things with good accuracy. 

Input on the other hand is "silent" and unobservable. When did you read in the status of the line? Usually the timing of the read is with respect to some other action that the device has taken. For example, read the input line 20 microseconds after setting the output line high.

The usual rule of thumb is to assume that it takes as long to read a GPIO line as it does to set it. This means we can use the delay mechanisms that we looked at with output in mind for input. 

One common and very useful trick when you are trying to get the timing of input correct is to substitute and output command to a spare GPIO line and monitor it with a logic analyzer. Place the output instruction just before the input instruction and where you see the line change on the logic analyzer should be close to the time that the input would be read in the unmodified program. You can use this to debug and fine tune and then remove the output statement.

In some applications the times are long and/or unimportant but in some they are critical.

The Basic Input Functions

We have already met the function that sets a GPIO line to input or output:

void bcm2835_gpio_fsel(uint8_t pin,uint8_t mode)

To set the GPIO line of your choice to input simply use BCM2835_GPIO_FSEL_INPT for  the mode.  

Once set to input the GPIO line is high impedance, it wont take very much current no matter what you connect it to, and you can read its input state using:

uint8_t bcm2835_gpio_lev(uint8_t pin)

This is all there is to using GPIO line as an input - apart from the details of the electronics and the small matter of interrupts.

Basic Input Circuit - The Switch

One of the most common input circuits is the switch or button.  If you want another external button you can use any GPIO line and the following circuit:

The 10K resistor isn't critical in value. It simply pulls the GPIO line high when the switch isn't pressed. When it is pressed a current of a little more than 0.3mA flows in the resistor. If this is too much increase the resistance to 100K or even more - but notice that the higher the resistor value the noisier the input to the GPIO and the more it is susceptible to RF interference.  

If you want a switch that pulls the line high instead of low, to reverse the logic just swap the positions of the resistor and the switch in the diagram. 

Although the switch is the simplest input device it is also very difficult to get right. When a user clicks a switch of any sort the action isn't clean - the switch bounces. What this means is that the logic level on the GPIO line goes high then low and high and bounces between the two until it settles down. There are electronic ways of debouncing switches but software does the job much better. All you have to do is but a delay of a millisecond or so after detecting a switch press and read the line again - if it is still low then record a switch press. Similarly when the switch is released read the state twice with a delay. You can vary the delay to modify the perceived characteristics of the switch.

A more sophisticated algorithm is based on the idea of integration to debounce a switch. All you have to do is read the state multiple times, every few milliseconds say. and keep a running sum of values. If say you read the switch 10 times then a running sum of 6 to 10 can be taken as an indication that the switch is high and less than this that the switch is low. 

The Potential Divider

If you have an input that is outside of the range of 0 to 3.3V then you can reduce it using a simple potential divider. 

 V is the input from the external logic and Vout it the connection to the GPIO input line:

voltageDiv

 

You can spend a lot of time on working out good values of R1 and R2. For loads that take a lot of current you need R1+R2 to be small and divided in the same ratio as the voltages.

For example for a 5V device R1=18K and R2=33K work well to drop the voltage to 3.3V.

The problem with a resistive divider is that it can round off fast pulses due to the small capacitive effects. This usually isn't a problem, but if it is then the solution is to use an FET buffer again. 

hilodrive

Notice that this is an inverting buffer but you can usually ignore this and simply correct in software i.e. read a 1 as a low and a 0 as a high state. The role of R1 is to make sure the FET is off when the 5V signal is absent and R2 limits the current in the FET to about 0.3mA.

In most case you should try the simple voltage divider and only move to an active buffer if it doesn't work.