cancel
Showing results for 
Search instead for 
Did you mean: 

Help finalizing custom Rust driver (st25r3911b)

RMuiz.1
Associate III

Hi!

A while back I started writing Rust driver for st25r3911b chip. Currently, it works and can read 14443A chip. The issue is that compared to official software (Discovery GUI) the read distance is about half. So if official software reads at 8-9cm then with rust driver it would just 5-6 cm.

I feel like I have messed up some register configurations. My knowledge of RF is very limited. Could someone point me in the right direction of what I should look into?
https://github.com/xpresshd/st25r3911b/blob/master/src/lib.rs#L168

Thanks!

 

1 ACCEPTED SOLUTION

Accepted Solutions

Hi,

 


@RMuiz.1 wrote:

What confuses me is why Intr jumps back high when I start reading interrupt registers



See  § "Interrupt interface" in the ST25R3911B datasheet: [...]IRQ pin transitions to low after the interrupt bit(s) that caused its transition to high has (have) been read.

It is likely that a second interrupt is signalled while reading the second interrutp register (likely I_rxe interrupt).

Make sure to configure the Salae SPI decoder with CPOL=0 and CPHA=1 to properly decode the SPI frames. The SPI CS handling seems to be erroneous (except if another devices are connected to the SPI bus):

BrianTIDAL_0-1688741138271.png

The SPI clock seems to be quite low (300 kHz). Our demos use a SPI clock = 3Mbps.

Rgds

BT

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

View solution in original post

11 REPLIES 11
Ulysses HERNIOSUS
ST Employee

Hi,

could be that this is an effect of not setting the antenna calibration and target registers the same way as in the original FW. Which trim value is being achieved, or does it return an error?

Regards, Ulysses

I did a few changes with the main firmware that doesn't impact driver logic and now the read distance is fine again. I'm very confused, but it seems to work. Maybe some race condition...

What is the correct way to check the error here? Currently, my calibrate logic looks like this (It should be the same as the official soft) https://github.com/xpresshd/st25r3911b/blob/jonas/src/lib.rs#L177

One thing that still bothers me is that driver crashes ~3 times per minute with IOError (Most often), FarmingError or InterruptTimeout. Even if there are no tags around.
It happens somewhere here https://github.com/xpresshd/st25r3911b/blob/jonas/src/lib.rs#L339
One thing I suspect is - `wait_for_interrupt` will sleep minimum 1ms and could be a lot longer if RTOS prioritizes other tasks. Could it be that there is a time limit in which I must process interrupt or it will move to another state?

Update:
I have noticed that after some reqa/wupa calls they stop getting back card data until the chip errors and is restarted. Could it be that I forgot to handle some error case? What could be the reason that reqa/wupa transmit is still called in a broken state, but no error is returned?

 

Hi,

please investigate the conditions in which your code returns IOError. The chip does not have such an error. Also InterruptTimeout should be more on your driver side. The FramingErrors sounds as being signaled by the ST25R3911B but you need to describe a bit more under which exact conditions. The error means incorrect framing over the RF. Such typically only happens close to the maximum operating range.

I think it would be helpful if you look at he SPI layer (maybe using logic-analyzer with SPI+INT pin) to be able to see what is happening on the chip and what is happening within your driver.

An NFC reader typically defines the pace there are typically no situations when it might be too late when only handling anticollision. Handling the FIFO water level (>96bytes) is of course timing critical.

Best Regards, Ulysses

 

IOError is taken from Rfal I think.
```
// If dont have end of receive and start of receive, throw io error
if !intr.contains(InterruptFlags::END_OF_RECEIVE)
|| !intr.contains(InterruptFlags::START_OF_RECEIVE)
{
return Err(Error::IOError);
}
```
It throwing errors is not the biggest concern, but that it fails to read tags until then. It works for a while and then reqa/wupa requests go through, but they never read tags in range. Not previous ones and not new ones.

I logged out interrupts, but I didn't see any difference between when it works and doesn't.

I have used a digital analyzer, but nothing out of the ordinary there. It seemed as if no tags were in the area.

Hi,

not having START_OF_RECEIVE may be ok but then you should get a NO_RESPONSE interrupt. Original RFAL will normally not return IO_ERROR.

If you have digital analyzer, then please record SPI+IRQ and share it!

Best Regards, Ulysses

Attached ErrorCapture.hex (Real extension ErrorCapture.sal) Capture made using https://www.saleae.com/downloads/

https://drive.google.com/file/d/1HP3trKfch0tgLm-TP4rdvEN691bfpKf_/view?usp=sharing

Error happens before 50 ms gap

Hi,

two issues seen here:

  1. CS is incorrectly driven here - does not go high between two read register commands. I assume your driver will not use the 0x40 on MISO as I_nre and thus driver signals IOError.Incorrect_driving_of_CS.png
  2. All Interrupt status registers need to be read within one SPI frame (DS: "The interrupt registers 0x17, 0x18 and 0x19 are to be read in one attempt.".) Single read registers will also cry out for problems. None of that seen here.

Which code base was the basis for this Rust driver? Must be quite old as the single interrupt reading is not recommended for quite some years (even before ams->ST transfer).

Best Regards, Ulysses

Ohh never noticed that CS behavior. That explains a lot 🙂 Will investigate and post an update of what happened here.

I thought reading multiple registers in one attempt is just optimization and reading multiple times would be fine. What kind of problems it can cause?

I used
https://github.com/nrfconnect/sdk-nrf/tree/f18f6929e239f01125d349dc8543c940b45b2001/lib/st25r3911b  https://github.com/stm32duino/ST25R3911B

Hi,

both codes on github are using read multiple for interrupt status. If I recall correctly when using single reads it can  happen that interrupts are lost (cleared without being present on MISO).

Regards, Ulysses