Open fadyanwar opened 2 years ago
Thanks for logging the issue @fadyanwar. Can you please share details on which specific card reader are you trying to use? cc: @Ellerbach who wrote most of this code and who has tested it.
Also did you try debugging it by any chance? If so, did you see if it was able to successfully connect to the device? From what i'm reading in that example there are several ways to connect to the reader, I'm curious as to which one you picked and to see if you have tried the others.
Hello @joperezr The card reader is RF522, the card itself is a ISO14443A and I'm connecting over SPI. I did test using a python script using the same configuration and it's working fine. I've tried to take out segments of code to figure out which line is not working, I think it's the loop part found here https://github.com/dotnet/iot/blob/2cc943168d4b20339a4c3046a5c8a952b273afcb/src/devices/Mfrc522/samples/Program.cs#L113
Find below full output
Hello MFRC522! Do you want to use the MFRC522 on a device like a Raspberry Pi or through a FT4222?
@joperezr @Ellerbach After some further debugging, I found out that this call is timing out as it calls ReadRegister(Register.ComIrq) which ends up calling SpiReadRegister(Register register) https://github.com/dotnet/iot/blob/43e66f2118c6bc56adf8b234c4824d88a85ae474/src/devices/Mfrc522/Mfrc522.cs#L727 which returns zero, so WaitForCommandToComplete(byte waitIrq) will loop for 36 ms then times out causing the timeout to cascade all the way up to mfrc522.ListenToCardIso14443TypeA(out card, TimeSpan.FromSeconds(2)) call which also happens to have an inverted timeout condition, so it will continue looping without doing anything.
I've created a PR to fix the inverted timeout condition but this doesn't fix the root cause issue as it was merely hiding it. https://github.com/dotnet/iot/pull/1871
Thank you a lot @fadyanwar!
As a side note if you put Fixes: https://github.com/dotnet/iot/issues/1869
or Fixes: #1869
in the first line of the pull request the issue gets auto closed when PR is merged. It's always a good idea to reference related issue in the description anyway. I've already edited your PR description to include that
Thanks @krwq just be aware that this PR does not resolve the root cause as it fixes an issue that was hiding it, so even after it's merged the issue should stay open.
In such cases I'd just go ahead with Contributes to #xyz
so we at least know it's related
@krwq @joperezr I've traced the timeout bug to an ioctl Linux system call that returns 2 for a result and sets read and write buffer bytes to zeros which bubbles up through several calls to become a timeout. https://github.com/dotnet/iot/blob/1cae134bbd2958bb1fa7ac608169c33afdba3533/src/System.Device.Gpio/System/Device/Spi/Devices/UnixSpiDevice.cs#L291
As per ioctl man page, it should return zero on success and only few requests return a positive integer. So I was wondering if the SPI_IOC_MESSAGE_1 is one of those few requests or something is wrong here.
Hi @krwq just wondering if anyone had a chance to look at this. Thanks.
same problem here. @fadyanwar did you find a workaround for this by any chance?
@joreg Yes, I used Python.
Same problem here, nobody could have a look yet?
I had a similar problem, which I was able to work around by creating the SpiDevice
directly rather than using board.CreateSpiDevice(connection)
. I examined the state of the pins with raspi-gpio. Prior to running the sample, the chip enable pin was configured as an output. After running the sample, it was reconfigured to be the alternate function for the chip enable. That seems like it should be correct - but it doesn't work. I have a setup where I can see activity on the pins via attached LEDs, and the chip enable doesn't change.
When I reconfigured it to an output with raspi-gpio and used SpiDevice.Create(connection)
, it worked.
@jdbruner I've got an idea what this could be (Wrong operation mode of the CS pin). Can you provide the exact code you use to create the Spi device and the binding, please?
@jdbruner Thanks for your answer! Unfortunately, in my case either before and after execution, the SDA pin is configured as OUTPUT already. What is the alternate function for this pin? I'd like to try it...
My setup is a Raspberry Pi 4B with the RFC522 connected to logical pins 9 (MISO), 10 (MOSI), 11 (SCLK), and 7 (CE1) - although I've also tried it with 8 (CE0). Prior to running the sample, raspi-gpio get
tells me (abbreviated):
BANK0 (GPIO 0 to 27):
GPIO 0: level=0 fsel=1 func=OUTPUT pull=UP
GPIO 1: level=1 fsel=0 func=INPUT pull=UP
GPIO 2: level=1 fsel=4 alt=0 func=SDA1 pull=UP
GPIO 3: level=1 fsel=4 alt=0 func=SCL1 pull=UP
GPIO 4: level=1 fsel=0 func=INPUT pull=NONE
GPIO 5: level=1 fsel=0 func=INPUT pull=UP
GPIO 6: level=1 fsel=0 func=INPUT pull=UP
GPIO 7: level=1 fsel=1 func=OUTPUT pull=UP
GPIO 8: level=1 fsel=1 func=OUTPUT pull=UP
GPIO 9: level=0 fsel=4 alt=0 func=SPI0_MISO pull=DOWN
GPIO 10: level=0 fsel=4 alt=0 func=SPI0_MOSI pull=DOWN
GPIO 11: level=0 fsel=4 alt=0 func=SPI0_SCLK pull=DOWN
...
When I run the sample as-is, it doesn't work. If I abort with ^C, raspi-gpio get
now tells me
BANK0 (GPIO 0 to 27):
GPIO 0: level=0 fsel=1 func=OUTPUT pull=UP
GPIO 1: level=1 fsel=0 func=INPUT pull=UP
GPIO 2: level=1 fsel=4 alt=0 func=SDA1 pull=UP
GPIO 3: level=1 fsel=4 alt=0 func=SCL1 pull=UP
GPIO 4: level=1 fsel=0 func=INPUT pull=NONE
GPIO 5: level=1 fsel=0 func=INPUT pull=UP
GPIO 6: level=1 fsel=0 func=INPUT pull=UP
GPIO 7: level=1 fsel=4 alt=0 func=SPI0_CE1_N pull=UP
GPIO 8: level=1 fsel=1 func=OUTPUT pull=UP
GPIO 9: level=0 fsel=4 alt=0 func=SPI0_MISO pull=DOWN
GPIO 10: level=0 fsel=4 alt=0 func=SPI0_MOSI pull=DOWN
GPIO 11: level=0 fsel=4 alt=0 func=SPI0_SCLK pull=DOWN
...
(GPIO 7 has been reconfigured as CE1). Next, if I leave the pin as-is and change the sample to create the SPI device with
SpiDevice spi = SpiDevice.Create(connection);
(which doesn't change the pin function) it still doesn't work. However, if I then reconfigure the pin back to an output using raspi-gpio set 7 op
, then the sample works as expected.
Have you tried using CE0 (pin8) and changing the line SpiConnectionSettings connection = new(0, 1);
to SpiConnectionSettings connection = new(0, 0);
? That would be the right combination.
Alternatively you can change the line to SpiConnectionSettings connection = new(0, -1);
, thus disabling automatic CS handling and therefore also the change of the pin mode. As long as there's only one device connected to the SPI bus, the CS line has no real function anyway. You can just pull the CS input of your RFC controller to low to make it work. I presume that's why it works when the pin mode is "output" (and the output value is low).
It currently looks to me as if selecting CE1 isn't properly handled in the driver, but mostly because there seems to be no option to do that on the hardware level. The kernel API we use just doesn't offer that option (but due to very poor documentation, I'm not sure).
@pgrawehr are you asking me? In my case, when it is configured as an output, the pin is not being held low. My setup has LEDs associated with each GPIO pin, so I can visually see what is happening. When GPIO 7 is configured as an output and I run the sample, I can see the chip select changing state in the polling loop. When it's configured as CE1 there is no activity on that pin - and the MFRC522 is non-responsive.
I get the same result when I use CE0 (pin 8) and new SpiConnectionSettings(0, 0)
It is counter-intuitive to me that this doesn't work when the CE1 pin is configured as the CE1 function; nonetheless, that what I observe.
@jdbruner Thanks for that detailed analysis.
I've found the cause: This documentation page specifies that the hardware CS lines are not used on the Raspi, because of some problems with the hardware. Instead, the driver actually uses the GPIO controller to handle the CS pin, which explains why it's mode must be set to output.
Should not be to difficult to implement this behavior in the RaspberryPiBoard handler.
When running the sample found at https://github.com/dotnet/iot/blob/2cc943168d4b20339a4c3046a5c8a952b273afcb/src/devices/Mfrc522/samples/Program.cs
using the below shown command, no result was shown when card was presented to RFID reader
dotnet run --project iot/src/devices/Mfrc522/samples/Mfrc522.Sample.csproj
.NET SDK (reflecting any global.json): Version: 6.0.300 Commit: 8473146e7d
Runtime Environment: OS Name: debian OS Version: 11 OS Platform: Linux RID: debian.11-arm64 Base Path: /home/pi/.dotnet/sdk/6.0.300/
Host (useful for support): Version: 6.0.5 Commit: 70ae3df4a6
.NET SDKs installed: 6.0.300 [/home/pi/.dotnet/sdk]
.NET runtimes installed: Microsoft.AspNetCore.App 6.0.5 [/home/pi/.dotnet/shared/Microsoft.AspNetCore.App] Microsoft.NETCore.App 6.0.5 [/home/pi/.dotnet/shared/Microsoft.NETCore.App]
To install additional .NET runtimes or SDKs: https://aka.ms/dotnet-download