Motoron Motor Controller library for Raspberry Pi
Loading...
Searching...
No Matches
i2c_set_addresses_example.py
1#!/usr/bin/env python3
2
3# This program is an interactive utility you can use to set the I2C
4# addresses for a single Motoron controller or multiple controllers.
5#
6# When you run this program in an terminal, it prompts you to enter a
7# command. Type the command you want to run and then press Enter.
8
9help_message = """
10To assign an I2C address to a Motoron, type "a" followed by the address
11(in decimal) while the JMP1 pin of the Motoron you wish to change is
12shorted to GND. For example, "a7" sets the address of the Motoron to
13decimal 17.
14
15Alternatively, you can type "a" by itself in order to automatically
16to have this program automatically pick an address for you.
17
18To make the Motoron start using its new address, you can reset it by
19power cycling it, driving its RST line low, or by typing "r".
20
21The "s" command does a simple scan of the bus to see which addresses
22have devices responding. This can help you make sure you have set up
23your I2C bus correctly.
24
25The "i" command goes further, sending extra commands to identify the
26Motoron devices on the bus and print information about them.
27
28Warning: The "i" command sends Motoron commands to every I2C device on
29the bus. If you have devices on your bus that are not Motorons, this
30could cause undesired behavior.
31
32Warning: The "a" and "r" commands use the I2C general call address (0), so
33they might cause undesired behavior on other devices that use that address.
34Also, they will not work if you disabled the general call address on a
35Motoron.
36"""
37
38start_message = """Motoron Set I2C Addresses Utility
39
40Type "h" for help, "a" followed by a number to assign an address, "r" to reset
41Motorons, "s" to scan, "i" to identify devices, or Ctrl+C to quit.
42
43Warning: If you have devices that are not Motorons, these commands could cause
44undesired behavior. Type "h" for more info.
45"""
46
47import readline
48import sys
49import time
50import motoron
51from smbus2 import SMBus, i2c_msg
52
53# Make a MotoronI2C object configured to use the general call address (0).
54mc = motoron.MotoronI2C(address=0)
55
56# The next address this program will try to use when you send an "a" command
57# to automatically assign an address.
58next_address = 17
59
60# This function defines which I2C addresses this program is
61# allowed to communicate with.
62def allow_address_communication(address):
63 # Addresses cannot be larger than 127.
64 if address >= 128: return False
65
66 # If you have devices on your bus and you want to prevent this
67 # code from talking to them, potentially causing unwanted
68 # operations, add their 7-bit addresses here with a line like this:
69 # if address == 0x6B: return False
70
71 return True
72
73# This function defines which I2C addresses this program is allowed
74# to communicate with.
75def allow_address_assignment(address):
76 return allow_address_communication(address) and address != 0
77
78# Checks to see if a device is responding at the specified address.
79def scan_address(address):
80 if not allow_address_communication(address): return False
81 try:
82 mc.bus.i2c_rdwr(i2c_msg.write(address, []))
83 return True
84 except OSError as e:
85 if e.args[0] == 6 or e.args[0] == 121: return False
86 raise
87
88def assign_address(line):
89 global next_address
90 desired_address_specified = False
91 desired_address = next_address
92 if len(line) > 1:
93 try:
94 desired_address = int(line[1:]) & 127
95 desired_address_specified = True
96 except ValueError:
97 pass
98
99 while True:
100 if allow_address_assignment(desired_address):
101 # Unless the address was explicitly specified by the user,
102 # make sure it is not already used by some other device.
103 if desired_address_specified or not scan_address(desired_address):
104 break
105 print("Found a device at address %d." % desired_address)
106
107 elif desired_address_specified:
108 print("Assignment to address %d not allowed." % desired_address)
109
110 # Try the next higher address.
111 while True:
112 desired_address = (desired_address + 1) & 127
113 if allow_address_assignment(desired_address): break
114
115 mc.enable_crc()
116
117 # Send a command to set the EEPROM device number to the desired
118 # address. This command will only be received by Motorons that
119 # are configured to listen to the general call address (which is
120 # the default) and will only be obeyed by Motorons that have JMP1
121 # shorted to GND.
122 mc.write_eeprom_device_number(desired_address)
123
124 print("Assigned address", desired_address)
125 next_address = desired_address + 1
126
127def scan_for_devices():
128 print("Scanning for I2C devices...")
129 for i in range(0, 128):
130 if scan_address(i):
131 print("Found device at address", i)
132
133# Note: This routine writes to many different addresses on your
134# I2C bus. If you have any non-Motoron devices on your bus,
135# this could cause unexpected changes to those devices.
136# You can modify allow_address_communication() to prevent this.
137def identify_devices():
138 print("Identifying Motoron controllers...")
139 for i in range(1, 128):
140 if not allow_address_communication(i): continue
141 test = motoron.MotoronI2C(bus=mc.bus, address=i)
142 try:
143 # Multiple Motorons on the same address sending different responses will
144 # cause CRC errors but we would like to ignore them.
145 test.disable_crc_for_responses()
146 v = test.get_firmware_version()
147 jumper_state = test.get_jumper_state() & 3
148 except OSError:
149 continue
150 jumper_string = ['both', 'on', 'off', 'err'][jumper_state]
151 print("%3d: product=0x%04X version=%x.%02x JMP1=%s" % (i, v['product_id'],
152 v['firmware_version']['major'], v['firmware_version']['minor'], jumper_string))
153
154def process_input_line(line):
155 if not line: return
156 elif line[0] == 'a': assign_address(line)
157 elif line[0] == 'r':
158 print("Reset")
159 mc.reset()
160 elif line[0] == 's': scan_for_devices()
161 elif line[0] == 'i': identify_devices()
162 elif line[0] == 'h' or line[0] == 'H' or line[0] == '?': print(help_message)
163 elif line == 'q' or line == 'quit': sys.exit(0)
164 else: print("Error: Unreocgnized command. Type h for help.")
165
166print(start_message)
167try:
168 while True:
169 process_input_line(input('Enter command: '))
170except (KeyboardInterrupt, EOFError):
171 print()
172
Represents an I2C connection to a Pololu Motoron Motor Controller.
Definition: motoron.py:1665