Article Index

How Fast Can We Measure?

The simplest way to find out how quickly we can take a measurement using the micro:bit is to perform a pulse width measurement using a busy wait. Apply in square wave to P0 we can measure the time that the pulse is high using:

   uBit.init();
   uint32_t start;
   volatile int i;
   while (1) {
      while(1== uBit.io.P0.getDigitalValue());
      while(0== uBit.io.P0.getDigitalValue());
      for(i=0;i<1000;i++){
       if(0==uBit.io.P0.getDigitalValue()) break;
      }
      printf("%d\n\r",i);
   }

This might look a little strange at first. The inner while loops are responsible for getting us to the right point in the waveform. First we loop until the line goes low, then we loop until it goes high again and finally measure how long before it goes low. You might think that we simply have to wait for it to go high and then measure how long till it goes low but this misses the possibility that the signal might be part way though a high period when we first measure it.

If you run this program with different pulse widths the result are very regular:

(y axis loop count x axis pulse time)

The equation relating time t and loop count n is:

t=4.88 n +3.38 microseconds

This works down to about 10 microseconds or slightly less. 

If you want to record the time in microseconds rather than using a loop count then you could use:

    uBit.init();
    uint32_t t;
    volatile int i;
    while (1) {
          while(1== uBit.io.P0.getDigitalValue());
          while(0== uBit.io.P0.getDigitalValue());
          t = us_ticker_read();
          for(i=0;i<1000;i++){
           if(0==uBit.io.P0.getDigitalValue()) break;
          }
          t= us_ticker_read()-t;
          printf("%d,%ld\n\r",i,t);
        }

This is accurate to around 10 microsecond. 

Notice that in either case if you try measuring pulse widths much shorter than the lower limit that works you will get results that look like longer pulses are being applied. The reason is simply that the micro:bit will miss the first transition to zero but will detect a second or third or later transistion. This is the digital equivalent to of the aliasing effect found in the Fourier Transform or general signal processing. 

Interrupts

There is a general feeling that realtime programming and interrupts go together and if you are not using an interrupt you are probably doing something wrong. In fact the truth is that if you are using an interrupt you probably are doing something wrong. Some organizations agree with the general idea that interrupts are dangerous so much that they are banned from being used at all - and this includes realtime software. 

In the case of the micro:bit we have a system of events that stand in as a software wrapping of the raw system interrupts that are available if you dig just a little deeper. 

As far as GPIO lines are concerned you can set an event to occur on any of the following:

MICROBIT_PIN_EVENT_ON_EDGE  fire on rising or falling edge you can specify which when you register the event.
MICROBIT_PIN_EVENT_ON_PULSE fire if pin is high or low you can set high or low to fire when you register the event. 
MICROBIT_PIN_EVENT_ON_TOUCH fire if pin touched
MICROBIT_PIN_EVENT_NONE disable events for this pin

The most commonly useful is the on-edge setting which fires and event if a GPIO line transitions from high to low or low to high. You can set the event type using the

int eventOn(int eventType)

As well as the eventOn setting you also have to register the event with the messagebus. You have to supply the, id of the pin generating the event, the event type, the function to be called when the event happens and how the event should be handled. For example

bus.listen(MICROBIT_ID_IO_P0, MICROBIT_PIN_EVT_PULSE_HI, onPulse, MESSAGE_BUS_LISTENER_IMMEDIATE)

will call onPulse when the PULSE HI event occurs on pin P0 and it will call the event handler at once.  The even types that you can specify are:

MICROBIT_PIN_EVT_RISE
MICROBIT_PIN_EVT_FALL
MICROBIT_PIN_EVT_PULSE_HI
MICROBIT_PIN_EVT_PULSE_LO

The event handler has the signature:

void eventHandler(MicroBitEvent evt)

and one of the most useful properties of the evt object is the timestamp of the event.

Events are only really useful when you have a low frequency condition that needs to be dealt with on a low priority basis. Their use can simplify the logic of your program but rarely does using an event speed things up because the overhead involved in event or interrupt handling is usually quite high. 

For example suppose you want to react to a doorbell push button. You could write a polling loop that simply checks the button status repeatedly and forever - or you could write an event to respond to the doorbell. How good a design this is depends on how much the doorbell press event has to interact with the rest of the program.

Finally before you dismiss the idea of having a micro:bit do nothing but ask repeatedly "is the doorbell pressed" - what else has it to do? 

If the answer is "not much" then a polling loop might well be your simplest option. 

Let's find out how much overhead is inherent in using events by repeating the pulse width measurement. This time we can't simply print the results as this would stop the event handling. As a compromise we save 20 readings in an array and then print them. It is also important to keep the event handling routines short as how long they take to complete. If the event handling routine takes longer then the pulse width that can be measured is longer. 

 

uint64_t t[20];
uint64_t temp=0;
int i=0;
 void onPulseEdge(MicroBitEvent evt) 
 { 

  t[i]=(evt.timestamp-temp);
  i++;
  temp = evt.timestamp; 
    if(i<20)return;
     uBit.io.P0.eventOn(MICROBIT_PIN_EVENT_NONE);
    for(i=1;i<20;i++){
        printf("%d\n\r",(int)t[i]);  
    }
 }

int main() {
    uBit.init();   
     uBit.messageBus.listen(MICROBIT_ID_IO_P0, MICROBIT_PIN_EVT_RISE , onPulseEdge, MESSAGE_BUS_LISTENER_IMMEDIATE) ;
      uBit.messageBus.listen(MICROBIT_ID_IO_P0, MICROBIT_PIN_EVT_FALL , onPulseEdge, MESSAGE_BUS_LISTENER_IMMEDIATE) ;
          uBit.io.P0.eventOn(MICROBIT_PIN_EVENT_ON_EDGE);
     

Notice we have event handler called when there is a rising edge and a falling edge. 

This records accurate times for pulses longer than 250 microseconds but starts to miss pulses as the pulse width shortens to 100 microsecond. At 100 microseconds it misses about one pulse in ten. If the event handlers took longer to do their task then the limit would be even larger. 

Events are great for handling things that happened on the scale of 100s of microseconds and preferably 1ms. 

Also notice that the documentation says that the shortest pulse that can be reliably detect, i.e. will fire a MICROBIT_PIN_EVENT_ON_PULSE event is 85 microseconds.

Events are only useful if the time that the event handler takes plus the overheads of servicing an event is less than the average repetition rate of the event.

Where Next?

Now that we have explored many of the ideas in using the GPIO lines for output and input the next question is can we do better by access the hardware directly. 

This is not necessary for most applications but when it is there really is no other way to do the job. 

 

Now On Sale!

You can now buy a print edition of micro:bit 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 

 

 The full contents can be seen below. 

Chapter List

  1. 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.

  2. 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.
  3. 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.

  4. 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.

  5. 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.

  6. I2C
    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.

  7. 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.

  8. A Custom Protocol - The DHT11/22

  9. The DS18B20 - One Wire Bus

  10. 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. 

  11. 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.

  12. Serial Connections
    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. 

  13. WiFi 
    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. 

  14. LED Display 
    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.

 

More Information

developer.mbed.org

http://lancaster-university.github.io/microbit-docs/

Related Articles

The BBC Micro:bit Is An Mbed Device In C/C++ 

Commando Jump Game For The Micro:bit In Python 

BBC Micro To micro:bit 

 

 

 

 

comments powered by Disqus