Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Sep 30, 2019. It is now read-only.

Commit e92026e

Browse files
committed
Add 1-Wire support via GPIO
1 parent bd058f7 commit e92026e

File tree

1 file changed

+348
-10
lines changed

1 file changed

+348
-10
lines changed

Adafruit_GPIO/FT232H.py

Lines changed: 348 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import subprocess
2727
import sys
2828
import time
29+
import struct
2930

3031
import ftdi1 as ftdi
3132

@@ -254,6 +255,18 @@ def _mpsse_sync(self, max_retries=10):
254255
if tries >= max_retries:
255256
raise RuntimeError('Could not synchronize with FT232H!')
256257

258+
def mpsse_clock(self, clock_hz, three_phase=False):
259+
# Compute divisor for requested clock.
260+
# Use equation from section 3.8.1 of:
261+
# http://www.ftdichip.com/Support/Documents/AppNotes/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf
262+
# Note equation is using 60mhz master clock instead of 12mhz.
263+
divisor = int(math.ceil((30000000.0-float(clock_hz))/float(clock_hz))) & 0xFFFF
264+
if three_phase:
265+
divisor = int(divisor*(2.0/3.0))
266+
logger.debug('Setting clockspeed with divisor value {0}'.format(divisor))
267+
# return command to set divisor from low and high byte values.
268+
return bytearray((0x86, divisor & 0xFF, (divisor >> 8) & 0xFF))
269+
257270
def mpsse_set_clock(self, clock_hz, adaptive=False, three_phase=False):
258271
"""Set the clock speed of the MPSSE engine. Can be any value from 450hz
259272
to 30mhz and will pick that speed or the closest speed below it.
@@ -273,16 +286,8 @@ def mpsse_set_clock(self, clock_hz, adaptive=False, three_phase=False):
273286
self._write('\x8C')
274287
else:
275288
self._write('\x8D')
276-
# Compute divisor for requested clock.
277-
# Use equation from section 3.8.1 of:
278-
# http://www.ftdichip.com/Support/Documents/AppNotes/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf
279-
# Note equation is using 60mhz master clock instead of 12mhz.
280-
divisor = int(math.ceil((30000000.0-float(clock_hz))/float(clock_hz))) & 0xFFFF
281-
if three_phase:
282-
divisor = int(divisor*(2.0/3.0))
283-
logger.debug('Setting clockspeed with divisor value {0}'.format(divisor))
284-
# Send command to set divisor from low and high byte values.
285-
self._write(str(bytearray((0x86, divisor & 0xFF, (divisor >> 8) & 0xFF))))
289+
clock_command = self.mpsse_clock(clock_hz, three_phase)
290+
self._write(str(clock_command))
286291

287292
def mpsse_read_gpio(self):
288293
"""Read both GPIO bus states and return a 16 bit value with their state.
@@ -815,3 +820,336 @@ def readS16BE(self, register):
815820
"""Read a signed 16-bit value from the specified register, in big
816821
endian byte order."""
817822
return self.readS16(register, little_endian=False)
823+
824+
class OneWireDevice(object):
825+
826+
def __init__(self, ft232h, pin, overdrive=False):
827+
self._pin = pin
828+
self._ft232h = ft232h
829+
self._buffer = False
830+
self._output = None
831+
832+
# setup the clock and get delay timing commands
833+
self._ft232h.mpsse_set_clock(30000000, False, False)
834+
self.enable_overdrive(overdrive)
835+
836+
# Two ways to delay. dump a byte to tms, or pulse the clock for n
837+
# bits. A 1 bit pulse seems to take the same as time as a 8bit
838+
# dump to TMS? Default is to pulse the clock.
839+
self._tms_dump = '\x4a\x01\xff' # Dump 8 bits to TMS
840+
self._pb = '\x8e\x01' # Pulse clock (1 bits)
841+
self._delay = self._pb
842+
843+
# MPSSE Command to read GPIO
844+
self._read_gpio = '\x81\x83'
845+
846+
# Set up our GPIO mask for 1-Wire, and leave it high
847+
self.set_pin(pin, GPIO.OUT, GPIO.HIGH)
848+
849+
850+
# Return the MPSSE command required to set the clock to a given frequency
851+
# for the provided delay
852+
def _get_delay_cmd(self, seconds):
853+
if seconds == 0:
854+
clock_hz = 30000000.0
855+
else:
856+
clock_hz = ( 1.00 / seconds ) * 2
857+
return self._ft232h.mpsse_clock(clock_hz, False)
858+
859+
# Calculate the delay clocks for 1Wire timings
860+
def enable_overdrive(self, overdrive):
861+
if overdrive:
862+
logger.debug('1Wire: Overdrive is enabled')
863+
# overdrive speeds
864+
self._overdrive = True
865+
self._clock_A = self._get_delay_cmd(0.0000010)
866+
self._clock_B = self._get_delay_cmd(0.0000075)
867+
self._clock_C = self._get_delay_cmd(0.0000075)
868+
self._clock_D = self._get_delay_cmd(0.0000025)
869+
self._clock_E = self._get_delay_cmd(0.0000010)
870+
self._clock_F = self._get_delay_cmd(0.0000070)
871+
self._clock_G = self._get_delay_cmd(0.0000025)
872+
self._clock_H = self._get_delay_cmd(0.0000700)
873+
self._clock_I = self._get_delay_cmd(0.0000085)
874+
self._clock_J = self._get_delay_cmd(0.0000400)
875+
else:
876+
# standard clock speeds
877+
logger.debug('1Wire: Overdrive is disabled')
878+
self._overdrive = False
879+
self._clock_A = self._get_delay_cmd(0.000006)
880+
self._clock_B = self._get_delay_cmd(0.000064)
881+
self._clock_C = self._get_delay_cmd(0.000060)
882+
self._clock_D = self._get_delay_cmd(0.000010)
883+
self._clock_E = self._get_delay_cmd(0.000009)
884+
self._clock_F = self._get_delay_cmd(0.000055)
885+
self._clock_G = self._get_delay_cmd(0.000000)
886+
self._clock_H = self._get_delay_cmd(0.000480)
887+
self._clock_I = self._get_delay_cmd(0.000070)
888+
self._clock_J = self._get_delay_cmd(0.000410)
889+
890+
# Buffer write commands and then send them to the MPSSE with a flush
891+
def enable_command_buffer(self):
892+
if self._buffer:
893+
raise Exception("Buffering was already enabled!!")
894+
self._buffer = True
895+
self._output = None
896+
897+
# flush buffered commands to the MPSSE
898+
def flush_command_buffer(self):
899+
self._buffer = False
900+
if self._output is not None:
901+
self._write(self._output)
902+
self._output = None
903+
904+
def _write(self, string):
905+
if self._buffer:
906+
if self._output is None:
907+
self._output = string
908+
else:
909+
self._output += string
910+
return
911+
self._ft232h._write(string)
912+
913+
def _read(self, length, timeout=5):
914+
return self._ft232h._poll_read(length, timeout)
915+
916+
# Set the GPIO to the state requested and update the self.low, self.high
917+
# values to take into account the changed pin.
918+
def set_pin(self, pin, mode, value):
919+
920+
# Update pin state to that requested
921+
if pin is not self._pin:
922+
self._ft232h.setup(pin, mode)
923+
self._ft232h.output(pin, value)
924+
925+
# Calculate the mask for the GPIO when 1-wire is low
926+
self._ft232h.setup(self._pin, GPIO.OUT)
927+
self._ft232h.output(pin, GPIO.LOW)
928+
self._low = self._ft232h.mpsse_gpio()
929+
930+
# Calculate the mask for the GPIO when 1-wire is high
931+
self._ft232h.setup(self._pin, GPIO.IN)
932+
self._ft232h.output(pin, GPIO.HIGH)
933+
self._high = self._ft232h.mpsse_gpio()
934+
935+
# Let the GPIO settle
936+
time.sleep(0.1)
937+
938+
# Here begins the 1-wire stuff
939+
940+
# Send a 1-wire reset on the GPIO, This makes all slaves listen up for commands.
941+
# It also detects the presance of the slaves. If nothing responds, then no devices
942+
# are connected and we return false.
943+
def reset(self):
944+
945+
logger.debug("1Wire: Reset")
946+
commands = self._clock_H + self._low + self._delay + self._high + self._clock_I +\
947+
self._delay + self._read_gpio + self._clock_J + self._delay + \
948+
self._read_gpio
949+
950+
self._write(str(commands))
951+
present = self._read(4)
952+
953+
if present == '\xff'*4:
954+
if self._overdrive:
955+
logger.debug("1Wire: No Devices Present. Disabling Overdrive")
956+
self.enable_overdrive(False)
957+
return self.reset()
958+
else:
959+
logger.debug("1Wire: No Devices Present")
960+
return False
961+
else:
962+
logger.debug("1Wire: Devices Present")
963+
return True
964+
965+
# Write a bit to the 1-wire bus, either a 1 or a 0
966+
def write_bit(self, bit):
967+
if bit:
968+
commands = self._clock_A + self._low + self._delay + self._high + \
969+
self._clock_B + self._delay
970+
else:
971+
commands = self._clock_C + self._low + self._delay + self._high + \
972+
self._clock_D + self._delay
973+
974+
self._write(str(commands))
975+
976+
def read_command(self, bits=1):
977+
for i in range(bits):
978+
commands = self._clock_A + self._low + self._delay + self._high + \
979+
self._clock_E + self._delay + self._read_gpio + self._clock_F + \
980+
self._delay
981+
self._write(str(commands))
982+
983+
def read_response(self, bits=1):
984+
states = []
985+
read = self._read(2 * bits)
986+
for i in range(0,2*bits,2):
987+
bit = bytearray([read[i], read[i+1]])
988+
states.append( struct.unpack("H", str(bit))[0] >> self._pin & 01 )
989+
if bits == 1:
990+
return states.pop()
991+
return states
992+
993+
# Read a bit from the 1-wire bus.
994+
def read_bit(self):
995+
self.read_command()
996+
return self.read_response()
997+
998+
# Use the write_bit function to write bytes out to the bus
999+
def write_byte(self, byte):
1000+
manage_buffer = self._buffer == False
1001+
if manage_buffer:
1002+
self.enable_command_buffer()
1003+
for i in range(8):
1004+
self.write_bit(byte & 1)
1005+
byte >>= 1
1006+
if manage_buffer:
1007+
self.flush_command_buffer()
1008+
1009+
# write multiple bytes to the bus
1010+
def write_bytes(self, data):
1011+
for byte in data:
1012+
self.write_byte(byte)
1013+
1014+
# Use the read_bit function to read bytes from the bus
1015+
def read_byte(self):
1016+
byte = 0
1017+
manage_buffer = self._buffer == False
1018+
if manage_buffer:
1019+
self.enable_command_buffer()
1020+
self.read_command(8)
1021+
if manage_buffer:
1022+
self.flush_command_buffer()
1023+
bits = self.read_response(8)
1024+
for i in range(8):
1025+
byte |= bits[i] << i
1026+
return byte
1027+
1028+
# Read multiple bytes from the 1-wire bus
1029+
def read_bytes(self, count):
1030+
data = bytearray(count)
1031+
for i in range(count):
1032+
data[i] = self.read_byte()
1033+
return data
1034+
1035+
# read multiple bits from the 1-wire bus. Used for device discovery
1036+
def read_bits(self, count):
1037+
bits = []
1038+
for i in range(count):
1039+
bits.append( self.read_bit() )
1040+
return bits
1041+
1042+
# There is only one device on the bus, so ask it to identify itself.
1043+
def rom_read(self):
1044+
rom = bytearray(8)
1045+
self.write_byte(0x33)
1046+
for i in range(8):
1047+
rom[i] = self.read_byte()
1048+
return rom
1049+
1050+
# There is only one device on the bus so skip ROM matching.
1051+
def skip_rom(self):
1052+
self.write_byte(0xcc)
1053+
1054+
# Target the ROM specified
1055+
def _match_rom(self, rom):
1056+
if type(rom) is str:
1057+
rom = self.string2bytes(rom)
1058+
self.write_byte(0x55)
1059+
self.write_bytes(rom)
1060+
1061+
# Address the ROM if given, else perform a skip_rom()
1062+
def address_rom(self, rom):
1063+
if rom is None:
1064+
self.skip_rom()
1065+
else:
1066+
self._match_rom(rom)
1067+
1068+
# Search for ROMs on the 1-wire bus
1069+
def search_roms(self):
1070+
roms_found = []
1071+
partials = [ [] ]
1072+
logger.debug("Search Start")
1073+
while len(partials) > 0:
1074+
rom = partials.pop()
1075+
roms_found.append( self.bytes2string(self._search(rom, partials)) )
1076+
logger.debug("Search Complete")
1077+
return roms_found
1078+
1079+
# When replaying the partial rom, flush the search out to the MPSSE every 10 bits
1080+
# improves performance.
1081+
def _search_flush_rom(self, count):
1082+
self.flush_command_buffer()
1083+
self.read_response(2*count)
1084+
return 0
1085+
1086+
# Do the search for each partial ROM
1087+
def _search(self, rom=[], partials=[]):
1088+
1089+
if self.reset() is False:
1090+
return
1091+
1092+
# Dump any partial rom to the MPSSE in 10bit chunks
1093+
self.enable_command_buffer()
1094+
self.write_byte(0xf0)
1095+
count = 0
1096+
for bit in rom:
1097+
if count == 10:
1098+
count = self._search_flush_rom(10)
1099+
self.enable_command_buffer()
1100+
count += 1
1101+
self.read_command(2)
1102+
self.write_bit(bit)
1103+
self._search_flush_rom(count)
1104+
1105+
# Continue the search from where we are.
1106+
for i in range(64 - len(rom)):
1107+
bits = self.read_bits(2)
1108+
if bits[0] != bits[1]:
1109+
rom.append(bits[0])
1110+
self.write_bit(bits[0])
1111+
elif bits == [False, False]:
1112+
np = list(rom)
1113+
np.append(True)
1114+
partials.append( np )
1115+
rom.append(False)
1116+
self.write_bit(False)
1117+
else:
1118+
raise Exception("Search Failed. Device Comms Interrupted")
1119+
1120+
complete = bytearray(8)
1121+
for i in range(8):
1122+
byte = 0
1123+
for o in range(8):
1124+
bit = rom[(i*8)+o]
1125+
byte |= bit << o
1126+
complete[i] = byte
1127+
1128+
logger.debug("Search Found: ROM {}".format( self.bytes2string(complete)))
1129+
if self.crc(complete) is not 0x00:
1130+
raise Exception("CRC Check Failed")
1131+
return complete
1132+
1133+
# Return an a string representation of the device ROM
1134+
def bytes2string(self, bytesarray):
1135+
return ":".join("{:02x}".format(c) for c in bytesarray)
1136+
1137+
# Convert a hexadecimal string to bytes
1138+
def string2bytes(self, string):
1139+
return bytearray(codecs.decode(string.replace(":",""),"hex"))
1140+
1141+
# Calculate CRC, result should be 0x00
1142+
def crc(self, data):
1143+
poly = 0x8c # x8,x5,x4,+ 1 inverse of 0x131 & 0xff
1144+
crc = 0x00
1145+
for byte in data:
1146+
for bit in range(8):
1147+
# When bit is on, shift and xor, else just shift
1148+
if ( byte ^ crc) & 0x01:
1149+
crc >>= 1
1150+
crc ^= poly
1151+
else:
1152+
crc >>= 1
1153+
byte >>= 1
1154+
return crc
1155+

0 commit comments

Comments
 (0)