Pages: [1]   Go Down
Author Topic: arduino to EM4095  (Read 4002 times)
0 Members and 1 Guest are viewing this topic.
CATALUNYA
Offline Offline
Full Member
***
Karma: 1
Posts: 112
I started my electronics career with MICROCHIP PIC16 microcontrollers and assembler. After 10 years without touching electronics, I restarted it as a hobby (and sometimes work) with ATMEL and Arduinos.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi all!

This is my first post in this Forum.  smiley-grin

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!
Logged

CATALUNYA
Offline Offline
Full Member
***
Karma: 1
Posts: 112
I started my electronics career with MICROCHIP PIC16 microcontrollers and assembler. After 10 years without touching electronics, I restarted it as a hobby (and sometimes work) with ATMEL and Arduinos.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Further information about my hardware:

http://sites.google.com/site/freeduinoprojekt/arduino-to-mikroe-rfi-reader
Logged

CATALUNYA
Offline Offline
Full Member
***
Karma: 1
Posts: 112
I started my electronics career with MICROCHIP PIC16 microcontrollers and assembler. After 10 years without touching electronics, I restarted it as a hobby (and sometimes work) with ATMEL and Arduinos.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.  smiley-wink 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 == smiley-cool
  {
    cadena ++;
    bitno = 0;
  }
}
Logged

CATALUNYA
Offline Offline
Full Member
***
Karma: 1
Posts: 112
I started my electronics career with MICROCHIP PIC16 microcontrollers and assembler. After 10 years without touching electronics, I restarted it as a hobby (and sometimes work) with ATMEL and Arduinos.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
Logged

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 508
Posts: 31394
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Logged

CATALUNYA
Offline Offline
Full Member
***
Karma: 1
Posts: 112
I started my electronics career with MICROCHIP PIC16 microcontrollers and assembler. After 10 years without touching electronics, I restarted it as a hobby (and sometimes work) with ATMEL and Arduinos.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 1
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have the mikroe rfid too, waiting to see your progress  smiley
Logged

CATALUNYA
Offline Offline
Full Member
***
Karma: 1
Posts: 112
I started my electronics career with MICROCHIP PIC16 microcontrollers and assembler. After 10 years without touching electronics, I restarted it as a hobby (and sometimes work) with ATMEL and Arduinos.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
/*******************************************************
 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!?  :smiley

Good Luck!

/me
Logged

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 508
Posts: 31394
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

CATALUNYA
Offline Offline
Full Member
***
Karma: 1
Posts: 112
I started my electronics career with MICROCHIP PIC16 microcontrollers and assembler. After 10 years without touching electronics, I restarted it as a hobby (and sometimes work) with ATMEL and Arduinos.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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!  smiley
Logged

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 508
Posts: 31394
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

CATALUNYA
Offline Offline
Full Member
***
Karma: 1
Posts: 112
I started my electronics career with MICROCHIP PIC16 microcontrollers and assembler. After 10 years without touching electronics, I restarted it as a hobby (and sometimes work) with ATMEL and Arduinos.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for your answers, Mike!  smiley

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

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley-wink
I dont see a problem when someone else with working PCB joins the topic smiley-wink

Code:
#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;
}
Logged

Pages: [1]   Go Up
Jump to: