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 CCS Technical Support

13MHz RFID

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
ariahope



Joined: 05 Jun 2014
Posts: 7

View user's profile Send private message

13MHz RFID
PostPosted: Thu Jun 05, 2014 2:39 pm     Reply with quote

Hi,
I work with RFID reader and writer 13MHz, MFRC522 from NXP.
At first I read and write internal register of it with SPI protocol without any problem it work very good.
As mentioned in "AN10833 MIFARE Type Identification Procedure" now I want to send "Request Command, TypeA" (REQA) and pickup "Answer to Request" from RFID TAG 1k, but I didn't read anything.
Code:
#include <18F26K20.h>
#device adc=10
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES HS
#use delay(clock=20000000)

#use FIXED_IO( B_outputs=PIN_B0 )
#define CS PIN_B0

//
#use FIXED_IO( A_outputs=PIN_A5 )
#define LED PIN_A5
//

//UART SETUP
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
//

//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)
//


void main()
{

   port_b_pullups(TRUE);
//adc
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
//end of adc

//watchdog
   setup_wdt(WDT_OFF);
//

//SPI
   setup_spi(SPI_MASTER|SPI_MODE_0|SPI_CLK_DIV_4);//ya 1 ya 2
//end of SPI
   
int8 value[2];
int t,j=1;
delay_ms(1000);
printf("hello MFRC522\r\n");
   while(j<=3)
   { 
if(j<4)
   {
   j++;
   output_low(LED);
   }


//**1.PERFORM A SOFT RESET**\\
   output_low(CS);
   spi_write(0x02);//WRITE ON CONFIGREG
   delay_ms(10);
   Spi_write(0x2F);//WRITE VALUE ON CONFIGREG
   delay_ms(10);
   output_high(CS);   
   delay_ms(100);
//**END OF SOFT RESET**\\



//**read operation only**\\

   output_low(CS);
   spi_write(0xA9);//0xa9 TxControlReg// 0x94 for FIFO levelReg// 0xEC for AutoTest REG//8c error//0x82setup Status1Reg0x8E for reading
   delay_ms(10);
   value[0]=spi_read(0);// reading from Status1Reg
   delay_ms(10);
   printf("TxControlReg0=%X\r\n",value[0]);
   output_high(CS);
   delay_ms(300);
 
//**end of read operation only**\\

//**turn on the antenna by enabling PINs TX1 and TX2. After a reset these pins disabled**\

   output_low(CS);
   spi_write(0x29);//WRITE ON TxControlReg
   delay_ms(10);
   Spi_write(0x83);//WRITE VALUE ON TxControlReg
   delay_ms(10);
   output_high(CS);   
   delay_ms(100);

//**End of turn on the antenna by enabling PINs TX1 and TX2 **\\

//**read operation only**\\

   output_low(CS);
   spi_write(0xA9);//0xa9 TxControlReg// 0x94 for FIFO levelReg// 0xEC for AutoTest REG//8c error//0x82setup Status1Reg0x8E for reading
   delay_ms(10);
   value[0]=spi_read(0);// reading from Status1Reg
   delay_ms(10);
   printf("TxControlReg1=%X\r\n",value[0]);
   output_high(CS);
   delay_ms(300);
 
//**end of read operation only**\\


//**Write 26h to the FIFO buffer**\
   output_low(CS);
   spi_write(0x12);//WRITE ON FIFODATAREG
   delay_ms(10);
   Spi_write(0x26);
   delay_ms(10);
   output_high(CS);
   delay_ms(100);

//**End of Write 26h to the FIFO buffer**\\

//**read FIFOlevelREG
   output_low(CS);
   spi_write(0x94);//0x94 for FIFO levelReg// 0xEC for AutoTest REG//8c error//0x82setup Status1Reg0x8E for reading
   delay_ms(10);
   value[0]=spi_read(0);// reading from FIFOlevelREG
   delay_ms(10);
   printf("FIFOlevelReg0=%X\r\n",value[0]);
   output_high(CS);
   delay_ms(300);
//**end of reading FIFOlevelREG


//**Enable Transceive Mode**\\
   output_low(CS);
   spi_write(0x02);//WRITE ON CONFIGREG
   delay_ms(10);
   Spi_write(0x2C);//WRITE VALUE ON CONFIGREG
   delay_ms(10);
   output_high(CS);   
   delay_ms(100);
//**End of Transceive Mode**\\

//**read FIFOlevelREG
   output_low(CS);
   spi_write(0x94);//0x94 for FIFO levelReg// 0xEC for AutoTest REG//8c error//0x82setup Status1Reg0x8E for reading
   delay_ms(10);
   value[0]=spi_read(0);// reading from FIFOlevelREG
   delay_ms(10);
   printf("FIFOlevelReg2=%X\r\n",value[0]);
   output_high(CS);
   delay_ms(300);
//**end of reading FIFOlevelREG


//**send data by set BitframingReg**\
   output_low(CS);
   spi_write(0x1A);//WRITE ON BitframingReg
   delay_ms(10);
   Spi_write(0x80);//WRITE VALUE ON BitframingReg
   delay_ms(10);
   output_high(CS);   
   delay_ms(100);
//**end of send data setting**\



   output_low(CS);
   spi_write(0x94);//0x94 for FIFO levelReg// 0xEC for AutoTest REG//8c error//0x82setup Status1Reg0x8E for reading
   delay_ms(10);
   value[0]=spi_read(0);// reading from Status1Reg
   delay_ms(10);
   printf("FIFOlevelReg1=%X\r\n",value[0]);
   output_high(CS);
   delay_ms(300);

//**read operation only**\\


//**read 2byte from FIFO Buffer**\
   
   for(t=1;t<=2;++t)
   {
   output_low(CS);
   spi_write(0x92);//setup Status1Reg0x8E for reading
   delay_ms(10);
   value[1]=spi_read(0);// reading from Status1Reg 
   delay_ms(10);
   printf("FIFO[%d]=%X\r\n",t,value[1]);
   output_high(CS);
   }
   
//**read 2byte from FIFO Buffer**\



   output_low(CS);
   spi_write(0x91);//0x91 Status2Reg//0xa9 TxControlReg// 0x94 for FIFO levelReg// 0xEC for AutoTest REG//8c error//0x82setup Status1Reg0x8E for reading
   delay_ms(10);
   value[0]=spi_read(0);// reading from Status1Reg
   delay_ms(10);
   printf("Status2Reg=%X\r\n",value[0]);
   output_high(CS);
   delay_ms(300);
 
//**end of read operation only**\\

   }

}


any help would be greatly appreciated
ariahope



Joined: 05 Jun 2014
Posts: 7

View user's profile Send private message

PostPosted: Fri Jun 06, 2014 4:21 am     Reply with quote

ANY Idea Ttelmah , PCM Programmer and ... ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Fri Jun 06, 2014 8:44 am     Reply with quote

Seriously I stopped looking when I saw you repeating code, rather than using routines to do the jobs. I suspect many others did the same.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Fri Jun 06, 2014 9:11 am     Reply with quote

Reduce your code to 10 lines or so, then we may be tempted to have a look at it.
I, for one, will not bother to scroll down several screens full.

Mike

PS.

Your code must also be complete and compilable, otherwise you are wasting time.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Jun 06, 2014 9:16 am     Reply with quote

I had the same problem. The program is difficult to understand because it is one large blob of code.
I suggest to Ariahope to split the program in multiple functions. For starters, a function to write to the external chip and another function for reading.

One golden rule is that a function should never be more than 40 lines of code, this is what normal people can keep track of in memory. This means that when your program get larger you will have to split it up into more functions.
ariahope



Joined: 05 Jun 2014
Posts: 7

View user's profile Send private message

PostPosted: Fri Jun 06, 2014 2:27 pm     Reply with quote

Hi I am sorry for long code, i summarize my code and explain it below:
this is my steps;
in summary at first I reset MFRC522 then I turn on antenna in step3,4 and 5 I send REQuest command, Type A (0x26) to Mifare CARD and then in step 6 I wait for Answer To reQuest, Type A

//**1.PERFORM A SOFT RESET**\\
//**2.turn on the antenna by enabling PINs TX1 and TX2. After a reset these pins disabled**\
//**3.Write 26h to the FIFO buffer**\
//**4.Enable Transceive Mode**\\
//**5.send data by set BitframingReg**\

//**6.read from FIFO Buffer**\
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Sat Jun 07, 2014 1:44 am     Reply with quote

You are missing the point.

It's to do with program structure.

Have two simple routines. One to write a byte/bytes to a numbered register. One to read a byte/bytes from a numbered register.

Then your main code just becomes half a dozen lines calling these routines.

So routines like:
Code:

#include <18F26K20.h>
#device adc=10
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES HS
#use delay(clock=20000000)

#define CS PIN_B0
#define LED PIN_A5

//UART SETUP
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
//

//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)
//

#define READFLAG 0x80 //bits for direction control on SPI commands
#define WRITEFLAG 0

//routine to read 'numbytes' bytes, from registers starting at 'address'
void read_block(int8 address, int8* data, int8 numbytes)
{
   int8 icount;
   int8 itemp;
   output_low(CS); //select chip
   for (icount=0;icount<=numbytes;icount++) //one more transfer than bytes
   {
       itemp=spi_read(address++*2 | READFLAG); //top bit set for a read
       if (icount!=0)
       {
           *data++=itemp;
       }
   }
   output_low(CS);
}

//routine to write 'numbytes' bytes to registers starting at 'address'
void write_block(int8 address, int8* data, int8 numbytes)
{
   int8 icount;
   int8 itemp;
   output_low(CS); //select chip
   for (icount=0;icount<=numbytes;icount++) //one more transfer than bytes
   {
       if (icount==0)
           itemp=spi_read(address++*2|WRITEFLAG);
       else
           itemp=spi_read(*data++);
   }
   output_low(CS);
}

void main()
{
   int8 block[8]; //Keep to C. Declare variables at the start of code blocks
   
   port_b_pullups(TRUE);
//adc
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
//end of adc

//watchdog
   setup_wdt(WDT_OFF);
//

//SPI
   setup_spi(SPI_MASTER|SPI_MODE_0|SPI_CLK_DIV_4);//ya 1 ya 2
//end of SPI
   

   delay_ms(1000);
   printf("hello MFRC522\r\n");
   output_low(LED); //counter seems pointless
   //Then you just setup the array for output with the data required
   //and access the registers.....
   //I'd #define the register names you want to use - reduces errors.


Now there are major problems with your code beyond this.

The very first thing you do, you say 'write on CONFIGREG'. You send '2', which is register address '1' (register numbers are doubled went sent to the chip). You then send '2F' to this. So you are sending 00101111. If you look at the command register bit description, this turns off the analog part of the receiver....
Also on these commands you should wait till the chip says it is ready. You do this by reading the register after writing it, and waiting for bit 4 to go low. Your long delays probably avoid the need for this, but it's better to use the signal the chip gives you.

So:
Code:

#define COMMANDREG 1

    block[0]=0x2F; //if this is right.....
    write_block(COMMANDREG,block,1); //write one byte chip
    do
    {
        read_block(COMMANDREG,block,1); //read register
    } while (bit_test(block[0],4)==1); //wait for 'power down' to go off


Then there are problems later. All 'address bytes' sent to the chip end with '0' (since they are multiplied by 2). Yet you have 29, and A9, as addresses being sent. Not possible.
ariahope



Joined: 05 Jun 2014
Posts: 7

View user's profile Send private message

PostPosted: Sun Jun 08, 2014 12:59 pm     Reply with quote

Hi Ttelmah like every time thank you alot,
I have some simple question
Quote:
//routine to read 'numbytes' bytes, from registers starting at 'address'
void read_block(int8 address, int8* data, int8 numbytes)
{
int8 icount;
int8 itemp;
output_low(CS); //select chip
for (icount=0;icount<=numbytes;icount++) //one more transfer than bytes
{
itemp=spi_read(address++*2 | READFLAG); //top bit set for a read
if (icount!=0)
{
*data++=itemp;
}
}
output_low(CS);
}

what does the difference between int8 and int8*?
and also what does *data mean?
why you don't use spi_write function?
excuse me for my simple question, I am beginner,
best regards.
ariahope



Joined: 05 Jun 2014
Posts: 7

View user's profile Send private message

PostPosted: Sun Jun 08, 2014 2:46 pm     Reply with quote

Hi, I hope I got what you said, I changed my code. because I just want to read Card Answer and nothing to do with it in this first phase I do all setup in a true while, this is my new code:
Code:
#include <18F26K20.h>
#device adc=10
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES HS
#use delay(clock=20000000)

#use FIXED_IO( B_outputs=PIN_B0 )
#define CS PIN_B0

//
#use FIXED_IO( A_outputs=PIN_A5 )
#define LED PIN_A5
//

//UART SETUP
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
//

//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)
//
#define CommandReg      0x01
#define status1Reg      0x07
#define status2Reg      0x08
#define FIFODataReg     0x09
#define FIFOLevelReg    0x0A
#define TxControlReg    0x14
#define BitframingReg   0x0D


//write register Function
void write_reg(int8 address,int8 value)
{
   output_low(CS);
   spi_write((address*2));
   delay_ms(10);
   spi_write(value);
   delay_ms(10);
   output_high(CS);
}
//end of write register

//read register Function and aslso printf it's value
void read_reg(int8 address,int8 numbyte)
{

int8 read_data;
int8 counter;
   for(counter=1;counter<=numbyte;++counter)
   {
   output_low(CS);
   spi_write((address*2)+0x80);
   delay_ms(10);
   read_data=spi_read(0);// reading from reg
   delay_ms(10);
   printf("address%X byte[%d]=%X\r\n",address,counter,read_data);
   output_high(CS);
   }

}
//end of read register and printf it's value

void main()
{

   port_b_pullups(TRUE);
//adc
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
//end of adc

//watchdog
   setup_wdt(WDT_OFF);
//

//SPI
   setup_spi(SPI_MASTER|SPI_MODE_0|SPI_CLK_DIV_4);//ya 1 ya 2
//end of SPI
   
int8 t=1;
delay_ms(1000);

//**.PERFORM A SOFT RESET**\\
write_reg(CommandReg,0x2F);
//**END OF SOFT RESET**\\

//Clear the internal buffer by writing 64 bytes of 00h and implement the Config command
for(t=1;t<=64;t++)
   {
   write_reg(FIFODataReg,0x00);
   }
   while(true)
   { 
delay_ms(2000);
printf("************\r\n");
printf("Start\r\n");
printf("************\r\n");
output_toggle(PIN_A5);

//**.PERFORM A SOFT RESET**\\
write_reg(CommandReg,0x2F);
//**END OF SOFT RESET**\\

//**turn on the antenna by enabling PINs TX1 and TX2. After a reset these pins disabled**\
write_reg(TxControlReg,0x83);
//**End of turn on the antenna by enabling PINs TX1 and TX2 **\\

//send request command to FIFO
write_reg(FIFODataReg,0x26);
//end

//**Enable Transceive Mode**\\
write_reg(CommandReg,0x2C);
//**End of Transceive Mode**\\


//**send data by set BitframingReg**\
write_reg(BitframingReg,0x80);
//**end of send data setting**\

read_reg(FIFODataReg,2);
printf("************\r\n");
printf("End\r\n");
printf("************\r\n");
   }

}

also here is Arduino library and example but it is very complicated for me.
https://github.com/miguelbalboa/rfid

all the best,
Ariahope


Last edited by ariahope on Sun Jun 08, 2014 11:35 pm; edited 1 time in total
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jun 08, 2014 4:03 pm     Reply with quote

In your first code, you use 0x83 to turn on the antenna:
Quote:
//**turn on the antenna by enabling PINs TX1 and TX2. After a reset these pins disabled**\

output_low(CS);
spi_write(0x29);//WRITE ON TxControlReg
delay_ms(10);
Spi_write(0x83);//WRITE VALUE ON TxControlReg
delay_ms(10);
output_high(CS);
delay_ms(100);


In your latest code you have dropped the 0x and changed it to 83 decimal.
Quote:

//**turn on the antenna by enabling PINs TX1 and TX2. After a reset these pins disabled**\
write_reg(TxControlReg,83);
//**End of turn on the antenna by enabling PINs TX1 and TX2 **\\

These are not the same number. Attention to detail is important.
You can't write successful code without it.
ariahope



Joined: 05 Jun 2014
Posts: 7

View user's profile Send private message

PostPosted: Sun Jun 08, 2014 11:38 pm     Reply with quote

Quote:
In your first code, you use 0x83 to turn on the antenna.
In your latest code you have dropped the 0x and changed it to 83 decimal.

Hi PCM Programmer it was my fault I corrected it. but it doesn't work yet.
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Mon Jun 09, 2014 12:15 am     Reply with quote

Basic C here. int8, is an int8
int8 *, is the _address_ of an int8. A pointer.

This really is basic C. You need to go through a C primer, before trying to program.

*data is the byte _addressed by_ the address 'data'.

This is one of the standard ways to allow you to access data in a 'calling' function from a 'called' function. Hand the address of a byte or in this case an array of bytes (in C there is a 'shortcut', that the name of an array _is_ it's address), and then just take data from or put data back into the array.

I use spi_read, rather than spi_write, since spi_read writes the byte, and returns the byte clocked out. Doing this ensures you are writing the byte and getting the byte back. For the 'write' operations not much difference, but using the read function, ensures there is not a byte 'left' in the register.

As I have already pointed out 'register addresses' as sent, always end in with a zero bit.
0x29, does not.

The format is

R/W address 0

Where R/W is 0/1 for read/write, and the address is a six bit address.

The TX control register is register 0x14. Doubling this gives 0x28 that needs to be sent, not 0x29.....

I was being 'generic', since I can see you needing to send more than one byte, but for the simple code as posted, just reading and writing one byte, use:
Code:

#define READFLAG 0x80
//routine to write one byte to a register
void write_reg(int8 address, int8 data)
{
   int8 itemp;
   output_low(CS); //select chip
   itemp=spi_read(address*2);
   itemp=spi_read(data);
   output_low(CS);
}

//routine to read one byte from a register
int8 read_reg(int8 address)
{
   int8 itemp;
   output_low(CS); //select chip
   itemp=spi_read((address*2) | READFLAG); //top bit set for a read
   itemp=spi_read(0);
   }
   output_low(CS);
   return(itemp);
}


As a general comment, get rid of the fixed_io and tris commands. For 99% of use, the compiler handles the tris better than you.
The start of your main then goes:
Code:

#define CONFIGREG 1
#define TXCONTROL 0x14
//etc.
void main()
{
   int8 value[2];
   int t,j=1;
   port_b_pullups(TRUE);
//adc
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
//end of adc

//watchdog
   setup_wdt(WDT_OFF);
//

//SPI
   setup_spi(SPI_MASTER|SPI_MODE_0|SPI_CLK_DIV_4);//ya 1 ya 2
//end of SPI
   output_high(CS); //you need to ensure this starts high

   delay_ms(1000);
   printf("hello MFRC522\r\n");

   output_low(LED);

//**1.PERFORM A SOFT RESET**\\
   write_reg(CONFIGREG, 0x2F);

   while (bit_test(read_reg(CONFIGREG),4)==1)) //test bit four
       ;
   //wait for chip to go ready

//etc.....


If you perform an spi_write, and then follow this with an spi_read, the read will return the value clocked 'back' during the write. spi_read(val), does both operations in one command, performing a write and a read.
It makes read the easier and safer command to use for all spi operations, just throw away the dummy byte returned during the first read.

Only real change functionally is using the data returned to actually see the chip is ready.

Key thing though is that several of your values are wrong.

Use #defines as I show, and let the compiler do the *2. Much safer!.
ariahope



Joined: 05 Jun 2014
Posts: 7

View user's profile Send private message

PostPosted: Tue Jun 10, 2014 2:33 am     Reply with quote

Hi Ttelmah,
your advises was great, really thanks.
in my second code I changed my basic problem did you see it?
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Tue Jun 10, 2014 9:00 am     Reply with quote

Note the way I wait for the chip to wake. Most commands don't need this, but the wake up does.

You have a sort of 'half multi byte' read, where you are specifying a number of bytes to read, but loop reading the same byte.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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