Grove Base Hat for Raspberry Pi too slow

It seem to take > 1000 microseconds to read one analog value. I want to continuously read 3 analog inputs in 1 milliseconds, is it possible with this hat (e.g. change ADC clock etc.)?

Code:

import datetime
import math
import sys
import time
from grove.adc import ADC


class GroveGSRSensor:

    def __init__(self, channel):
        self.channel = channel
        self.adc = ADC()

    @property
    def GSR(self):
        a = datetime.datetime.now()
        value = self.adc.read(self.channel)
        b = datetime.datetime.now()
        print("time: ",(b-a).microseconds)
        return value

Grove = GroveGSRSensor


def main():
    if len(sys.argv) < 2:
        print('Usage: {} adc_channel'.format(sys.argv[0]))
        sys.exit(1)

Output:

Detecting...
time:  1659
GSR value: 580
time:  1492
GSR value: 580
time:  1461
GSR value: 581
time:  1488
GSR value: 580
time:  1583
GSR value: 581
time:  1576
GSR value: 580
time:  1572
GSR value: 580
time:  1608
GSR value: 580

I know python is not efficient, but it seems to much, and there is no C library for me to test right away.

Now I created a C version, but still it took ~300 microseconds to read a value. Sometimes there is a spike to 1000ms, probably has to do with the OS. Maybe I should use arduino? But Arduino Nano 33 IOT has a firmware bug at this point… Any suggestions?
C code:

  #include<stdio.h>
  #include<stdlib.h>
  #include <unistd.h>            
  #include <fcntl.h>            
  #include <sys/ioctl.h>
  #include <linux/i2c.h>         
  #include <linux/i2c-dev.h>
  #include <i2c/smbus.h>
  #include <sys/time.h>

  int main()
  {   
     int file_i2c;
     int value;
     char reg = 0x30;
     char read_buffer[3];
     struct timeval st, et;

     char *filename = (char*)"/dev/i2c-1";
     if ((file_i2c = open(filename, O_RDONLY)) < 0)
     {
        printf("Failed to open the i2c bus");
        return 0;
     }
     
     int addr = 0x8;      // Grove Hat ADC address
     if (ioctl(file_i2c, I2C_SLAVE_FORCE, addr) < 0)
     {
        printf("Failed to acquire bus access and/or talk to slave.\n");
        return 0;
     }
     
     while (1) {
        gettimeofday(&st,NULL);
        i2c_smbus_write_byte(file_i2c, reg);
        gettimeofday(&et,NULL);
        value = i2c_smbus_read_word_data(file_i2c, reg);
        printf("%d\n", value);
        printf("time: %ld\n", et.tv_usec - st.tv_usec);

     }


     return 0;
  }

What if you timed not one read but 10 in a row, how long does that take ?
It looks like in your C example you timed a write, is that correct?

Thanks for the reply! Yes, it was a mistake, that I should timed both write and read together instead of just the write operation. Follow your suggestion, I found indeed I can do more read following one write instructions. So here is the measurement results:
i2c_smbus_write_byte(file_i2c, reg); // ~270 μs
i2c_smbus_read_word_data(file_i2c, reg); // ~820 μs
Since write_byte transmitted 1 byte while read_word transmitted 3 bytes, it makes sense that read_word costs roughly three times more time.
I contacted SeeedStudio customer service, they told me the firmware limits adc read rate and it’s better not to change that…

Note I tested on both raspberry pi 3b and zero w which have different processors but the same results. So it is likely just a firmware limitation.

1 Like