Author Topic: Fast reading from sensors  (Read 213 times)

Nick_W

  • Full Member
  • ***
  • Posts: 215
    • View Profile
Re: Fast reading from sensors
« on: January 30, 2017, 02:39:26 pm »
FYI here is my test code:

Code: [Select]
// Test of timing for reading analog sound signal

Define PinMode Pin8 As AnalogInput
//spi test
Define PinMode Pin5 As DigitalOutput

Class SoundTest
    Shared jdata As Json
    Shared spi1 As ExternalSPI
    Shared numberofsamples As Integer
    Shared mqtt_data As ListOfByte
    Shared mqtt_topic As String
    Shared running As Boolean //crude mutex
   
    Shared Event Boot()
        Lplan.SetMidPowerMode(5000)
        numberofsamples = 128 // a sample is 2 bytes
        jdata = New Json
        spi1 = New ExternalSPI
        mqtt_topic = "MCThings/" + Device.mcUID().ToString("X8") + "/"
        mqtt_data = New ListOfByte
        mqtt_data.Add("Booted")
        Lplan.Publish(mqtt_topic + "Status", mqtt_data)
        //SoundTest.runallTest()
    End Event
   
    Shared Event runtests() RaiseEvent Every 1 Minutes
        If running Then
            Return
        End If
        '        mqtt_data.Clear()
        '        mqtt_data.Add(numberofsamples.ToString)
        '        Lplan.Publish(mqtt_topic + "numsamples", mqtt_data)
        If numberofsamples > 4096 Then
            numberofsamples = 128
        End If
        SoundTest.runallTest()
        numberofsamples *= 2
    End Event
   
    Shared Sub runallTest()
        If running Then
            Return
        End If
        running = True
        SoundTest.testAnalog()
        Thread.Sleep(10000000)
        SoundTest.testSPISingle()
        Thread.Sleep(10000000)
        SoundTest.testSPIContinuous()
        Thread.Sleep(10000000)
        running = False
    End Sub
   
    Shared Function testAnalog() As Nothing
        //test read analog pin
        SoundTest.LEDFlash()
       
        Dim Values As ListOfShort = New ListOfShort
        Dim duration As Integer = Device.GetTimeSpan()
        For count As Integer = 0 To numberofsamples - 1
            Values.Add(Pin8)
        Next
        duration = Device.GetTimeSpan()
        SoundTest.Publish("analog", duration, Values.Count)
    End Function
   
    Shared Sub testSPISingle()
        //test read spi single
        SoundTest.LEDFlash()
       
        Dim Values As ListOfShort = New ListOfShort
        Dim value As Short
        Dim duration As Integer = Device.GetTimeSpan()
        For count As Integer = 0 To numberofsamples - 1
            Values.Add(spi1.Read)
        Next
        duration = Device.GetTimeSpan()
        SoundTest.Publish("spi_single", duration, Values.Count)
       
    End Sub
   
    Shared Sub testSPIContinuous()
        //test spi continuous reads
        SoundTest.LEDFlash()
       
        Dim duration As Integer = Device.GetTimeSpan()
        Dim Bytes As ListOfByte = spi1.Read(numberofsamples * 2)
        duration = Device.GetTimeSpan()
        Dim Values As ListOfShort = New ListOfShort
        Dim value As Short
        '        For count As Integer = 0 To Bytes.Count() - 2 Step 2   //does not work for some reason
        '            value = Bytes.ExtractShort(count)
        '            Values.Add(value)
        '        Next
        Dim count As Integer = 0
        While count < Bytes.Count()
            value = Bytes.ExtractShort(count)
            Values.Add(value)
            count += 2
        End While
        SoundTest.Publish("spi_continuous", duration, Values.Count)
       
    End Sub
   
    Shared Sub Publish(test As String, duration As Integer, samples As Integer)
        Dim uspersample As Float = duration / samples
        mqtt_data.Clear()
        jdata.Clear()
        jdata.Add("test", test)
        jdata.Add("duration_us", duration)
        jdata.Add("samples", samples)
        jdata.Add("us_per_sample", uspersample)
        mqtt_data.Add(jdata.ToString)
        Lplan.Publish(mqtt_topic + "Data", mqtt_data)
    End Sub
   
    Shared Function LEDFlash() As Nothing
        LedGreen = True
        Thread.Sleep(3000)
        LedGreen = False
    End Function
   
End Class

Class ExternalSPI
    //class to read external spi sensor
    Shared sensor As Spi
   
    Public Sub New()
        Pin5 = True
        sensor = Spi.Create(125000, 0, Pin.Pin0, Pin.Pin1, Pin.Pin3, Pin.Pin5) //125KHz spi interface
    End Sub
   
    Public Function Read() As Short
        //read single short value
        Return Read(2).ExtractShort(0)
    End Function
   
    Public Function Read(numbytes As Integer) As ListOfByte
        //read data (number of bytes)
        Dim data As ListOfByte = New ListOfByte
        data.AddElements(numbytes) 'size of data to read
        data = sensor.Transfer(data)
        Return data
    End Function
   
End Class

and here are my results:

Code: [Select]
[I 2017-01-30 15:14:07,373] MCThings/00011532/Data       : Decoded JSON:
                                                           {
                                                             "test": "analog",
                                                             "duration_us": 7721,
                                                             "samples": 128,
                                                             "us_per_sample": 60.320312
                                                           }
[I 2017-01-30 15:14:19,119] MCThings/00011532/Data       : Decoded JSON:
                                                           {
                                                             "test": "spi_single",
                                                             "duration_us": 34790,
                                                             "samples": 128,
                                                             "us_per_sample": 271.796875
                                                           }
[I 2017-01-30 15:15:37,063] MCThings/00011532/Data       : Decoded JSON:
                                                           {
                                                             "test": "analog",
                                                             "duration_us": 34882,
                                                             "samples": 256,
                                                             "us_per_sample": 136.257812
                                                           }
[I 2017-01-30 15:15:47,164] MCThings/00011532/Data       : Decoded JSON:
                                                           {
                                                             "test": "spi_single",
                                                             "duration_us": 89203,
                                                             "samples": 256,
                                                             "us_per_sample": 348.449219
                                                           }
[I 2017-01-30 15:16:00,304] MCThings/00011532/Data       : Decoded JSON:
                                                           {
                                                             "test": "spi_continuous",
                                                             "duration_us": 32989,
                                                             "samples": 256,
                                                             "us_per_sample": 128.863281
                                                           }
[I 2017-01-30 15:17:07,292] MCThings/00011532/Data       : Decoded JSON:
                                                           {
                                                             "test": "analog",
                                                             "duration_us": 125183,
                                                             "samples": 512,
                                                             "us_per_sample": 244.498047
                                                           }
[I 2017-01-30 15:17:17,535] MCThings/00011532/Data       : Decoded JSON:
                                                           {
                                                             "test": "spi_single",
                                                             "duration_us": 234772,
                                                             "samples": 512,
                                                             "us_per_sample": 458.539062
                                                           }
[I 2017-01-30 15:17:27,902] MCThings/00011532/Data       : Decoded JSON:
                                                           {
                                                             "test": "spi_continuous",
                                                             "duration_us": 65796,
                                                             "samples": 512,
                                                             "us_per_sample": 128.507812
                                                           }
[I 2017-01-30 15:18:38,242] MCThings/00011532/Data       : Decoded JSON:
                                                           {
                                                             "test": "analog",
                                                             "duration_us": 457550,
                                                             "samples": 1024,
                                                             "us_per_sample": 446.826172
                                                           }
[I 2017-01-30 15:20:11,731] MCThings/00011532/Data       : Decoded JSON:
                                                           {
                                                             "test": "analog",
                                                             "duration_us": 1731659,
                                                             "samples": 2048,
                                                             "us_per_sample": 845.536621
                                                           }
[I 2017-01-30 15:20:23,723] MCThings/00011532/Data       : Decoded JSON:
                                                           {
                                                             "test": "spi_single",
                                                             "duration_us": 2169586,
                                                             "samples": 2048,
                                                             "us_per_sample": 1059.368164
                                                           }
[I 2017-01-30 15:20:35,235] MCThings/00011532/Data       : Decoded JSON:
                                                           {
                                                             "test": "spi_continuous",
                                                             "duration_us": 262909,
                                                             "samples": 2048,
                                                             "us_per_sample": 128.373535
                                                           }
[I 2017-01-30 15:21:53,454] MCThings/00011532/Data       : Decoded JSON:
                                                           {
                                                             "test": "analog",
                                                             "duration_us": 6834015,
                                                             "samples": 4096,
                                                             "us_per_sample": 1668.460693
                                                           }
There are a few publishing's missed, but you get the idea.

As you can see the time per sample (sample is 2 bytes) goes up with the number of samples, except for the continuous spi read test. It seems that the individual reads take place at the expected rate, but after a certain number of reads (or time) there is a delay (probably while the OS does something else). The continuous spi read test does not do this, as I suspect the spi read is atomic, and can't be interrupted. So one long read always takes the same time per byte, but multiple reads gets split up into time sliced chunks by the OS, so overall it slows down by the number of chunks read at a time. The more chunks, the slower it gets.

I was hitting 3.2ms per sample (2 bytes) at 8096 reads.

Any ideas on how to work around this? I know it's an extreme case, but there are probably other circumstances where you don't want successive reads/writes delayed by random amounts. Something like Thread.preventInterrupt(True) guards you could put around time critical code.
« Last Edit: January 30, 2017, 02:44:09 pm by Nick_W »