libftdi Archives

Subject: RE: Can someone give me a good explanation of ftdi_set_bitmode()?

From: "Michael Plante" <michael.plante@xxxxxxxxx>
To: <libftdi@xxxxxxxxxxxxxxxxxxxxxxx>
Date: Sat, 28 Aug 2010 19:53:17 -0500
John Oyler wrote:
>> Michael Plante wrote:
>> > John Oyler wrote:
>> >>> The example code I've been using merely sets this to 0x00.
>> >
>> > Setting it to 0 works fine for me.  I run SPI (with no chip-select),
along
>> > with ADBUS6-7, on port A.
>> >
>>
>> What are you using ADBUS6 and 7 for, if I might ask? And are you willing
to show the
>> code for it? I'm still having a hell of a time with ADBUS4. I don't have
the scope at
>>  my disposal here on the weekend, but it's still giving me the behavior
that makes me
>>  think CS and ADBUS4 are either both high or both low, but one or the
other isn't happening.


ADBUS6 goes to some FETs, and ADBUS7 goes to a reset circuit.  I operate
both of them in 3 states:  logic-high, logic-low, and Hi-Z.  To get Hi-Z, I
set the pin as input, and to get low/high, I set the pin as output.  When
Hi-Z, pull-up resistors force a value (slowly).  I can describe what I'm
doing.  As mentioned before, my setup code is long, and probably mostly
superfluous, out of paranoia:  I set almost every setting I can find in
libftdi.  Note that I only use port B when not using port A, so I'm not sure
how much help I'll be on that part.

My setup sequence goes as follows (again, this is probably overkill, and
possibly flat-out silly) :

1. enumerate all devices and pick one, then open it (port A).
2. set bitmode to BITMODE_MASK, BITMODE_RESET (232 mode)
3. set various serial port parameters (probably irrelevant)
4. commented-out: set chunksize (decided I was ok with default of 4k)
5. set latency timer to 3ms
6. set lower timeouts in ftdi context
7. purge buffers and read ftdi until nothing left
8. set bitmode to 0, BITMODE_RESET
9. set bitmode to 0, BITMODE_MPSSE
10. run my sync routine (with bad commands), then sleep a little (don't
remember why)
11. send an MPSSE command to Hi-Z/input the high ADBUS pins (unused).
Aside: I have pull-ups enabled in the EEPROM, so power draw on the CMOS
inputs is not a big issue.
12. send an MPSSE command to set the clock divisor (==2)
13. disable the loopback (MPSSE)
14. purge/read again, then sleep some more

The way a function that simultaneously reads and writes SPI works is roughly
as follows:

1. run my sync routine
2. send MPSSE command (3+# payload bytes)
3. optionally send the "send immediate" command
4. while no timeout and not as many bytes as expected:
4a. read until I get 0 bytes or until circular buffer is full
4b. if I got too much, purge it all and fail out
5. run sync routine again
6. purge/read all remaining bytes and discard them




To set ADBUS pins, I have the following (deleted error checking code, and
manually inlined some abstractions I had) :

....arguments to function are ucMask and ucVal:
  // 0x80 -> ADBUS7/GPIOL3
  // 0x40 -> ADBUS6/GPIOL2
  // 0x20 -> ADBUS5/GPIOL1
  // 0x10 -> ADBUS4/GPIOL0
  // 0x08 -> TMS/CS        -> OUTPUT
  // 0x04 -> TDO/DI (MISO) ->  INPUT
  // 0x02 -> TDI/DO (MOSI) -> OUTPUT
  // 0x01 -> TCK/SK        -> OUTPUT
  ucMask &= 0xF0;
  ucMask |= 0x0B; // ensure low nibble set such that TDO/DI input, others
out.
  ucVal  &= 0xF0; // mask off ADBUS0-3.
  ucVal  |= m_bCLKidle ? 0x01 : 0x00; // turn on clock pin, iff it idles
high.
  unsigned char pchData[3]={0x80, ucVal, ucMask};
  ftdi_write_data(m_pFtdiC, pchData, 3);

Note that JTAG stuff is in comments, but completely untested; it's there for
possible future use.  Also note that, prior to sending this, I optionally
run the sync routine, and afterwards, I optionally send send-immediate and
run the sync routine again.

Example commands I might send for bit-bang using MPSSE include :
ucMask=0x0B,ucVal=0x00
to cause both pins to go Hi-Z, or
ucMask=0xCB,ucVal=(bPin6 ? 0x40:0)|(bPin7 ? 0x80:0)
to drive both as outputs with configurable values.  I could mix-and-match
inputs and outputs, but my use case doesn't call for it.


Note that I have arranged my code in a sort of OSI-like protocol stack of
abstractions (not shown); you might consider something like this, because
MPSSE is just a pain otherwise.




>> This doesn't look like it's going to work... if the init function that
sets it up needs to
>> do a ftdi_usb_open(), then you can't do it a second time on a second
context object. Nor is
>> it obvious what parts of the internal structure could be copied.

You may have to open "B" first, then "A".  Or maybe the other way around.  I
haven't tried to use both at the same time.  Ok, no, actually, worse:  I
tried using both at the same time from two different programs (I don't think
they were both open at the same time, but I never figured it out...I posted
to libusb-devel a couple months ago about this), and it sometimes bricked
things so that I had to either reboot Linux or unplug/replug the device.  In
my particular case, it's actually easier to reboot, since I usually don't
have physical access. :(

HTH,
Michael


--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+unsubscribe@xxxxxxxxxxxxxxxxxxxxxxx   

Current Thread