Compare commits

..

30 commits

Author SHA1 Message Date
Limor "Ladyada" Fried
a12fee3983
Update README.md 2019-09-29 22:44:33 -04:00
Limor "Ladyada" Fried
72a7e96125
Update README.md 2019-07-18 16:05:02 -04:00
Limor "Ladyada" Fried
5b7b116ef0
Merge pull request #106 from vestom/py3
FTH232H: Make compatible with Python3
2019-05-26 17:00:45 -04:00
Tommy Vestermark
521309de57 FTH232H: Make compatible with Python3
- Fix some indentations
- Convert use of str() to bytes()
- Append b' to byte literals
- Fix some integer divisions / -> //
2019-04-27 09:55:00 +10:00
Limor "Ladyada" Fried
a92a23d6b5
Merge pull request #105 from gizmohd/master
Adding support for the Nvidia Jetson Nano Board
2019-04-10 08:24:34 -04:00
Darren McDaniel
7b8e666e84
Fix indent issue 2019-04-10 00:09:12 -04:00
Darren McDaniel
3ab79950de
Added Jetson functionality to GPIO 2019-04-10 00:05:38 -04:00
Darren McDaniel
74365514d1
Added Detection of Jetson Nano Board 2019-04-10 00:02:08 -04:00
Limor "Ladyada" Fried
2e84c14e22
Merge pull request #53 from frankalicious/fix-SPI-cs-assert-during-startup
fix unwanted SPI cs assert during startup
2019-04-04 17:53:50 -04:00
Limor "Ladyada" Fried
93e8ac6f0e
Merge pull request #104 from mpratt14/patch-10
FT232H.py: make print statements compatible with python 3
2019-04-04 15:29:22 -04:00
mpratt14
687adfb76b
FT232H.py: make print statements compatible with python 3
Similar to #102 

In the future consider more print statements for where and when errors would appear in code
2019-04-04 15:20:19 -04:00
Limor "Ladyada" Fried
498d8a1b9f
Merge pull request #102 from mpratt14/patch-7
setup.py: make print statements compatible with both Python 2 and 3
2019-04-02 21:00:11 -04:00
mpratt14
fcf67c0209
setup.py: make print statements compatible with both Python 2 and 3 2019-04-02 20:37:50 -04:00
Limor "Ladyada" Fried
d232fce7b2
Merge pull request #100 from mpratt14/patch-5
Fix mistakes from previous pull request for SPI methods
2019-04-02 00:46:04 -04:00
Limor "Ladyada" Fried
6fb18c6e37
Merge pull request #101 from mpratt14/patch-6
Fix previous pull request for setup.py
2019-04-02 00:45:48 -04:00
mpratt14
d943526240
Fix previous pull request for setup.py
doing a better job than #96 

prints possible requirement for root or admin privileges
tries to import pip before calling ensurepip (which isnt needed for python 3)

this time, don't even keep the method from ez_setup.py, there's no point...
commenting it out with ''' ''' gave me an IOError

bump version because why not?
2019-04-02 00:22:52 -04:00
mpratt14
9f9f23204e
Removed line with tab 2019-04-02 00:16:00 -04:00
mpratt14
aba58cb25f
Formatting and Indentation fix 2019-04-02 00:10:43 -04:00
mpratt14
63df8b9fb2
Fix mistakes in SPI method from previous pull request
Fix mistakes from #98 
This time, extensively tested

Also added support for read requests of odd length, read requests of length 1 working
Also applied same ideas to write requests
2019-04-02 00:03:19 -04:00
Limor "Ladyada" Fried
377c684950
Merge pull request #98 from mpratt14/patch-4
SPI Methods: Prevention of hardware limit errors and data corruption
2019-03-30 01:33:07 -04:00
mpratt14
57adb1e500
Merge branch 'master' into patch-4 2019-03-30 00:18:21 -04:00
Limor "Ladyada" Fried
96651c95fe
Merge pull request #97 from mpratt14/patch-3
setup.py: use the routine modern method for initial install ensuring of setuptools
2019-03-28 23:59:06 -04:00
Limor "Ladyada" Fried
0ec1977df2
Merge pull request #95 from mpratt14/patch-2
Add SPI method: bulkread
2019-03-28 23:58:46 -04:00
mpratt14
8a10df5416
Applying Hardware limit and data error prevention fixes
Applying fixes described here:
#94 
#95 

In order to:
Prevent a data stream larger than 64 KB from passing per command and warn the user
Fix the weird data corruption error that may or may not occur from full hardware limit length reads
2019-03-28 23:42:28 -04:00
mpratt14
662d0d9d31
setup.py: use the routine modern method for installing setuptools
My suggestion for fixing the deprecated method for installing or updating setuptools using ez_setup.py
Also ensures that both pip and setuptools are 'bootstrapped' to the python environment, which does not always happen on a fresh install in Windows.

Fixes #96 

This can be made more robust by detecting if pip or setuptools is installed with `pip --version`, etc...
2019-03-28 23:15:44 -04:00
mpratt14
268cd87672
Update FT232H.py 2019-03-26 00:45:02 -04:00
mpratt14
1f974c7744
Add SPI method: bulkread
Designed for communication with SPI Flash memory chips.

Single-use or combinations of the existing methods are not efficient or functional for the use case of NOR/NAND flash chip reading and writing. It is essential that between reading and writing the Chip Select remains asserted (High) for the entire period. Usage of the `write` and `read` methods is therefore not possible in combination because each of them de-asserts CS at the end of the method. There is no need for that behavior to change though.

The `transfer` method is inefficient because it sends a command to the FT232H that not only allows Full-Duplex but actually REQUIRES it for a command to complete. This is due to the design of the MPSSE. If I use the same FT232H command and attempt to read more than I am writing, a timeout occurs. In other words, the FT232H only allows communication at all during a Full-duplex command when there is data to be handled in Full-duplex, the amount you read MUST BE equal to the amount you write.

For example, an SPI read of a NOR flash chip: After instructing the FT232H to open the connection to the flash chip, you write the command to the slave as 1 byte, then the address as 3 bytes and the chip responds AFTER the write, not DURING, for as long as CS is asserted. In order to read only 1 of the 64 blocks of a 4 MB flash chip using the `transfer` method, I would have to append 65,532 zeros to the array that I am writing to the chip to keep the connection alive for each iteration of the loop, which is mandated both by the slave (NOR Flash) with CS, and by the master (FT232H) with the full-duplex command. Again, half-duplex read then write is a very simple matter, as with any SPI slave, that would be treated as two separate commands, `read` and then `write`. But on many SPI slaves, half-duplex write then read is almost always in the same instruction, where CS assertion must not be interrupted between commands of the master (FT232H), and this is a very popular implementation.

I have also designed this method to solve the issue #94 that I posted






For a while, I thought it should work with a single write command and two poll reads
...not true...


in parallel order, double read still doesnt fix it:
```
spi._ft232h._write(str(bytearray((commandR, len_lowR, len_highR))))
spi._ft232h._write(str(bytearray((commandR, len_lowR, len_highR))))
payload1 = spi._ft232h._poll_read(lengthR)
payload2 = spi._ft232h._poll_read(lengthR)
```

but in series order, double read does give clean output:
```
spi._ft232h._write(str(bytearray((commandR, len_lowR, len_highR))))
payload1 = spi._ft232h._poll_read(lengthR)
spi._ft232h._write(str(bytearray((commandR, len_lowR, len_highR))))
payload2 = spi._ft232h._poll_read(lengthR)
```





This is tested both in situations where the expected output is all ff, the expected output is all 00, or the expected output is real life data, confirmed with CRC32.

My take on this is basically sacrificing a little more python environment memory, to save the chips buffer from suffering. I am convinced that the problem is NOT with the poll_read function.
I am not sure if it is just my chip with this problem or many more, but this surely prevents it from appearing during heavy use, at practically any frequency. I have tried setting my clock as low as 1 MHz.







Therefore I propose this method, bulkread (I can't think of a better name, maybe readblock) with the following features...

  - both the array to write and the length to read back are optional (one or the other), configurable, and with defaults
  - allows a read up to the limit of the FT232H capabilities, both hard limit in the datasheet (64 KB) by ensuring input is within the range...
  - and soft limit handling from data corruption issue observed in my real life testing by simply performing two separate poll reads (see #94)
  - Warning the user about the data length limits
  - Deasserting CS is the VERY LAST action sent to the FT232H
  - the buffer flush command (0x87) is not used, in my testing, it makes no difference, less talking to the master means more talking to the slave.
  - a very simple mode setting, to allow writing only with the same method, not having to change methods by setting readmode to 0
  - all math is moved to the top, before anything is pushed to the device


Similar logic should be applied to every other method in the library, to inform the user before errors occur, and prevent errors due to (most likely) hardware defects.


@ladyada @tdicola Please help me out with the logger.debug line...I'm not sure about the syntax or purpose or usage of it
2019-03-26 00:35:32 -04:00
Limor "Ladyada" Fried
ede3d7d2be
Merge pull request #93 from mpratt14/patch-1
Allow basic support for libFTDI1.3
2019-03-22 16:34:13 -04:00
mpratt14
8c3bdde5be
Allow basic support for libFTDI1.3
Between libFTDI versions 1.2 and 1.3. The largest difference is a simple syntax difference on one function, where they removed one of the three arguments. Simply try the one for <=1.2, and if that throws a TypeError, try the syntax for 1.3+

here is a screenshot:
https://www.dropbox.com/s/m7a1ybx3ss2jotg/Screenshot%202019-03-11%2021.30.17.png?dl=0

This change is present in another commit, but with other changes. I am hoping that this simpler commit can be accepted easily...

Signed-off-by: Michael Pratt <mpratt51@gmail.com>
2019-03-22 16:24:22 -04:00
Alexander Frank
8cf257fbf8 fix unwanted SPI cs assert during startup
First set the chipselect to high then change the pin to output.
By fixing the order the pin does not go low and then high for a short
time.
2016-11-24 09:28:31 +01:00
5 changed files with 190 additions and 71 deletions

View file

@ -164,7 +164,7 @@ class FT232H(GPIO.BaseGPIO):
self._mpsse_enable()
self._mpsse_sync()
# Initialize all GPIO as inputs.
self._write('\x80\x00\x00\x82\x00\x00')
self._write(b'\x80\x00\x00\x82\x00\x00')
self._direction = 0x0000
self._level = 0x0000
@ -181,14 +181,17 @@ class FT232H(GPIO.BaseGPIO):
# Get modem status. Useful to enable for debugging.
#ret, status = ftdi.poll_modem_status(self._ctx)
#if ret == 0:
# logger.debug('Modem status {0:02X}'.format(status))
# logger.debug('Modem status {0:02X}'.format(status))
#else:
# logger.debug('Modem status error {0}'.format(ret))
# logger.debug('Modem status error {0}'.format(ret))
length = len(string)
ret = ftdi.write_data(self._ctx, string, length)
try:
ret = ftdi.write_data(self._ctx, string, length)
except TypeError:
ret = ftdi.write_data(self._ctx, string); #compatible with libFtdi 1.3
# Log the string that was written in a python hex string format using a very
# ugly one-liner list comprehension for brevity.
#logger.debug('Wrote {0}'.format(''.join(['\\x{0:02X}'.format(ord(x)) for x in string])))
#logger.debug('Wrote {0}'.format(''.join(['\\x{0:02X}'.format(x) for x in bytearray(string)])))
if ret < 0:
raise RuntimeError('ftdi_write_data failed with error {0}: {1}'.format(ret, ftdi.get_error_string(self._ctx)))
if ret != length:
@ -224,7 +227,7 @@ class FT232H(GPIO.BaseGPIO):
index += ret
# Buffer is full, return the result data.
if index >= expected:
return str(response)
return bytes(response)
time.sleep(0.01)
raise RuntimeError('Timeout while polling ftdi_read_data for {0} bytes!'.format(expected))
@ -240,14 +243,14 @@ class FT232H(GPIO.BaseGPIO):
error response. Should be called once after enabling MPSSE."""
# Send a bad/unknown command (0xAB), then read buffer until bad command
# response is found.
self._write('\xAB')
self._write(b'\xAB')
# Keep reading until bad command response (0xFA 0xAB) is returned.
# Fail if too many read attempts are made to prevent sticking in a loop.
tries = 0
sync = False
while not sync:
data = self._poll_read(2)
if data == '\xFA\xAB':
if data == b'\xFA\xAB':
sync = True
tries += 1
if tries >= max_retries:
@ -258,20 +261,20 @@ class FT232H(GPIO.BaseGPIO):
to 30mhz and will pick that speed or the closest speed below it.
"""
# Disable clock divisor by 5 to enable faster speeds on FT232H.
self._write('\x8A')
self._write(b'\x8A')
# Turn on/off adaptive clocking.
if adaptive:
self._write('\x96')
self._write(b'\x96')
else:
self._write('\x97')
self._write(b'\x97')
# Turn on/off three phase clock (needed for I2C).
# Also adjust the frequency for three-phase clocking as specified in section 2.2.4
# of this document:
# http://www.ftdichip.com/Support/Documents/AppNotes/AN_255_USB%20to%20I2C%20Example%20using%20the%20FT232H%20and%20FT201X%20devices.pdf
if three_phase:
self._write('\x8C')
self._write(b'\x8C')
else:
self._write('\x8D')
self._write(b'\x8D')
# Compute divisor for requested clock.
# Use equation from section 3.8.1 of:
# http://www.ftdichip.com/Support/Documents/AppNotes/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf
@ -281,14 +284,14 @@ class FT232H(GPIO.BaseGPIO):
divisor = int(divisor*(2.0/3.0))
logger.debug('Setting clockspeed with divisor value {0}'.format(divisor))
# Send command to set divisor from low and high byte values.
self._write(str(bytearray((0x86, divisor & 0xFF, (divisor >> 8) & 0xFF))))
self._write(bytes(bytearray((0x86, divisor & 0xFF, (divisor >> 8) & 0xFF))))
def mpsse_read_gpio(self):
"""Read both GPIO bus states and return a 16 bit value with their state.
D0-D7 are the lower 8 bits and C0-C7 are the upper 8 bits.
"""
# Send command to read low byte and high byte.
self._write('\x81\x83')
self._write(b'\x81\x83')
# Wait for 2 byte response.
data = self._poll_read(2)
# Assemble response into 16 bit value.
@ -301,11 +304,11 @@ class FT232H(GPIO.BaseGPIO):
"""Return command to update the MPSSE GPIO state to the current direction
and level.
"""
level_low = chr(self._level & 0xFF)
level_high = chr((self._level >> 8) & 0xFF)
dir_low = chr(self._direction & 0xFF)
dir_high = chr((self._direction >> 8) & 0xFF)
return str(bytearray((0x80, level_low, dir_low, 0x82, level_high, dir_high)))
level_low = (self._level & 0xFF)
level_high = ((self._level >> 8) & 0xFF)
dir_low = (self._direction & 0xFF)
dir_high = ((self._direction >> 8) & 0xFF)
return bytes(bytearray((0x80, level_low, dir_low, 0x82, level_high, dir_high)))
def mpsse_write_gpio(self):
"""Write the current MPSSE GPIO state to the FT232H chip."""
@ -395,8 +398,8 @@ class SPI(object):
self._ft232h = ft232h
# Initialize chip select pin if provided to output high.
if cs is not None:
ft232h.setup(cs, GPIO.OUT)
ft232h.set_high(cs)
ft232h.setup(cs, GPIO.OUT)
self._cs = cs
# Initialize clock, mode, and bit order.
self.set_clock_hz(max_speed_hz)
@ -467,64 +470,161 @@ class SPI(object):
"""Half-duplex SPI write. The specified array of bytes will be clocked
out the MOSI line.
"""
#check for hardware limit of FT232H and similar MPSSE chips
if (len(data) > 65536):
print('the FTDI chip is limited to 65536 bytes (64 KB) of input/output per command!')
print('use for loops for larger reads')
exit(1)
# Build command to write SPI data.
command = 0x10 | (self.lsbfirst << 3) | self.write_clock_ve
logger.debug('SPI write with command {0:2X}.'.format(command))
# Compute length low and high bytes.
# NOTE: Must actually send length minus one because the MPSSE engine
# considers 0 a length of 1 and FFFF a length of 65536
length = len(data)-1
len_low = length & 0xFF
len_high = (length >> 8) & 0xFF
# splitting into two lists for two commands to prevent buffer errors
data1 = data[:len(data)//2]
data2 = data[len(data)//2:]
len_low1 = (len(data1) - 1) & 0xFF
len_high1 = ((len(data1) - 1) >> 8) & 0xFF
len_low2 = (len(data2) - 1) & 0xFF
len_high2 = ((len(data2) - 1) >> 8) & 0xFF
self._assert_cs()
# Send command and length.
self._ft232h._write(str(bytearray((command, len_low, len_high))))
# Send data.
self._ft232h._write(str(bytearray(data)))
# Send command and length, then data, split into two commands, handle for length 1
if len(data1) > 0:
self._ft232h._write(bytes(bytearray((command, len_low1, len_high1))))
self._ft232h._write(bytes(bytearray(data1)))
if len(data2) > 0:
self._ft232h._write(bytes(bytearray((command, len_low2, len_high2))))
self._ft232h._write(bytes(bytearray(data2)))
self._deassert_cs()
def read(self, length):
"""Half-duplex SPI read. The specified length of bytes will be clocked
in the MISO line and returned as a bytearray object.
"""
#check for hardware limit of FT232H and similar MPSSE chips
if (1 > length > 65536):
print('the FTDI chip is limited to 65536 bytes (64 KB) of input/output per command!')
print('use for loops for larger reads')
exit(1)
# Build command to read SPI data.
command = 0x20 | (self.lsbfirst << 3) | (self.read_clock_ve << 2)
logger.debug('SPI read with command {0:2X}.'.format(command))
# Compute length low and high bytes.
# NOTE: Must actually send length minus one because the MPSSE engine
# considers 0 a length of 1 and FFFF a length of 65536
len_low = (length-1) & 0xFF
len_high = ((length-1) >> 8) & 0xFF
#force odd numbers to round up instead of down
lengthR = length
if length % 2 == 1:
lengthR += 1
lengthR = lengthR//2
#when odd length requested, get the remainder instead of the same number
lenremain = length - lengthR
len_low = (lengthR - 1) & 0xFF
len_high = ((lengthR - 1) >> 8) & 0xFF
self._assert_cs()
# Send command and length.
self._ft232h._write(str(bytearray((command, len_low, len_high, 0x87))))
# Perform twice to prevent error from hardware defect/limits
self._ft232h._write(bytes(bytearray((command, len_low, len_high))))
payload1 = self._ft232h._poll_read(lengthR)
self._ft232h._write(bytes(bytearray((command, len_low, len_high))))
payload2 = self._ft232h._poll_read(lenremain)
self._deassert_cs()
# Read response bytes.
return bytearray(self._ft232h._poll_read(length))
# Read response bytes
return bytearray(payload1 + payload2)
def bulkread(self, data = [], lengthR = 'None', readmode = 1):
"""Half-duplex SPI write then read. Send command and payload to slave as bytearray
then consequently read out response from the slave for length in bytes.
Designed for use with NOR or NAND flash chips, and possibly SD cards...etc...
Read command is cut in half and performed twice in series to prevent single byte errors.
Hardware limits per command are enforced before doing anything.
Read length is an optional argument, so that it can function similar to transfer
but still half-duplex.
For reading without writing, one can send a blank array or skip that argument.
"""
#check for hardware limit of FT232H and similar MPSSE chips
if (1 > lengthR > 65536)|(len(data) > 65536):
print('the FTDI chip is limited to 65536 bytes (64 KB) of input/output per command!')
print('use for loops for larger reads')
exit(1)
#default mode is to act like `transfer` but half-duplex
if (lengthR == 'None')&(readmode == 1):
lengthR = len(data)
#command parameters definition and math
#MPSSE engine sees length 0 as 1 byte, so - 1 lengths
commandW = 0x10 | (self.lsbfirst << 3) | self.write_clock_ve
lengthW = len(data) - 1
len_lowW = (lengthW) & 0xFF
len_highW = ((lengthW) >> 8) & 0xFF
commandR = 0x20 | (self.lsbfirst << 3) | (self.read_clock_ve << 2)
#force odd numbers to round up instead of down
length = lengthR
if lengthR % 2 == 1:
length += 1
length = length//2
#when odd length requested, get the remainder instead of the same number
lenremain = lengthR - length
len_lowR = (length - 1) & 0xFF
len_highR = ((length - 1) >> 8) & 0xFF
#logger debug info
logger.debug('SPI bulkread with write command {0:2X}.'.format(commandW))
logger.debug('and read command {0:2X}.'.format(commandR))
#begin command set
self._assert_cs()
#write command, these have to be separated due to TypeError
self._ft232h._write(bytes(bytearray((commandW, len_lowW, len_highW))))
self._ft232h._write(bytes(bytearray(data)))
#read command, which is divided into two commands
self._ft232h._write(bytes(bytearray((commandR, len_lowR, len_highR))))
payload1 = self._ft232h._poll_read(length)
self._ft232h._write(bytes(bytearray((commandR, len_lowR, len_highR))))
payload2 = self._ft232h._poll_read(lenremain)
self._deassert_cs()
#end command set
# Read response bytes
return bytearray(payload1 + payload2)
def transfer(self, data):
"""Full-duplex SPI read and write. The specified array of bytes will be
clocked out the MOSI line, while simultaneously bytes will be read from
the MISO line. Read bytes will be returned as a bytearray object.
"""
#check for hardware limit of FT232H and similar MPSSE chips
if (len(data) > 65536):
print('the FTDI chip is limited to 65536 bytes (64 KB) of input/output per command!')
print('use for loops for larger reads')
exit(1)
# Build command to read and write SPI data.
command = 0x30 | (self.lsbfirst << 3) | (self.read_clock_ve << 2) | self.write_clock_ve
logger.debug('SPI transfer with command {0:2X}.'.format(command))
# Compute length low and high bytes.
# NOTE: Must actually send length minus one because the MPSSE engine
# considers 0 a length of 1 and FFFF a length of 65536
length = len(data)
len_low = (length-1) & 0xFF
len_high = ((length-1) >> 8) & 0xFF
# Send command and length.
data1 = data[:len(data)//2]
data2 = data[len(data)//2:]
len_low1 = (len(data1) - 1) & 0xFF
len_high1 = ((len(data1) - 1) >> 8) & 0xFF
len_low2 = (len(data2) - 1) & 0xFF
len_high2 = ((len(data2) - 1) >> 8) & 0xFF
payload1 = ''
payload2 = ''
#start command set
self._assert_cs()
self._ft232h._write(str(bytearray((command, len_low, len_high))))
self._ft232h._write(str(bytearray(data)))
self._ft232h._write('\x87')
# Perform twice to prevent error from hardware defect/limits
# Send command and length, then data, split into two commands, handle for length 1
if len(data1) > 0:
self._ft232h._write(bytes(bytearray((command, len_low1, len_high1))))
self._ft232h._write(bytes(bytearray(data1)))
payload1 = self._ft232h._poll_read(len(data1))
if len(data2) > 0:
self._ft232h._write(bytes(bytearray((command, len_low2, len_high2))))
self._ft232h._write(bytes(bytearray(data2)))
payload2 = self._ft232h._poll_read(len(data2))
#self._ft232h._write('\x87')
self._deassert_cs()
# Read response bytes.
return bytearray(self._ft232h._poll_read(length))
return bytearray(payload1 + payload2)
class I2CDevice(object):
"""Class for communicating with an I2C device using the smbus library.
@ -542,7 +642,7 @@ class I2CDevice(object):
# Enable drive-zero mode to drive outputs low on 0 and tri-state on 1.
# This matches the protocol for I2C communication so multiple devices can
# share the I2C bus.
self._ft232h._write('\x9E\x07\x00')
self._ft232h._write(b'\x9E\x07\x00')
self._idle()
def _idle(self):
@ -560,9 +660,9 @@ class I2CDevice(object):
def _transaction_end(self):
"""End I2C transaction and get response bytes, including ACKs."""
# Ask to return response bytes immediately.
self._command.append('\x87')
self._command.append(b'\x87')
# Send the entire command to the MPSSE.
self._ft232h._write(''.join(self._command))
self._ft232h._write(b''.join(self._command))
# Read response bytes and return them.
return bytearray(self._ft232h._poll_read(self._expected))
@ -603,12 +703,12 @@ class I2CDevice(object):
"""
for i in range(length-1):
# Read a byte and send ACK.
self._command.append('\x20\x00\x00\x13\x00\x00')
self._command.append(b'\x20\x00\x00\x13\x00\x00')
# Make sure pins are back in idle state with clock low and data high.
self._ft232h.output_pins({0: GPIO.LOW, 1: GPIO.HIGH}, write=False)
self._command.append(self._ft232h.mpsse_gpio())
# Read last byte and send NAK.
self._command.append('\x20\x00\x00\x13\x00\xFF')
self._command.append(b'\x20\x00\x00\x13\x00\xFF')
# Make sure pins are back in idle state with clock low and data high.
self._ft232h.output_pins({0: GPIO.LOW, 1: GPIO.HIGH}, write=False)
self._command.append(self._ft232h.mpsse_gpio())
@ -619,12 +719,12 @@ class I2CDevice(object):
"""Write the specified number of bytes to the chip."""
for byte in data:
# Write byte.
self._command.append(str(bytearray((0x11, 0x00, 0x00, byte))))
self._command.append(bytes(bytearray((0x11, 0x00, 0x00, byte))))
# Make sure pins are back in idle state with clock low and data high.
self._ft232h.output_pins({0: GPIO.LOW, 1: GPIO.HIGH}, write=False)
self._command.append(self._ft232h.mpsse_gpio() * _REPEAT_DELAY)
# Read bit for ACK/NAK.
self._command.append('\x22\x00')
self._command.append(b'\x22\x00')
# Increase expected response bytes.
self._expected += len(data)

View file

@ -422,5 +422,8 @@ def get_platform_gpio(**keywords):
elif plat == Platform.MINNOWBOARD:
import mraa
return AdafruitMinnowAdapter(mraa, **keywords)
elif plat == Platform.JETSON_NANO:
import Jetson.GPIO
return RPiGPIOAdapter(Jetson.GPIO, **keywords)
elif plat == Platform.UNKNOWN:
raise RuntimeError('Could not determine platform.')

View file

@ -26,6 +26,7 @@ UNKNOWN = 0
RASPBERRY_PI = 1
BEAGLEBONE_BLACK = 2
MINNOWBOARD = 3
JETSON_NANO = 4
def platform_detect():
"""Detect if running on the Raspberry Pi or Beaglebone Black and return the
@ -45,16 +46,18 @@ def platform_detect():
return BEAGLEBONE_BLACK
elif plat.lower().find('armv7l-with-glibc2.4') > -1:
return BEAGLEBONE_BLACK
elif plat.lower().find('tegra-aarch64-with-ubuntu') > -1:
return JETSON_NANO
# Handle Minnowboard
# Assumption is that mraa is installed
try:
import mraa
if mraa.getPlatformName() == 'MinnowBoard MAX':
try:
import mraa
if mraa.getPlatformName()=='MinnowBoard MAX':
return MINNOWBOARD
except ImportError:
pass
# Couldn't figure out the platform, just return unknown.
return UNKNOWN
@ -67,7 +70,7 @@ def pi_revision():
for line in infile:
# Match a line of the form "Revision : 0002" while ignoring extra
# info in front of the revsion (like 1000 when the Pi was over-volted).
match = re.match(r'Revision\s+:\s+.*(\w{4})$', line, flags=re.IGNORECASE)
match = re.match('Revision\s+:\s+.*(\w{4})$', line, flags=re.IGNORECASE)
if match and match.group(1) in ['0000', '0002', '0003']:
# Return revision 1 if revision ends with 0000, 0002 or 0003.
return 1
@ -91,7 +94,7 @@ def pi_version():
with open('/proc/cpuinfo', 'r') as infile:
cpuinfo = infile.read()
# Match a line like 'Hardware : BCM2709'
match = re.search(r'^Hardware\s+:\s+(\w+)$', cpuinfo,
match = re.search('^Hardware\s+:\s+(\w+)$', cpuinfo,
flags=re.MULTILINE | re.IGNORECASE)
if not match:
# Couldn't find the hardware, assume it isn't a pi.
@ -103,11 +106,6 @@ def pi_version():
# Pi 2
return 2
elif match.group(1) == 'BCM2835':
rev_match = re.search(r'^Revision\s+:\s+(\w{4}).*$', cpuinfo,
flags=re.MULTILINE | re.IGNORECASE)
if rev_match and rev_match.group(1) == '9000':
# Pi Zero (1.2, 1.3, or W)
return 0
# Pi 3 / Pi on 4.9.x kernel
return 3
else:

View file

@ -1,3 +1,14 @@
!!!Deprecation Warning!!!
===================
This library has been deprecated in favor of [our python3 Blinka library](https://github.com/adafruit/Adafruit_Blinka). We have replaced all of the libraries that use this repo with CircuitPython libraries that are Python3 compatible, and support a [wide variety of single board/linux computers](https://circuitpython.org/blinka)!
Visit https://circuitpython.org/blinka for more information
CircuitPython has [support for almost 200 different drivers](https://circuitpython.readthedocs.io/projects/bundle/en/latest/drivers.html), and a as well as [FT232H support for Mac/Win/Linux](https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h)!
!!!Deprecation Warning!!!
===================
Adafruit Python GPIO Library
============================

View file

@ -1,23 +1,30 @@
try:
# Try using ez_setup to install setuptools if not already installed.
from ez_setup import use_setuptools
use_setuptools()
except ImportError:
# Ignore import error and assume Python 3 which already has setuptools.
pass
from setuptools import setup, find_packages
print('Adafruit GPIO Library')
print('Works best with Python 2.7')
print('THIS INSTALL SCRIPT MAY REQUIRE ROOT/ADMIN PERMISSIONS')
print('Especially if you installed python for "all users" on Windows')
print('\ntry the following in your systems terminal if ensurepip is not sufficient:')
print('$ python -m ensurepip --upgrade')
print('$ python -m pip install --upgrade pip setuptools')
import sys
try:
import pip
from setuptools import setup, find_packages
except ImportError:
import ensurepip
ensurepip.version()
ensurepip.bootstrap()
from setuptools import setup, find_packages
# Define required packages.
requires = ['adafruit-pureio']
# Assume spidev is required on non-windows & non-mac platforms (i.e. linux).
if sys.platform != 'win32' and sys.platform != 'darwin':
requires.append('spidev')
setup(name = 'Adafruit_GPIO',
version = '1.0.3',
version = '1.0.4',
author = 'Tony DiCola',
author_email = 'tdicola@adafruit.com',
description = 'Library to provide a cross-platform GPIO interface on the Raspberry Pi and Beaglebone Black using the RPi.GPIO and Adafruit_BBIO libraries.',