Giter VIP home page Giter VIP logo

Comments (11)

moqmar avatar moqmar commented on May 27, 2024

Closing & reopening the port after each read is a workaround (see below), but I couldn't find any code called by NewSPI() that could solve this problem and is not also called from ReadCard()...

assertNil(port.Close())
port, err = spireg.Open("SPI0.0")
assertNil(err)
conn, err = mfrc522.NewSPI(port, reset, irq)
assertNil(err)

from periph.

maruel avatar maruel commented on May 27, 2024

Thanks a lot for detailed report! Can you confirm the interrupt line with an oscilloscope? If not, we'll probably need help with debugging this.

from periph.

duckworthd avatar duckworthd commented on May 27, 2024

I too have encountered this issue on a Raspberry Pi 3. Reinitializing the driver (halting & recreating the PortCloser and Dev) solve the issue.

from periph.

brackendawson avatar brackendawson commented on May 27, 2024

Thanks a lot for detailed report! Can you confirm the interrupt line with an oscilloscope? If not, we'll probably need help with debugging this.

I am facing the same issue, here's a trace of the IRQ line:
DS2_QuickPrint1

It's reading the UID 3 times then you see the issue trailing off after that, so the IRQ line is falling but I'm unsure if that's before or after the error is seen.

Code

package main

import (
	"encoding/hex"
	"log"
	"time"

	"periph.io/x/periph/conn/spi/spireg"
	"periph.io/x/periph/experimental/devices/mfrc522"
	"periph.io/x/periph/host"
	"periph.io/x/periph/host/rpi"
)

func main() {
	if _, err := host.Init(); err != nil {
		log.Fatal("Failed to init periphio: ", err)
	}

	p, err := spireg.Open("")
	if err != nil {
		log.Fatal("Failed to open spireg: ", err)
	}

	nfc, err := mfrc522.NewSPI(p, rpi.P1_22, rpi.P1_18)
	if err != nil {
		log.Fatal("Failed to init MFRC522: ", err)
	}
	defer nfc.Halt()

	for {
		uid, err := nfc.ReadUID(10 * time.Second)
		log.Printf("UID: %s, err: %s", hex.EncodeToString(uid), err)
	}
}

Log
alan@brackenpi:~ $ ./mfrc522test 
2021/03/06 15:50:00 UID: f76783d97e, err: %!s(<nil>)
2021/03/06 15:50:00 UID: f76783d97e, err: %!s(<nil>)
2021/03/06 15:50:00 UID: f76783d97e, err: %!s(<nil>)
2021/03/06 15:50:00 UID: , err: mfrc522: back data expected 5, actual 1
2021/03/06 15:50:00 UID: , err: mfrc522 lowlevel: IRQ error
2021/03/06 15:50:00 UID: , err: mfrc522 lowlevel: IRQ error
2021/03/06 15:50:00 UID: , err: mfrc522 lowlevel: IRQ error
2021/03/06 15:50:00 UID: , err: mfrc522 lowlevel: IRQ error
2021/03/06 15:50:00 UID: , err: mfrc522 lowlevel: IRQ error
2021/03/06 15:50:00 UID: , err: mfrc522 lowlevel: IRQ error
2021/03/06 15:50:00 UID: , err: mfrc522 lowlevel: IRQ error
2021/03/06 15:50:00 UID: , err: mfrc522 lowlevel: IRQ error
2021/03/06 15:50:01 UID: , err: mfrc522 lowlevel: IRQ error
... etc

Happy do do more debug.

from periph.

brackendawson avatar brackendawson commented on May 27, 2024

This is interesting:

periph/host/sysfs/gpio.go

Lines 191 to 192 in 2d212de

// TODO(maruel): According to pigpio, the correct way to consume the
// interrupt is to call Seek().

from periph.

maruel avatar maruel commented on May 27, 2024

Yeah that's a separate work item. It's possible that edges are missed. It's fairly rare on RPi but on AllWinner based CPUs it's sadly totally unreliable.

from periph.

brackendawson avatar brackendawson commented on May 27, 2024

I see. Do you think It's the MFRC522 interrupting immediately (even without a tag) and the code reading that as an error somehow, or do you think the interrupt line falling is just an artefact of the repeated read attempts? I suppose we'd need to instrument the code with GPIO's to tell for sure (my scope is only 2-channel).

from periph.

maruel avatar maruel commented on May 27, 2024

I have no idea, I never used this device myself.

from periph.

brackendawson avatar brackendawson commented on May 27, 2024

DS2_QuickPrint2

When reading a UID once there are always two device interrupts, as seen above. There is only one call to gpio.PinIn.WaitForEdge() at the start of selectCard, this means that the next call to WaitForEdge will return immediately as there has been an edge since the last call. So we either need to prevent the second device interrupt from happening or service the host interrupt appropriately.


The device interrupt selected (above) interrupts when "receiver has detected the end of a valid data stream". We will get many of these during any transaction, and apparently at least one if we try to read with no card present as this condition doesn't clear itself after one failed read. There doesn't appear to be a more fine grained interrupt available, so it looks like we have to pick a sensible point to service the host GPIO interrupt.

I think we can call WaitForEdge(0) before line 198 in low_level.go: https://github.com/google/periph/blob/master/experimental/devices/mfrc522/commands/low_level.go#L196-L209
This will clear the host GPIO interrupt before we asynchronously call WatForEdge(timeout), we don't expect a device interrupt until after ComIrqReg is cleared by line 207. The docstring for this function already says it is waiting for IRQ to "strobe", not for it to have previously "strobed".

In theory we could prevent the second device interrupt by not clearing ComIrqReg in Init() which is called after WaitForEdge() in selectCard(), but doing so prevents any UID being read, I'm not sure why.

I also realise this whole conversation should probably move to this repo? https://github.com/periph/devices

from periph.

maruel avatar maruel commented on May 27, 2024

Yes, I didn't transfer the issues to the new repos yet. I just realized it's actually fairly easy, it's just a bit tedious as I have to do it for individual issues. Will try on an inactive issue first to confirm it works.

from periph.

maruel avatar maruel commented on May 27, 2024

Attempting to migrate an issue results in a 500 (!) so let's stick it here for now.

from periph.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.