Go Down

Topic: arduino to EM4095 (Read 5335 times) previous topic - next topic

suby

Hi all!

This is my first post in this Forum.  :D

I've bought a RFID reader card from Mikroelektronika.
It is based on EM4095 IC, so it just translates from RF to TTL with CLK and DEMOD_OUT signals.

After some hours and several downloads, I don't get a suitable frame from this IC.  :-/

My questions are:

1) Has anyone checked this hardware with Arduino controllers?
2) Any good sample code to interface it?

Thanks!

suby


suby

Hi all!

I've done a lot of progress since I've got an oscilloscope from my Workshop. There was something wrong at the EM4095's MOD pin setting.  8-)

The thing is that I realised that the ARDUINO controller seems to run slower than should be for 16 MIPS. I could understand that a very stupid program such as an output toggle could be performed in 2 us, but on the oscilloscope I get 10 us!!!!   :o

Does anyone understand this behaviour ????  :-X

I've changed all my code and learned how to set interrupts to let the ARDUINO find the 125 kHz clock (CLK) and the demodulator OUT signals.  ;) The thing is that my code seems to be Ok but I cannot get always the same string at the output when reading a tag.

Has anyone fought against this EM4095 with an ARDUINO????  :'(

I attach a copy of my test program.

Thanks in advance !!!!

/me


Quote

#include <LED.h>

#define  CLK  2
#define  OUT  3
#define  MOD  8
#define  SHD  7

LED led = LED(13);
boolean val = false;
unsigned char count,bitno,i;
char sequ[10];
char* cadena;

/*
 Init() function
*/
void setup()
{
 // global variables
 count = bitno = 0;
 cadena = sequ;
 for (i=0;i<10;i++) sequ=0;
 
 // i/o setting
 pinMode(CLK,INPUT);
 pinMode(OUT,INPUT);
 pinMode(MOD,OUTPUT);
 pinMode(SHD,OUTPUT);

 // em4095
 digitalWrite(MOD,HIGH);
 digitalWrite(SHD,HIGH);
 delay(100);
 digitalWrite(SHD,LOW);
 digitalWrite(MOD,LOW);

 // led
 led.blink(500,2);

 // UART
 Serial.begin(9600);
 Serial.println("em4095 RFid reader for ARDUINO");

 // interrupts
 attachInterrupt(0,rf_clock,RISING);
}

void loop()
{
 // process header
 if (!(sequ[0] & 0xff) || !(sequ[1] & 0x01))
 {
   detachInterrupt(0);
   count = bitno = 0;
   cadena = sequ;
   for (i=0;i<10;i++) sequ = 0;
   led.on();
   Serial.print("Bad header: ");
   Serial.print(sequ[0],HEX);
   Serial.print(",");
   Serial.print(sequ[1],HEX);
   Serial.println();
   delay(100);
   led.off();
   attachInterrupt(0,rf_clock,RISING);
 }

 // process frame
 if (count >= 64)
 {
   detachInterrupt(0);
   cadena = sequ;
   count = bitno = 0;

   for (i=0;i<8;i++)
   {
     Serial.print(sequ,DEC);
     Serial.print(",");
   }
   Serial.println();    
   
   led.blink(500,2);
   
   for (i=0;i<10;i++) sequ = 0;
 

   delay(1000);
   attachInterrupt(0,rf_clock,RISING);
 }
}

/*
 interrupt routine
  loads the bits array
*/
void rf_clock()
{
 val = !digitalRead(OUT);
 bitWrite(*cadena,bitno,val);
 count++;
 bitno++;
 if (bitno == 8)
 {
   cadena ++;
   bitno = 0;
 }
}


suby

Hi all!

I've recently bought a MIKROELEKTRONICA RFid READER HW 1.01 and I'm planning to plug it to an Arduino Duemilianove board. After several tests, I have some questions:

1) Anyone knows what kind of encoding are using in Mikroelektronika's transponders? Manchester, Bi-phase or PSK?
According to your examples, it doesn't seem Manchester. Maybe Bi-phase?
How can I know this?

2) Regarding my hardware, my wiring is something like this:

PB0/T1-ICAP <------- DEM/OUT (1)
PD5/EXT-T1 <------- CLK (2)
PD6 -------> SHD (3)
PD7 -------> MOD (4)

I'm trying decode the EM4095 assuming Manchester encoding. My code is using CLK as a clock for Timer1 and ICP1 as a capture signal. According to all the information I have, this should be Ok.

My Timer1 piece of code looks like this:
Quote

/*******************************************************
Initialize function for Timer1
*******************************************************/
void timer1Init(boolean edge)
{
 TCCR1A = TCCR1B = 0; // stop timer1
 TCNT1 = 0;  // start from 0000
 ICR1 = 0; // using timer1 capture
 
 // rising or falling edge at ICP1
 if (edge == 1)
   TCCR1B = (1<<ICES1) | (1<<CS12) | (1<<CS11) | (1<<CS10);  // ICP1 rising
 else
   TCCR1B = (1<<CS12) | (1<<CS11) | (1<<CS10) ; // ICP1 falling
 
 // timer1 interrupt mask register
 TIMSK1 |= (1<<ICIE1) | (1<<TOIE1);
}

/*******************************************************
Timer1 oveRFlow interrupt // VECTOR 13
*******************************************************/
ISR(TIMER1_OVF_vect)
{
 TCNT1 = 0;
 // set counter for debug
 TIFR1 &= ~(1 << TOV1);
}

/*******************************************************
Timer1 Capture interrupt // VECTOR 10
*******************************************************/
ISR(TIMER1_CAPT_vect )
{
 int value = ICR1; // get current capture
 int currentWidth;
   
 if (edgeDir)
 {
   TCCR1B &= ~(1<<ICES1); // set ICP1 at falling edge
   edgeDir = false;
 }
 else
 {
   TCCR1B |= (1<<ICES1); // set ICP1 at rising edge
   edgeDir = true;
 }
 
 currentWidth = value - oldWidth;
 oldWidth = value;

 if (currentWidth > 40)
 {
   bitValue = ~bitValue;
   bitStore = true;
 }

 if (bitStore) // store current bitValue into RFBuff array
 {
//    if (bitValue) PORTC |= LD; // turn led (only debug)
//    else PORTC &= ~LD;
   if (bitValue) digitalWrite(13,HIGH);
   else digitalWrite(13,LOW);
   
   RFBitStore(bitValue);
   bitTransNum++; // increase counter
 }
 bitStore = ~bitStore;
 TIFR1 &= ~(1 << ICF1);
}



Any suggestion?  :?:

Thanks in advance!

Grumpy_Mike

Quote
It is based on EM4095 IC, so it just translates from RF to TTL with CLK and DEMOD_OUT signals.


Quote
Anyone knows what kind of encoding are using in Mikroelektronika's transponders?



You have answered your own question. The IC does not use any sort of encoding. The encoding is purely a function of the RFID card you are using. So find out what that is and you will know.


suby

I've contacted microElektronika regarding this subject. The transponder uses Manchester encoding.

Really this is my first time with RFID and I've learned a lot of new things.

Anyway thanks for your answer!

Marcelo T

I have the mikroe rfid too, waiting to see your progress  :)

suby

I'm a bit disappointed with this reader.

Regarding to Mikroelektronica's answer, they say

Manchester encoding
64 bits

I've tried to translate the code from their PIC's C to the Arduino IDE. It's here:

Code: [Select]

/*******************************************************
project:  RFID Reader
target:   ARDUINO Duemilianove with Atmega328
input:    RFID READER V1.01 by Mikroelektronika
author:   mailto:sammarcoarmengol@gmail.com
compiler: ARDUINO - 0016

Based on the code written by Mikroelektronika for EasyPIC5

Manchester 64 bits
 
*******************************************************/

unsigned char
 
 one_seq,    // counts the number of 'logic one' in series
 data_in;    // gets data bit depending on data_in_1st and data_in_2nd
int
 cnt1, cnt2, // auxiliary counters
 data_index;
volatile char cnt;        // interrupt counter
volatile char sync_flag;  // in the sync routine if this flag is set
char i;
char data[256];
char data_valid[64];
char bad_synch;

/*******************************************************
 This is external INT1 interrupt (for sync and sample)
 - this interrupt is enabled once we get falling edge on RB0 (in the INT0 interrupt routine)
 it is enabled until we get 128 data bits
*******************************************************/
void clock() {
// ISR(INT1_vect) {
 cnt++;
}

/*******************************************************
 This is external INT0 interrupt (for sync start)
 - once we get falling edge on RB0 we are disabling INT0 interrupt
*******************************************************/
void demod() {
// ISR(INT0_vect) {
 cnt = 0;
 sync_flag = 1;
//  EIMSK &= ~(1<<INT0);
//  EIMSK |= (1<<INT1);
}

/*******************************************************
Parity check with Checksum
*******************************************************/
char CRC_Check(char *bit_array) {

 char row_count, row_bit, column_count;
 unsigned char row_sum, column_sum;
 char row_check[5];
 char column_check[11];

 // row parity check:
 row_count = 9;                     // count rows
 while (row_count < 59) {
   column_count = 0;                // count columns
   while (column_count < 5) {
      row_check[column_count] = (bit_array[row_count+column_count] >> 2);
      column_count++;
   }
   row_bit = 0;                     // count row bits
   row_sum = 0;
   while (row_bit < 4) {
     row_sum += row_check[row_bit];
     row_bit++;
   }
 row_sum &= 0x01;
 if (row_sum != row_check[4]) return 0;

 row_count += 5;
 } // end row parity check

 // column parity check
 column_count = 9;                  // count columns
 while (column_count < 13) {
   row_bit = 0;                     // count column bits
   row_count = 0;                   // count rows
   while (row_bit < 11) {
     column_check[row_bit] = bit_array[column_count+row_count] >> 2;
     row_bit++;
     row_count += 5;
   }
   row_bit = 0;                     // count column bits
   column_sum = 0;

   while (row_bit < 10) {
      column_sum += column_check[row_bit];
      row_bit++;
   }
   column_sum &= 1;
   if (column_sum != column_check[10]) return 0;
   column_count++;
 } // end column parity check

 if (bit_array[63] == 1)  return 0;
 return  1;
}

/*******************************************************
Initialize function for ARDUINO I/O
*******************************************************/
void setup() {
 noInterrupts();
 // I/O
 pinMode(3,INPUT);  // CLK pin as INPUT
 pinMode(2,INPUT);  // DEMOD/OUT pin as INPUT
 pinMode(4,OUTPUT);
 pinMode(5,OUTPUT);
 pinMode(13,OUTPUT);
 
 digitalWrite(2,LOW);
 digitalWrite(3,LOW);
 digitalWrite(4,LOW);
 digitalWrite(5,LOW);

 interrupts();
 Serial.begin(9600);
}

/*******************************************************
  Main loop
*******************************************************/
void loop() {
 char dummy;
 
start:
 // Global registers
 bad_synch = 0;                // set bad synchronization variable to zero
 sync_flag = 0;                // sync_flag is set when falling edge on RB0 is detected
 one_seq = 0;                  // counts the number of 'logic one' in series
 data_in = 0;                  // gets data bit
 data_index = 0;               // marks position in data array
 cnt = 0;                      // interrupt counter
 cnt1 = 0;                     // auxiliary counter
 cnt2 = 0;                     // auxiliary counter
 
 attachInterrupt(0, demod, FALLING); // enable external interrupt INT0

 do dummy = 1;
 while (sync_flag == 0); // wait for falling edge at INT0
 
detachInterrupt(0); // disable INT0
attachInterrupt(1, clock, RISING); // enable INT1

 while (cnt != 16); // wait for 16 clocks at clk
 cnt = 0;
 data[0] = (PORTD & (1<<2)) >> 2;
 Serial.print("0,");
 Serial.println(PORTD & (1<<2),HEX);

 for (data_index = 1; data_index < 256; data_index++) {   // getting 128 bits of data from RB0
   do ;
   while (cnt != 32);  // getting bit from RB0 every 32 clocks on RB1
   
   cnt = 0;
   data[data_index] = (PORTD & (1<<2));
   
   Serial.print(data_index,DEC);
   Serial.print(",");
   Serial.println(PORTD & (1<<2),HEX);
   
   if (data_index & 1)
     if (data[data_index] ^ data[data_index-1] == 0) {
       bad_synch = 1;
       break;  //bad synchronisation
       }
 }
 detachInterrupt(1); // disable external interrupt on INT1 (for sync and sample)
 
 if (bad_synch) goto start;   // try again
 one_seq = 0;
 for(cnt1 = 0; cnt1 <= 127; cnt1++) {    // we are counting 'logic one' in the data array
    if (data[cnt1 << 1] == 4)  one_seq++;  // "logig one" is at bit 2 !!!!
    else one_seq = 0;

    if (one_seq == 9) break;   // if we get 9 'logic one' we break from the loop
 }   //   (the position of the last  'logic one' is in the cnt1)
 
 if ((one_seq == 9) && (cnt1 < 73)) {   // if we got 9 'logic one' before cnt1 position 73
                                         //   we write that data into data_valid array
    Serial.println("5");
    data_valid[0] = 1;  //   (it has to be before cnt1 position 73 in order
    data_valid[1] = 1;  //    to have all 64 bits available in data array)
    data_valid[2] = 1;
    data_valid[3] = 1;
    data_valid[4] = 1;
    data_valid[5] = 1;
    data_valid[6] = 1;
    data_valid[7] = 1;
    data_valid[8] = 1;

    for(cnt2 = 9; cnt2 <= 63; cnt2++) {      // copying the rest of data from the data array into data_valid array
       cnt1++;
       data_valid[cnt2] = data[cnt1 << 1];
    }
    if (CRC_Check(data_valid) == 1) {  // if data in data_valid array pass the CRC check
      Serial.println("CRC CHECK OK!");
      for (i=0; i<=64; i++)
        if (data_valid[i] == 0) Serial.print("0");
        else Serial.print("1");
      Serial.println();
      digitalWrite(13,HIGH); // turn on led
    }
 }
 delay(200);
 digitalWrite(13,HIGH); // turn off led
   delay(200);

}


This was my last version. Just remove all the Serial.print() instances (I've written them for debugging purposes).

The interrupts work but I cannot go beyond the bad_synch mark.

Try it with this code and tell me your experience with it. Who knows!?  ::)

Good Luck!

/me

Grumpy_Mike

You have your global registers defined inside the loop(), this makes them not global but redefined each time round the loop. To make them global define them outside a function.

You define PINs 2 & 3 and inputs and then you write a low value to them. This in effect makes sure that the internal pull up resistor is off which it is by default, what do you mean by this.

Basically you are trying to run before you can walk and doing the whole thing at once. This makes it difficult to spot any other mistakes you have made. Just strip it down to the essentials of detecting either a zero or a one. Make that work before you start looking at how to join those together to read the tag.

suby

Really I've been playing with Arduino for a month. I've been several years without touching a microcontroller.

Let me explain all these issues:

Quote
You have your global registers defined inside the loop(), this makes them not global but redefined each time round the loop. To make them global define them outside a function.


Which registers? The code just resets several flags to zero at start-up. Look that there are several wait conditions that stop the code until the condition is set.

Quote
You define PINs 2 & 3 and inputs and then you write a low value to them. This in effect makes sure that the internal pull up resistor is off which it is by default, what do you mean by this.


This was just what I was planning to do. Really this has no effect to code behaviour.

Quote
Just strip it down to the essentials of detecting either a zero or a one. Make that work before you start looking at how to join those together to read the tag.


Obviously there are many errors in my code and I haven't solved them properly. Anytime I fail I try to understand what's wrong just trying to make the microcontroller detect a pin change or switch a led and things like these. As you may agree, the problems usually come from a lack of knowledge (I'm not used to Atmega internals or to gcc) and also wrong tools. To debug this application properly, a good oscilloscope is a must!  :-?
That's the reason that most people visit Forums like this.

Thanks for your valuable comments!  :)

Grumpy_Mike

Quote

Which registers?


your code says:-

Quote
// Global registers
 bad_synch = 0;                // set bad synchronization variable to zero
 sync_flag = 0;                // sync_flag is set when falling edge on RB0 is detected
 one_seq = 0;                  // counts the number of 'logic one' in series
 data_in = 0;                  // gets data bit


You could call them variables but you referd to them as registers so I did.

Quote
To debug this application properly, a good oscilloscope is a must!

Normally I would be the first to agree but this is decoding inputs. The only thing a scope could help you with is toggling a pin at certain points in the code and seeing if that is in the position you expect it to be in the data stream.

When I wrote the software for a reader to decode Manchester encoding, I took a different approach. I fired of an interrupt service routine each reader clock and then looked at the signal level and gathers the data like that. Then I could analyse the data stream quite easy. Unfortunately I have not got one of these readers but might build my own one day. Sadly I am covered by a confidentially agreement not to that sort of thing from my previous employer.

suby

Thanks for your answers, Mike!  :)

It would be great if you try to link this Mikroelektronika's RFID Reader to the Arduino or build one of your own.

tomek123

Hi,
I playe a bit with EM4095 and Arduino today. It seems that Mike was pointing in right direction.  I modified first code a bit and it makes 512 times PORTD byte saving to array. If You send this array to serial port it looks like:

Quote
CLK:000111111000000111110000001111110000001111110000001111110000011111100000


So each level is seen for 5-6 Arduino cycles... So if You make too much operations in interrupt code You can miss some EM4095 cycles/data.
I have problems now with some noise on DEMOD_OUT on PCB i have bought. After the  PCB manufactuer helps me with that i will try to make some "light" interrupt code that will be able (or not...) to solve the lack of EM4095 opensource for Arduino ;)
I dont see a problem when someone else with working PCB joins the topic ;)

Code: [Select]

#define  CLK  2
#define  OUT  3
#define  MOD  9
#define  SHD  8
byte pins;
byte bitsb[513];
unsigned int  count,i;
/*
Init() function
*/
void setup()
{
// i/o setting
pinMode(CLK,INPUT);
pinMode(OUT,INPUT);
pinMode(MOD,OUTPUT);
pinMode(SHD,OUTPUT);
// em4095
digitalWrite(MOD,HIGH);
digitalWrite(SHD,HIGH);
delay(250);
digitalWrite(SHD,LOW);
digitalWrite(MOD,LOW);

// UART
Serial.begin(9600);
Serial.println("em4095 RFid reader for ARDUINO");

}

void loop()
{
 delay(2000);
rf_clock1();
// process frame
if (count >= 512)
{
  count = 0;
  Serial.print("CLK:");
   for (i=0;i<512;i++)
  {
    pins=bitsb[i]&B00000100;
   
     if (pins== 0){Serial.print("0");}else {Serial.print("1");};
  }
  Serial.println();  
  Serial.print("OUT:");  
   for (i=0;i<512;i++)
  {
    pins=bitsb[i]&B00001000;
   
     if (pins== 0){Serial.print("1");}else {Serial.print("0");};
  }
Serial.println();
delay(250);
}
}
/*
interrupt routine
 loads the bits array
*/
void rf_clock1()
{
for (i=0;i<512;i++) { bitsb[i] = PIND;};
count=512;
}

Go Up