PN532 - SPI

25 Apr 2012

Hello,

I am trying to communicate with a NXP PN532 (nfc) through SPI. My first try was to use the spi class of mbed. Unfortunately the frame I have to send is a lot longer than 16 bits (the max allowed by void the function format( int bits,int mode = 0)) so it appears to me that I cannot use this class. Am I wrong? If so, Is there another solution?

Best regrads

26 Apr 2012

Hello,

I found a post talking about a similar topic : http://mbed.org/forum/mbed/topic/2978/?page=1#comment-15155

Using the code from this post I adapted mine:

#include "mbed.h"

Serial serialConn(p9, p10);  // tx, rx
SPI my_spi(p5, p6, p7);

int spi_data[9];
    
int main() {

    spi_data[0] = (0x00); //preambule
    spi_data[1] = (0x00); //start
    spi_data[2] = (0xFF); //start
    spi_data[3] = (0x01); //packet length
    spi_data[4] = (0xFF); //checksum
    spi_data[5] = (0xD4); //tfi
    spi_data[6] = (0x02); //data
    spi_data[7] = (0x2A); //dcs   
    spi_data[7] = (0x00); //post
    
    my_spi.format(16, 0);
    my_spi.frequency(5000000);
    
    int i = 0;
    for(i = 0; i<9; i++) {
        serialConn.printf("%d",LPC_SSP1->SR);
        while (!(LPC_SSP1->SR & 2));   //if TNF-Bit = 1 (FIFO not full); TNF-Bit is Bit 1 in SSPxSR
        LPC_SSP1->DR = spi_data[i];  // write to FIFO data register
        serialConn.printf("%d", spi_data[i]);
    }
    serialConn.printf("\n");
    
    for(i = 0; i<20; i++) {
        while (!(LPC_SSP1->SR & 4));   //if TNF-Bit = 1 (FIFO not full); TNF-Bit is Bit 1 in SSPxSR
        uint8_t var = LPC_SSP1->DR;  // write to FIFO data register
        serialConn.printf("%d", var);
    }
}

My problem is that the code does not past this line as if the FIFO was always full:

        while (!(LPC_SSP1->SR & 2));   //if TNF-Bit = 1 (FIFO not full); TNF-Bit is Bit 1 in SSPxSR

What am I doing wrong?

26 Apr 2012

I forgot to say that I am using the LPC11U24 version.

26 Apr 2012

in http://mbed.org/forum/mbed/topic/2978/?page=1#comment-15155 states : On mbed p5, p6, p7 is SSP1 and p11, p12, p13 is SSP0. Isn't it the opposite? I think it is so because after configuring my spi :

SPI my_spi(p5, p6, p7);

The content of LPC_SSP1->SR is 3 and the content of LPC_SSP0->SR is 0. Also if a configure the other spi

SPI my_spi(p11 p12, p13);

The content of LPC_SSP1->SR is 0 and the content of LPC_SSP0->SR is 3. I am a bit confused.

thanks

26 Apr 2012

Quote:

On mbed p5, p6, p7 is SSP1 and p11, p12, p13 is SSP0. Isn't it the opposite? I think it is so because after configuring my spi :

I think you are right for the LPC11U24. The schematic shows that p5, p6, p7 is SSP0 and p11, p12, p13 is SSP1: http://mbed.org/media/uploads/chris/mbed-010.2-schematic.pdf

However, on the LPC1768 the schematic shows that p5, p6, p7 is SSP1 and p11, p12, p13 is SSP0:

http://mbed.org/media/uploads/chris/mbed-005.1.pdf

Nasty inconsistency...

Other comments: The 16 bit mode means that every single message transfer is 16 bits wide. Doesnt mean that the total message is limited to 16 bits. In your case you fill the spi_data array with 8 bit values (0x00 etc). However the transaction will consist of 16 bits, meaning that 8 dummy zero bits are added and the receiver will get confused. I think you should use my_spi.format(8, 0) and send your bytes one after the other like in your code.

Second problem I noticed that the final two lines of code to set up the spi_data array overlap.

...
    spi_data[7] = (0x2A); //dcs   
    spi_data[7] = (0x00); //post

That should probably be

...
    spi_data[7] = (0x2A); //dcs   
    spi_data[8] = (0x00); //post
26 Apr 2012

Thanks for your fast reply. Now it seems like I am able to write to the FIFO or at least the programm execute normally until the end. However, the resonse is FF FF FF FF FF FF which is not normal.

I was wondering, is the output FIFO and the input FIFO the same?

To write to the FIFO I do this :

LPC_SSP1->DR = spi_data[i];

And to read from the FIFO I do this:

uint8_t var = LPC_SSP1->DR; 

For me it seems like I am reading and writing to the same FIFO. Is it ok?

26 Apr 2012

I think with the change to 8bit SPI mode you can probably use the standard SPI class methods for read and write. No need to check status bit yourself. What I miss in your code is the SPI chipselect signal. Normal SPI devices ignore all communication when the cs is not low and they dont accept the data until cs goes high again. You seem to read back all 1s, which would be the case when the miso line is open or when the slave device does not respond.

26 Apr 2012

Hello,

1- You are rigth, I dont manage my CS. I didn't know if I have to use it when not using the spiwrite method of mbed (because the example I found here : http://mbed.org/forum/mbed/topic/2978/?page=1#comment-15155 does not use it). I will change this.

2- If I can use the SPI class methods for read and write that is were I get confuse (but I would love to use them!). The problem I see is that:

1) I have to send 12 bytes at one time before getting an answer of 12 bytes also.

2) If I use spi.write(0x02) I can only send 1 byte and then I get an answer of, I think, 1 byte. (that is what I understand from the write method description)

3) When I get my answer, it is on 12 bytes. That is why I wanted to use a for loop and retrive each byte of the 12 bytes one at the time.

From your answer I understand that you mean, I could use a code like this:

#include "mbed.h"

SPI spi(p5, p6, p7); // mosi, miso, sclk
DigitalOut cs(p8);

Serial pc(USBTX, USBRX); // tx, rx

int main() {

    spi.format(8,3);
    spi.frequency(1000000);

    cs = 0;

    spi.write(0x00);
    spi.write(0x00);
    spi.write(0xFF);
    spi.write(0x01);
    spi.write(0xFF);
    spi.write(0xD4);
    spi.write(0x02);
    spi.write(0x2A);

    int response= spi.write(0x00);
    pc.printf("FRAME = 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X   \n", response);

    cs = 1;
}

Will the variable response contain all the 12 byte of the frame that I get as a response?

thanks a lot, your help is very appreciated (there is something but it is not exactly the expected).

26 Apr 2012

Hello,

1- You are rigth, I dont manage my CS. I didn't know if I have to use it when not using the spiwrite method of mbed (because the example I found here : http://mbed.org/forum/mbed/topic/2978/?page=1#comment-15155 does not use it). I will change this.

2- If I can use the SPI class methods for read and write that is were I get confuse (but I would love to use them!). The problem I see is that:

1) I have to send 12 bytes at one time before getting an answer of 12 bytes also.

2) If I use spi.write(0x02) I can only send 1 byte and then I get an answer of, I think, 1 byte. (that is what I understand from the write method description)

3) When I get my answer, it is on 12 bytes. That is why I wanted to use a for loop and retrive each byte of the 12 bytes one at the time.

From your answer I understand that you mean, I could use a code like this:

#include "mbed.h"

SPI spi(p5, p6, p7); // mosi, miso, sclk
DigitalOut cs(p8);

Serial pc(USBTX, USBRX); // tx, rx

int main() {

    spi.format(8,3);
    spi.frequency(1000000);

    cs = 0;

    spi.write(0x00);
    spi.write(0x00);
    spi.write(0xFF);
    spi.write(0x01);
    spi.write(0xFF);
    spi.write(0xD4);
    spi.write(0x02);
    spi.write(0x2A);

    int response= spi.write(0x00);
    pc.printf("FRAME = 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X   \n", response);

    cs = 1;
}

Will the variable response contain all the 12 byte of the frame that I get as a response?

thanks a lot, your help is very appreciated (there is something but it is not exactly the expected).

27 Apr 2012

The spi is like a shift register. You have to send 12 spi.write(xx) to get 12 byte in. Your response get only the first byte.

unsigned char response[12];
for (i=0;i<12;i++){
  response[i] = spi.write(0xff);
}
cs = 1;

The spi hardware can generate a cs signal for you, but this is not implemented by the standard lib. The reason - i think - is because the hardware cs goes high if the spi fifo get empty. If you want to send a block of data with cs low -the normal way to communicate to a device - you have to do it before the fifo gets empty. To be fast enough you have to use direct register access. A c++ class is to slow.

27 Apr 2012

Thank you for your reply.

To communicate with the PN532 I must first send 12 bytes of data and THEN receive 12 bytes. Isn't it? Using your code I would send 1 byte get 1 byte send 1 byte get 1 byte and so on. This cannot work as far as I understand.

A typical dialog looks like this :

/media/uploads/RFID/dialog.png

The frame I have to send is like this:

/media/uploads/RFID/frame.png

best regrads

27 Apr 2012

From a hardware perspective SPI communications always involve transmitting AND receiving bits at the same time. The master generates a clockbit and the masterdata on MOSI is shifted in by the slave. At the same time a databit from the slave is clocked in by the master on the MISO pin. However, in practice the master is typically either sending actual data while receiving dummy bytes that are just thrown away OR the master is sending dummy bytes and receives valid data from the slave.

In your case you would send 12 bytes (and receive 12 junk bytes), the slave then interprets the complete received message and then the master receives the corresponding 12 bytes response from the slave. The master needs to send 12 dummy bytes to receive this result.

I had a really quick look at the datasheet of the PN532. The actual communication seems to be even a bit more complex. You need to send a 1 byte command first to poll the slave and read 1 statusbyte to find out if it is ready to send you the results. These commands are represented by DW,SR, DR etc in your interaction diagram shown above.

09 May 2012

Thank you for your reply Wim. I am trying to use SPI bus for the first time and these lines are helpful. What I have not figured out is how master writes to a specfic register address on the slave side. For instance how do we write 0x88, to a slave register, whose address is 0xC1? The CTRL1 register in the following code has an address of

Kind regards, Hamid

  1. include "mbed.h"
  1. define STAT1 0x0
  2. define CTRL1 0x1
  3. define CTRL2 0x2
  4. define CTRL3 0x3
  5. define DATAR 0x4
  1. define CTRL1C 0x88
  2. define CTRL1R 0xC3
  3. define CTRL1W 0xC2
  4. define STAT1R 0xC1

function defintion void calibrate11200(void); void reset(void);

SPI spi(p11, p12, p13); mosi, miso, sclk SPI spi(p5, p6, p7); mosi, miso, sclk DigitalOut cs(p8);

Serial pc(USBTX, USBRX); tx, rx

int main() { Setup the spi for 8 bit data, high steady state clock, second edge capture, with a 1MHz clock rate spi.format(8,0); format ( # of bits, poloarti = 0,1,2,3) spi.frequency(5000000); spi clock frequency 5MHz, T = 200 nS (ds, page 4) reset(); while(1) { calibrate11200(); pc.printf(".......................begine whil loop here \n\r"); cs = 0; Select the device by seting chip select low calibrate11200(); see calibration fun. spi.write(STAT1R); int stat1returns = spi.write(0x00); pc.printf("STAT1 returned = 0x%X \r\n", stat1returns);

spi.write(CTRL1); int CTRL1returns = spi.write(CTRL1C); pc.printf("CTRL1 returned = 0x%X \r\n", CTRL1returns);

spi.write(DATAR); int DATA1 = spi.write(0x00); pc.printf("data1 register = 0x%X \r\n", DATA1); pc.printf("\n\r.......................loop ended here \n\r"); cs = 1; } }

01 Jun 2012

Hey Hermann, were you able to get your PN532 working after all. Can you share some simple code?

Hermann Helmholz wrote:

Thank you for your reply.

To communicate with the PN532 I must first send 12 bytes of data and THEN receive 12 bytes. Isn't it? Using your code I would send 1 byte get 1 byte send 1 byte get 1 byte and so on. This cannot work as far as I understand.

A typical dialog looks like this :

/media/uploads/RFID/dialog.png

The frame I have to send is like this:

/media/uploads/RFID/frame.png

best regrads

Hey Hermann Helmholz