Non-Inverting Drivers

The software solution to driving a servo via a simple inverting buffer is elegant if slightly messy when it comes to computing the duty cycle needed.

The traditional solution is to use two transistors to create a non-inverting buffer:

 

There is a way to use a single transistor as a non-inverting buffer using a common base configuration: 

In this variation on a common base mode the transistor's base is connected to the 3.3V line  and its collector to the 5V supply. Note that the two power supplies have to share a common earth.

If the GPIO output is low then R6 sets the  base emitter voltage to 0.6V and the transistor is hard on, pulling the output to the servo low.

If the GPIO output is high the base emitter voltage is zero and the transistor is cut off, making the output to the servo high. 

You can see that this is non-inverting, but the problem is that the current that flows through R7 is also the emitter current, which is the current the GPIO line has to sink. What this means is that the current in R7 is limited to around 1mA and this circuit provides no amplification. Of course you could add another transistor to provide current amplification but in this case you would be better off going back to the standard 2-transistor arrangement. 

This circuit does, however, work with most servos so in this role it is useful. The current in the GPIO line is 1mA and this is well within the drive power of a standard GPIO line.

Here is a "non-inverted" version of the test program given earlier. The range of duty cycle is limited to  make sure it works with all servos. Change the range or center value to make it work with your servo:

  if (!bcm2835_init())
        return 1;
    bcm2835_gpio_fsel(18, BCM2835_GPIO_FSEL_ALT5);
    bcm2835_pwm_set_clock(375);
    bcm2835_pwm_set_mode(0, 1, 1);
    bcm2835_pwm_set_range(0, 1024);

    for(;;){
     bcm2835_pwm_set_data(0,30);
     bcm2835_delayMicroseconds(2000000);
      bcm2835_pwm_set_data(0, 70);
      bcm2835_delayMicroseconds(2000000);
      bcm2835_pwm_set_data(0, 110);
      bcm2835_delayMicroseconds(2000000);
    }

  

What Else Can You Use PWM For?

PWM lines are incredibly versatile and it is always worth asking the question "could I use PWM?" when you are considering almost any problem. 

The LED example shows how you can use PWM as s power controller. You can extend this idea to a computer controlled switch mode power supply. All you need is a capacitor to smooth out the voltage and perhaps a transformer to change the voltage.

You can also use PWM to control the speed of a DC motor and if you add a simple bridge circuit you can control its direction and speed. 

Finally, you can use a PWM signal as a modulated carrier for data communications. For example, most infrared controller make use of a 38KHz carrier, which is roughly a 26 microseconds. This is switched on and off for 1ms and this is well within the range that the PWM can manage. So all you have to do is replace the red LED in the previous circuit with an infrared LED and you have the start of a remote control or data transmission link.

Some Hardware Details

Advanced Topic

The PWM hardware is more complicated than what is required just to produced a simple PWM signal. It also has a serialize mode which can clock a 32 bit word out of a register to create a pulse train with the characteristic you require. To make this even more useful it also supports the use of DMA to keep the serialization queue full. These features are beyond the scope of this book but if you understand how things work they are not difficult to use. 

The PWM has a large number of registers associated with it.

A control register and status register for both channels and a pair of data and range registers for each channel, plus a DMA and a FIFO register for serialization. 

The offsets from bcm2835_pwm as word addresses are:

BCM2835_PWM_CONTROL 0
BCM2835_PWM_STATUS  1
BCM2835_PWM_DMAC    2
BCM2835_PWM0_RANGE  4
BCM2835_PWM0_DATA   5
BCM2835_PWM_FIF1    6
BCM2835_PWM1_RANGE  8
BCM2835_PWM1_DATA   9

There is also a single clock which has the same registers as the GP clocks described in the previous chapter with word offset from bcm2835_clk given by:

BCM2835_PWMCLK_CNTL     40
BCM2835_PWMCLK_DIV      41

You can look up the details of the control and status registers and write your own functions to make use of the addition modes of operation. 

One easy to implement and useful addition is to modify the PWM clock source and rate. The function given at the end of the previous chapter is easy to modify to work with the PWM clock:

void bcm2835_pwm_set_clock_source(
          uint32_t source, 
          uint32_t divisorI,
          uint32_t divisorF) {
if (bcm2835_clk == MAP_FAILED
      || bcm2835_pwm == MAP_FAILED)
  return;
divisorI &= 0xfff;
divisorF &= 0xfff;
source &= 0xf;
uint8_t mask = bcm2835_peri_read(
  bcm2835_clk + BCM2835_PWMCLK_CNTL) & 0xffffffef;
bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, 
   BCM2835_PWM_PASSWRD | mask);
while ((bcm2835_peri_read(bcm2835_clk + BCM2835_PWMCLK_CNTL) & 0x80) != 0) {};
bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_DIV, BCM2835_PWM_PASSWRD | (divisorI << 12) | divisorF);
bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | source | 0x200);
bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x210 | source);
}

This works in the same way as the previous function. If first disables the clock, then sets the new divisor and source and then enables the clock again.

If you use PLLD then the clock can be as high as 500MHz. This allows you to set a range of 256 and get an effective repeat frequency of 1.9MHz which means you can get a PWM sample every half a microsecond. 

Repeating the previous triangle wave generator given earlier but at this new frequency pushes the upper limit on audio generation using this method to around 20KHz. 

  bcm2835_gpio_fsel(18, BCM2835_GPIO_FSEL_ALT5);
  bcm2835_pwm_set_clock_source(6, 2, 0);
  bcm2835_pwm_set_mode(0, 1, 1);
  bcm2835_pwm_set_range(0, 256);
  int i;
   for (;;) {
    for (i = 0; i < 256; i = i + 10) {
       bcm2835_pwm_set_data(0, i);
       bcm2835_delayMicroseconds(2);
    }
   }

Using the same filter circuit given earlier the output looks a better when you take into account the frequency is now 20KHz:

 

There are more sophisticated coding methods that can create higher quality audio than this simple approach. However this is at least gives you the basic tools to do the job. 

 

 

 

 

 

Now On Sale!

You can now buy a print edition of Raspberry Pi IoT in C

You can buy it from:

USA and World   Amazon.com
Canada              Amazon.ca
UK                     Amazon.co.uk
France               Amazon.fr
Germany            Amazon.de
Spain                 Amazon.es
Brazil                  Amazon.br
Italy                    Amazon.it
Japan                 Amazon.co.jp
Mexico               Amazon.com.mx 

 

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)

 

 

comments powered by Disqus