Faster firmware ideas

The current firmware is quite slow in various situations.

We’ve speeded up things a lot by reducing the time for various sleeps in the code, and rather catching i2c exceptions and retrying and things like that, but even so, there are quite a lot of things where it has to take absolutely ages due to the firmware design, such as ultrasonic read. Analog read is not super fast either. Our modified grovepi.py is much faster, but even so, students find that it is not fast enough to do some of their ideas.

I had some thoughts on this, and there are various things that could be done,

Implement an optional value caching mode - complex change
1)The first time that a sensor is read, the value is read, then returned once it is done.
2)The sensor is then added to a list of sensors to poll repeatedly.
3)In the main loop, it cycles round the already read pins, doing those particular reads, and then putting them into a cache.
4)Next time the sensor is read, just the cache value is returned.

Ultrasonic read done with pin change interrupts
Ultrasonic read currently uses pulsein, which means it stalls for the full time the pulse is sent out.

If this cache mechanism as described above was implemented, ultrasonic read could be done using pinchange interrupts instead. This would mean that it would be practical to use multiple ultrasonic rangers on one grovepi, whereas currently the sampling rate is very very slow, making it much less usable for robotics applications.
http://playground.arduino.cc/Main/PinChangeIntExample

Return error value on non-finished sensor read - simple change
Currently, when you do i2c read on the grovepi, it returns the contents of b. So if you send a command, and call i2c read before it is finished, it returns old data (or dodgy data if the length is wrong). So you have to sleep for the maximum length of time that a command might take.

In b, there is conveniently an extra pointless byte in the data (b[0]) which is currently unused. If in senddata() it set this to 0xff at the end, then in each of the command handlers, it set it to 0x00 when the data is ready, then rather than sleep for the maximum length of time, the python code could poll until 0x00 was returned. This would make ultrasonic read a lot faster in cases where something is in front of the sensor, and analog read could be faster too. It’d be a one line change in sendData, and a line everywhere that b is written.

void sendData()
{
  if(cmd[0] == 1)
    Wire.write(val);
  if(cmd[0] == 3 || cmd[0] == 7 || cmd[0] == 56)
    Wire.write(b, 3);
  if(cmd[0] == 8 || cmd[0] == 20)
    Wire.write(b, 4);
  if(cmd[0] == 30 || cmd[0] == 40)
    Wire.write(b, 9);
  b[0]=0xff;// EXTRA LINE TO SET ERROR VALUE FOR NEXT READ
}

//Analog Read
    if(cmd[0]==3)
    {
      aRead=analogRead(cmd[1]);
      b[1]=aRead/256;
      b[2]=aRead%256;
      b[0]=0x00; // EXTRA LINE TO SET SUCCESSFUL READ VALUE
                 // SET THIS AFTER b[] is filled.
    }

Hey Joe,
They all look like great changes that we can work out into the next software and firmware update.

It might be difficult to discuss about these on the forums so I just created a milestone in Github so can you add all of these individually here: https://github.com/DexterInd/GrovePi/issues?q=is%3Aopen+is%3Aissue and assign Next Update Tag to them.

We can discuss more about each of them and look into how to realize them and sort out problems if any.

-Karan

I love this idea of caching and to list list sensors to poll. I have a project with the dust sensor that needs a minimum 30 seconds data sampling.
I see the thing like that :

  • A command to Start sampling and add Dust sensor to a poll list of sensors
  • store data in a rolling register (a simple array)
  • a command to read the data in cache and make concentration calculations
  • a command to remove the sensor of the list to poll