SPI - Newbie question

First, let me preface this by saying while I'm not a complete newbie with electronics, it's something I'm not super familiar with, code is more of my thing.

So I'm wanting to interface with a TI CC1101 (data sheet) in order to interface with another device. It states it's a 4-pin SPI, although the imp is a 3-pin SPI configuration (which I undertand - I think! - what they're doing.) What I don't understand is CC1101's SO pin acts as a digital out, and I need to wait for it to go low before reading / writing to / from a register. I'm a little confused how I'd do this in code. Can I do something like this?

hardware.spi257.configure(flags, clock * 1000); // configure SPI_257 at about n X 1k
local so = hardware.pin2;
so.configure(DIGITAL_IN);

Is that going to mess with the SPI or should it act properly?

Sorry for the newbie question with the hardware side of things.

No need to apologize.  We expect many of our users to be software developers with some or limited hardware experience so please ask away!  I’ll forward this post to our HW experts so that they can supply the appropriate information.

Of course, if any of our users have the hardware know-how to answer these questions, please feel free to jump and help.

Thanks!

Nong

(Edit, again: That’s strange, apparently using the strikeout causes it to actually delete the text after you refresh the page…)

Reading Comprehension Fail. Not sure about your actual question, but my guess would be that it should be possible since that pin should be configured as an input already.

So here the 4 wire means “has an nCS pin”. Just hook this up to a GPIO and drive it low, then wait for SO to go low before you send data.


The most recent hardware.configure takes precedence, so if you want to receive data from the chip, you’ll want to do this:

1 Drive nCS low
2 Configure SO as a GPIO input
3 Wait until it goes low
4 Configure SPI (will turn SO back into an SPI input)
5 Send and receive data (SPI receives a byte concurrent with every sent byte, unless you configure it to be SIMPLEX_TX)
6 Drive nCS high

If you are only ever transmitting, you could leave SO configured as a GPIO input and configure SPI with SIMPLEX_TX which then shouldn’t touch the SPI MISO pin on the imp - which is the one you’d have connected to the 1101’s SO pin.


Thanks, Hugo.


I actually want to just read incoming data, and never transmit. I’m planning on intercepting specific messages from a medical device. I certainly don’t want to transmit anything to it - as errant messages could prove fatal - yikes!

(Sorry - mean never transmit out of the CC1101, but I guess I will need to TX & RX.) Hmmm… so much to learn. Wish it was just as simple as using serial - haha!

On SPI, if you’re the master you can’t receive without sending; you clock data out whenever the clock is running.


That doesn’t necessarily mean you’ll transmit, but you will need to consult the datasheet closely to work it all out. There’s no standard for how to hook a transceiver to SPI so every case is different…

Hugo - thanks for all the tips!

I finally got the parts I ordered and am starting to play around with the RF board. Upon reading a few other forums regarding SPI, it was suggested that I read a known value, such as the part number or version, I should receive one byte, 0x00 and 0x04 respectively.

Is spi.read() working? I seem to get nothing back, however the function appears to be working. When I do a server.log("SPI Read = " + spi.read(1)), I get just the "SPI Read = " portion.

Ideas?

Well, turns out that I’m just getting non-printable responses. I wish the response would be in integer form rather than string format. When I try to do an tointeger() on it, it won’t even convert. I’d hate to have a switch…case on a bunch of strings.


Anyway - here’s my read event:

function read(addr)
    {
        imp.sleep(0.000005);
        csn.write(0);
        imp.sleep(0.000002);
        so.configure(DIGITAL_IN);
        while (so.read());
        hardware.spi257.configure(flags, 1000)
        hardware.spi.write(format("\\x%02X",addr));
        local x = hardware.spi.read(1);
        server.log("SPI Read = " + x);
        imp.sleep(0.000002);
        csn.write(0);
        return x;
    }

When I try to do an tointeger() on it, it won’t even convert.

Yes, this isn’t very well-documented in Squirrel. The string.tointeger method is for strings such as “2012”; it’s the equivalent of C’s atoi() function. The thing you want, to access the byte value of part of a string, is indexing using square brackets [], again like in C, though I can’t find it mentioned in the Squirrel manual.

So after “x = hardware.spi.read(1)”, if the hardware has sent you one byte of 0x04, what you need to do is to access the first byte of the string x, noting that they’re numbered from 0 upwards:

if (x[0] == 4) print(“hurrah”);

Peter

The official Squirrel documentation is absolutely dire, it barely constitutes a reference. It’s on my list to write a Squirrel tutorial or at least a language FAQ for the wiki.


Rob
Fen Consultants, UK

I’m still just getting 0 back, so I suspect there’s something else wrong either with the wiring (although I’ve checked several times) or with my implementation. I suspect the latter . . .


Thanks for the info!

I’ve been running into a brick wall since the start of this thread. Can EI confirm that spi.read() actually works? I’m trying to read a static register and what I get back varies from 0x00, to 0x0F3, to 0x0FF. It’s a bit inconsistent but most of the time I get 0x00.


I also read that when interfacing with this chip that a pull-up resistor should be added to the chip select pin . . . well, a bit embarrassed to admit, I’m not 100% sure what that means (again, software dude, hardware newb). From what I gather, am I to put a resistor from the CS line to ground? I can post a picture - but I think we’ll be getting out of the scope of the support of the forum, as this is stuff I should already know.

Thanks!

A “pull-up” resistor is intended to draw the signal level “up” (high, operating voltage 3.3V or 5V) when the pin is otherwise not being actively driven high/low by anything else.  As such, it should be a large resistance value (10Kohm ?) so that the real circuit can drive it low when needed without having to waste too much current overpowering the resistor.

A pull-down resistor is the same idea, except it gets tied to ground instead of the operating voltage.

So in your case, something like a 10Kohm resistor would get connected between the CS line and the power supply voltage for the circuit.

Thanks - that is how I have it set up, but still getting inconsistent results. Not sure what else to try.


Thanks again for the help!

Can you try just shorting SPI TX to SPI RX? You should then receive exactly what you send, and is a good sanity check (but only really checks the imp, because…)


SPI has various options about data being clocked on the rising or falling edge, and about whether the clock should idle high or low. You need to get the right combination otherwise things won’t work with your device. Did you look at this at all?

Yes, I’ve read the data sheet several times and tried to understand it to the best of my ability.


I did try shorting TX to RX, but it does not echo.

The code:
function ReadReg(regAddr, regType)
{
    local addr = regAddr | regType;
    SelectDigitalRead();                    // Make SO to digital pin
    SelectChip()                            // Select CC1101
    WaitMiso();                             // Wait until MISO goes low
    SelectSPI();                            // Go back to SPI mode
    server.log(“TX - " + format(”%02X",addr));
    hardware.spi.write(format("%c",addr));  // Write
    local x = hardware.spi.read(1);         // Get the value
    DeselectChip()                          // Deselect CC1101
}


The result (F1 and F0 are correct.)
Thursday, August 30, 2012 21:45:15: TX - F1
Thursday, August 30, 2012 21:45:15: RX - FF
Thursday, August 30, 2012 21:45:15: TX - F0
Thursday, August 30, 2012 21:45:15: RX - FF
</div>

Ack. Digging in, I see that we don’t expose the readwrite call in squirrel (yet) which means that this test won’t work - every bus operation on SPI is both a read and a write, so you need to do both at once.


I was under the mistaken impression that the write call returned the data read, but it doesn’t. I’ve filed a bug/feature request. Sorry.

Ah, okay. So that means for the time being SPI read() does not work properly?

Looking more, I believe that actually that should have worked; if you write a single byte, a byte will be received and left in the FIFO for the next read to pick up. Hmm.


Looking at the CC1101 datasheet, you should have MSB first, clock idling low and latching data on the rising edge, which is the default SPI setup, so that should be fine.

Leaving aside the loopback failure for now (I’ll try and wire this up tomorrow to check), I do notice that your code won’t actually read the CC1101 registers. You need this:

hardware.spi257.write(format("%c", addr);
hardware.spi.read(1); // discard status byte received during last transmit
hardware.spi257.write("\xff"); // junk output byte during receive
local x = hardware.spi257.read(1);

…because a read doesn’t actually issue any clocks. Only a write will do that, and the byte received is a side effect of the write.

Thanks for the input & help, it’s very much appreciated!


You mention that latching data on the rising edge is the default SPI setup, is that changeable in configure()? I don’t see anything in the Wiki regarding where the data latches.

I implemented the code & still getting nothing (0x00). I tried with and without the pullup resistor. I’m thinking a bummed chip . . . they were “cheap” and from eBay.