Rinsen/OneWire

Onewire DS2482100DeviceNotFoundException under linux (Azure IoT Edge)

LeivoSepp opened this issue ยท 22 comments

I couldnt get the Onewire working for IoT Edge on Raspberry.
IoT Edge on Rasperry: this mean Linux on Raspberry and solution is running as a docker on it.
I2C is working and docker can see it. I have another I2C device connected and working which is using drivers from https://github.com/dotnet/iot.
I even tried disconnect another device from the I2C bus to leave just Onewire alone but still the same error message.
It was working under Windows IoT core.

Unhandled Exception: Rinsen.IoT.OneWire.DS2482100DeviceNotFoundException: No DS2482-100 detected, check that AD0 and AD1 is correct in ctor and that the physical connection to the DS2482-100 one wire bridge is correct. ---> System.IO.IOException: Error 121 performing I2C data transfer.
at System.Device.I2c.UnixI2cDevice.ReadWriteInterfaceTransfer(Byte* writeBuffer, Byte* readBuffer, Int32 writeBufferLength, Int32 readBufferLength)
at System.Device.I2c.UnixI2cDevice.Transfer(Byte* writeBuffer, Byte* readBuffer, Int32 writeBufferLength, Int32 readBufferLength)
at System.Device.I2c.UnixI2cDevice.Write(ReadOnlySpan 1 value)
at Rinsen.IoT.OneWire.DS2482Channel.OneWireReset()
at Rinsen.IoT.OneWire.DS2482DeviceFactory.PrivateCreateDs2482_100(I2cDevice i2cDevice, Boolean disposeI2cDevice)
--- End of inner exception stack trace ---
at Rinsen.IoT.OneWire.DS2482DeviceFactory.PrivateCreateDs2482_100(I2cDevice i2cDevice, Boolean disposeI2cDevice)
at HomeModule.Measuring.RinsenOneWireClient.ReadSensors() in /app/Measuring/RinsenOneWireClient.cs:line 25
at HomeModule.Schedulers.HomeTemperature.ReadTemperature() in /app/Schedulers/HomeTemperature.cs:line 41
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.b__7_1(Object state)
at System.Threading.QueueUserWorkItemCallbackDefaultContext.<>c.<.cctor>b__5_0(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.QueueUserWorkItemCallbackDefaultContext.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

How can we troubleshoot this to get it working?

I will try to do some investigations and get back to you.

But it's for sure related to me only testing on Windows right now.

I would guess it's related to this code
https://github.com/Rinsen/OneWire/blob/master/src/Rinsen.IoT.OneWire/I2cDeviceFactory.cs

But it could also be something else. That error you get is not so good since it's quite generic but gave a specific message and can be related to other things than not finding the ds2482 device unfortunately.

I have double checked my code but can't find any obvious issues when I compare it to the samples that exist here.
https://github.com/dotnet/iot/tree/master/src/devices

Could you try to update the System.Device.Gpio package to the latest and see if that makes any difference? I would guess not but it doesn't hurt to try. To upgrade just install the latest version in your "hosting project". If this fails for any strange reason I could push out a new beta version referencing a new version.

Is it with the exact same hardware setup that you got it working on Windows IoT Core?
The most logical would be that the device is on another address or not connected properly but if it work on Windows IoT core that's not an option.

Thanks @Rinsen for looking it.
This solution has been working many years in Windows IoT Core. Few weeks ago I started refactoring to port this solution into IoT Edge world. The concept of the containers is much nicer than the Windows IoT Core was :)
I will do the update ASAP and let you know.

Some not so issue related questions but in a way. I am interested in going a similar way and leave Windows Iot Core.

Do you have some guide or quick start path that you have used that was good for the IoT Edge parts?

Is the experience of running in containers good in development? Is it possible to remote debug from VS on a PC?

I have been thinking about running in Linux direct without any container in between previously but don't really know what way I want to go today.

If you have been developed Windows IoT Core then from my point of view is easier to for IoT Edge using dotnetcore2 framefork.
You have to rewrite some of your code but in general it will work.
Going directly on Linux or using containers is depend what kind of services are you using from Azure. For example my solution is very complex and I was using a lot Azure.
My main arguments for refactoring are following:

  1. I can do development everywhere and the code deployment is fully automated by CI-CD pipeline. The container will be delivered to my Raspberry through IoT Hub.
  2. I can get rid of the expensive Stream Analytics on Azure (around $70 per month - I have sponsored subscription, but still it is expensive). Now I deployed the Stream Analytics module on my Edge device Rasprerry PI and the Stream Analytics cost now less than a dollar in a month.

Here is architecture of my "old" system, I havent updated the picture yet according to IoT Edge.
Debugging is a challenge, I havent found very good way currently. Just using Console.Writeline in the code to see what's going on in real world (on the device) and monitoring it using PuTTY.
http://internetofthing.io/post/home-iot-project-smart-home-security

Hi, if it helps, I have started to refactor my project from Windows IOT core to dotnet core and then deploy this via a container running on Debian Jessie. I have just built a test rig with a DS2482S-100 with three DS18B20 temp sensors on, this reports correctly on i2cdetect, and I can read the temperatures using owfs, so I know the hardware works. When I run the dotnet app I get the following error:

Unhandled Exception: Rinsen.IoT.OneWire.DS2482100DeviceNotFoundException: No DS2482-100 detected, check that AD0 and AD1 is correct in ctor and that the physical connection to the DS2482-100 one wire bridge is correct. ---> System.IO.IOException: Error 121 performing I2C data transfer.
at System.Device.I2c.UnixI2cDevice.ReadWriteInterfaceTransfer(Byte* writeBuffer, Byte* readBuffer, Int32 writeBufferLength, Int32 readBufferLength)
at System.Device.I2c.UnixI2cDevice.Transfer(Byte* writeBuffer, Byte* readBuffer, Int32 writeBufferLength, Int32 readBufferLength)
at System.Device.I2c.UnixI2cDevice.Write(ReadOnlySpan`1 value)
at Rinsen.IoT.OneWire.DS2482Channel.OneWireReset() in c:\tmp\code\dotnetcontainer1\Rinsen.IoT.OneWire\DS2482Channel.cs:line 331
at Rinsen.IoT.OneWire.DS2482.OneWireReset() in c:\tmp\code\dotnetcontainer1\Rinsen.IoT.OneWire\DS2482.cs:line 66
at Rinsen.IoT.OneWire.DS2482DeviceFactory.PrivateCreateDs2482_100(I2cDevice i2cDevice, Boolean disposeI2cDevice) in c:\tmp\code\dotnetcontainer1\Rinsen.IoT.OneWire\DS2482DeviceFactory.cs:line 39
--- End of inner exception stack trace ---
at Rinsen.IoT.OneWire.DS2482DeviceFactory.PrivateCreateDs2482_100(I2cDevice i2cDevice, Boolean disposeI2cDevice) in c:\tmp\code\dotnetcontainer1\Rinsen.IoT.OneWire\DS2482DeviceFactory.cs:line 43
at Rinsen.IoT.OneWire.DS2482DeviceFactory.CreateDS2482_100(Boolean ad0, Boolean ad1) in c:\tmp\code\dotnetcontainer1\Rinsen.IoT.OneWire\DS2482DeviceFactory.cs:line 25
at dotnetcontainer1.Program.Main(String[] args) in c:\tmp\code\dotnetcontainer1\Program.cs:line 16
Aborted

I can attach a debugger and step through the code on the pi, so happy to help wherever.

Hi @alastaid good to know.
Just asking: have you done these steps on your Raspberry:

  1. Have you enabled I2C on Raspberry:
    boot/config.txt -> uncommenting
    dtparam=i2c_arm=on
    dtparam=i2s=on
    dtparam=spi=on
  2. If you are using Azure IoT Edge tools either VSCode or Visual Studio :
    Comment out following lines from the file Dockerfile.arm32v7
    '# RUN useradd -ms /bin/bash moduleuser
    '# USER moduleuser
  3. Adding to the deployment file deployment.template.json the following lines under your module:
    "createOptions": {
    "HostConfig": {
    "Privileged": true
    }
    }

These steps allow docker to run in root permissions and then it can see I2C from the Raspberry.

I will try to find some simpler task than doing a reset to find if the device is there. A reset is doing a lot more than just detecting the device so it would be nice to narrow it down to the minimum. I will try to put something together later today and get back with a new version.

@LeivoSepp, I have enabled the I2C in the boot files, and am not using IOT Edge, currently I am just using native dotnet 2.1 code. When I have got it working I will move it to a pipeline to build a container and run it this way, but for now I am getting this error on native code with no container to just eliminate everything else.

What tool are you using to debug? Vs code or something else?

Visual Studio 2019

Hi all, success! So while I don't pretend to understand all the code etc (this is just a hobby for me) I got it working, The issue is the address of the DS2482_100 set here (in DS2482DeviceFactory.cs):
public DS2482_100 CreateDS2482_100(bool ad0, bool ad1)
{
byte address = 0x18;
if (ad0)
{
address |= 1 << 0;
}
if (ad1)
{
//address |= 1 << 1;
}
When I run I2Cdetect on my pi it shows the address as 0x18, hence I commented out the line for if(ad1) which changes the address to something else (cant remember what) and it all works see here:
Capture

Awesome @alastaid ๐Ÿ‘

Do you know how the ad0 and ad1 flags are supposed to work? If not the issue might be that the chip is configured with another adress the what I have used as examples. These two bits give the possibility to have two chips on the same buss and adress then individually. So you just send in a true or false corresponding to the hardware configuration.

I maybe should add a section about that in the documentation part.

And nice to see that remote on device debugging is possible ๐Ÿ˜ got me really motivated to start to move to Linux Asap.

@Rinsen , assume I am clueless on most things with this :-), I guessed at the ad0 and ad1, so I send false, true in the method call. I based this on looking at the web, for my Pi, to get I2Cdetect to work, I had to send "i2cdetect -y 1" (if I replace the 1 with a 0 it fails) so I just assumed I should use ad0 flag false and ad1 flag true.
The debugging works great when you get it sorted, full VS experience, basically I code in VS, use Build->Publish which is configured to make an Arm build locally on the PC, then copy the files to the Pi, and essentially just follow the steps here https://www.hanselman.com/blog/RemoteDebuggingWithVSCodeOnWindowsToARaspberryPiUsingNETCoreOnARM.aspx
to setup remote debugging, I then run the executable on the pi, halt the code with a ReadLine(), goto Debug->Process in VS, attach to the process via SSH as root, then kick the program back running by pressing return and it will halt at any breakpoints with all the local values etc.

@alastaid
Then you have a good opportunity to learn :)

If you look at the datasheet on the "Typical Operating Circuit" and "I2C Interface - Slave Address" on page 15 for the DS2482-100 you will find that AD0 and AD1 is possible to connect to GND or 5V and this represents true or false in the factory method that I have in the library. So if you connect both to GND you need to send in both as false but if you for example connect AD1 to 5V you need to send in true in the AD1 bool.

https://datasheets.maximintegrated.com/en/ds/DS2482-100.pdf

That's great! Will try to get it up and running :)

@Rinsen , I was trying to avoid reading documents like that, its all black magic to me :-). However, you are correct and so is your code! I had copied a wiring diagram without understanding it, which means I had grounded AD0 and AD1, and if I call the CreateDS2482_100() method with false,false it works, so my mistake, and thanks for your efforts on this.

@alastaid This library is more or less only built based on datasheets lika that ๐Ÿ˜‰

Thanks a lot!
I can confirm from my side that putting the parameters (false, false) I got mine also working.
My solution is based on Azure IoT Edge solution, this mean the code is sitting in the container and Raspberry itself has a Raspbian-stretch OS.
Following is the beauty of using IoT Edge solution: I have no access to my home network but still I was able to deploy the solution into my Raspberry through IoT Hub and get this thing working.

So as an update, I can now run the dotnet app in a container on the pi and it works! See below. It does look like you can attach a remote debugger to the dotnet app in a container, you just have to build the container with an ssh server and vsdbg, but for me I am happy to debug running native dotnet app and then ship it as a container. (https://blog.quickbird.uk/debug-netcore-containers-remotely-9a103060b2ff)
Capture

So happy that this wasn't more complicated than this :) I'm so happy to help and in the same time I have got a log of new knowledge about a lot of great things that I look forward to play with!

This really shows the strength of dotnet core that you can take code build for Windows on Windows and it will just work in Linux a few years later more or less without any changes. Lots of awesomeness there :)

I will need to find some time soon to start experimenting on both Linux on the Raspberry and also the Azure IoT Edge, having the possibility to remotely both update and configure devices is just awesome as soon as something leaves the desk and things need to be worked on.

I will also close this issue now since you both seem to get things going ๐Ÿ‘