Author Topic: Problems with I2c configuration  (Read 451 times)

Nick_W

  • Full Member
  • ***
  • Posts: 215
    • View Profile
Problems with I2c configuration
« on: August 17, 2016, 09:42:58 am »
I'm having some problems with my BME280 module, so I tried some experiments with the internal Temperature Sensor (to eliminate external errors).

I don't seem to be able to define an I2c object as shared (might not be just I2c, but this is what I am testing).

For example, this code works (the MQTT class just makes MQTT stuff easier):

Code: [Select]
Class MQTT
    Shared mcUIDString As String
   
    Shared Sub Publish(topic As String, value As String)
        If mcUIDString = Nothing Then
            mcUIDString = Device.mcUID().ToString("X8")
        End If
        Dim text_string As ListOfByte = New ListOfByte()
        text_string.Add(value)
        Lplan.Publish("MCThings/" + mcUIDString + "/" + topic, text_string)
    End Sub
   
    Shared Sub Publish(topic As String, value As Object)
        Dim text As String = value.ToString()
        If mcUIDString = Nothing Then
            mcUIDString = Device.mcUID().ToString("X8")
        End If
        Dim text_string As ListOfByte = New ListOfByte()
        text_string.Add(text)
        Lplan.Publish("MCThings/" + mcUIDString + "/" + topic, text_string)
    End Sub
   
    Shared Sub Publish_exact(topic As String, text As String)
        Dim text_String As ListOfByte = New ListOfByte()
        text_String.Add(text)
        Lplan.Publish(topic, text_String)
    End Sub
   
    Shared Sub BeaconPublish(data_Type As Byte, data As Integer)
        data = data & 0x0fffffff //blank top byte (can only send 24 bits maximum)
        Dim hi_byte As Byte = ((data >> 16) & 0xff).ToByte()
        Dim mid_byte As Byte = ((data >> 8) & 0xff).ToByte()
        Dim low_byte As Byte = (data & 0xff).ToByte()
        Dim beconData As ListOfByte = New ListOfByte()
        beconData.Add(data_Type)
        beconData.Add(hi_byte)
        beconData.Add(mid_byte)
        beconData.Add(low_byte)
        Lplan.SetBeaconData(beconData)
        Lplan.SendBeacon()
    End Sub
   
    Shared Sub Subscribe(topic As String)
        Lplan.Subscribe(topic)
    End Sub
   
End Class

Class Main
   
    //Shared Internal_Temp As TempSensor
    Shared booted As Boolean
    Shared count As Integer
   
    Shared Event Boot()
       
        booted = True
        count = 5
        //Internal_Temp = New TempSensor()
       
    End Event
   
    Shared Event Publish_Values() RaiseEvent Every 10 Seconds
        LedGreen = True
       
        If booted Then
            MQTT.Publish("Status", "Booted")
            booted = False
        End If   
       
        Dim Internal_Temp As TempSensor = New TempSensor()
        Dim TempC As Float = Internal_Temp.GetTemp()
        MQTT.Publish("Temperature", TempC)
        Dim Uptime As Integer = Device.Uptime()
        MQTT.Publish("Uptime", Uptime)
        Dim BattVolt As Integer = Device.BatteryVoltage()
        MQTT.Publish("BatteryVoltage", BattVolt)
        count = count + 1
        MQTT.Publish("Count", count)
       
        LedGreen = False
    End Event 
End Class

Class TempSensor
    // Function returns the temperature in degree celcius or
    // Float.NaN if something is wrong
   
    Public sensor As I2c
   
    Public Sub New()
        sensor = I2c.Create(400000, Pin.SCL, Pin.SDA, 0x48)
    End Sub
   
    Public Function GetTemp() As Float
        // Define the properties of the I2C peripheral and device address
        //Dim sensor As I2c
        //sensor = I2c.Create(400000, Pin.SCL, Pin.SDA, 0x48)
       
        // Power up the sensor and give it some time to settle
        Device.EnableTempSensor()
        Thread.Sleep(40000) // See page 13 of the datasheet
       
        // Read the sensor (only 2 bytes to read
        Dim res As ListOfByte = sensor.Read(2)
       
        // See Tmp102 documentation how to interpret the data (page 8)
        Dim temp As Float = Float.NaN
        If res <> Nothing Then
            // Shift the partial part to the right nibble
            Dim part As Float = res(1) >> 4
            // Temperature partial is 1/16*n where n is between 0 and 15           
            part = part / 16
            // Sign extend the byte to an integer
            temp = res(0).SignExtend() + part
        Else
            LedRed = True
            Thread.Sleep(50000)
            LedRed = False
        End If
       
        // power off
        Device.DisableTempSensor()
        Return temp
    End Function
   
    Shared Function GetDieTemp() As Float
        // Just get the temperature and return
        Return Device.TempDie
    End Function
   
    Shared Function ToFarenheit(celcius As Float) As Float
        Return (celcius * 9) / 5 + 32
    End Function
   
    Shared Function ToCelcius(farenheit As Float) As Float
        Return (farenheit - 32) * 5 / 9
    End Function
   
End Class

Note the "Dim Internal_Temp As TempSensor = New TempSensor()" in Class Main.

If I Try to Make this a shared variable of class main, it causes the module to reset. This does not work:

Code: [Select]
Class MQTT
    Shared mcUIDString As String
   
    Shared Sub Publish(topic As String, value As String)
        If mcUIDString = Nothing Then
            mcUIDString = Device.mcUID().ToString("X8")
        End If
        Dim text_string As ListOfByte = New ListOfByte()
        text_string.Add(value)
        Lplan.Publish("MCThings/" + mcUIDString + "/" + topic, text_string)
    End Sub
   
    Shared Sub Publish(topic As String, value As Object)
        Dim text As String = value.ToString()
        If mcUIDString = Nothing Then
            mcUIDString = Device.mcUID().ToString("X8")
        End If
        Dim text_string As ListOfByte = New ListOfByte()
        text_string.Add(text)
        Lplan.Publish("MCThings/" + mcUIDString + "/" + topic, text_string)
    End Sub
   
    Shared Sub Publish_exact(topic As String, text As String)
        Dim text_String As ListOfByte = New ListOfByte()
        text_String.Add(text)
        Lplan.Publish(topic, text_String)
    End Sub
   
    Shared Sub BeaconPublish(data_Type As Byte, data As Integer)
        data = data & 0x0fffffff //blank top byte (can only send 24 bits maximum)
        Dim hi_byte As Byte = ((data >> 16) & 0xff).ToByte()
        Dim mid_byte As Byte = ((data >> 8) & 0xff).ToByte()
        Dim low_byte As Byte = (data & 0xff).ToByte()
        Dim beconData As ListOfByte = New ListOfByte()
        beconData.Add(data_Type)
        beconData.Add(hi_byte)
        beconData.Add(mid_byte)
        beconData.Add(low_byte)
        Lplan.SetBeaconData(beconData)
        Lplan.SendBeacon()
    End Sub
   
    Shared Sub Subscribe(topic As String)
        Lplan.Subscribe(topic)
    End Sub
   
End Class

Class Main
   
    Shared Internal_Temp As TempSensor
    Shared booted As Boolean
    Shared count As Integer
   
    Shared Event Boot()
       
        booted = True
        count = 5
        Internal_Temp = New TempSensor()
       
    End Event
   
    Shared Event Publish_Values() RaiseEvent Every 10 Seconds
        LedGreen = True
       
        If booted Then
            MQTT.Publish("Status", "Booted")
            booted = False
        End If   
       
        //Dim Internal_Temp As TempSensor = New TempSensor()
        Dim TempC As Float = Internal_Temp.GetTemp()
        MQTT.Publish("Temperature", TempC)
        Dim Uptime As Integer = Device.Uptime()
        MQTT.Publish("Uptime", Uptime)
        Dim BattVolt As Integer = Device.BatteryVoltage()
        MQTT.Publish("BatteryVoltage", BattVolt)
        count = count + 1
        MQTT.Publish("Count", count)
       
        LedGreen = False
    End Event 
End Class

Class TempSensor
    // Function returns the temperature in degree celcius or
    // Float.NaN if something is wrong
   
    Public sensor As I2c
   
    Public Sub New()
        sensor = I2c.Create(400000, Pin.SCL, Pin.SDA, 0x48)
    End Sub
   
    Public Function GetTemp() As Float
        // Define the properties of the I2C peripheral and device address
        //Dim sensor As I2c
        //sensor = I2c.Create(400000, Pin.SCL, Pin.SDA, 0x48)
       
        // Power up the sensor and give it some time to settle
        Device.EnableTempSensor()
        Thread.Sleep(40000) // See page 13 of the datasheet
       
        // Read the sensor (only 2 bytes to read
        Dim res As ListOfByte = sensor.Read(2)
       
        // See Tmp102 documentation how to interpret the data (page 8)
        Dim temp As Float = Float.NaN
        If res <> Nothing Then
            // Shift the partial part to the right nibble
            Dim part As Float = res(1) >> 4
            // Temperature partial is 1/16*n where n is between 0 and 15           
            part = part / 16
            // Sign extend the byte to an integer
            temp = res(0).SignExtend() + part
        Else
            LedRed = True
            Thread.Sleep(50000)
            LedRed = False
        End If
       
        // power off
        Device.DisableTempSensor()
        Return temp
    End Function
   
    Shared Function GetDieTemp() As Float
        // Just get the temperature and return
        Return Device.TempDie
    End Function
   
    Shared Function ToFarenheit(celcius As Float) As Float
        Return (celcius * 9) / 5 + 32
    End Function
   
    Shared Function ToCelcius(farenheit As Float) As Float
        Return (farenheit - 32) * 5 / 9
    End Function
   
End Class

So if I change Internal_sensor from a local variable to a Shared variable, the module resets. What am I doing wrong? The TempSensor object should be created at boot, and should persist as a shared variable of class Main, but I'm guessing from the resets, it is being destroyed. No errors in MCStudio, and builds fine.

I'm wanting to do this as I want to create a BME280 object (one per sensor), but it seems that I have to create a new object every time I want to use it. I can't make a persistent I2C object.

Any suggestions would be appreciated.

Share on Facebook Share on Twitter


mc-John

  • Global Moderator
  • Full Member
  • *****
  • Posts: 212
    • View Profile
Re: Problems with I2c configuration
« Reply #1 on: August 17, 2016, 03:54:47 pm »
Is this problem related to the "odd memory behavior" problem?

Nick_W

  • Full Member
  • ***
  • Posts: 215
    • View Profile
Re: Problems with I2c configuration
« Reply #2 on: August 17, 2016, 04:08:43 pm »
Not as such,

I'm trying to create a persistent I2C object (persists between timed events). But I can't get it to work.

The object works if you create it in the event. If you create it at boot (or any other time), it doesn't work in Shared Events (resets). I was looking at memory to see what was happening, but maybe got lead astray by the "odd memory behavior".

So ignoring weird memory things, how do you create a shared I2C object, that can be used in a Shared event without having to re-create it every time?

If I re-create it every time, then everything that is stored in the I2c module (calibration factors etc) have to be re-read into local variables each time you want to read the sensor. You also have to set up the resolution, filtering, period, etc. etc.  Not really the point of a class.

I should be able to do this once (when the instance of the class is created as an object (in New)), then just call the readTemperature() method to read the I2C register and calculate the temperature or whatever.

I don't want to have to create a new object every time I want to read anything over I2C.

If I make everything Shared (ie don't use Public/Private at all), and don't create an instance of the object, it works - but then you can only use it for one sensor...

Any Suggestions?

mc-John

  • Global Moderator
  • Full Member
  • *****
  • Posts: 212
    • View Profile
Re: Problems with I2c configuration
« Reply #3 on: August 18, 2016, 09:35:01 am »
We found the problem. I2C in some cases overwrites a shared variable.

We will fix it and we will try to get it out today.

-John-

Nick_W

  • Full Member
  • ***
  • Posts: 215
    • View Profile
Re: Problems with I2c configuration
« Reply #4 on: August 18, 2016, 10:59:46 am »
Thanks John,

I now have the class working (with your pressure conversion function), so I'll integrate it into the rest of my program, and wait for the fix.

Thanks for the quick feedback.

Nick_W

  • Full Member
  • ***
  • Posts: 215
    • View Profile
Re: Problems with I2c configuration
« Reply #5 on: August 18, 2016, 12:23:55 pm »
John,

Tom sent me the binaries (7-365) I just loaded everything and it works ;D

I now have my persistent I2c object functioning for both internal temperature sensor, and external BME280 temp/humid/press sensor.

Thank you!

Now if I can just find out why it keeps running out of memory and resetting....
Like Like x 1 View List