Working SPI example with eImp?

Hi,
Can you please share a fully working example of an SPI device connected to the eImp?
I am trying to connect an RFID reader to eImp but no success so far and I do not know how to proceed (not sure if the problem is my configuration of eImp SPI protocol, the connection over a level converter to the Arduino shield, my eImp code or a mix of all of them)
I am using NXP PN532 configured to work in SPI mode. I use the Arduino shield manufactured by SeeedStudio:
http://www.nxp.com/documents/user_manual/141520.pdf
http://www.seeedstudio.com/wiki/NFC_Shield_V1.0#Resources
The level converter between the shield (5V) and the eImp(3.3V)
https://www.sparkfun.com/products/8745?

Thanks for any help that you can provide.

There have been various SPI examples posted, but SPI devices tend to be very unique (unlike i2c ones) so it’s rarely applicable to different devices.

Posting some basic code that you’re trying to get working would help? (eg, try to read an ID register on the chip)

How do you get the spi to output ONE BYTE OF DATA?

Also I am using an 74HC595 and the MISO ( pin 2) as a hardware reset,
since this is output only but the configure .spi257 seems to prevent this

To output one byte, just configure and write. The clock will start and the bits will be clocked:

// 4MHz, output only
hardware.spi257.configure(SIMPLEX_TX, 4000);

// ensure pin 2 is a GPIO output, and driven high (595 not in reset)
hardware.pin2.configure(DIGITAL_OUT);
hardware.pin2.write(1);

// Clock a byte out
hardware.spi257.write(byte);

Note that the HC595 has two clocks; one is the shift in clock (which you should connect to imp pin 5), the other one (STCP, pin 12) needs to have a rising edge any time you want the shift register contents to appear on the parallel outputs.

Note that if you tie this to the SHCP clock, your parallel outputs will then be one clock behind. You may want to just hook it to another GPIO and give it a single clock when the whole byte has been written, to bring it all to the outputs at once.

@jmg: I just noticed the level converter you’re using is one that’s really rather better for i2c than spi - it may not be fast enough for SPI. It relies on 10k pullups, slowed down by the pin capacitance, to return the line to logic 1 on the receiving side.

HOWEVER

Looking at the seeedstudio schematic, the NXP chip is actually 3.3v, and they’re already running it through a level shifter (U6), and powering it from an LDO (U4). The level shifter will work fine with both rails the same voltage, and the LDO will probably just give you a bit of dropout. I’d try feeding 3.3v into the 5v shield input (it can’t hurt it) and wiring the SPI bus on the shield directly up to the imp with no extra level translator at all.

Thanks Hugo,
I have tried to power the board with 3.3V as you suggested. I still observe
the same bahaviour “dumb” behaviour.
You can see my code at
http://pastebin.com/Ex7LRnd6
I have ported the SeeedStudio library (probably I’ve introduced bugs) and I have tried all combinations of SPI configuration parameters (CLOCK_IDLE_HIGH, CLOCK_IDLE_LOW, CLOCK_2ND_EDGE) with no success.
This is the output in my pannel using the eImp:
http://pastebin.com/Bp3UDzbQ

And here is the equivalent output of the original working code in Arduino:
http://pastebin.com/rKGUnH3c

Note that arduino does not require to write a byte to read a byte (i.e. there are bytes that are written without reading a response bytes; there are also several bytes read without writing a byte before)

I’ll take a look. Note that the arduino does write a byte when you read, and read a byte when you write - it’s just those are silently generated or ignored as appropriate. There is no way to do unidirectional traffic on SPI, it’s always bidirectional.

Some notes:

If you want to turn an int into hex, this is the easiest way to do it: format("%02x", integer) … there’s no need to write your own function :slight_smile:

Your readspistatus command is also incorrect, because you write the command (generates 8 clocks, sends the command), and then try to read a byte (which doesn’t generate any clocks to receive the response).

You should try this mod:

`function readspistatus() {
hardware.pin1.write(0);//pull CS low
imp.sleep(0.002);
spiwrite(PN532_SPI_STATREAD);
// clock reply in; data is ignored
hardware.spi257.write(0);

// read data from RX register
local value= hardware.spi257.read(1);
hardware.pin1.write(1);//pull CS high
return value;

}
`

Give that a try?

Thanks Hugo!
Squirrel documentation is not very browsable. Good to know about the format function :slight_smile:

Related to SPI, you are right. you always write a byte when reading another byte. In fact my original code had it but with so many “trial and error” changes things got a bit messy. In fact that is what happens in function spiwrite(byte). You write byte and read the response just afterwards. Since this function is used by readspistatus, there should not be a need to write an additional 0x00 as you propose in your updated code.
You need to write 0x02 (PN532_SPI_STATREAD) when you want to read a byte/status/data from PN532.
See updated functions:

function readspistatus() { hardware.pin1.write(0);//pull CS low imp.sleep(0.002);
// clock reply in; data is ignored
local value= spiwrite(PN532_SPI_STATREAD);


hardware.pin1.write(1);//pull CS high
return value;

}

function spiwrite(byte){

local tempString="\\\\x"+intToHex(byte);
hardware.spi257.write(tempString);
local resp=hardware.spi257.read(1);
foreach(i, val in resp){
        server.show(tempString +"-> (" +resp.len() + ") " + val);
}

return resp; //read n bytes

}

Unfortunately SPI communication keeps not working :frowning:

Sorry, the previous code in more readable format:

`
function readspistatus() {
hardware.pin1.write(0);//pull CS low
imp.sleep(0.002);

// clock reply in; data is ignored
local value= spiwrite(PN532_SPI_STATREAD);


hardware.pin1.write(1);//pull CS high
return value;

}

function spiwrite(byte){

local tempString="\\\\x"+intToHex(byte);
hardware.spi257.write(tempString);
local resp=hardware.spi257.read(1);
foreach(i, val in resp){
        server.show(tempString +"-> (" +resp.len() + ") " + val);
}

return resp; //read n bytes

}
`

No, you’re misunderstanding the timeline here.

SPI is a clocked bus. No data can be sent or received unless there’s a clock. When there is a clock, bits are sent and received at the same time; in effect, this means that both ends will have whatever they are going to send ready to go before the clock starts.

This means, when you write PN532_SPI_STATREAD, you will receive a byte. This byte WILL NOT be the status value - because until the last bit of the command byte has been clocked over the bus, the chip does not even know you want to read the status. Reading the status takes 16 clocks - or two bytes written by the master. You need to write the status read command, discard the junk byte that was received during the command transmission, then write a junk byte (which will be ignored by the slave) during which the status byte will be received by the master.

To illustrate how the API works (and there are clearer, multibyte versions in release-14 you’ll be glad to know), here’s what happens during each call:

hardware.spi257.write(PN532_SPI_STATREAD); // 8 clocks are generated and the byte is sent on the bus. The received byte is stored in a holding register, but is not returned.

value = hardware.spi257.read(1); // no clocks are generated. The contents of the holding register, populated by the last spi write call, are returned.

Re-writing your functions to be more what you need:

`function readspistatus() {
hardware.pin1.write(0);//pull CS low
imp.sleep(0.002);

// Send status command to PN532; ignore returned byte
spi_txrx(PN532_SPI_STATREAD);

// Collect status response, send junk 0x00 byte
local value = spi_txrx(0x00);

hardware.pin1.write(1);//pull CS high
return value;

}

function spi_txrx(byte) {
// Write the single byte
hardware.spi257.write(format("%c", byte));

// Collect the response from the holding register
local resp=hardware.spi257.read(1);

// Show what we sent
server.log(format("SPI tx %02x, rx %02x", byte, resp[0]));

// Return the byte
return resp[0];

}`

Give that a try?

Thank you Hugo!
Sorry about the silence due to the Christmas break and many thanks for the SPI for dummies lessons.
I just made a quick test and it is working (at least I am receiving data).
I will update the code and upload soon a working version when I get it fully working.

Glad it’s working - I actually googled looking for a good SPI tutorial but didn’t find one :frowning:

Looking forward to the PN532 code (as I’m sure others are too, it’s a pretty popular NFC chip)

Thanks to Hugo, I have been able to get NFC working with eImp. I uploaded the HelloWorld project to github.
The sketch just initialises the NFC shield (chip NXP PN532) and then waits for an RFID/NFC card to be presented to the reader. When a card is detected, its id is sent to the server in real time.
https://github.com/jmgjmg/eImpNFC

fyi, when you get release 14, the SPI code gets to look neater, eg:

`function readspistatus() {
hardware.pin1.write(0);//pull CS low
imp.sleep(0.002);

// Send status command to PN532 and collect status (returns a 2 byte string
// first byte is junk read during command write, second byte is status)
local r = hardware.spi257.writeread(format("%c\\x00", PN532_SPI_STATREAD));

hardware.pin1.write(1);//pull CS high

// Return status byte
return r[1];

}`

Great :slight_smile: