Browse Source

Added code to do some communication with LPCs

Now we have code to connect to the serial port, put the LPC into ISP
mode, unlock the flash, and update echo and serial port settings.  The
code's way nicer than lpc21isp so far, which is all I really wanted I
guess.
Clara Hobbs 6 years ago
parent
commit
44b8a17953
1 changed files with 172 additions and 0 deletions
  1. 172
    0
      alpaca_isp/__init__.py

+ 172
- 0
alpaca_isp/__init__.py View File

@@ -0,0 +1,172 @@
1
+# Copyright 2017 Clayton G. Hobbs
2
+# 
3
+# Licensed under the Apache License, Version 2.0 (the "License");
4
+# you may not use this file except in compliance with the License.
5
+# You may obtain a copy of the License at
6
+# 
7
+# http://www.apache.org/licenses/LICENSE-2.0
8
+# 
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS,
11
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+# See the License for the specific language governing permissions and
13
+# limitations under the License.
14
+
15
+from enum import Enum
16
+import time
17
+
18
+import serial
19
+
20
+
21
+class LPC:
22
+    """Interface for LPC in-system programming"""
23
+
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
29
+        self._echo = True
30
+
31
+    def open(self):
32
+        """Open the serial port to communicate with the microcontroller"""
33
+        self._uart = serial.Serial(self.serport, baudrate=self.baudrate,
34
+                timeout=self.timeout)
35
+
36
+    def readline(self):
37
+        """Read a line terminated with '\r\n'"""
38
+        s = b""
39
+        while True:
40
+            c = self._uart.read(1)
41
+            if not c:
42
+                # If we timed out, give up
43
+                raise RecvTimeout(s)
44
+            s += c
45
+            if s.endswith(b"\r\n"):
46
+                return s
47
+
48
+    def writeline(self, line):
49
+        """Write a line to the microcontroller and read the echoed response"""
50
+        self._uart.write(line)
51
+        self._uart.flush()
52
+
53
+        if not self._echo:
54
+            return
55
+        # Read the response, raising the exception if there is one
56
+        response = self.readline()
57
+        # If we got the wrong response, raise an exception
58
+        if response != line:
59
+            raise ISPError("Wrong text echoed: {}".format(response))
60
+
61
+    def send_command_raw(self, cmd):
62
+        """Send a command to the microcontroller, returning bytes"""
63
+        self.writeline(cmd)
64
+        return self.readline()
65
+
66
+    def send_command(self, cmd):
67
+        """Send a command to the microcontroller, returning the result"""
68
+        rr = self.send_command_raw(cmd)
69
+        lr = [int(n) for n in rr.split()]
70
+        lr[0] = ReturnCode(lr[0])
71
+        return lr
72
+
73
+    def start_isp(self, delay=0.01):
74
+        """Enter ISP mode by controlling the DTR (/RST) and RTS (/ISP) lines
75
+
76
+        This operation is performed synchronously.
77
+        """
78
+        self._uart.rts = True
79
+        time.sleep(delay)
80
+        self._uart.dtr = True
81
+        time.sleep(delay)
82
+        self._uart.dtr = False
83
+        time.sleep(delay)
84
+        self._uart.rts = False
85
+
86
+    def start_comms(self, verbose=False):
87
+        """Start communication with the microcontroller"""
88
+        # Synchronize with the MCU
89
+        while True:
90
+            # Send a ?
91
+            self._uart.write(b"?")
92
+            self._uart.flush()
93
+            if verbose:
94
+                print("?")
95
+            # Receive a response
96
+            try:
97
+                s = self.readline()
98
+            except RecvTimeout:
99
+                continue
100
+            # If we got the right response, break
101
+            if s == b"Synchronized\r\n":
102
+                break
103
+        # Tell the MCU we've synchronized
104
+        s = self.send_command_raw(b"Synchronized\r\n")
105
+        # Next, it should say OK, at which point we're done synchronizing
106
+        if s != b"OK\r\n":
107
+            raise ISPError("Wrong response during synchronization")
108
+
109
+        # Send clock frequency in kHz
110
+        s = self.send_command_raw("{:d}\r\n".format(self.clock).encode("utf-8"))
111
+        # Next, it should say OK
112
+        if s != b"OK\r\n":
113
+            raise ISPError("Wrong response during synchronization")
114
+
115
+    def close(self):
116
+        """Close the serial port"""
117
+        self._uart.close()
118
+
119
+    def unlock(self, code="23130"):
120
+        """Unlock the flash write, erase, and go commands"""
121
+        return self.send_command("U {}\r\n".format(code).encode("utf-8"))
122
+
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(
126
+            "utf-8"))
127
+        # Update the baud rate and number of stop bits for our UART connection
128
+        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
137
+        return r
138
+
139
+
140
+class ReturnCode(Enum):
141
+    """LPC ISP return codes
142
+
143
+    From UM10800, section 25.6.1.16.
144
+    """
145
+    CMD_SUCCESS = 0
146
+    INVALID_COMMAND = 1
147
+    SRC_ADDR_ERROR = 2
148
+    DST_ADDR_ERROR = 3
149
+    SRC_ADDR_NOT_MAPPED = 4
150
+    DST_ADDR_NOT_MAPPED = 5
151
+    COUNT_ERROR = 6
152
+    INVALID_SECTOR = 7
153
+    SECTOR_NOT_BLANK = 8
154
+    SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION = 9
155
+    COMPARE_ERROR = 10
156
+    BUSY = 11
157
+    PARAM_ERROR = 12
158
+    ADDR_ERROR = 13
159
+    ADDR_NOT_MAPPED = 14
160
+    CMD_LOCKED = 15
161
+    INVALID_CODE = 16
162
+    INVALID_BAUD_RATE = 17
163
+    INVALID_STOP_BIT = 18
164
+    CODE_READ_PROTECTION_ENABLED = 19
165
+
166
+
167
+class ISPError(IOError):
168
+    """Generic error for ISP"""
169
+
170
+
171
+class RecvTimeout(ISPError):
172
+    """Timeout while receiving a command"""

Loading…
Cancel
Save