CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Using MFRC522 RFID Reader with PIC16F877
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
Mario_KA



Joined: 16 Nov 2017
Posts: 22

View user's profile Send private message

Using MFRC522 RFID Reader with PIC16F877
PostPosted: Thu Nov 30, 2017 6:51 am     Reply with quote

I managed to implement the MFRC522. The headerfile is based on https://github.com/ljos/MFRC522

main.c
Code:
#include <main.h>
#include <lcd16216.c>
#define CS PIN_A5
#use rs232( baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, ERRORS)

//spi modes
#define SPI_MODE_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1  (SPI_L_TO_H)
#define SPI_MODE_2  (SPI_H_TO_L)
#define SPI_MODE_3  (SPI_H_TO_L | SPI_XMIT_L_TO_H)

byte FoundTag; // Variable used to check if Tag was found
byte ReadTag; // Variable used to store anti-collision value to read Tag information
byte TagData[16]; // Variable used to store Full Tag Data
byte GoodTagSerialNumber[4] = {0x9E, 0x80, 0xB1, 0x59}; // The Tag Serial number we are looking for
int i=0;
char buffer[20],buffer2[20],text[20];
byte version;
int GoodTag=0; // Variable used to confirm good Tag Detected

#include <mario_rfid.h>

void checktag()
{
   if (GoodTag == 1)
   {
      printf("Access granted\r\n");   
      GoodTag=0;
      delay_ms(500);
   }
   else
   {
      printf("Access Denied\r\n");   
      GoodTag=0;
      delay_ms(500);
   }
}
void readRFID()
{
    // Get anti-collision value to properly read information from the Tag
    ReadTag = antiCollision(TagData);
 
    printf("Tag detected.\r\n");
    printf("Serial Number: \r\n");
    text = "Tag Serial";
   
   for(i=0;i<=2;i++)
   {
    sprintf(buffer2,"%2X",(TagData[i])); //display version in hexadecimal
    delay_ms(20);
    printf(buffer2);
    printf(", ");
   }
    sprintf(buffer2,"%2X",(TagData[i])); //display version in hexadecimal
    delay_ms(20);
    printf(buffer2);
    printf("\r\nCheck Validity \r\n");
   
   for(int i=0; i <= 3; i++)
   {
    if (GoodTagSerialNumber[i] != TagData[i])
   {
    GoodTag=0;
    break; // if not equal, then break out of the "for" loop
   }
   }
   
   if (TagData[3]==GoodTagSerialNumber[3])
   {
   // if we made it to 4 loops then the Tag Serial numbers are matching
   GoodTag=1;
   }
}


void print(){
version = readFromRegister(VersionReg);

if(!version)
{
 
  text = "NO DEVICE";
  lcd_gotoxy(1, 1);//go to position 1,1 on lcd
   lcd_print(text);
 
}
if(version)
{
 
  text = "DEVICE found";
  lcd_gotoxy(1, 1);//go to position 1,1 on lcd
  lcd_print(text);//print on lcd
  sprintf(buffer,"%2X",(version)); //display version in hexadecimal
  lcd_gotoxy(1, 2); //go to second line of lcd
  lcd_print(buffer);
}
}

void main()
{
   setup_oscillator(OSC_8MHZ, 3);  //Adjust Oscillator for proper Serial Communication
   setup_spi(SPI_MASTER|SPI_MODE_0|SPI_CLK_DIV_16);
   lcd_init();
   lcd_clear();
   delay_ms(50);
   begin(); //initialize MFRC522
   print(); //print Firmwareverion on LCD
   
   while(TRUE)
   {
     //  Check to see if a Tag was detected
     // If yes, then the variable FoundTag will contain "MI_OK"
    FoundTag = requestTag(MF1_REQIDL, TagData);
    printf("Checking for Tag \r\n");
    delay_ms(2000);
   
   
     if (FoundTag == MI_OK)
     {
        readRFID();
        checktag();
        delay_ms(500);
     }
       
     else printf("No Tag found");
     
   }
}
         


RFID.h
Code:
#define     MAX_LEN               16        // Maximum length of an array. CHECK IF IT IS MAXIMUM LENGTH/SIZE OF FIFO!!!!!!!!!!!

//MF522 MFRC522 error codes.
#define     MI_OK                 0         // Everything A-OK.
#define     MI_NOTAGERR           1         // No tag error
#define     MI_ERR                2         // General error

//MF522 Command word
#define     MFRC522_IDLE          0x00      // NO action; Cancel the current command
#define     MFRC522_MEM           0x01      // Store 25 byte into the internal buffer.
#define     MFRC522_GENID         0x02      // Generates a 10 byte random ID number.
#define     MFRC522_CALCCRC       0x03      // CRC Calculate or selftest.
#define     MFRC522_TRANSMIT      0x04      // Transmit data
#define     MFRC522_NOCMDCH       0x07      // No command change.
#define     MFRC522_RECEIVE       0x08      // Receive Data
#define     MFRC522_TRANSCEIVE    0x0C      // Transmit and receive data,
#define     MFRC522_AUTHENT       0x0E      // Authentication Key
#define     MFRC522_SOFTRESET     0x0F      // Reset

//Mifare_One tag command word
#define     MF1_REQIDL            0x26      // find the antenna area does not enter hibernation
#define     MF1_REQALL            0x52      // find all the tags antenna area
#define     MF1_ANTICOLL          0x93      // anti-collision
#define     MF1_SELECTTAG         0x93      // election tag
#define     MF1_AUTHENT1A         0x60      // authentication key A
#define     MF1_AUTHENT1B         0x61      // authentication key B
#define     MF1_READ              0x30      // Read Block
#define     MF1_WRITE             0xA0      // write block
#define     MF1_DECREMENT         0xC0      // debit
#define     MF1_INCREMENT         0xC1      // recharge
#define     MF1_RESTORE           0xC2      // transfer block data to the buffer
#define     MF1_TRANSFER          0xB0      // save the data in the buffer
#define     MF1_HALT              0x50      // Sleep


//------------------ MFRC522 registers---------------
//Page 0:Command and Status
#define     Reserved00            0x00
#define     CommandReg            0x01
#define     CommIEnReg            0x02
#define     DivIEnReg             0x03
#define     CommIrqReg            0x04
#define     DivIrqReg             0x05
#define     ErrorReg              0x06
#define     Status1Reg            0x07
#define     Status2Reg            0x08
#define     FIFODataReg           0x09
#define     FIFOLevelReg          0x0A
#define     WaterLevelReg         0x0B
#define     ControlReg            0x0C
#define     BitFramingReg         0x0D
#define     CollReg               0x0E
#define     Reserved01            0x0F
//Page 1:Command
#define     Reserved10            0x10
#define     ModeReg               0x11
#define     TxModeReg             0x12
#define     RxModeReg             0x13
#define     TxControlReg          0x14
#define     TxAutoReg             0x15
#define     TxSelReg              0x16
#define     RxSelReg              0x17
#define     RxThresholdReg        0x18
#define     DemodReg              0x19
#define     Reserved11            0x1A
#define     Reserved12            0x1B
#define     MifareReg             0x1C
#define     Reserved13            0x1D
#define     Reserved14            0x1E
#define     SerialSpeedReg        0x1F
//Page 2:CFG
#define     Reserved20            0x20
#define     CRCResultRegM         0x21
#define     CRCResultRegL         0x22
#define     Reserved21            0x23
#define     ModWidthReg           0x24
#define     Reserved22            0x25
#define     RFCfgReg              0x26
#define     GsNReg                0x27
#define     CWGsPReg              0x28
#define     ModGsPReg             0x29
#define     TModeReg              0x2A
#define     TPrescalerReg         0x2B
#define     TReloadRegH           0x2C
#define     TReloadRegL           0x2D
#define     TCounterValueRegH     0x2E
#define     TCounterValueRegL     0x2F
//Page 3:TestRegister
#define     Reserved30            0x30
#define     TestSel1Reg           0x31
#define     TestSel2Reg           0x32
#define     TestPinEnReg          0x33
#define     TestPinValueReg       0x34
#define     TestBusReg            0x35
#define     AutoTestReg           0x36
#define     VersionReg            0x37
#define     AnalogTestReg         0x38
#define     TestDAC1Reg           0x39
#define     TestDAC2Reg           0x3A
#define     TestADCReg            0x3B
#define     Reserved31            0x3C
#define     Reserved32            0x3D
#define     Reserved33            0x3E
#define     Reserved34            0x3F
//-----------------------------------------------


//Reads the value at a register.
byte readFromRegister(byte addr) {
  byte val;
  output_low(CS);
  spi_write(((addr<<1)&0x7E) | 0x80);
  val =spi_read(0x00);
  output_high(CS);
  return val;
}

//writes Values to specified registers.
void writeToRegister(byte addr, byte val) {
  output_low(CS);

  //Address format: 0XXXXXX0
  spi_write((addr<<1)&0x7E);
  spi_write(val);

  output_high(CS);
}

//Mask to update registers
void setBitMask(byte addr, byte mask) {
  byte current;
  current = readFromRegister(addr);
  writeToRegister(addr, current | mask);
}

//remove bitmask  maybe not necessary
void clearBitMask(byte addr, byte mask) {
  byte current;
  current = readFromRegister(addr);
  writeToRegister(addr, current & (~mask));
}

//Initialize RFID Reader
//Does the setup for the MFRC522.
void reset() {
  writeToRegister(CommandReg, MFRC522_SOFTRESET);
}



void begin() {
  output_high(CS);

  reset();

  //Timer: TPrescaler*TreloadVal/6.78MHz = 24ms
 writeToRegister(TModeReg, 0x8D);   
  delay_ms(20);// Tauto=1; f(Timer) = 6.78MHz/TPreScaler
  writeToRegister(TPrescalerReg, 0x3E);  // TModeReg[3..0] + TPrescalerReg
  delay_ms(20);
  writeToRegister(TReloadRegL, 30);
  delay_ms(20);
  writeToRegister(TReloadRegH, 0);
  delay_ms(20);
  writeToRegister(TxAutoReg, 0x40);      // 100%ASK
  delay_ms(20);
  writeToRegister(ModeReg, 0x3D);        // CRC initial value 0x6363
  delay_ms(20);
 //writeToRegister(TxControlReg, 0x82);     
  delay_ms(20);
 setBitMask(TxControlReg, 0x03);        // Turn antenna on.
}

//Checking MFRC522 Firmwareversion
byte getFirmwareVersion() {
  byte response;
  response = readFromRegister(VersionReg);
  return response;
}


/**************************************************************************/
/*!

  @brief   Sends a command to a tag.

  @param   cmd     The command to the MFRC522 to send a command to the tag.
  @param   data    The data that is needed to complete the command.
  @param   dlen    The length of the data.
  @param   result  The result returned by the tag.
  @param   rlen    The number of valid bits in the resulting value.

  @returns Returns the status of the calculation.
           MI_ERR        if something went wrong,
           MI_NOTAGERR   if there was no tag to send the command to.
           MI_OK         if everything went OK.

 */
/**************************************************************************/

int commandTag(byte cmd, byte *data, int dlen, byte *result, int *rlen) {
  int status = MI_ERR;
  byte irqEn = 0x00;
  byte waitIRq = 0x00;
  byte lastBits, n;
  int i;

  switch (cmd) {
  case MFRC522_AUTHENT:
    irqEn = 0x12;
    waitIRq = 0x10;
    break;
  case MFRC522_TRANSCEIVE:
    irqEn = 0x77;
    waitIRq = 0x30;
    break;
  default:
    break;
  }

  writeToRegister(CommIEnReg, irqEn|0x80);    // interrupt request
  clearBitMask(CommIrqReg, 0x80);             // Clear all interrupt requests bits.
  setBitMask(FIFOLevelReg, 0x80);             // FlushBuffer=1, FIFO initialization.

  writeToRegister(CommandReg, MFRC522_IDLE);  // No action, cancel the current command.

  // Write to FIFO
  for (i=0; i < dlen; i++) {
    writeToRegister(FIFODataReg, data[i]);
  }

  // Execute the command.
  writeToRegister(CommandReg, cmd);
  if (cmd == MFRC522_TRANSCEIVE) {
    setBitMask(BitFramingReg, 0x80);  // StartSend=1, transmission of data starts
  }

  // Waiting for the command to complete so we can receive data.
  i = 25; // Max wait time is 25ms.
  do {
    delay_ms(1);
    // CommIRqReg[7..0]
    // Set1 TxIRq RxIRq IdleIRq HiAlerIRq LoAlertIRq ErrIRq TimerIRq
    n = readFromRegister(CommIrqReg);
    i--;
  } while ((i!=0) && !(n&0x01) && !(n&waitIRq));

  clearBitMask(BitFramingReg, 0x80);  // StartSend=0

  if (i != 0) { // Request did not time out.
    if(!(readFromRegister(ErrorReg) & 0x1D)) {  // BufferOvfl Collerr CRCErr ProtocolErr
      status = MI_OK;
      if (n & irqEn & 0x01) {
        status = MI_NOTAGERR;
      }

      if (cmd == MFRC522_TRANSCEIVE) {
        n = readFromRegister(FIFOLevelReg);
        lastBits = readFromRegister(ControlReg) & 0x07;
        if (lastBits) {
          *rlen = (n-1)*8 + lastBits;
        } else {
          *rlen = n*8;
        }

        if (n == 0) {
          n = 1;
        }

        if (n > MAX_LEN) {
          n = MAX_LEN;
        }

        // Reading the recieved data from FIFO.
        for (i=0; i<n; i++) {
          result[i] = readFromRegister(FIFODataReg);
        }
      }
    } else {
      status = MI_ERR;
    }
  }
  return status;
}


/**************************************************************************/
/*

  @brief   Checks to see if there is a tag in the vicinity.

  @param   mode  The mode we are requsting in.
  @param   type  If we find a tag, this will be the type of that tag.
                 0x4400 = Mifare_UltraLight
                 0x0400 = Mifare_One(S50)
                 0x0200 = Mifare_One(S70)
                 0x0800 = Mifare_Pro(X)
                 0x4403 = Mifare_DESFire

  @returns Returns the status of the request.
           MI_ERR        if something went wrong,
           MI_NOTAGERR   if there was no tag to send the command to.
           MI_OK         if everything went OK.

 */
/**************************************************************************/
int requestTag(byte mode, byte *data) {
  int status, len;
  writeToRegister(BitFramingReg, 0x07);  // TxLastBists = BitFramingReg[2..0]

  data[0] = mode;
  status = commandTag(MFRC522_TRANSCEIVE, data, 1, data, &len);

  if ((status != MI_OK) || (len != 0x10)) {
    status = MI_ERR;
  }

  return status;
}

/**************************************************************************/
/*!

  @brief   Handles collisions that might occur if there are multiple
           tags available.

  @param   serial  The serial nb of the tag.

  @returns Returns the status of the collision detection.
           MI_ERR        if something went wrong,
           MI_NOTAGERR   if there was no tag to send the command to.
           MI_OK         if everything went OK.

 */
/**************************************************************************/
int antiCollision(byte *serial) {
  int status, i, len;
  byte check = 0x00;

  writeToRegister(BitFramingReg, 0x00);  // TxLastBits = BitFramingReg[2..0]

  serial[0] = MF1_ANTICOLL;
  serial[1] = 0x20;
  status = commandTag(MFRC522_TRANSCEIVE, serial, 2, serial, &len);
  len = len / 8; // len is in bits, and we want each byte.
  if (status == MI_OK) {
    // The checksum of the tag is the ^ of all the values.
    for (i = 0; i < len-1; i++) {
      check ^= serial[i];
    }
    // The checksum should be the same as the one provided from the
    // tag (serial[4]).
    if (check != serial[i]) {
      status = MI_ERR;
    }
  }

  return status;
}

/**************************************************************************/
/*!

  @brief   Calculates the CRC value for some data that should be sent to
           a tag.

  @param   data    The data to calculate the value for.
  @param   len     The length of the data.
  @param   result  The result of the CRC calculation.

 */
/**************************************************************************/
void calculateCRC(byte *data, int len, byte *result) {
  int i;
  byte n;

  clearBitMask(DivIrqReg, 0x04);   // CRCIrq = 0
  setBitMask(FIFOLevelReg, 0x80);  // Clear the FIFO pointer

  //Writing data to the FIFO.
  for (i = 0; i < len; i++) {
    writeToRegister(FIFODataReg, data[i]);
  }
  writeToRegister(CommandReg, MFRC522_CALCCRC);

  // Wait for the CRC calculation to complete.
  i = 0xFF;
  do {
    n = readFromRegister(DivIrqReg);
    i--;
  } while ((i != 0) && !(n & 0x04));  //CRCIrq = 1

  // Read the result from the CRC calculation.
  result[0] = readFromRegister(CRCResultRegL);
  result[1] = readFromRegister(CRCResultRegM);
}


The Code is ready to use. You can just read RFID Tags/Serialnumbers.
To write Tags you have to edit/add some more functions from LJOS Library.
merhuman



Joined: 10 Dec 2017
Posts: 2

View user's profile Send private message

PostPosted: Thu Dec 21, 2017 1:18 pm     Reply with quote

Hi Mario_KA, Im currently doing a project similar to yours. However, i use pic16f877a and feed it with 5v power source and crystal is 8Mhz. Yes, i also use lm1117 3.3v to down the voltage from 5v to 3.3v for supplying the mfrc522. I connect my pic and mfrc522 like this:

PIN_C5 (pin 24) -- MOSI
PIN_C4 (pin 25) -- MISO
PIN_C3 (pin 18) -- SCK
PIN_E2 (pin 10) -- SS
PIN_E0 (pin 8) -- RST

I tried to port the arduino code to c file too, but i didnt work. I also tried your code but the result still the same. The SPI communication between pic and mfrc522 is fine, but when it comes to transfer data to PICC tag the result is not so good.
Also im using ccs c 5.015. Really need some help about this. Thanks
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Dec 21, 2017 7:14 pm     Reply with quote

Are you using the PDIP-40 package for the 16F877A ? Probably.

You have MISO connected to the wrong pin on the PIC. MISO should
connect to pin RC4/SDI/SDA, which is on pin 23 of the PDIP-40 package
as shown below:
merhuman wrote:

I connect my pic and mfrc522 like this:

PIN_C5 (pin 24) -- MOSI
PIN_C4 (pin 25) -- MISO <-- Should be pin 23 on the PIC
PIN_C3 (pin 18) -- SCK
PIN_E2 (pin 10) -- SS
PIN_E0 (pin 8) -- RST

merhuman



Joined: 10 Dec 2017
Posts: 2

View user's profile Send private message

PostPosted: Fri Dec 22, 2017 1:20 am     Reply with quote

Hi PCM programmer. Yes, you are right. I mistyped the number 25. It's pin 23 on my hardware tho Smile . Sorry, i was exhausted.

But as i mentioned before, the write and read work fine. Here is the code i use

main.h
Code:

#include <16F877A.h>
#device ADC=16

#include <stdlib.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES NOBROWNOUT         //No brownout reset
#FUSES NOLVP                     //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#use delay(crystal = 8000000)
#use spi(MASTER, SPI1, BAUD = 9600, MODE=0, BITS=8, STREAM=XFER)


#use standard_io(B)
#use standard_io(C)
#use standard_io(D)
#use standard_io(E)

//*******************header of RFID********************

#define SSLOW (output_low(PIN_E2))
#define SSHIGH (output_high(PIN_E2))
#define RSTLOW (output_low(PIN_E0))
#define RSTHIGH (output_high(PIN_E0))

//PCD_Register
//Page 0: Command and status
#define CommandReg         0x01  // starts and stops command execution
#define ComIEnReg          0x02  // enable and disable interrupt request control bits
#define DivIEnReg          0x03  // enable and disable interrupt request control bits
#define ComIrqReg          0x04  // interrupt request bits
#define DivIrqReg          0x05  // interrupt request bits
#define ErrorReg           0x06  // error bits showing the error status of the last command executed
#define Status1Reg         0x07  // communication status bits 
#define Status2Reg         0x08  // receiver and transmitter status bits
#define FIFODataReg        0x09  // input and output of 64 byte FIFO buffer
#define FIFOLevelReg       0x0a  // number of bytes stored in the FIFO buffer
#define WaterLevelReg      0x0b  // level for FIFO underflow and overflow warning
#define ControlReg         0x0c  // miscellaneous control registers
#define BitFramingReg      0x0d  // adjustments for bit-oriented frames
#define CollReg            0x0e  // bit position of the first bit-collision detected on the RF interface

//Page 1: Command
#define ModeReg            0x11  // defines general modes for transmitting and receiving
#define TxModeReg          0x12  // defines transmission data rate and framing
#define RxModeReg          0x13  // defines reception data rate and framing
#define TxControlReg       0x14  // controls the logical behavior of the antenna driver pins TX1 and TX2
#define TxASKReg           0x15  // controls the setting of the transmission modulation
#define TxSelReg           0x16  // selects the internal sources for the antenna driver
#define RxSelReg           0x17  // selects internal receiver settings
#define RxThresholdReg     0x18  // selects thresholds for the bit decoder
#define DemodReg           0x19  // defines demodulator settings
#define MfTxReg            0x1c  // controls some MIFARE communication transmit parameters
#define MfRxReg            0x1d  // controls some MIFARE communication receive parameters
#define SerialSpeedReg     0x1f  // selects the speed of the serial UART interface

//Page 2: Configuration
#define CRCResultRegH      0x21  // shows the MSB and LSB values of the CRC calculation 
#define CRCResultRegL      0x22 
#define ModWidthReg        0x24  // controls the ModWidth setting?
#define RFCfgReg           0x26  // configures the receiver gain
#define GsNReg             0x27  // selects the conductance of the antenna driver pins TX1 and TX2 for modulation
#define CWGsPReg           0x28  // defines the conductance of the p-driver output during periods of no modulation
#define ModeGsPReg         0x29  // defines the conductance of the p-driver output during periods of modulation
#define TModeReg           0x2a  // defines settings for the internal timer 
#define TPrescalerReg      0x2b  // the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg.
#define TReloadRegH        0x2c  // defines the 16-bit timer reload value
#define TReloadRegL        0x2d
#define TCounterValueRegH  0x2e  // shows the 16-bit timer value
#define TCounterValueRegL  0x2f

//Commands
#define PCD_Idle              0x00  // no action, cancels current command execution
#define PCD_Mem               0x01  // stores 25 bytes into the internal buffer
#define PCD_GenerateRandomID  0x02  // generates a 10-byte random ID number
#define PCD_CalcCRC           0x03  // activates the CRC coprocessor or performs a self-test
#define PCD_Transmit          0x04  // transmits data from the FIFO buffer
#define PCD_NoCmdChange       0x07  // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit
#define PCD_Receive           0x08  // activates the receiver circuits
#define PCD_Transceive        0x0c  // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission
#define PCD_MFAuthent         0x0e  // performs the MIFARE standard authentication as a reader
#define PCD_SoftReset         0x0f  // resets the MFRC522

///Mifare_One tag command word
#define     MF1_REQIDL            0x26      // find the antenna area does not enter hibernation
#define     MF1_REQALL            0x52      // find all the tags antenna area
#define     MF1_ANTICOLL          0x93      // anti-collision
#define     MF1_SELECTTAG         0x93      // election tag
#define     MF1_AUTHENT1A         0x60      // authentication key A
#define     MF1_AUTHENT1B         0x61      // authentication key B
#define     MF1_READ              0x30      // Read Block
#define     MF1_WRITE             0xA0      // write block
#define     MF1_DECREMENT         0xC0      // debit
#define     MF1_INCREMENT         0xC1      // recharge
#define     MF1_RESTORE           0xC2      // transfer block data to the buffer
#define     MF1_TRANSFER          0xB0      // save the data in the buffer
#define     MF1_HALT              0x50      // Sleep

//Status code

#define MI_OK                    0
#define MI_NOTAGERR              1
#define MI_ERR                   2

#define MAX_LEN                  16



and here is the main.c
Code:

void main()
{
   
   spi_init(XFER, TRUE);
   delay_ms(100);
   LCD_Init();
   LCD_PutCmd(0x01);
   LCD_PutCmd(0x80);
   RSTHIGH;                   // set rst pin of mfrc522 high
   PCD_Init();
   infoVersion();
   
   while(TRUE)
   {
      //TODO: User Code
      FoundTag = requestTag(MF1_REQIDL, TagData);
      LCD_PutCmd(0x01);
      LCD_PutCmd(0x80);
      delay_ms(2000);
      if(FoundTag == MI_OK)
      {
         LCD_PutChar("tag found");
      }
      else
      {
         LCD_PutChar("no tag found");
      }
   }

}


//******** RFID function ***********
//Read from register
unsigned int8 PCD_RdReg(unsigned int8 reg)
{
   unsigned int8 address;
   unsigned int8 value = 0;
   SSLOW;
   delay_us(20);
   address = ((reg << 1) & 0x7e) | 0x80;
   spi_xfer(XFER, address);
   value = spi_xfer(XFER, 0x00);
   delay_us(20);
   SSHIGH;
   return value;
}


//Write to register
void PCD_WrReg(unsigned int8 reg, unsigned int8 value)
{
   unsigned int8 address;
   SSLOW;
   delay_us(20);
   address = ((reg << 1) & 0x7e);
   spi_xfer(XFER, address);
   spi_xfer(XFER, value);
   delay_us(20);
   SSHIGH;
}

//Initialize the mfrc522 chip
void PCD_Init(void)
{
   PCD_HReset();
   delay_ms(50);
   PCD_Reset();
   //PCD_WrReg(TxModeReg, 0x00);
   //PCD_WrReg(RxModeReg, 0x00);
   //PCD_WrReg(ModWidthReg, 0x26);
   PCD_WrReg(TModeReg, 0x8D);
   PCD_WrReg(TPrescalerReg, 0x3e);
   PCD_WrReg(TReloadRegH, 0x00);
   PCD_WrReg(TReloadRegL, 0x30);
   PCD_WrReg(TxASKReg, 0x40);
   PCD_WrReg(ModeReg, 0x3d);
   PCD_AntennaOn();
}

unsigned int8 getFirmwareVersion(void)
{
   unsigned int8 response = PCD_RdReg(VersionReg);
   return response;
}

int commandTag(byte cmd, byte *data, int dlen, byte *result, int *rlen)
{
   int status = MI_ERR;
   byte irqEn = 0x00;
   byte waitIRq = 0x00;
   byte lastBits, n;
   int j;
   
   switch (cmd)
   {
      case PCD_MFAuthent:
         irqEn = 0x12;
         waitIRq = 0x10;
         break;
         
      case PCD_Transceive:
         irqEn = 0x77;
         waitIRq = 0x30;
         break;
         
      default:
         break;
   }
   PCD_WrReg(ComIEnReg, irqEn|0x80);    // interrupt request
   PCD_ClrBitMsk(ComIrqReg, 0x80);             // Clear all interrupt requests bits.
   PCD_SetBitMsk(FIFOLevelReg, 0x80);             // FlushBuffer=1, FIFO initialization.

   PCD_WrReg(CommandReg, PCD_Idle);  // No action, cancel the current command.

   // Write to FIFO
   for (j=0; j < dlen; j++)
   {
      PCD_WrReg(FIFODataReg, data[j]);
   }

   // Execute the command.
   PCD_WrReg(CommandReg, cmd);
   if (cmd == PCD_Transceive)
   {
      PCD_SetBitMsk(BitFramingReg, 0x80);  // StartSend=1, transmission of data starts
   }

   // Waiting for the command to complete so we can receive data.
   j = 25; // Max wait time is 25ms.
   do {
      delay_ms(1);
      // CommIRqReg[7..0]
      // Set1 TxIRq RxIRq IdleIRq HiAlerIRq LoAlertIRq ErrIRq TimerIRq
      n = PCD_RdReg(ComIrqReg);
      j--;
   } while ((j!=0) && !(n&0x01) && !(n&waitIRq));

   PCD_ClrBitMsk(BitFramingReg, 0x80);  // StartSend=0

   if (j != 0)
   { // Request did not time out.
      if(!(PCD_RdReg(ErrorReg) & 0x1D))
      {  // BufferOvfl Collerr CRCErr ProtocolErr
         status = MI_OK;
         if (n & irqEn & 0x01)
         {
            status = MI_NOTAGERR;
         }

         if (cmd == PCD_Transceive)
         {
            n = PCD_RdReg(FIFOLevelReg);
            lastBits = PCD_RdReg(ControlReg) & 0x07;
            if (lastBits)
            {
               *rlen = (n-1)*8 + lastBits;
            }
            else
            {
               *rlen = n*8;
            }

            if (n == 0)
            {
               n = 1;
            }

            if (n > MAX_LEN)
            {
               n = MAX_LEN;
            }

            // Reading the recieved data from FIFO.
            for (j=0; j<n; j++)
            {
               result[j] = PCD_RdReg(FIFODataReg);
            }
         }
      }
      else
      {
         status = MI_ERR;
      }
  }
  return status;
}

int requestTag(byte mode, byte *data)
{
   int status, len;
   PCD_WrReg(BitFramingReg, 0x07);
   data[0] = mode;
   status = commandTag(PCD_Transceive, data, 1, data, &len);
   if((status != MI_OK) || (len != 0x10))
   {
      status = MI_ERR;
   }
   return status;
}

int antiCollision(byte *serial)
{
   int status, i, len;
   byte check = 0x00;
   PCD_WrReg(BitFramingReg, 0x00);
   serial[0] = MF1_ANTICOLL;
   serial[1] = 0x20;
   status = commandTag(PCD_Transceive, serial, 2, serial, &len);
   len = len / 8;
   if (status == MI_OK)
   {
      for(i = 0; i < len-1; i++)
      {
         check ^= serial[i];
      }
      if(check != serial[i])
      {
         status = MI_ERR;
      }
   }
   return status;
}

void calculateCRC(byte *data, int len, byte *result)
{
   int i;
   byte n;
   PCD_ClrBitMsk(DivIrqReg, 0x04);
   PCD_SetBitMsk(FIFOLevelReg, 0x80);
   
   for(i = 0; i < len; i++)
   {
      PCD_WrReg(FIFODataReg, data[i]);
   }
   PCD_WrReg(CommandReg, PCD_CalcCRC);
   
   i = 0xff;
   do{
      n = PCD_RdReg(DivIrqReg);
      i--;
   }while((i != 0) && !(n & 0x04));
   result[0] = PCD_RdReg(CRCResultRegL);
   result[1] = PCD_RdReg(CRCResultRegH);
}

////////////////////////////////////
void PCD_ClrBitMsk(char reg, char mask)
{
   unsigned int8 tmp = 0x00;
   tmp = PCD_RdReg(reg);
   PCD_WrReg(reg, tmp&(~mask));
}

///////////////////////////////////
void PCD_SetBitMsk(char reg, char mask)
{
   unsigned int8 tmp = 0x00;
   PCD_WrReg(reg, tmp|mask);
}

//Soft Reset
void PCD_Reset(void)
{
   PCD_WrReg(CommandReg,PCD_SoftReset);
   delay_ms(50);
   while(PCD_RdReg(CommandReg) & (1<<4));
}

//Hard Reset
void PCD_HReset(void)
{
   RSTHIGH;
   delay_us(1);
   RSTLOW;
   delay_us(1);
   RSTHIGH;
   delay_us(1);
}

//Turn the antenna on
void PCD_AntennaOn(void)
{
   unsigned int8 value = PCD_RdReg(TxControlReg);
   if((value & 0x03) != 0x03)
   {
      PCD_WrReg(TxControlReg, value | 0x03);
   }
}

//Turn the antenna off
void PCD_AntennaOff(void)
{
   PCD_ClrBitMsk(TxControlReg, 0x03);
}

void infoVersion(void)
{
   version = PCD_RdReg(VersionReg);
   if(!version)
   {
      LCD_PutChar("no device");
   }
   else
   {
      LCD_PutChar("device found");
      LCD_PutCmd(0xc0);
      LCD_Check(version);
   }
}


Most of the code is similar to Mario_KA's code. Just the name of the registers and commands are a little bit different because of the ported code from arduino i have made from last month.

I stuck at requestTag(), it just return MI_ERR all the time. Is it because of the transmission time? I'm trying to figure it out by reading the references:

an10833 https://www.nxp.com/docs/en/application-note/AN10833.pdf

an10834https://www.nxp.com/docs/en/application-note/AN10834.pdf

an10927https://www.nxp.com/docs/en/application-note/AN10927.pdf

But still haven't figure it out.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Dec 22, 2017 2:36 am     Reply with quote

I suggest that you post your problem in the main forum so everyone can
look at it. Most things don't get solved in the Code Library. They may
get solved in the main forum:
http://www.ccsinfo.com/forum/viewforum.php?f=1

Also, I suggest that you read this 4-page thread. Mario_KA's questions
start on page 2.
http://www.ccsinfo.com/forum/viewtopic.php?t=51393


merhuman wrote:

I use pic16f877a and feed it with 5v power source and crystal is
8Mhz. Yes, i also use lm1117 3.3v to down the voltage from 5v to 3.3v
for supplying the mfrc522
.

They are not going to like it when they find out you are running the
MFRC522 at 3.3v and the PIC at 5v. Read the thread in the link above,
starting at page 1. They discuss this issue.
mohammad3d



Joined: 28 Mar 2009
Posts: 17

View user's profile Send private message Send e-mail

MFRC522 module
PostPosted: Sun Oct 07, 2018 2:54 am     Reply with quote

Hi Every one,
I worked on Mario_KA program and apply some little change on his program.
Now, I tested with 2 different mfrc522 module and my program work great.
Please note that connect MFRC522 RST pin directly to +3.3V power.
All another pin connect directly to +5v PIC micro without any level converter.

main.c
Code:
 

//main.c File
#include <16F887.h>
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage programing, B3(PIC16) or B5(PIC18) used for I/O
#FUSES XT
#use delay(crystal=4000000)//Set frequency at 4Mhz
#include <C_LCD.h>//2x16 Character LCD driver

//Note:Connect MFRC522 module to 5v PIC without any Level converter .It'll work fine.
//Note:mfrc522 work in SPI slave mode(PIC is MASTER)
//mfrc522 connection PIN
#define CS PIN_A1//mfrc 522 chip select pin(SS) to PIC pin3
//MFRC522 module RST  pin to +3.3v
//MFRC522 module MOSI pin to PIC16f877 pin 24(RC5/SDO)
//MFRC522 module MISO pin to PIC16f877 pin 23(RC4/SDI)
//MFRC522 module SCK  pin to PIC16f877 pin 18(RC3/SCK)

#include <MFRC522_driver.h>//mfrc 522 Driver

//spi modes
#define SPI_MODE_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1  (SPI_L_TO_H)
#define SPI_MODE_2  (SPI_H_TO_L)
#define SPI_MODE_3  (SPI_H_TO_L | SPI_XMIT_L_TO_H)

byte FoundTag; // Variable used to check if Tag was found
byte ReadTag; // Variable used to store anti-collision value to read Tag information
byte TagData[16]; // Variable used to store Full Tag Data
byte GoodTagSerialNumber[4] = {0x3D, 0xCA, 0x2B, 0x62}; // The Tag Serial number we are looking for
int i=0;
byte version;
int GoodTag=0; // Variable used to confirm good Tag Detected



void Get_UID()
{
    // Get Tag UID
   ReadTag = antiCollision(TagData);
   lcd_gotoxy(1,1);
   /// display Tag UID in hexadecimal
   for(i=0;i<=2;i++)printf(lcd_putc,"%2X,",TagData[i]);
   printf(lcd_putc,"%2X",(TagData[i]));               
}

void Search_for_matching_Tag()
{
 GoodTag=0;
 for(int i=0; i <= 3; i++)
   {
    if (GoodTagSerialNumber[i] != TagData[i])
       {
         GoodTag=0;
          break; // if not equal, then break out of the "for" loop
       }
   }
   
   if (TagData[3]==GoodTagSerialNumber[3])
   {
   // if we made it to 4 loops then the Tag Serial numbers are matching
   GoodTag=1;
   }
   lcd_gotoxy(1,2);
   if (GoodTag == 1)
   {
     printf(lcd_putc,"Access granted  ");       
   }
   else
   {
     printf(lcd_putc,"Access Denied   ");   
     GoodTag=0;     
   }
}
void Get_Chip_Version(){
while(True)
     {
       version = readFromRegister(VersionReg);

       if(!version)
         {
           lcd_gotoxy(1,1);
           printf(lcd_putc,"NO DEVICE");
 
         }
       if(version)
         {
          lcd_gotoxy(1,1);
          printf(lcd_putc,"DEVICE found"); 
          lcd_gotoxy(1, 2);
          printf(lcd_putc,"ver %2X",version);
          break;
         }
     }   
}

void main()
{
   setup_spi(SPI_MASTER|SPI_MODE_0|SPI_CLK_DIV_64);
   lcd_init();
   lcd_putc('\f');
   delay_ms(50);
   MFRC_522_init(); //initialize MFRC522
   Get_Chip_Version(); //print Firmwareverion on LCD
   delay_ms(2000);
   lcd_putc('\f');
   while(TRUE)
   {     
     //  Check to see if a Tag was detected
     // If yes, then the variable FoundTag will contain "MI_OK"
    FoundTag = requestTag(MF1_REQIDL, TagData);
    lcd_gotoxy(1,1);
    printf(lcd_putc,"Checking for Tag \r\n");     
   
     if (FoundTag == MI_OK)
     {
       
        lcd_gotoxy(1,2);     
        printf(lcd_putc,"Tag found       ");
        delay_ms(1000);
        lcd_putc('\f');
        Get_UID();
        Search_for_matching_Tag();
        delay_ms(1000);
     }
     
     else
         {
         lcd_gotoxy(1,2);         
         printf(lcd_putc,"No Tag found    ");
         }
     
   }
}




C_LCD.h file


Code:


//C_LCD.h file
#define _lcd_h_
#include <math.h>
void lcd_init(void);             
byte lcd_read_byte(void);         
byte lcd_read_nibble(void);       
void lcd_send_byte(byte address, byte n); 
void lcd_send_nibble(byte n);   
void lcd_gotoxy(byte x, byte y);
char lcd_getc(byte x, byte y);   
void lcd_putc(char c);           
//Define LCD connection Pins
#define LCD_RS_PIN         PIN_D1   
#define LCD_RW_PIN         PIN_D2
#define LCD_ENABLE_PIN     PIN_D3
#define LCD_DATA4          PIN_D4
#define LCD_DATA5          PIN_D5
#define LCD_DATA6          PIN_D6
#define LCD_DATA7          PIN_D7

#define lcd_output_enable(x)   output_bit(LCD_ENABLE_PIN, x) 
#define lcd_enable_tris()   output_drive(LCD_ENABLE_PIN)

#define lcd_output_rs(x)   output_bit(LCD_RS_PIN, x) 
#define lcd_rs_tris()      output_drive(LCD_RS_PIN)

#define lcd_output_rw(x)   output_bit(LCD_RW_PIN, x)
#define lcd_rw_tris()      output_drive(LCD_RW_PIN)

#define lcd_line_one   0x00   
#define lcd_line_two   0x40   
#define lcd_line_three   0x14
#define lcd_line_four   0x54
#define LCD_TYPE 0x02         


byte const LCD_INIT_STRING[4] = {0x28 | (LCD_TYPE << 2), 0x0C, 0x01, 0x06};
void lcd_init(void)   
{

byte i;

output_drive(LCD_DATA4); 
output_drive(LCD_DATA5);
output_drive(LCD_DATA6);
output_drive(LCD_DATA7);

lcd_enable_tris();
lcd_rs_tris();
lcd_rw_tris();

lcd_output_rs(0);     
lcd_output_rw(0);       
lcd_output_enable(0);   

delay_ms(15);

for(i=1;i<=3;i++)       
   {               
   lcd_send_nibble(0x03);   
   delay_ms(5);       
   }               
                   

lcd_send_nibble(0x02);     
for(i=0;i<=3;i++)
   lcd_send_byte(0,LCD_INIT_STRING[i]);
}                           

// ***************************************************
byte lcd_read_byte(void)   
{
byte low,high;
output_float(LCD_DATA4); 
output_float(LCD_DATA5);
output_float(LCD_DATA6);
output_float(LCD_DATA7);

lcd_output_rw(1);       
delay_cycles(1);       
lcd_output_enable(1);     
delay_cycles(1);         
high = lcd_read_nibble(); 
lcd_output_enable(0);     
               
delay_cycles(1);       
lcd_output_enable(1);     
delay_cycles(1);         
low = lcd_read_nibble();   
lcd_output_enable(0);     

output_drive(LCD_DATA4);   
output_drive(LCD_DATA5);
output_drive(LCD_DATA6);
output_drive(LCD_DATA7);

return((high<<4) | low);   
}

// ***************************************************
byte lcd_read_nibble(void)   
{

byte n = 0x00; 

n |= input(LCD_DATA4);       
n |= input(LCD_DATA5) << 1;
n |= input(LCD_DATA6) << 2;
n |= input(LCD_DATA7) << 3;

return(n);   
}

// ***************************************************
void lcd_send_byte(byte address, byte n)   
{                               

lcd_output_rs(0);     
while(bit_test(lcd_read_byte(),7)); 
lcd_output_rs(address); 
delay_cycles(1);   
lcd_output_rw(0);   
delay_cycles(1);     
lcd_output_enable(0);   
lcd_send_nibble(n >> 4); 
lcd_send_nibble(n & 0x0F); 
}

// ***************************************************
void lcd_send_nibble(byte n) 
{

output_bit(LCD_DATA4, bit_test(n, 0)); 
output_bit(LCD_DATA5, bit_test(n, 1));
output_bit(LCD_DATA6, bit_test(n, 2));
output_bit(LCD_DATA7, bit_test(n, 3));
   
delay_cycles(1);     
lcd_output_enable(1); 
delay_us(2);         
lcd_output_enable(0);   
}

// ***************************************************
void lcd_gotoxy(byte x, byte y) 
{

byte address;

if(y==1)             
   address=lcd_line_one;     
else if(y==2)     
   address=lcd_line_two;     
else if(y==3)
   address=lcd_line_three;     
else if(y==4)
   address=lcd_line_four;   

address+=x-1;             
lcd_send_byte(0,0x80|address); 
}                     

// ***************************************************
char lcd_getc(byte x, byte y)
{

char value;

lcd_gotoxy(x,y);           
while(bit_test(lcd_read_byte(),7)); 
lcd_output_rs(1);       
value = lcd_read_byte(); 
lcd_output_rs(0);       

return(value);   
}

// ***************************************************
void lcd_putc(char c) 
{

switch (c)
   {
   case '\f':   
      lcd_send_byte(0,0x01); 
      delay_ms(2);     
      break;
   case '\n':     
      lcd_gotoxy(1,0x02);     
      break;
    case '\b':     
      lcd_send_byte(0,0x10);
      break;           
   default:       
      lcd_send_byte(1,c);   
      break;
   }
}     
// ***************************************************   




MFRC522_Driver.h file


Code:


// MFRC522_Driver.h file
#define     MAX_LEN               16        // Maximum length of an array. CHECK IF IT IS MAXIMUM LENGTH/SIZE OF FIFO!!!!!!!!!!!

//MF522 MFRC522 error codes.
#define     MI_OK                 0         // Everything A-OK.
#define     MI_NOTAGERR           1         // No tag error
#define     MI_ERR                2         // General error

//MF522 Command word
#define     MFRC522_IDLE          0x00      // NO action; Cancel the current command
#define     MFRC522_MEM           0x01      // Store 25 byte into the internal buffer.
#define     MFRC522_GENID         0x02      // Generates a 10 byte random ID number.
#define     MFRC522_CALCCRC       0x03      // CRC Calculate or selftest.
#define     MFRC522_TRANSMIT      0x04      // Transmit data
#define     MFRC522_NOCMDCH       0x07      // No command change.
#define     MFRC522_RECEIVE       0x08      // Receive Data
#define     MFRC522_TRANSCEIVE    0x0C      // Transmit and receive data,
#define     MFRC522_AUTHENT       0x0E      // Authentication Key
#define     MFRC522_SOFTRESET     0x0F      // Reset

//Mifare_One tag command word
#define     MF1_REQIDL            0x26      // find the antenna area does not enter hibernation
#define     MF1_REQALL            0x52      // find all the tags antenna area
#define     MF1_ANTICOLL          0x93      // anti-collision
#define     MF1_SELECTTAG         0x93      // election tag
#define     MF1_AUTHENT1A         0x60      // authentication key A
#define     MF1_AUTHENT1B         0x61      // authentication key B
#define     MF1_READ              0x30      // Read Block
#define     MF1_WRITE             0xA0      // write block
#define     MF1_DECREMENT         0xC0      // debit
#define     MF1_INCREMENT         0xC1      // recharge
#define     MF1_RESTORE           0xC2      // transfer block data to the buffer
#define     MF1_TRANSFER          0xB0      // save the data in the buffer
#define     MF1_HALT              0x50      // Sleep


//------------------ MFRC522 registers---------------
//Page 0:Command and Status
#define     Reserved00            0x00
#define     CommandReg            0x01
#define     CommIEnReg            0x02
#define     DivIEnReg             0x03
#define     CommIrqReg            0x04
#define     DivIrqReg             0x05
#define     ErrorReg              0x06
#define     Status1Reg            0x07
#define     Status2Reg            0x08
#define     FIFODataReg           0x09
#define     FIFOLevelReg          0x0A
#define     WaterLevelReg         0x0B
#define     ControlReg            0x0C
#define     BitFramingReg         0x0D
#define     CollReg               0x0E
#define     Reserved01            0x0F
//Page 1:Command
#define     Reserved10            0x10
#define     ModeReg               0x11
#define     TxModeReg             0x12
#define     RxModeReg             0x13
#define     TxControlReg          0x14
#define     TxAutoReg             0x15
#define     TxSelReg              0x16
#define     RxSelReg              0x17
#define     RxThresholdReg        0x18
#define     DemodReg              0x19
#define     Reserved11            0x1A
#define     Reserved12            0x1B
#define     MifareReg             0x1C
#define     Reserved13            0x1D
#define     Reserved14            0x1E
#define     SerialSpeedReg        0x1F
//Page 2:CFG
#define     Reserved20            0x20
#define     CRCResultRegM         0x21
#define     CRCResultRegL         0x22
#define     Reserved21            0x23
#define     ModWidthReg           0x24
#define     Reserved22            0x25
#define     RFCfgReg              0x26
#define     GsNReg                0x27
#define     CWGsPReg              0x28
#define     ModGsPReg             0x29
#define     TModeReg              0x2A
#define     TPrescalerReg         0x2B
#define     TReloadRegH           0x2C
#define     TReloadRegL           0x2D
#define     TCounterValueRegH     0x2E
#define     TCounterValueRegL     0x2F
//Page 3:TestRegister
#define     Reserved30            0x30
#define     TestSel1Reg           0x31
#define     TestSel2Reg           0x32
#define     TestPinEnReg          0x33
#define     TestPinValueReg       0x34
#define     TestBusReg            0x35
#define     AutoTestReg           0x36
#define     VersionReg            0x37
#define     AnalogTestReg         0x38
#define     TestDAC1Reg           0x39
#define     TestDAC2Reg           0x3A
#define     TestADCReg            0x3B
#define     Reserved31            0x3C
#define     Reserved32            0x3D
#define     Reserved33            0x3E
#define     Reserved34            0x3F
//-----------------------------------------------


//Reads the value at a register.
byte readFromRegister(byte addr) {
  byte val;
  output_low(CS);
  delay_us(10);
  spi_write(((addr<<1)&0x7E) | 0x80);
  delay_us(100);
  val =spi_read(0x00);
  output_high(CS);
  return val;
}

//writes Values to specified registers.
void writeToRegister(byte addr, byte val) {
  output_low(CS);
  delay_us(10);
  //Address format: 0XXXXXX0
  spi_write((addr<<1)&0x7E);
  delay_us(10);
  spi_write(val);

  output_high(CS);
}

//Mask to update registers
void setBitMask(byte addr, byte mask) {
  byte current;
  current = readFromRegister(addr);
  writeToRegister(addr, current | mask);
}

//remove bitmask  maybe not necessary
void clearBitMask(byte addr, byte mask) {
  byte current;
  current = readFromRegister(addr);
  writeToRegister(addr, current & (~mask));
}

//Initialize RFID Reader
//Does the setup for the MFRC522.
void reset() {
  writeToRegister(CommandReg, MFRC522_SOFTRESET);
}



void MFRC_522_init() {
  output_high(CS); 
 //software reset
  reset();

  //Timer: TPrescaler*TreloadVal/6.78MHz = 24ms
 writeToRegister(TModeReg, 0x8D);   
  delay_ms(20);// Tauto=1; f(Timer) = 6.78MHz/TPreScaler
  writeToRegister(TPrescalerReg, 0x3E);  // TModeReg[3..0] + TPrescalerReg
  delay_ms(20);
  writeToRegister(TReloadRegL, 30);
  delay_ms(20);
  writeToRegister(TReloadRegH, 0);
  delay_ms(20);
  writeToRegister(TxAutoReg, 0x40);      // 100%ASK
  delay_ms(20);
  writeToRegister(ModeReg, 0x3D);        // CRC initial value 0x6363
  delay_ms(20);
 //writeToRegister(TxControlReg, 0x82);     
  delay_ms(20);
 setBitMask(TxControlReg, 0x03);        // Turn antenna on.
}

//Checking MFRC522 Firmwareversion
byte getFirmwareVersion() {
  byte response;
  response = readFromRegister(VersionReg);
  return response;
}


/**************************************************************************/
/*!

  @brief   Sends a command to a tag.

  @param   cmd     The command to the MFRC522 to send a command to the tag.
  @param   data    The data that is needed to complete the command.
  @param   dlen    The length of the data.
  @param   result  The result returned by the tag.
  @param   rlen    The number of valid bits in the resulting value.

  @returns Returns the status of the calculation.
           MI_ERR        if something went wrong,
           MI_NOTAGERR   if there was no tag to send the command to.
           MI_OK         if everything went OK.

 */
/**************************************************************************/

int commandTag(byte cmd, byte *data, int dlen, byte *result, int *rlen) {
  int status = MI_ERR;
  byte irqEn = 0x00;
  byte waitIRq = 0x00;
  byte lastBits, n;
  int i;

  switch (cmd) {
  case MFRC522_AUTHENT:
    irqEn = 0x12;
    waitIRq = 0x10;
    break;
  case MFRC522_TRANSCEIVE:
    irqEn = 0x77;
    waitIRq = 0x30;
    break;
  default:
    break;
  }

  writeToRegister(CommIEnReg, irqEn|0x80);    // interrupt request
  clearBitMask(CommIrqReg, 0x80);             // Clear all interrupt requests bits.
  setBitMask(FIFOLevelReg, 0x80);             // FlushBuffer=1, FIFO initialization.

  writeToRegister(CommandReg, MFRC522_IDLE);  // No action, cancel the current command.

  // Write to FIFO
  for (i=0; i < dlen; i++) {
    writeToRegister(FIFODataReg, data[i]);
  }

  // Execute the command.
  writeToRegister(CommandReg, cmd);
  if (cmd == MFRC522_TRANSCEIVE) {
    setBitMask(BitFramingReg, 0x80);  // StartSend=1, transmission of data starts
  }

  // Waiting for the command to complete so we can receive data.
  i = 25; // Max wait time is 25ms.
  do {
    delay_ms(1);
    // CommIRqReg[7..0]
    // Set1 TxIRq RxIRq IdleIRq HiAlerIRq LoAlertIRq ErrIRq TimerIRq
    n = readFromRegister(CommIrqReg);
    i--;
  } while ((i!=0) && !(n&0x01) && !(n&waitIRq));

  clearBitMask(BitFramingReg, 0x80);  // StartSend=0

  if (i != 0) { // Request did not time out.
    if(!(readFromRegister(ErrorReg) & 0x1D)) {  // BufferOvfl Collerr CRCErr ProtocolErr
      status = MI_OK;
      if (n & irqEn & 0x01) {
        status = MI_NOTAGERR;
      }

      if (cmd == MFRC522_TRANSCEIVE) {
        n = readFromRegister(FIFOLevelReg);
        lastBits = readFromRegister(ControlReg) & 0x07;
        if (lastBits) {
          *rlen = (n-1)*8 + lastBits;
        } else {
          *rlen = n*8;
        }

        if (n == 0) {
          n = 1;
        }

        if (n > MAX_LEN) {
          n = MAX_LEN;
        }

        // Reading the recieved data from FIFO.
        for (i=0; i<n; i++) {
          result[i] = readFromRegister(FIFODataReg);
        }
      }
    } else {
      status = MI_ERR;
    }
  }
  return status;
}


/**************************************************************************/
/*

  @brief   Checks to see if there is a tag in the vicinity.

  @param   mode  The mode we are requsting in.
  @param   type  If we find a tag, this will be the type of that tag.
                 0x4400 = Mifare_UltraLight
                 0x0400 = Mifare_One(S50)
                 0x0200 = Mifare_One(S70)
                 0x0800 = Mifare_Pro(X)
                 0x4403 = Mifare_DESFire

  @returns Returns the status of the request.
           MI_ERR        if something went wrong,
           MI_NOTAGERR   if there was no tag to send the command to.
           MI_OK         if everything went OK.

 */
/**************************************************************************/
int requestTag(byte mode, byte *data) {
  int status, len;
  writeToRegister(BitFramingReg, 0x07);  // TxLastBists = BitFramingReg[2..0]

  data[0] = mode;
  status = commandTag(MFRC522_TRANSCEIVE, data, 1, data, &len);

  if ((status != MI_OK) || (len != 0x10)) {
    status = MI_ERR;
  }

  return status;
}

/**************************************************************************/
/*!

  @brief   Handles collisions that might occur if there are multiple
           tags available.

  @param   serial  The serial nb of the tag.

  @returns Returns the status of the collision detection.
           MI_ERR        if something went wrong,
           MI_NOTAGERR   if there was no tag to send the command to.
           MI_OK         if everything went OK.

 */
/**************************************************************************/
int antiCollision(byte *serial) {
  int status, i, len;
  byte check = 0x00;

  writeToRegister(BitFramingReg, 0x00);  // TxLastBits = BitFramingReg[2..0]

  serial[0] = MF1_ANTICOLL;
  serial[1] = 0x20;
  status = commandTag(MFRC522_TRANSCEIVE, serial, 2, serial, &len);
  len = len / 8; // len is in bits, and we want each byte.
  if (status == MI_OK) {
    // The checksum of the tag is the ^ of all the values.
    for (i = 0; i < len-1; i++) {
      check ^= serial[i];
    }
    // The checksum should be the same as the one provided from the
    // tag (serial[4]).
    if (check != serial[i]) {
      status = MI_ERR;
    }
  }

  return status;
}

/**************************************************************************/
/*!

  @brief   Calculates the CRC value for some data that should be sent to
           a tag.

  @param   data    The data to calculate the value for.
  @param   len     The length of the data.
  @param   result  The result of the CRC calculation.

 */
/**************************************************************************/
void calculateCRC(byte *data, int len, byte *result) {
  int i;
  byte n;

  clearBitMask(DivIrqReg, 0x04);   // CRCIrq = 0
  setBitMask(FIFOLevelReg, 0x80);  // Clear the FIFO pointer

  //Writing data to the FIFO.
  for (i = 0; i < len; i++) {
    writeToRegister(FIFODataReg, data[i]);
  }
  writeToRegister(CommandReg, MFRC522_CALCCRC);

  // Wait for the CRC calculation to complete.
  i = 0xFF;
  do {
    n = readFromRegister(DivIrqReg);
    i--;
  } while ((i != 0) && !(n & 0x04));  //CRCIrq = 1

  // Read the result from the CRC calculation.
  result[0] = readFromRegister(CRCResultRegL);
  result[1] = readFromRegister(CRCResultRegM);
}



This program fully tested and work Great.
Enjoy,
bharath0209



Joined: 23 Jul 2019
Posts: 7

View user's profile Send private message

Re: MFRC522 module
PostPosted: Tue Jul 23, 2019 3:40 am     Reply with quote

Hey Mohammad3d,
Thanks a lot for the code.
I have used it after modifying to be compatible with xc8 compiler and was successful until detecting the version of the RFID module.
After which it always returns MI_ERR when i checked the error using LCD.
It is stuck at RequestTag function.
It doesn't give right values from next steps.
If you have similar issues, it would be a great help f you could revert.
Would be happy to post the code if required.
Thanks

Surprised Surprised
bharath0209



Joined: 23 Jul 2019
Posts: 7

View user's profile Send private message

Facing Same issue! Help.
PostPosted: Tue Jul 23, 2019 3:47 am     Reply with quote

Hey merhuman,
I'm facing same issue after almost two years of your post !
This is one of the few good resources available for interfacing pic16f877a with rfid.
None other seems to work. This program worked for me at least to read data from versionreg.
It is stuck after similar to you.
I would be grateful if you could help me out with this in case you've managed to solve it and remembered it.
Thanks.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

Re: MFRC522 module
PostPosted: Tue Jul 23, 2019 6:25 am     Reply with quote

bharath0209 wrote:
Hey Mohammad3d,
I have used it after modifying to be compatible with xc8 compiler

In CCS an 'int' is an unsigned 8-bit value. But in XC8 it's a signed 16-bit
value. So you need to use 'unsigned char' in XC8 anytime you see 'int'
in CCS. (This is true for the PCB, PCM, and PCH CCS compilers).
Also, if you got the SPI mode wrong, don't expect the program to work.
bharath0209



Joined: 23 Jul 2019
Posts: 7

View user's profile Send private message

Re: MFRC522 module
PostPosted: Tue Jul 23, 2019 6:32 am     Reply with quote

Thanks for the reply.
Yeah, I used unsigned char and also the spi mode works well as I tested it between two pic16f877a controllers.
In this, I'm able to read the versionReg. Only after that, the program keeps returning MI_ERR
Is there anything else I can check ?
bharath0209



Joined: 23 Jul 2019
Posts: 7

View user's profile Send private message

Re: MFRC522 module
PostPosted: Tue Jul 23, 2019 6:36 am     Reply with quote

Here's my code..
Main function
Code:

#include <xc.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define _XTAL_FREQ 16000000 


#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)



//Note:Connect MFRC522 module to 5v PIC without any Level converter .It'll work fine.
//Note:mfrc522 work in SPI slave mode(PIC is MASTER)
//mfrc522 connection PIN
#define CS RB2//mfrc 522 chip select pin(SS) to PIC pin3
//MFRC522 module RST  pin to +3.3v
//MFRC522 module MOSI pin to PIC16f877 pin 24(RC5/SDO)
//MFRC522 module MISO pin to PIC16f877 pin 23(RC4/SDI)
//MFRC522 module SCK  pin to PIC16f877 pin 18(RC3/SCK)

#include "MFRC522_driver.h"//mfrc 522 Driver

//spi modes
#define SPI_MODE_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1  (SPI_L_TO_H)
#define SPI_MODE_2  (SPI_H_TO_L)
#define SPI_MODE_3  (SPI_H_TO_L | SPI_XMIT_L_TO_H)

byte FoundTag; // Variable used to check if Tag was found
byte ReadTag; // Variable used to store anti-collision value to read Tag information
byte TagData[16]; // Variable used to store Full Tag Data
byte GoodTagSerialNumber[4] = {0x3D, 0xCA, 0x2B, 0x62}; // The Tag Serial number we are looking for
int i=0;
byte version;
int GoodTag=0; // Variable used to confirm good Tag Detected



void Get_UID()
{
    // Get Tag UID
   ReadTag = antiCollision(TagData);
    Lcd_Clear();   
    Lcd_Set_Cursor(1,1);
    char uid1[10];
    char uid2[10];
     for(i=0;i<=2;i++)/// display Tag UID in hexadecimal
     { sprintf(uid1,"%2X",TagData[i]);
    Lcd_Print_String(uid1);}
  sprintf(uid2,"%2X",TagData[i]);
    Lcd_Print_String(uid2); 
    __delay_ms(500);

}

void Search_for_matching_Tag()
{
 GoodTag=0;
 for(int i=0; i <= 3; i++)
   {
    if (GoodTagSerialNumber[i] != TagData[i])
       {
         GoodTag=0;
          break; // if not equal, then break out of the "for" loop
       }
   }
   
   if (TagData[3]==GoodTagSerialNumber[3])
   {
   // if we made it to 4 loops then the Tag Serial numbers are matching
   GoodTag=1;
   }
       
    Lcd_Set_Cursor(2,1);
   if (GoodTag == 1)
   {
     Lcd_Print_String("Access Granted!");
          __delay_ms(1500);

   }
   else
   {
     Lcd_Print_String("Access Denied!"); 
     __delay_ms(1500);

     GoodTag=0;     
   }
}
void Get_Chip_Version(){
while(1)
     {
       version = readFromRegister(VersionReg);

       if(!version)
         {
           Lcd_Clear();
           Lcd_Set_Cursor(1,1);
           Lcd_Print_String("No Device");   
                     __delay_ms(500);

 
         }
       if(version)
         {
           Lcd_Clear();
           Lcd_Set_Cursor(1,1);
          Lcd_Print_String("Device Found");     
          Lcd_Set_Cursor(2, 1);
          char ver[10];
          sprintf(ver,"ver:%2X",version);
          Lcd_Print_String(ver);
          __delay_ms(2500);
          if(version==0x92|version==0x91)
          {
           Lcd_Clear();
           Lcd_Set_Cursor(1,1);
           Lcd_Print_String("Device : MFRC522");
           Lcd_Set_Cursor(2,3);
           Lcd_Print_String("V1.0 or V2.0");
           __delay_ms(2000);
          break;
          }
         }
     }   
}

void main()
{
    TRISB=0;
    TRISD=0;
   //setup_spi(SPI_MASTER|SPI_MODE_0|SPI_CLK_DIV_64);
   Lcd_Start();
   Lcd_Clear();
   __delay_ms(50);
   MFRC_522_init(); //initialize SPI and MFRC522
   Get_Chip_Version(); //print Firmwareverion on LCD
   __delay_ms(2000);
 
   while(1)
   {     
     //  Check to see if a Tag was detected
     // If yes, then the variable FoundTag will contain "MI_OK"
   
    Lcd_Clear();
    Lcd_Set_Cursor(1,1);
    Lcd_Print_String("Checking for Tag");
    __delay_ms(1000);
     FoundTag = requestTag(MF1_REQIDL, TagData);
   
     if (FoundTag == MI_OK)
     {
       
        Lcd_Set_Cursor(2,1);   
        Lcd_Print_String("Tag Found");
        __delay_ms(500);
       
        Get_UID();
        Search_for_matching_Tag();
        __delay_ms(100);
     }
     
     else
         {
        Lcd_Set_Cursor(2,1);   
        Lcd_Print_String("No Tag Found E:");
        Lcd_Print_Char(FoundTag+'0');
        __delay_ms(500);
         }
     
   }
}




Library and Lcd Functions

Code:

#include<xc.h>
#define _XTAL_FREQ 16000000 

// MFRC522_Driver.h file
#define     MAX_LEN               16        // Maximum length of an array. CHECK IF IT IS MAXIMUM LENGTH/SIZE OF FIFO!!!!!!!!!!!

//MF522 MFRC522 error codes.
#define     MI_OK                 0         // Everything A-OK.
#define     MI_NOTAGERR           1         // No tag error
#define     MI_ERR                2         // General error

//MF522 Command word
#define     MFRC522_IDLE          0x00      // NO action; Cancel the current command
#define     MFRC522_MEM           0x01      // Store 25 byte into the internal buffer.
#define     MFRC522_GENID         0x02      // Generates a 10 byte random ID number.
#define     MFRC522_CALCCRC       0x03      // CRC Calculate or selftest.
#define     MFRC522_TRANSMIT      0x04      // Transmit data
#define     MFRC522_NOCMDCH       0x07      // No command change.
#define     MFRC522_RECEIVE       0x08      // Receive Data
#define     MFRC522_TRANSCEIVE    0x0C      // Transmit and receive data,
#define     MFRC522_AUTHENT       0x0E      // Authentication Key
#define     MFRC522_SOFTRESET     0x0F      // Reset

//Mifare_One tag command word
#define     MF1_REQIDL            0x26      // find the antenna area does not enter hibernation
#define     MF1_REQALL            0x52      // find all the tags antenna area
#define     MF1_ANTICOLL          0x93      // anti-collision
#define     MF1_SELECTTAG         0x93      // election tag
#define     MF1_AUTHENT1A         0x60      // authentication key A
#define     MF1_AUTHENT1B         0x61      // authentication key B
#define     MF1_READ              0x30      // Read Block
#define     MF1_WRITE             0xA0      // write block
#define     MF1_DECREMENT         0xC0      // debit
#define     MF1_INCREMENT         0xC1      // recharge
#define     MF1_RESTORE           0xC2      // transfer block data to the buffer
#define     MF1_TRANSFER          0xB0      // save the data in the buffer
#define     MF1_HALT              0x50      // Sleep


//------------------ MFRC522 registers---------------
//Page 0:Command and Status
#define     Reserved00            0x00
#define     CommandReg            0x01
#define     CommIEnReg            0x02
#define     DivIEnReg             0x03
#define     CommIrqReg            0x04
#define     DivIrqReg             0x05
#define     ErrorReg              0x06
#define     Status1Reg            0x07
#define     Status2Reg            0x08
#define     FIFODataReg           0x09
#define     FIFOLevelReg          0x0A
#define     WaterLevelReg         0x0B
#define     ControlReg            0x0C
#define     BitFramingReg         0x0D
#define     CollReg               0x0E
#define     Reserved01            0x0F
//Page 1:Command
#define     Reserved10            0x10
#define     ModeReg               0x11
#define     TxModeReg             0x12
#define     RxModeReg             0x13
#define     TxControlReg          0x14
#define     TxAutoReg             0x15
#define     TxSelReg              0x16
#define     RxSelReg              0x17
#define     RxThresholdReg        0x18
#define     DemodReg              0x19
#define     Reserved11            0x1A
#define     Reserved12            0x1B
#define     MifareReg             0x1C
#define     Reserved13            0x1D
#define     Reserved14            0x1E
#define     SerialSpeedReg        0x1F
//Page 2:CFG
#define     Reserved20            0x20
#define     CRCResultRegM         0x21
#define     CRCResultRegL         0x22
#define     Reserved21            0x23
#define     ModWidthReg           0x24
#define     Reserved22            0x25
#define     RFCfgReg              0x26
#define     GsNReg                0x27
#define     CWGsPReg              0x28
#define     ModGsPReg             0x29
#define     TModeReg              0x2A
#define     TPrescalerReg         0x2B
#define     TReloadRegH           0x2C
#define     TReloadRegL           0x2D
#define     TCounterValueRegH     0x2E
#define     TCounterValueRegL     0x2F
//Page 3:TestRegister
#define     Reserved30            0x30
#define     TestSel1Reg           0x31
#define     TestSel2Reg           0x32
#define     TestPinEnReg          0x33
#define     TestPinValueReg       0x34
#define     TestBusReg            0x35
#define     AutoTestReg           0x36
#define     VersionReg            0x37
#define     AnalogTestReg         0x38
#define     TestDAC1Reg           0x39
#define     TestDAC2Reg           0x3A
#define     TestADCReg            0x3B
#define     Reserved31            0x3C
#define     Reserved32            0x3D
#define     Reserved33            0x3E
#define     Reserved34            0x3F
//-----------------------------------------------

#define byte unsigned char









#define RS RD2 //Reset pin of LCD
#define EN RD3 //Enable pin of LCD
#define D4 RD4 //Data bit 0 of LCD
#define D5 RD5 //Data bit 1 of LCD
#define D6 RD6 //Data bit 2 of LCD
#define D7 RD7 //Data bit 3 of LCD

//    LCD Settings

void Lcd_SetBit(char data_bit) //Based on the Hex value Set the Bits of the Data Lines
{
    if (data_bit & 1)
        D4 = 1;
    else
        D4 = 0;

    if (data_bit & 2)
        D5 = 1;
    else
        D5 = 0;

    if (data_bit & 4)
        D6 = 1;
    else
        D6 = 0;

    if (data_bit & 8)
        D7 = 1;
    else
        D7 = 0;
}

void Lcd_Cmd(char a) {
    RS = 0;
    Lcd_SetBit(a); //Incoming Hex value
    EN = 1;
    __delay_ms(4);
    EN = 0;
}

void Lcd_Clear() {
    Lcd_Cmd(0); //Clear the LCD
    Lcd_Cmd(1); //Move the cursor to first position
}

void Lcd_Set_Cursor(char a, char b) {
    char temp, z, y;
    if (a == 1) {
        temp = 0x80 + b - 1; //80H is used to move the cursor
        z = temp >> 4; //Lower 8-bits
        y = temp & 0x0F; //Upper 8-bits
        Lcd_Cmd(z); //Set Row
        Lcd_Cmd(y); //Set Column
    } else if (a == 2) {
        temp = 0xC0 + b - 1;
        z = temp >> 4; //Lower 8-bits
        y = temp & 0x0F; //Upper 8-bits
        Lcd_Cmd(z); //Set Row
        Lcd_Cmd(y); //Set Column
    }
}

void Lcd_Start() {
    Lcd_SetBit(0x00);
    // for(int i=1065244; i<=0; i--)  NOP(); 
    Lcd_Cmd(0x03);
    __delay_ms(5);
    Lcd_Cmd(0x03);
    __delay_ms(50); //changed from 11
    Lcd_Cmd(0x03);
    Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD
    Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD
    Lcd_Cmd(0x08); //Select Row 1
    Lcd_Cmd(0x00); //Clear Row 1 Display
    Lcd_Cmd(0x0C); //Select Row 2
    Lcd_Cmd(0x00); //Clear Row 2 Display
    Lcd_Cmd(0x06);
}

void Lcd_Print_Char(char data) //Send 8-bits through 4-bit mode
{
    char Lower_Nibble, Upper_Nibble;
    Lower_Nibble = data & 0x0F;
    Upper_Nibble = data & 0xF0;
    RS = 1; // => RS = 1
    Lcd_SetBit(Upper_Nibble >> 4); //Send upper half by shifting by 4
    EN = 1;
    //for(int i=2130483; i<=0; i--)  NOP();
    EN = 0;
    Lcd_SetBit(Lower_Nibble); //Send Lower half
    EN = 1;
    // for(int i=2130483; i<=0; i--)  NOP();
    EN = 0;
}

void Lcd_Print_String(char *a) {
    int i;
    for (i = 0; a[i] != '\0'; i++)
        Lcd_Print_Char(a[i]); //Split the string using pointers and call the Char function
}







/*
void spi_write(byte value )
{
   SSPBUF = dat;

}
byte spiRead() //REad the received data
{
    while ( !SSPSTATbits.BF ); // Wait for Data Receive complete
    return(SSPBUF); // read the received data from the buffer
}
*/

/**
  Section: Macro Declarations
 */



/**
  Section: Module APIs
 */

void SPI_Initialize(void) {

       
    TRISC5 = 0;
    TRISC4=1;

        SSPSTAT =0b00000000; //| 0b00000000;// sDataSample | sTransmitEdge;
        TRISC3 = 0;
   
   
    SSPCON = 0b00110001; //| 0b00010010;//sType | sClockIdle,fosc/64;

}

byte SPI_Exchange8bit(byte data) {
    // Clear the Write Collision flag, to allow writing
    SSPCONbits.WCOL = 0;

    SSPBUF = data;

    while (SSPSTATbits.BF == 0) {
    }

    return (SSPBUF);
}

byte SPI_Exchange8bitBuffer(byte *dataIn, byte bufLen, byte *dataOut) {
    int bytesWritten = 0;

    if (bufLen != 0) {
        if (dataIn != NULL) {
            while (bytesWritten < bufLen) {
                if (dataOut == NULL) {
                    SPI_Exchange8bit(dataIn[bytesWritten]);
                } else {
                    dataOut[bytesWritten] = SPI_Exchange8bit(dataIn[bytesWritten]);
                }

                bytesWritten++;
            }
        } else {
            if (dataOut != NULL) {
                while (bytesWritten < bufLen) {
                    dataOut[bytesWritten] = SPI_Exchange8bit(0x00);

                    bytesWritten++;
                }
            }
        }
    }

    return bytesWritten;
}

//Reads the value at a register.
byte readFromRegister(byte addr) {
  byte val;
  //output_low(CS);
  CS=0;
  __delay_us(10);
  //spi_write(((addr<<1)&0x7E) | 0x80);
  byte temp = SPI_Exchange8bit(((addr<<1)&0x7E) | 0x80);
  __delay_us(100);
  //val =spi_read(0x00);
  val= SPI_Exchange8bit(0x00);
  //output_high(CS);
  CS=1;
  return val;
}

//writes Values to specified registers.
void writeToRegister(byte addr, byte val) {
  //output_low(CS);
    CS=0;
   __delay_us(10);
  //Address format: 0XXXXXX0
  //spi_write((addr<<1)&0x7E);
  byte temp = SPI_Exchange8bit(((addr<<1)&0x7E) | 0x80);
  __delay_us(10);
//  spi_write(val);
  byte temp2 = SPI_Exchange8bit(val);

   CS=1;
  //output_high(CS);
}

//Mask to update registers
void setBitMask(byte addr, byte mask) {
  byte current;
  current = readFromRegister(addr);
  writeToRegister(addr, current | mask);
}

//remove bitmask  maybe not necessary
void clearBitMask(byte addr, byte mask) {
  byte current;
  current = readFromRegister(addr);
  writeToRegister(addr, current & (~mask));
}

//Initialize RFID Reader
//Does the setup for the MFRC522.
void reset() {
  writeToRegister(CommandReg, MFRC522_SOFTRESET);
}



void MFRC_522_init() {
  //output_high(CS);
    SPI_Initialize();
   
    CS=1;
 //software reset
  reset();

  //Timer: TPrescaler*TreloadVal/6.78MHz = 24ms
 writeToRegister(TModeReg, 0x8D);   
  __delay_ms(20);// Tauto=1; f(Timer) = 6.78MHz/TPreScaler
  writeToRegister(TPrescalerReg, 0x3E);  // TModeReg[3..0] + TPrescalerReg
  __delay_ms(20);
  writeToRegister(TReloadRegL, 30);
  __delay_ms(20);
  writeToRegister(TReloadRegH, 0);
  __delay_ms(20);
  writeToRegister(TxAutoReg, 0x40);      // 100%ASK
  __delay_ms(20);
  writeToRegister(ModeReg, 0x3D);        // CRC initial value 0x6363
  __delay_ms(20);
 //writeToRegister(TxControlReg, 0x82);     
  __delay_ms(20);
 
 
  byte temp0 = readFromRegister(TxControlReg);
    if (!(temp0 & 0x03))
    {
        setBitMask(TxControlReg, 0x03);
    }
  Lcd_Clear();
  Lcd_Set_Cursor(1,3);
  Lcd_Print_String("Init Done...");
  __delay_ms(1500);
 //setBitMask(TxControlReg, 0x03);        // Turn antenna on.
}

//Checking MFRC522 Firmwareversion
byte getFirmwareVersion() {
  byte response;
  response = readFromRegister(VersionReg);
  return response;
}


/**************************************************************************/
/*!

  @brief   Sends a command to a tag.

  @param   cmd     The command to the MFRC522 to send a command to the tag.
  @param   data    The data that is needed to complete the command.
  @param   dlen    The length of the data.
  @param   result  The result returned by the tag.
  @param   rlen    The number of valid bits in the resulting value.

  @returns Returns the status of the calculation.
           MI_ERR        if something went wrong,
           MI_NOTAGERR   if there was no tag to send the command to.
           MI_OK         if everything went OK.

 */
/**************************************************************************/

int commandTag(byte cmd, byte *data, int dlen, byte *result, int *rlen) {
  int status = MI_ERR;
  byte irqEn = 0x00;
  byte waitIRq = 0x00;
  byte lastBits, n;
  int i;

  switch (cmd) {
  case MFRC522_AUTHENT:
    irqEn = 0x12;
    waitIRq = 0x10;
    break;
  case MFRC522_TRANSCEIVE:
    irqEn = 0x77;
    waitIRq = 0x30;
    break;
  default:
    break;
  }

  writeToRegister(CommIEnReg, irqEn|0x80);    // interrupt request
  clearBitMask(CommIrqReg, 0x80);             // Clear all interrupt requests bits.
  setBitMask(FIFOLevelReg, 0x80);             // FlushBuffer=1, FIFO initialization.

  writeToRegister(CommandReg, MFRC522_IDLE);  // No action, cancel the current command.

  // Write to FIFO
  for (i=0; i < dlen; i++) {
    writeToRegister(FIFODataReg, data[i]);
  }

  // Execute the command.
  writeToRegister(CommandReg, cmd);
  if (cmd == MFRC522_TRANSCEIVE) {
    setBitMask(BitFramingReg, 0x80);  // StartSend=1, transmission of data starts
  }

  // Waiting for the command to complete so we can receive data.
  i = 25; // Max wait time is 25ms.
  do {
    __delay_ms(1);
    // CommIRqReg[7..0]
    // Set1 TxIRq RxIRq IdleIRq HiAlerIRq LoAlertIRq ErrIRq TimerIRq
    n = readFromRegister(CommIrqReg);
    i--;
  } while ((i!=0) && !(n&0x01) && !(n&waitIRq));

  clearBitMask(BitFramingReg, 0x80);  // StartSend=0

  if (i != 0) { // Request did not time out.
    if(!(readFromRegister(ErrorReg) & 0x1D)) {  // BufferOvfl Collerr CRCErr ProtocolErr
      status = MI_OK;
      if (n & irqEn & 0x01) {
        status = MI_NOTAGERR;
      }

      if (cmd == MFRC522_TRANSCEIVE) {
        n = readFromRegister(FIFOLevelReg);
        lastBits = readFromRegister(ControlReg) & 0x07;
        if (lastBits) {
          *rlen = (n-1)*8 + lastBits;
        } else {
          *rlen = n*8;
        }

        if (n == 0) {
          n = 1;
        }

        if (n > MAX_LEN) {
          n = MAX_LEN;
        }

        // Reading the recieved data from FIFO.
        for (i=0; i<n; i++) {
          result[i] = readFromRegister(FIFODataReg);
        }
      }
    } else {
      status = MI_ERR;
    }
  }
  return status;
}


/**************************************************************************/
/*

  @brief   Checks to see if there is a tag in the vicinity.

  @param   mode  The mode we are requsting in.
  @param   type  If we find a tag, this will be the type of that tag.
                 0x4400 = Mifare_UltraLight
                 0x0400 = Mifare_One(S50)
                 0x0200 = Mifare_One(S70)
                 0x0800 = Mifare_Pro(X)
                 0x4403 = Mifare_DESFire

  @returns Returns the status of the request.
           MI_ERR        if something went wrong,
           MI_NOTAGERR   if there was no tag to send the command to.
           MI_OK         if everything went OK.

 */
/**************************************************************************/
int requestTag(byte mode, byte *data) {
  int status, len;
  writeToRegister(BitFramingReg, 0x07);  // TxLastBists = BitFramingReg[2..0]

  data[0] = mode;

 
  status = commandTag(MFRC522_TRANSCEIVE, data, 1, data, &len);

 

  if ((status != MI_OK) || (len != 0x10)) {

    status = MI_ERR;
  }

  return status;
}

/**************************************************************************/
/*!

  @brief   Handles collisions that might occur if there are multiple
           tags available.

  @param   serial  The serial nb of the tag.

  @returns Returns the status of the collision detection.
           MI_ERR        if something went wrong,
           MI_NOTAGERR   if there was no tag to send the command to.
           MI_OK         if everything went OK.

 */
/**************************************************************************/
int antiCollision(byte *serial) {
  int status, i, len;
  byte check = 0x00;

  writeToRegister(BitFramingReg, 0x00);  // TxLastBits = BitFramingReg[2..0]

  serial[0] = MF1_ANTICOLL;
  serial[1] = 0x20;
  status = commandTag(MFRC522_TRANSCEIVE, serial, 2, serial, &len);
  len = len / 8; // len is in bits, and we want each byte.
  if (status == MI_OK) {
    // The checksum of the tag is the ^ of all the values.
    for (i = 0; i < len-1; i++) {
      check ^= serial[i];
    }
    // The checksum should be the same as the one provided from the
    // tag (serial[4]).
    if (check != serial[i]) {
      status = MI_ERR;
    }
  }

  return status;
}

/**************************************************************************/
/*!

  @brief   Calculates the CRC value for some data that should be sent to
           a tag.

  @param   data    The data to calculate the value for.
  @param   len     The length of the data.
  @param   result  The result of the CRC calculation.

 */
/**************************************************************************/
void calculateCRC(byte *data, int len, byte *result) {
  int i;
  byte n;

  clearBitMask(DivIrqReg, 0x04);   // CRCIrq = 0
  setBitMask(FIFOLevelReg, 0x80);  // Clear the FIFO pointer

  //Writing data to the FIFO.
  for (i = 0; i < len; i++) {
    writeToRegister(FIFODataReg, data[i]);
  }
  writeToRegister(CommandReg, MFRC522_CALCCRC);

  // Wait for the CRC calculation to complete.
  i = 0xFF;
  do {
    n = readFromRegister(DivIrqReg);
    i--;
  } while ((i != 0) && !(n & 0x04));  //CRCIrq = 1

  // Read the result from the CRC calculation.
  result[0] = readFromRegister(CRCResultRegL);
  result[1] = readFromRegister(CRCResultRegM);
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jul 23, 2019 7:20 pm     Reply with quote

The code library post shows the spi setup should be like this for CCS:
Code:
 setup_spi(SPI_MASTER|SPI_MODE_0|SPI_CLK_DIV_16);

You have this spi setup:
Quote:
void SPI_Initialize(void) {

TRISC5 = 0;
TRISC4 = 1;

SSPSTAT =0b00000000; // 0x00
TRISC3 = 0;

SSPCON = 0b00110001; // 0x31
}


Here are the Spi register values for each mode, for clock divisor 16:
Code:

SPI Mode   SSPCON   SSPSTAT               
  0        0x21     0x40
  1        0x21     0x00
  2        0x31     0x40
  3        0x31     0x00

From the table above, we can see that you have set it up for SPI mode 3.
But the original post in the Code Library uses spi mode 0. Based on the
MFRC522 data sheet, I think it might work with Mode 3, but that's not
what the original post has. You should try to duplicate the original post
as closely as possible.
bharath0209



Joined: 23 Jul 2019
Posts: 7

View user's profile Send private message

PostPosted: Tue Jul 23, 2019 10:18 pm     Reply with quote

Yeah. I'm sorry I didn't mention this.
But I have tried all the modes changing the SSPCON and SSPSTAT registers.
This is just the last one I've tried.
bharath0209



Joined: 23 Jul 2019
Posts: 7

View user's profile Send private message

PostPosted: Wed Jul 24, 2019 6:05 am     Reply with quote


UPDATE

Found the error in Register write function where I forgot to remove "| 0x80" which is only to read.
After that, it is working in mode 3 of spi and not in mode 1.

Now, it detects the tags and again had some trouble in reading the UID of tags.
It is giving MI_NOTAGERROR as a result with Anticollision function which is called only after it detects tag.
Tried with many different tags, but shows same error.

I really appreciate your time in looking into the code earlier.
If you didn't point out the mode, I may take even more time to find the bug.
bharath0209



Joined: 23 Jul 2019
Posts: 7

View user's profile Send private message

PostPosted: Thu Jul 25, 2019 5:44 am     Reply with quote


New UPDATE


I finally got it to work with different tags.
I had to change the Receiver gain to 38db and increase the supply voltage to 3.7 volts for it to work perfectly.

-Thanks.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group