libftdi Archives

Subject: Re: I'm still struggling with SPI.

From: John Oyler <john.oyler@xxxxxxxxxxxxxx>
To: libftdi@xxxxxxxxxxxxxxxxxxxxxxx
Date: Fri, 27 Aug 2010 14:19:21 -0500

On Aug 27, 2010, at 11:41 AM, Michael Plante wrote:

John Oyler wrote:
Then I loop through, trying to read them back. That doesn't quite work,
the first two
reads give 0x00, then while trying to read the 3rd address, I get back
the value of
the 1st, then while trying to read the 4th I get the value for the 2nd,
and so forth.

Did you get a chance to see (on the scope) if /CS was staying low for the
entire command sequence?  In other words, when you write the register
address out, and then you wait for the reply, does /CS stay active/low in
between, or does it pulse high briefly?  Is the problem intermittent, and,
if so, how often does it work or not?

Yes, CS stays low for the entire command sequence. In fact, I've discovered that both chip selects do... NSS_CONFIG and NSS_DATA. Still haven't had luck making only one go low at a time, which seems to be the only thing I need. 

As soon as the command sequence ends, both go high again. 

The problem is repeatable, and predictable. With the code I linked to last night, it will always be exactly 2 reads behind.

I don't need to read registers though...

I would suggest error checking (by reading the registers) is a good idea.
Additionally, this will tell you if you know how to read things correctly,
and give you confidence on your RSSI reads.

I'm tickled that I can read anything back at all, at this point. Eventually, i will read through them for error-checking, but right now I think it's a detail to fill in later.

For that, I need to set ADBUS4 low, and leave ADBUS3 (the typical chip
select) high.

You need to change pindir to 0x1b then, I think, rather than 0x0b.  ADBUS4
is 0x10.  Otherwise, ADBUS4 will be Hi-Z/input, and will float to whatever
the circuit lets it go to (not looking at schematic at the moment, or I'd
tell you what that is...sorry).

If I change pindir to 0x1b (or even 0x13) globally, it all stops working. If I change it to those values from within send_command() conditionally (on config_or_data), my initial write/read works, but when trying to read from the data fifo, things go hinky. If I change it at the top of send_command, period, then I see about 2/3rds of the register reads as 0x00, but the remaining third are identical in value and placement as they normally are (off by two). 

I'm under the impression that that's supposed to be the bitmask that tells you which pins are output. Setting the 5th pin to output shouldn't make it work like this, I would not think.

I can see some of the ftdi commands that the flashrom coders
use, they're in AN108. Those ones even make sense.

Could you elaborate?  By knowing which ones make sense to you, I might be
able to rule out possibilties.

SET_BITS_LOW is just 0x80. It takes two arguments, the first byte is supposed to be the value you're putting on ADBUS. The second byte is pindir, which should tell you which are output. 0x11 and 0x20 are the write and read commands respectively (that read one byte at a time, and msb first). There are other similar ones there that would allow for the concurrent writing and reading, for one bit at a time, in different directions. 

Other things, like line 117...
That seems like it's just packing a 0x00 into the buffer to send.

Yea, that looks like 0.  The idea is probably that they're trying to make
SCK and MOSI idle low, but I'm not sure.  You could certainly try changing
it to

- buf[i++] = 0 & ~cs_bits; /* assertive */
+ buf[i++] =     ~cs_bits; /* assertive */

but you MIGHT have to change it back.  Do you know if your SCK is supposed
to idle high or low?

Idle low, it seems.

 I don't have the datasheet in front of me right now.
I assume you've gone through and chosen all your commands for clocking in
and out on the correct rising/falling edges, as well as LSbit/MSbit first,
rather than just copying their commands, right?  

I've only copied so far, I don't understand it well enough. Hell, I can't even figure out what +VE and -VE mean in the app note.

That's 16 different
possibilities there, so the likelihood of getting it right accidentally by
copy&paste is low.  And getting some of those things wrong will sometimes
allow some commands to appear to work and not others.

I just made my code reconfigurable and tried different settings when my
first guess failed.  Bad, I know, but it only increased source line count by
maybe 0.1%. :)  The MPSSE commands are to some extent a bitfield, so it's
not too hard to do that.  Of course, FTDI doesn't spell this out precisely,
but it's not hard to see the pattern.

Some of the debug messages I've stripped from this claim that that's
asserting CS# (ADBUS3), but I don't see how.

Chip select, in most (all?) SPI setups is active-low, so setting ADBUS3 to 0
will assert it.  Setting it to 1 will de-assert it.  The slave interprets it
as inverted, but you should still see 0V on the line when you set it to 0,
and 3.3/5.0 when you set it to 1

Well, if I'm setting it to 0x00 effectively, that also explains why the second chip select (ADBUS4) goes low as well. But if I change that "0 & ~cs_bits" to a conditional to 0x10, it doesn't keep ADBUS4 high as I would expect.

cs_bits is useless there, and pindir doesn't seem to be the answer
it's value of 11, even with inverted logic, would seem to set ADBUS2 low,
not 3, which is MISO.

cs_bits is still used at the end of the function to restore /CS high.  As
far as pindir, yes, that matters.  pindir=0x0b does not set pins high or
low; it sets input versus output.  So MISO is the only one that remains an
input.  The other three (MOSI,SCK,/CS) remain outputs.  It also sets
ADBUS4-7 to inputs, which you've said you don't want (see above...0x1b is

I don't know how to use gdb, but it may be time to learn...

Have you tried "ddd"?

Only downside is, last I tried it (~2004), you have to close it and reopen
it when you recompile your code.

and I'll hook it up to the oscilloscope tomorrow morning when I'm back at
work. But again...
I'm not sure what that will show either, I already know that ADBUS3 is
low, or I'd not
get any SPI commands to work, even in the crappy way that they seem to be

Well, maybe.  Could you post a screenshot (or camera-phone photo) of the
scope, with the entire waveform for a single-register read command, showing
everything from the address output to the bytes coming back, including SCK,
MOSI, MISO, and /CS?

And I know with some certainty that ADBUS4 (which instead I want to go
low) isn't...

Well, you only need a DMM to know that.  Just set it permanently low and see
if it really is.  Set it permanently high and see if it is.  You need to try
both to really be sure that you're controlling it, though.

It happens to be low, both ADBUS3 and 4 are, for the duration of my successful spi commands, only going high again once the SPI command is over. But the radio chip defaults to config. Ugh. 

Ok, here's something bizarre, towards the top of ft2232_spi_command() I put in this block of code:

uint_t chipselect;

if (config_or_data) {
chipselect = 0x01;
pindir = 0x1b;
} else {
chipselect = 0x00;
pindir = 0x0b

And I change line 117 to buf[++i] = chipselect; ... The clock goes high whenever the clock signal isn't forcing it low. This is as you'd expect (pindir makes that pin an output, and I'm putting a 1 on it). But it doesn't seem to work if chipselect = 0x02 with MOSI... that still behaves normally. Nor does it work with it set to 0x08 for CS, or 0x10 for ADBUS4.

John O.

libftdi - see for details.
To unsubscribe send a mail to libftdi+unsubscribe@xxxxxxxxxxxxxxxxxxxxxxx

Current Thread