How to connect multiple RC522 RFID Reader to Raspberry PI? - raspberry-pi3

I want to know if it is possible to connect multiple RC522 to one Raspberry PI, if yes how do we do it? I read in some articles that with CS(chip select) pin we can control Readers, but the CS pin is not present on RC522 I have.
Can you please help me?

Chip Select (CS) is referred to as SS or NSS in some of the RFC522 documentation, is that the issue? If so, connect your CS0 to NSS on one module, CS1 to the NSS on the other, and you can use both modules on the same SPI bus.
If you need more devices than that, you could switch to the I2C interface. In I2C mode, a number of the pins on the chip become address selects, so you can put a whole bunch of them on the same I2C bus. The data sheet for the chip is always helpful with this sort of information. Section 8.1, "Digital interfaces" may be particularly helpful.
In I2C mode, you have 5 bits of addressing, so you can put up to 32 devices on the bus.

Posted this answer before on the raspberry pi stackexchange.
I'll just repost it here for visibility.
You can use the RST Pins to select the reader you want to use. Connect all the other pins in parallel (see schematic below). Just set all the RST pins to low, except the one on the pin you want to use. Set that one to high. Then initialize SPI, read/write, and close SPI again.
I wrote a more detailed explanation here.
This is the schematics and code I made:
Schematic for 2 readers
Schematic for 4 readers
Code to run it all (using pimylifeup's MFRC522-Python Library):
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
import spidev
class NFC():
def __init__(self, bus=0, device=0, spd=1000000):
self.reader = SimpleMFRC522()
self.close()
self.bus
self.boards = {}
self.bus = bus
self.device = device
self.spd = spd
def reinit(self):
self.reader.READER.spi = spidev.SpiDev()
self.reader.READER.spi.open(self.bus, self.device)
self.reader.READER.spi.max_speed_hz = self.spd
self.reader.READER.MFRC522_Init()
def close(self):
self.reader.READER.spi.close()
def addBoard(self, rid, pin):
self.boards[rid] = pin
def selectBoard(self, rid):
if not rid in self.boards:
print("readerid " + rid + " not found")
return False
for loop_id in self.boards:
GPIO.output(self.boards[loop_id], loop_id == rid)
return True
def read(self, rid):
if not self.selectBoard(rid):
return None
self.reinit()
cid, val = self.reader.read_no_block()
self.close()
return val
def write(self, rid, value):
if not self.selectBoard(rid):
return False
self.reinit()
self.reader.write_no_block(value)
self.close()
return True
if __name__ == "__main__":
nfc = NFC()
nfc.addBoard("reader1",5)
nfc.addBoard("reader2",6)
data = nfc.read("reader1")
nfc.write("reader2",data)

Related

How to find dma_request_chan() failure reason details?

In an external kernel module, using DMA Engine, when calling dma_request_chan() returns an error pointer of value -19, i.e. ENODEV or "No such device".
Now, in the active device tree, I do find a dma-names entry with what I'm trying to get a channel for, so my suspicion is that something else deeper in the forest is already not found.
How do I find out what's wrong?
Background:
I have a Zynq MP Ultrascale+ board here, with an FPGA design which uses AXI VDMA block to provide one channel of data to be received on the Cortex A's Linux, where the data is written to DDR4 by the FPGA and to be read from Linux.
I found that there is a Xilinx DMA driver included in the kernel, in the Xilinx source repo anyway, currently kernel version 5.6.0.
And that that driver has no user space interface, such that an intermediate kernel driver is needed.
This is depicted, and they have an example here: Section "4 DMA Proxy Design". I modified the code in the dma-proxy.c of the zip file linked there such that it uses only the RX channel, i.e. also only tries to request it.
The code for that is here, to not make this post huge:
Modified dma-proxy.c at onlinegdb.com
Line 407 has the function create_channel(), which used to use dma_request_slave_channel() which ditches the error code of the function it wraps, so to see the error, I am using that one instead: dma_request_chan().
The function create_channel() is called in function dma_proxy_probe() # line 470 (the occurences before that are deactivated by compile switch).
So by way of this call, dma_request_chan() will be called with the parameters:
create_channel(pdev, &channels[RX_CHANNEL], "dma_proxy_rx", DMA_DEV_TO_MEM);
The Device Tree for my board has an added node for dma-proxy driver as is shown at the top of the dma-proxy.c
dma_proxy {
compatible ="xlnx,dma_proxy";
dmas = <&axi_dma_0 0>;
dma-names = "dma_proxy_rx";
};
The name "axi_dma_0" matches with the name in the axi DMA device tree node:
axi_dma_0: dma#a0000000 {
#dma-cells = <0x1>;
clock-names = "s_axi_lite_aclk", "m_axi_s2mm_aclk";
clocks = <0x3 0x47 0x3 0x47>;
compatible = "xlnx,axi-dma-7.1", "xlnx,axi-dma-1.00.a";
interrupt-names = "s2mm_introut";
interrupt-parent = <0x1d>;
interrupts = <0x0 0x2>;
reg = <0x0 0xa0000000 0x0 0x1000>;
xlnx,addrwidth = <0x28>;
xlnx,sg-length-width = <0x1a>;
phandle = <0x1e>;
dma-channel#a0000030 {
compatible = "xlnx,axi-dma-s2mm-channel";
dma-channels = <0x1>;
interrupts = <0x0 0x2>;
xlnx,datawidth = <0x40>;
xlnx,device-id = <0x0>;
};
If I now look here:
% cat /proc/device-tree/dma_proxy/dma-names
dma_proxy_rx
Looks like my dma_proxy_rx, that I'm trying to request the channel for, is in there.
Edit:
In the boot log, I see this:
xilinx-vdma a0000000.dma: Please ensure that IP supports buffer length > 23 bits
irq: no irq domain found for interrupt-controller#a0010000 !
xilinx-vdma a0000000.dma: unable to request IRQ 0
xilinx-vdma a0000000.dma: WARN: Device release is not defined so it is not safe to unbind this driver while in use
xilinx-vdma a0000000.dma: Xilinx AXI DMA Engine Driver Probed!!
There are warnings - but in the end, the Xilinx AXI DMA Engine got "probed", meaning the lowest level driver loaded and is ready, right?
So it looks to me like there should be my device, but the kernel disagrees.
I've got the same problem with similar configuration. After digging a lot of kernel source code (especially drivers/dma/xilinx/xilinx_dma.c) I've solved this problem by changing channel number in dmas parameter from 0 to 1 in dma-proxy device tree entry like this:
dma_proxy {
compatible ="xlnx,dma_proxy";
dmas = <&axi_dma_0 1>;
dma-names = "dma_proxy_rx";
};
It seems that dma-proxy example is written for AXI DMA block with both mm2s (channel #0) and s2mm (channel #1) channels. And if we remove mm2s channel from AXI DMA block, the s2mm channel stays #1.

Implement high impedance 'Z' input output property with chisel

My board (apf27) has a processor (i.MX27) and a FPGA (Spartan3A) that communicate through a "memory bus" called WEIM in proc datasheet.
I want to transfer data from the FPGA to the processor. I managed to do it with a simple Output() IO :
val io = IO(new Bundle {
...
val data = Output(UInt(16.W))
val oen = Input(Bool())
...
I can read data from the processor, but that "lock" the bus. I have to release it for the nand component also present on it.
To release it I can use the signal oen (output enable) but I can't assign a high impedance value like 'Z' in Verilog/VHDL to 'release' it.
What is the right way to do it in Chisel3 ? I saw something called 'AnalogRawModule" in chisel3 github is it the things to use ?
Analog is what you're looking for. It is basically an escape to allow bidirectional wires and other signals that aren't really supported by Chisel to still connect through your Chisel design.
Here's an example:
import chisel3._
import chisel3.experimental.Analog
class AnalogBlackBox extends BlackBox {
val io = IO(new Bundle {
val bus = Analog(32.W)
})
}
class AnalogModule extends Module {
val io = IO(new Bundle {
val bus = Analog(32.W)
})
val inst = Module(new AnalogBlackBox)
inst.io.bus <> io.bus
}
object AnalogDriver extends App {
chisel3.Driver.execute(args, () => new AnalogModule)
}
You can't drive Analog-type wires in Chisel and unfortunately you can't do concatenation or bit select (although we should support that), but you can at least connect signals through. If you need to do any kind of bit selection or concatenation, you need to do that in a BlackBox.

Reading serial output from Pyserial doesnt work reliably

I am connecting to device using code blow on MacOS and out of 100 times this code would make connection only 1 or two times and dones't respond(since there is no timeout) rest of the times.
ser = serial.Serial(port="/dev/xyz",timeout = None, baudrate=115200, parity = serial.PARITY_NONE, bytesize = serial.EIGHTBITS, stopbits = serial.STOPBITS_ONE)
def exitSer(ser):
print("Closing")
ser.close()
atexit.register(exitSer, ser)
if ser.is_open:
time.sleep(2)
while(1):
print(ser.readline().decode("utf-8"))
Could you please tell me how to use programs like fcntl etc to find if this port is completely free and available for use and how to set tty port's flags to free after making port free forcibly.
Once this works, I have to run this multithreaded where each thread is running different devices expecting output in lines. Any suggestions for that just in case this works.
def startSerial(tty_id):
ser = serial.Serial(port = tty_id, timeout = None)
ser.close()
ser.open()
if ser.isOpen():
print(ser.portstr, ":connection successful.")
return ser
else:
return False
Calling ser.close() before .open() fixed it. I tested it about 200 times and i haven't been dissappointed so far. I am testing it now in multithreaded and hopefully that works too.
Thank you everybody.

touchscreen ft5x06 not responding?

I am using kontron smarc-samx6i board run with nxp imx6q processor. I am currently working with yocto In that I need to interface a touch screen of ft5316 through I2C . For that I edited the device tree as follows:
polytouch: edt_ft5x06#39 {
compatible = "edt","edt_ft5x06","edt-ft5x06";
reg = <0x39>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_smx6_i2c_gpio_1>;
irq_pin=<&gpio3 1 0>;
interrupt-parent = <&gpio3>;
interrupts = <0 70 0x04>;
};
When I am using i2cdump command the touchscreen responds successfully, but when I am working with module it won't respond.
When I am using the below command i am getting following output
root#smarc-samx6i:~# cat /proc/bus/input/devices
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="gpio-keys.27"
P: Phys=gpio-keys/input0
S: Sysfs=/devices/soc0/gpio-keys.27/input/input0
U: Uniq=
H: Handlers=kbd event0 evbug
B: PROP=0
B: EV=23
B: KEY=4000 100000 0 0 0
B: SW=1
My device did not probe and i am not getting any error while instantiating the device using the command:
echo edt_ft5x06 0x39> /sys/bus/i2c/devices/i2c-1/new_device
Instantiated device edt_ft5x06 at 0x39 device
How can i make it work!!
I assume that by "when working with the module it won't respond" you mean it won't respond to any touch events on the touchscreen. Did the driver module correctly load? Is it built-in or used as a loadable module? Did you check "dmesg" for confirming the driver loaded properly or output of lsmod? If the driver loaded properly, are you getting interrupts?
What is the output of "cat /proc/interrupts"? Do you see the interrupt requests increasing when you press the touchscreen? If not then, then you have a problem with interrupts. If you see the interrupts, can you check with an utility like "evtest" to see if you get touchscreen events?

Configure Linux I2C Speed

I am using I2C on the Snowball board, running at 400KHz by default and would like to reduce this to 100KHz.
I use the api defined in and configure as follows
m_fd = open(m_filename.c_str(), O_RDWR);
if (ioctl(m_fd, I2C_SLAVE_FORCE, m_addr) < 0)
{
throw I2cError(DeviceConfigFail);
}
Does anyone know how I would go about changing the speed to standard mode.
Thanks
You can change the I2C SCL frequency in your driver's 'struct i2c_gpio_platform_data'.
static struct i2c_gpio_platform_data xyz_i2c_gpio_data = {
.sda_pin = GPIO_XYZ_SDA,
.scl_pin = GPIO_XYZ_SCL,
.udelay = 5, //#udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz
....
};
Changing 'udelay' changes your 'xyz' i2c device's clock frequency.
You should change the I2C Frequency in driver source file of the corresponding peripheral (ie: Slave device to which you are communicating through I2C. Example: EEPROM/Camera etc.)
You may find some macro defined in that driver source code... like:
#define EEPROM_I2C_FREQ 400000 //400KHz
Change it to:
#define EEPROM_I2C_FREQ 100000 //100KHz
Only for that corresponding driver, I2C frequency/speed will be changed.

Resources