I2C :: How to interface a SPI sensor
Topic last updated
05 Feb 2012, by
Gerald MERCIER.
56 replies
Hi !
I am new on SPI interface. I enjoy to understand this fabulous technology !
My problème : Write and read data (temperature) on an EM4325 rfid tag (yes, yes, it is also a sensor !)
http://www.datasheets.org.uk/indexdl/Datasheet-093/DSA0072652.pdf
First :: I read the class doc.
First or second, I read the wiki page on SPI.
So I start my script like follow :
Serial pc(USBTX, USBRX);
SPI device(p5, p6, p7);//mosi on mosi, miso on miso, slc on sclc gnd on gnd and power supply with 2 V DC
DigitalOut cs(p8);//cs information
DigitalOut myled(LED1);
int main() {
myled = 1;
cs=1;
while(1) {
myled=0;
wait(1);
int rep = device.write(0x00);
pc.printf("%d", rep);
myled = 1;
wait(1);
}
}
My question : how to read a data in spi. I have understood that I need cs = 1 and write 0x00 with write method of the spi class.
Replies
As an SPI Master device you cant receive anything on spi without sending, so what you've done is correct, you send a 0x00 byte, and read the byte you receive, (its not the reply, its what was in the slave devices buffer as it received the new byte),
If the mbed is the slave device its easier
http://mbed.org/projects/libraries/api/mbed/trunk/SPISlave
Thanks for you reply ! but... To summarise what you have written, the integer "rep" in my code is the value witch is in the eeprom of the EM4325.
Bt how to read the temperature value ?
There are no need to read a register like any example of i2c sensor class development.
Regards,
GG
I'm not sure I understand what you're question is, the datasheet should explain what bytes you need to send to get the temperature( it doesn't though neither I found did) and how to convert the value from raw to Celsius, there must be a more detailed one?
Okay.... Now I understand, the byte I send will determine what kind of information (in the slave) my integer "rep" will return.
For myself, it was a statue integer to determine if the information was correctly written in the slave !
Regards,
ah ok =) glad you've got it figured out, sorry for misunderstanding the question
Also don't forget to setup the SPI interface using device.format( b, m ) where b is your bits per read/write and m is your SPI mode. The bits per r/w should be in the datasheet for the part and the SPI mode can be determined by looking at the timing diagrams (when the serial data gets setup and read in respect to the clock sync signal. After that you might also need to call device.frequency(f) where f is a compatible SPI frequency if needed. I think the code might assume defaults, but it's always good to double check! Hope that helps :)
Thanks for your answer !
I have a complete datasheet, but it confidential.
I through all the document to looking for what byte I need to write an what frequency the device run. Is it in the memory map ?
I'm afraid the communications layer on top of the SPI protocol could be anything, might be as simple as sending the memory address you want the byte from but the memory map looks far too complex for that, there should be a whole section on it in the datasheet
<edit>
It could just stream out the data continuously, if you set the mbed up as the SPI slave as the fact sheet says, you could use interupts. You may need to send an initial command still though,
without a datasheet its all assumptions
Hi Gerald! Here's the datasheet you want, http://www.emmicroelectronic.com/webfiles/product/rfid/ds/EM4325_FS.pdf
Take a look at "BAP tag or embedded application with EM4325 as SPI slave and another component as SPI Master" on the third page and make sure you have yours setup in a similar way (though I'm sure you can omit the AUX->Wakeup connection for now).
The cool thing about SPI (usually) is that the clock frequency isn't as picky as other protocols like RS-232. Usually, vendors will specify only a 'max SPI frequency,' generally limited by the chip's internal clock cycle. Since this vendor didn't specify any min/max clock setups, let's start low and see what happens.
Serial pc(USBTX, USBRX);
SPI device(p5, p6, p7);
DigitalOut cs(p8);
DigitalOut myled(LED1);
int main() {
myled = 1;
cs=1;
// New Code
char rep = 0xAA;
device.mode(8,1);
device.frequency(50000) // 50kHz on sck
pc.printf("Starting SPI Communication =^.^=\n");
while(1) {
myled=0;
wait(1);
cs = 0; // Most SPI devices use CS as active-low, which means logic 0 is when the chip is selected
rep = device.write(0x00);
cs = 1;
pc.printf("Reply from device is: %d \n", rep);
myled = 1;
wait(1);
}
}
@End code
Try that, and if it doesn't work then cycle through using SPI modes 0-3 while moving the frequency down a bit. Let me know if it works :D!
Oh ya, also try reading address 0x04 and other locations, doesn't look like 0x00 is a good address to read...
Ya, slave mode looks like it would be much easier, and if we could get a full data sheet it would make things much nicer! Did the chip come with any other information Gerald? Given that it's a device that takes security into consideration, reading data from it might require a few extra steps before we get a reply :3 although throwing it a few random bits never hurts. Also try changing the SPI mode to device.mode(16,1) since a few of those addresses were larger than 0xFF
Thanks for you reply !
I have just tried to work with your remarks, "mode" and "frequency" indication.
In a part of the datasheet, I can read :
Quote:
The maximum SCLK frequency from the spi master shall be 2 MHz
So, ok for
device.frequency(50000) // 50kHz on sck
But for the format(8,1) I don't understand...
--
With the new code, rep = 0 !
I will try to work with another mode ?!
I have changed the mode (enigmatic things !) for the mode (1,16). Now rep = 249.
Moreover, it the same "rep" value when I write 0xFF
does this always output the same value?
while(1) {
for(uint16_t i = 0; i < 255; ++i){
uint16_t rep = device.write(i);
pc.printf("Reply from device is: %d \n", rep);
wait(5);
}
}
many rep=0 in the last code ! just the 00 for whitch rep = 249.....
it appears from that pdf the addresses you want are 0x100, and 0x101; as the reply is always from the previous command on spi not the one you just sent,
device.write(0x100); //command
uint16_t rep1 = device.write(0x00); //send dummy byte to get reply
device.write(0x101); //command
uint16_t rep2 = device.write(0x00); //send dummy byte to get reply
does this work?
probably not you probably have to send a command before that saying that the next command will be the register i want to read,
I have already try the 100 adress.
Without uint16_t rep1 = device.write(0x00);, send dummy byte to get reply, the answer is the same.
But with it, it is now rep = 170. But when I put a finger on thee sensor, the temperature do not increase....
you need to combine, rep1 and rep2 into a value, if they are 8bit values,
int16_t value;
(uint8_t*)value[0] = rep2; //LSW
(uint8_t*)value[1] = rep1; //MSW
or the other way round im not sure,
Im not sure this is what your getting returned, but its worth a try, it could be an error value :/
It was a mistake in my last post.... rep1 and rep2 was equal to 0;
I have coded that:
uint16_t value[2];
value[0] = rep2; //LSW
value[1] = rep1; //MSW
pc.printf("Reply from device is: %d \n", value);
And the value = 268468216 and the value no change with the temperature.
if both rep1 and rep2 are 0, we probably need to send a command saying were going to read a value,
your code is outputting the pointer to the variable "value", not its value, notice it wasn't an array in my code, but that doesn't matter if we haven't managed to get any data yet :/
Im not sure what you mean by "the register i need to write", to get the sensor data you need to send 0xE5 to the device, within 20ms it should respond with 9 bytes of data, just keep sending 0x00 to get all the bytes
OKay, I propose for my infinity loop the follow code :
while(1) {
myled=0;
wait(1);
cs = 0;
device.write(0xE5);
wait(0.2);
rep = decide.write(0x00);
cs = 1;
// That what I do not understand *
....
//
myled = 1;
wait(1);
}
- In other words, how can I extract from the 9 bytes the sensor data ?
here's a (horribly) rough way to check your reply:
cs = 0;
char idx = 0x00;
// Array to hold *possible* data
char replies[128];
// Make sure memory within is known
do
{
replies[idx++] = 0;
}
while(idx<128)
idx = 0;
// Try desperately to get a response
while(idx<128) // EDITED: make sure to change this to idx < 128 o_o'
{
replies[idx++] = device.write( "why are you ignoring me ._.?" );
replies[idx++] = device.write( 0x00 );
}
for( idx = 0; idx < 128; idx++ )
if(replies[idx] > 0x00)
pc.printf("Non-zero value found in array at %i.\n Value: %d\n", idx, replies[idx]);
if(replies)
delete[] replies;
It's not pretty, but it should dump anything the device sends you into the array then output it's array position and value to your USB-serial connection. Make sure you replace the string with addresses of interest :P ... This should give us some good debug info for how to talk to the device :)
The device should respond within 20ms, so id send the command wait for 20ms, then try to get the data,
uint8_t packet[9];
while(1){
cs = 0;
device.write(0xE5); //command byte
wait(20);
uint8_t reply = device.write(0x00); // itl send 0x00 before packet
wait(1);
for(uint8_t i = 0; i < 9; ++i) {
packet[i] = device.write(0x00);
wait(1);
}
cs = 1; // must raise cs between commands but after the reply
}
Okay, but when I printf the data in the tab packet, after the cs=1 command, as follow:
for(uint8_t j=0; j<9;j++){
uint8_t value = packet[j];
printf("value : %d\n", value);
}
8 times "value = 0" appear in my terminal !
have you put the device back into 8bit spi mode?
device.mode(8,0);
can try (8,1), (8,2) and (8,3) too,
The command is right at least we know that much now
It is the good way !
Mode(3, 0)
248 | 0 | 93 | 0 | 0 | 0 | 0 | 0 | 0
The value (byte ?) 93 mean to be the temperature information, but neither in °C nor °F. I will read the datasheet (but in finality that not what I would like to do with that chip...)
Mode(3, 1)
same results
--
just 3 questions before going to sleep ;) :
- Why we use the mode(3, 0) -> if you have a google training about that... (that the 8 of the "command code" in the datasheet ?
- What is LSW / MSW ?
- What the difference between "Get sensor data" with 0xE4 and "Get sensor data after new sample" with 0xE5 ?
Regards,
GM
you mean mode(8,0)? mode(3,0) isnt a mode, needs to be 8bit or 16bit,
LSW means Least Significant Word and MSW is Most Significant Word,
and a word is 2 bytes,
0xE4 send the temperature it has in its memory, 0xE5 checks the temperature and sends that
anyway to reconstruct the data returned,
byte 0 = reply status (dont know what that means)
byte 1 - 4 is a 32bit value for the temperature that we need to reconstruct
uint8_t value[4];
value[0] = packet[3];
value[1] = packet[4]; //LSW
value[2] = packet[1];
value[3] = packet[2]; //MSW
uint32_t int_value = *(reinterpret_cast<uint32_t *>(value); //convert the value to a 32bit integer
Im not sure about the byte order though
Please log in to post a reply.
Hi !
I am new on SPI interface. I enjoy to understand this fabulous technology !
My problème : Write and read data (temperature) on an EM4325 rfid tag (yes, yes, it is also a sensor !)
http://www.datasheets.org.uk/indexdl/Datasheet-093/DSA0072652.pdf
First :: I read the class doc. First or second, I read the wiki page on SPI.
So I start my script like follow :
Serial pc(USBTX, USBRX); SPI device(p5, p6, p7);//mosi on mosi, miso on miso, slc on sclc gnd on gnd and power supply with 2 V DC DigitalOut cs(p8);//cs information DigitalOut myled(LED1); int main() { myled = 1; cs=1; while(1) { myled=0; wait(1); int rep = device.write(0x00); pc.printf("%d", rep); myled = 1; wait(1); } }My question : how to read a data in spi. I have understood that I need cs = 1 and write 0x00 with write method of the spi class.