|
@@ -22,19 +22,19 @@ class LPC:
|
22
|
22
|
"""Interface for LPC in-system programming"""
|
23
|
23
|
|
24
|
24
|
def __init__(self, serport, baudrate=115200, clock=12000, timeout=0.1):
|
25
|
|
- self.serport = serport
|
26
|
|
- self.baudrate = baudrate
|
27
|
|
- self.clock = clock
|
28
|
|
- self.timeout = timeout
|
|
25
|
+ self._serport = serport
|
|
26
|
+ self._baudrate = baudrate
|
|
27
|
+ self._clock = clock
|
|
28
|
+ self._timeout = timeout
|
29
|
29
|
self._echo = True
|
30
|
30
|
|
31
|
31
|
def open(self):
|
32
|
32
|
"""Open the serial port to communicate with the microcontroller"""
|
33
|
|
- self._uart = serial.Serial(self.serport, baudrate=self.baudrate,
|
34
|
|
- timeout=self.timeout)
|
|
33
|
+ self._uart = serial.Serial(self._serport, baudrate=self._baudrate,
|
|
34
|
+ timeout=self._timeout)
|
35
|
35
|
|
36
|
|
- def readline(self):
|
37
|
|
- """Read a line terminated with '\r\n'"""
|
|
36
|
+ def _readline(self):
|
|
37
|
+ """Read a line terminated with b'\r\n'"""
|
38
|
38
|
s = b""
|
39
|
39
|
while True:
|
40
|
40
|
c = self._uart.read(1)
|
|
@@ -45,35 +45,43 @@ class LPC:
|
45
|
45
|
if s.endswith(b"\r\n"):
|
46
|
46
|
return s
|
47
|
47
|
|
48
|
|
- def writeline(self, line):
|
49
|
|
- """Write a line to the microcontroller and read the echoed response"""
|
|
48
|
+ def _writeline(self, line, plain=False):
|
|
49
|
+ """Write a line to the microcontroller and read the echoed response
|
|
50
|
+
|
|
51
|
+ If plain is True, the command is taken to be raw binary data.
|
|
52
|
+ """
|
50
|
53
|
self._uart.write(line)
|
51
|
54
|
self._uart.flush()
|
52
|
55
|
|
53
|
|
- if not self._echo:
|
|
56
|
+ # If echo is disabled, don't try to read back what we sent
|
|
57
|
+ if not self.echo:
|
54
|
58
|
return
|
|
59
|
+
|
55
|
60
|
# Read the response, raising the exception if there is one
|
56
|
|
- response = self.readline()
|
|
61
|
+ if plain:
|
|
62
|
+ response = self._uart.read(len(line))
|
|
63
|
+ else:
|
|
64
|
+ response = self._readline()
|
57
|
65
|
# If we got the wrong response, raise an exception
|
58
|
66
|
if response != line:
|
59
|
67
|
raise ISPError("Wrong text echoed: {}".format(response))
|
60
|
68
|
|
61
|
|
- def send_command_raw(self, cmd):
|
|
69
|
+ def _send_command_raw(self, cmd):
|
62
|
70
|
"""Send a command to the microcontroller, returning bytes"""
|
63
|
|
- self.writeline(cmd)
|
64
|
|
- return self.readline()
|
|
71
|
+ self._writeline(cmd)
|
|
72
|
+ return self._readline()
|
65
|
73
|
|
66
|
|
- def send_command(self, cmd):
|
|
74
|
+ def _send_command(self, cmd):
|
67
|
75
|
"""Send a command to the microcontroller, returning the result"""
|
68
|
|
- rr = self.send_command_raw(cmd)
|
|
76
|
+ rr = self._send_command_raw(cmd)
|
69
|
77
|
lr = [int(n) for n in rr.split()]
|
70
|
78
|
lr[0] = ReturnCode(lr[0])
|
71
|
79
|
return lr
|
72
|
80
|
|
73
|
|
- def start_isp(self, delay=0.01):
|
|
81
|
+ def enter_isp(self, delay=0.01):
|
74
|
82
|
"""Enter ISP mode by controlling the DTR (/RST) and RTS (/ISP) lines
|
75
|
83
|
|
76
|
|
- This operation is performed synchronously.
|
|
84
|
+ This operation is performed synchronously, with delays.
|
77
|
85
|
"""
|
78
|
86
|
self._uart.rts = True
|
79
|
87
|
time.sleep(delay)
|
|
@@ -83,8 +91,8 @@ class LPC:
|
83
|
91
|
time.sleep(delay)
|
84
|
92
|
self._uart.rts = False
|
85
|
93
|
|
86
|
|
- def start_comms(self, verbose=False):
|
87
|
|
- """Start communication with the microcontroller"""
|
|
94
|
+ def synchronize(self, verbose=False):
|
|
95
|
+ """Begin communication with the microcontroller"""
|
88
|
96
|
# Synchronize with the MCU
|
89
|
97
|
while True:
|
90
|
98
|
# Send a ?
|
|
@@ -94,20 +102,21 @@ class LPC:
|
94
|
102
|
print("?")
|
95
|
103
|
# Receive a response
|
96
|
104
|
try:
|
97
|
|
- s = self.readline()
|
|
105
|
+ s = self._readline()
|
98
|
106
|
except RecvTimeout:
|
99
|
107
|
continue
|
100
|
108
|
# If we got the right response, break
|
101
|
109
|
if s == b"Synchronized\r\n":
|
102
|
110
|
break
|
103
|
111
|
# Tell the MCU we've synchronized
|
104
|
|
- s = self.send_command_raw(b"Synchronized\r\n")
|
|
112
|
+ s = self._send_command_raw(b"Synchronized\r\n")
|
105
|
113
|
# Next, it should say OK, at which point we're done synchronizing
|
106
|
114
|
if s != b"OK\r\n":
|
107
|
115
|
raise ISPError("Wrong response during synchronization")
|
108
|
116
|
|
109
|
117
|
# Send clock frequency in kHz
|
110
|
|
- s = self.send_command_raw("{:d}\r\n".format(self.clock).encode("utf-8"))
|
|
118
|
+ s = self._send_command_raw("{:d}\r\n".format(self._clock).encode(
|
|
119
|
+ "utf-8"))
|
111
|
120
|
# Next, it should say OK
|
112
|
121
|
if s != b"OK\r\n":
|
113
|
122
|
raise ISPError("Wrong response during synchronization")
|
|
@@ -118,22 +127,65 @@ class LPC:
|
118
|
127
|
|
119
|
128
|
def unlock(self, code="23130"):
|
120
|
129
|
"""Unlock the flash write, erase, and go commands"""
|
121
|
|
- return self.send_command("U {}\r\n".format(code).encode("utf-8"))
|
|
130
|
+ return self._send_command("U {}\r\n".format(code).encode("utf-8"))
|
|
131
|
+
|
|
132
|
+ @property
|
|
133
|
+ def baudrate(self):
|
|
134
|
+ """The baud rate used for communication"""
|
|
135
|
+ return self._uart.baudrate
|
|
136
|
+
|
|
137
|
+ @baudrate.setter
|
|
138
|
+ def baudrate(self, br):
|
|
139
|
+ r = self._send_command("B {} {}\r\n".format(br,
|
|
140
|
+ self._uart.stopbits).encode("utf-8"))
|
|
141
|
+ # Update the baud rate for our UART
|
|
142
|
+ if r[0] != ReturnCode.CMD_SUCCESS:
|
|
143
|
+ raise ISPError(r)
|
|
144
|
+ self._uart.baudrate = br
|
|
145
|
+
|
|
146
|
+ @property
|
|
147
|
+ def stopbits(self):
|
|
148
|
+ """The number of stop bits used for communication"""
|
|
149
|
+ return self._uart.stopbits
|
|
150
|
+
|
|
151
|
+ @stopbits.setter
|
|
152
|
+ def stopbits(self, sb):
|
|
153
|
+ r = self._send_command("B {} {}\r\n".format(self._uart.baudrate,
|
|
154
|
+ sb).encode("utf-8"))
|
|
155
|
+ # Update the number of stop bits for our UART
|
|
156
|
+ if r[0] != ReturnCode.CMD_SUCCESS:
|
|
157
|
+ raise ISPError(r)
|
|
158
|
+ self._uart.stopbits = sb
|
|
159
|
+
|
|
160
|
+ @property
|
|
161
|
+ def echo(self):
|
|
162
|
+ """Whether the microcontroller echoes characters back to the host"""
|
|
163
|
+ return self._echo
|
|
164
|
+
|
|
165
|
+ @echo.setter
|
|
166
|
+ def echo(self, setting):
|
|
167
|
+ setting = bool(setting)
|
|
168
|
+ r = self._send_command("A {}\r\n".format(int(setting)).encode("utf-8"))
|
|
169
|
+ if r[0] != ReturnCode.CMD_SUCCESS:
|
|
170
|
+ raise ISPError(r)
|
|
171
|
+ self._echo = setting
|
122
|
172
|
|
123
|
|
- def setbaudrate(self, baudrate, stopbits):
|
124
|
|
- """Update the baud rate and number of stop bits"""
|
125
|
|
- r = self.send_command("B {} {}\r\n".format(baudrate, stopbits).encode(
|
|
173
|
+ def write_ram(self, start, data, count=None):
|
|
174
|
+ """Write count bytes from data to RAM at the given start address
|
|
175
|
+
|
|
176
|
+ Start and count must be multiples of four. If count is not specified,
|
|
177
|
+ len(data) is used.
|
|
178
|
+ """
|
|
179
|
+ # Get the length of the data we're writing
|
|
180
|
+ if count is None:
|
|
181
|
+ count = len(data)
|
|
182
|
+ # Ask to write data
|
|
183
|
+ r = self._send_command("W {} {}\r\n".format(start, count).encode(
|
126
|
184
|
"utf-8"))
|
127
|
|
- # Update the baud rate and number of stop bits for our UART connection
|
|
185
|
+ # If the MCU is okay with what we intend to do, send the data
|
128
|
186
|
if r[0] == ReturnCode.CMD_SUCCESS:
|
129
|
|
- self._uart.baudrate = baudrate
|
130
|
|
- self._uart.stopbits = stopbits
|
131
|
|
- return r
|
132
|
|
-
|
133
|
|
- def echo(self, setting):
|
134
|
|
- """Set whether echo is enabled or disabled"""
|
135
|
|
- r = self.send_command("A {}\r\n".format(int(setting)).encode("utf-8"))
|
136
|
|
- self._echo = setting
|
|
187
|
+ # NOTE: this is right for LPC8xx chips, not others
|
|
188
|
+ ok = self._writeline(data[:count], plain=True)
|
137
|
189
|
return r
|
138
|
190
|
|
139
|
191
|
|