Wiegand help from a old topic

I'm trying some code from a long time ago from here.

#include "Particle.h"

const int WIEGAND_D0_PIN = D2; // Green
const int WIEGAND_D1_PIN = D3; // White

void wiegandInterrupt(); // forward declaration
bool decodeWiegand(unsigned long value); // forward declaration

volatile int cardBitCount = 0;
volatile unsigned long cardValue = 0;
volatile unsigned long cardReadStart = 0;

void setup() {
	Serial.begin(9600);

	// Wiegand pulse are narrow, typically 100 microseconds, so interrupts are desirable to accurately
	// detect them
	attachInterrupt(WIEGAND_D0_PIN, wiegandInterrupt, FALLING);
	attachInterrupt(WIEGAND_D1_PIN, wiegandInterrupt, FALLING);
}

void loop() {
	if (cardReadStart != 0) {
		if (cardBitCount == 26) {
			// Got a valid 26-bit card
			if (decodeWiegand(cardValue)) {
				// Is valid
				Particle.publish("card", String(cardValue), PRIVATE);
			}
			cardReadStart = 0;
			cardBitCount = 0;
		}
		else
		if (millis() - cardReadStart > 500) {
			Serial.println("failed to read enough bits");
			cardReadStart = 0;
			cardBitCount = 0;
		}
	}
}

void wiegandInterrupt() {
	if (cardBitCount == 0) {
		cardReadStart = millis();
		cardValue = 0;
	}
	else {
		cardValue <<= 1;
	}

	if (pinReadFast(WIEGAND_D1_PIN) == LOW) {
		cardValue |= 1;
	}
	cardBitCount++;
}

// Note: in the following table the bit numbers are 0-based, 0 - 25 for a 26-bit Wiegand code!
// Bit 25: Even parity, first half of bits
// Bits 24 - 17: Facility code, MSB first 0 - 255
// Bits 16 - 1: Card code, MSB first, 0 - 65536
// Bit 0: Odd parity, second half of bits
bool decodeWiegand(unsigned long value) {
	bool valid = false;

	int facility = (value >> 17) & 0xff;
	int card = (value >> 1) & 0xffff;

	unsigned long tempValue = value;
	int parity = 0;
	for(int ii = 0; ii < 13; ii++) {
		if (tempValue & 1) {
			parity++;
		}
		tempValue >>= 1;
	}
    if ((parity & 0x1) == 1) {
    	// First parity passed
    	parity = 0;
		for(int ii = 0; ii < 13; ii++) {
			if (tempValue & 1) {
				parity++;
			}
			tempValue >>= 1;
		}
		if ((parity & 0x1) == 0) {
			// Second parity passed; looks valid
			Serial.printlnf("value=0x%x facility=%d card=%d", value, facility, card);
			valid = true;
		}
		else {
	    	Serial.printlnf("even parity error value=0x%x", value);
		}
    }
    else {
    	Serial.printlnf("odd parity error value=0x%x", value);
    }
    return valid;
}

When I run this on a argon I'm just not getting enough bits. The reader is made for a 26bit h10301 format and that is what the card is. I'm running a i2c level shift board for now to get the 5v output to a 3.3 for the board.

I also have added system threading.

I think the problem you are having is related to interrupt latency on the Argon (also Boron, B SoM, Tracker, all nRF52 devices). I believe I tried this in the past and it did not work reliably. Basically, the difference in pulse widths between 0 and 1 is such that a delayed interrupt is enough to cause the wrong value to be interpreted.

It's theoretically possible to use the SPI peripheral to read the signal without interrupt latency, but because Wiegand requires two signals, it requires both SPI peripherals and a lot of pins so it didn't seem practical. You can see the DMA technique in JSN-SR04_Gen3_RK but it will be a lot of work to convert to be able to handle Wiegand.

I haven't tried the P2/Photon 2, but the GPIO is slow and that will likely be an issue on the RTL872x platform.

Is there any chip to put out there that could read it and then pass the info over spi or i2c?

I've never seen a Wiegand to I2C bridge chip, but that's exactly what is needed. I almost implement one using a small PIC processor, but got distracted before I did it.

If I found a small micro controller that could be programed similar to particle / arduino that code should work for that little chip? Then I would have to save it and ship it back to the particle device?

@darkstar2002 I use a sidecar processor on one board to support a Wiegand card reader. The processor is a ATmega328P (aka Arduino UNO) - the Photon then talks over I2C to the ATmega328P which tells it when it has read a card or keypad input.

It is possible to use a smaller/cheaper microcontroller, however, UNO is a great prototyping platform and there is space should you want to add other card protocols.

IMHO this would likely be the best solution with the Argon for the reasons @rickkas7 explained about the interrupt timing. For me the Photon has got enough going on managing the business logic and the user interface and cloud comms.

1 Like

Thank you all for the help.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.