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 micro:bit'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.
Now On Sale!
You can now buy a print edition of micro:bit IoT in C.
You can buy it from:
The full contents can be seen below.
Getting Started With C/C++
Anyone who wants to use the BBC micro:bit to its full potential as an IoT device needs to look outside the coding environments provided by its own website. As an mbed device, however, the micro:bit is capable of being programmed in C/C++. Here we look at how to use the mbed online compiler for a simple demo program.
- Offline C/C++ Development
We have already discovered how to use the online editor to create a C/C++ program. Now we are going to move to the desktop with an offline approach. This has the advantage that we can use any tools we care to select and no Internet connection is needed.
First Steps With The GPIO
The most basic task when working with the micro:bit is controlling the I/O lines. This isn't difficult if you use the framework provided but there some subtle points to watch out for. This chapter looks a the basics of using the GPIO.
Working Directly With The Hardware - Memory Mapping.
The framework makes working with the GPIO and other devices as easy as it can be but there are many layers of software to go through before you get to the hardware. Writing directly to the hardware can make things up to ten times faster and give you access to things that their framework doesn't. It is also an educational experience to deal with the raw hardware directly.
Pulse Width Modulation, Servos And More
In this chapter we take a close look at pulse width modulation PWM including, sound, driving LEDs and servos.
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.
I2C Temperature Measurement
Using I2C devices is fairly easy once you have successfully used one - and hence know what information you need and what to look for in a working system. In this chapter we use the HTU21D temperature and humidity sensor as a case study of I2C in action. It also happens to be a useful sensor.
The 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.
SPI MCP3008/4 AtoD
The SPI bus can be difficult to make work at first but once you know what to look for about how the slave claims to work it gets easier. To demonstrate how its done let's add eight channels of 12 bit AtoD using the MCP3008.
The serial port is one of the oldest of ways of connecting devices together but it is still very, very useful. The micro:bit has a single serial interface but it can be directed to use any of the GPIO piins as Rx and Tx.
The micro:bit has a radio that works in Bluetooth LE and point-to-point ad-hoc mode, but at the moment it lacks WiFi connectivity. The solution is to use the low cost ESP8266 to make the connection via the micro:bit's serial port.
The micro:bit's LED display may only be 5x5 but it is very versatile. If you want to make use of it directly then you are going to have to master some lower level functions.
The GPIO lines at their most basic output function can be set high or low by the processor. How fast they can be set high or low depends on the speed of the processor.
Using the GPIO line in its Pulse Width Modulation (PWM) mode you can generate pulse trains up to 9.6MHz, i.e. pulses as short as just a little more than 0.1 microseconds.
The reason for the increase in speed is that the GPIO controls a pulse generator and once set to generate pulses of a specific type the pulse generator just gets on with it without needing any intervention from the GPIO line or the processor. In fact the pulse output can continue after your program has ended if you forget to reset it.
Of course, even though the PWM line can generate pulses as short as 0.1 microseconds, it can only change the pulses it produces each time that processor can modify it. For example, you can't use PWM to produce a single 0.1 microsecond pulse because you can't disable the PWM generator in just 0.1 microsecond.
Some Basic micro:bit PWM Facts
There are some facts worth getting clear right from the start, although some of the meanings will only become clear as we progress.
First what is PWM?
The simple answer is that a Pulse Width Modulated signal has pulses that repeat at a fixed rate - say one pulse every millisecond but the width of the pulse can be changed.
There are two basic things to specify about the pulse train that is generated - its repetition rate and the width of each pulse. Usually the repetition rate is set as a simple repeat period and the width of each pulse is specified as a percentage of the repeat period the duty cycle.
So for example a 1ms repeat and a 50% duty cycle specifies a 1ms period which is high for 50% of the time i.e. a pulse width of 0.5ms. The two extremes are 100% duty cycle i.e. the line is always high and 0% duty cycle i.e. the line is always low.
What this means is that generally you select a repeat rate and stick to it and what you change as the program runs is the duty cycle.
In many cases PWM is implemented using special PWM generator hardware that is built either into the processor chip or provided by an external chip. The processor simply sets the repeat rate by writing to a register and then changes the duty cycle by writing to another register. This generally provides the best sort of PWM with no load on the processor and generally glitch free operation. You can even buy addon boards that will provide additional channels of PWM without adding to the load on the processor.
The alternative to dedicated PWM hardware is to implement it in software. You can quite easily work out how to do this. All you need is to set a timing loop to set the line high at the repetition rate and then set it low again according to the duty cycle. You can implement this either using interrupts or a polling loop.
In the case of the micro:bit the PWM lines are not implemented using special PWM hardware. What happens is that a general purpose facility - the GPIOTE and the PPI - to allow the GPIO lines to trigger events and respond to tasks is used. The software sets things up so that the system timer automatically toggles the specified GPIO line a the selected repetition rate and duty cycle. This works, saves the processors time but it is sophisticated and at times a little difficult to use.
You can use the three "main" GPIO lines - P0, P1 and P2 for PWM. You can also use P3, P4 and P10 but as these are also connected to the LED display these also make the LED's flash - more of which in the chapter on the LED display. For the moment we will concentrate on using P0, P1 and P2.
As a single timer is used the repetition rate is shared between all of the GPIO lines being used as PWM outputs. That is all PWM lines operate at the same frequency - i.e. the last frequency set.
You can however set different duty cycles for each of the PWM lines you are using.
You can set the repetition rate in multiples of 4 microseconds i.e. the timer tick is 4 microseconds.
The fastest pulse repetition rate you can specify is 1 microsecond but this gives a 27 microsecond repeat rate.
The slowest is 0.262 seconds. That is you can't use a PWM line to flash an LED once every second.
As you can guess - there are no PWM inputs, just 6 outputs. If for some reason you need to decode or respond to a PWM input then you need to program it using the GPIO input lines and the pulse measuring techniques introduced in the previous chapters. If you are really ambitious you could use the GPIOTE and PPI facilities to automatically analyze the incoming PWM signal. Again you would use the timer to record the repetition rate and duty cycle.
The micro:bit framework attempts to provide PWM in easy to use forms. It provides functions which target the two main uses of PWM - DtoA conversion and controlling servo motors. More about both topics later in the chapter.
Instead of letting you specify a repeat rate and duty cycle the framework provides two sets of functions one for working with an analog output and one for working with a servo.
Of the two the analog output functions are the simplest and the most direct. The servo functions are best described later in connection with implementing a servo driver.
You can set the repeat period using either:
int setAnalogPeriod(int period) int setAnalogPeriodUs(int period)
the first sets the period in milliseconds and the second works in microseconds.
The next function sets the duty cylce - but not in an obvious way:
int setAnalogValue(int value)
The value can be anything between 0 and 1023 with 0 corresponding to a duty cycle of 0% and 1023 corresponding to 100%.
There one small detail that you have to be aware of. The setAnalogValue function also sets up the pin for analog output if it already isn't set up. What this means is that you have to set an analog value before you set an analog period.
Three are also two utility functions that let you read the current set period:
int getAnalogPeriod(int period) int getAnalogPeriodUs(int period)
You can use these functions on P0, P1, P2, P3, P4 and P10 but, as already noted P2,P4 and P10 are connected to the LED display and are best avoided if possible for general PWM work.
Although you can set the repeat rate down to 1 microsecond the PWM mechanism has a smallest time of around 27 microseconds and the timer tick is 4 microseconds making this the maximum precision.
Set Actual microseconds 1 27 10 27 30 35 100 107 500 507 1000 1007
The longest time you can set is around 262 milliseconds corresponding to the longest time a 32 bit timer running at 4 microseconds per tick can count to.
You could get different maximum and minimum rates by programming the timer yourself - but this is a difficult problem.
- Next >>