123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- # Copyright 2017 Clayton G. Hobbs
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
-
- from enum import Enum
- import time
-
- import serial
-
-
- class LPC:
- """Interface for LPC in-system programming"""
-
- def __init__(self, serport, baudrate=115200, clock=12000, timeout=0.1):
- self.serport = serport
- self.baudrate = baudrate
- self.clock = clock
- self.timeout = timeout
- self._echo = True
-
- def open(self):
- """Open the serial port to communicate with the microcontroller"""
- self._uart = serial.Serial(self.serport, baudrate=self.baudrate,
- timeout=self.timeout)
-
- def readline(self):
- """Read a line terminated with '\r\n'"""
- s = b""
- while True:
- c = self._uart.read(1)
- if not c:
- # If we timed out, give up
- raise RecvTimeout(s)
- s += c
- if s.endswith(b"\r\n"):
- return s
-
- def writeline(self, line):
- """Write a line to the microcontroller and read the echoed response"""
- self._uart.write(line)
- self._uart.flush()
-
- if not self._echo:
- return
- # Read the response, raising the exception if there is one
- response = self.readline()
- # If we got the wrong response, raise an exception
- if response != line:
- raise ISPError("Wrong text echoed: {}".format(response))
-
- def send_command_raw(self, cmd):
- """Send a command to the microcontroller, returning bytes"""
- self.writeline(cmd)
- return self.readline()
-
- def send_command(self, cmd):
- """Send a command to the microcontroller, returning the result"""
- rr = self.send_command_raw(cmd)
- lr = [int(n) for n in rr.split()]
- lr[0] = ReturnCode(lr[0])
- return lr
-
- def start_isp(self, delay=0.01):
- """Enter ISP mode by controlling the DTR (/RST) and RTS (/ISP) lines
-
- This operation is performed synchronously.
- """
- self._uart.rts = True
- time.sleep(delay)
- self._uart.dtr = True
- time.sleep(delay)
- self._uart.dtr = False
- time.sleep(delay)
- self._uart.rts = False
-
- def start_comms(self, verbose=False):
- """Start communication with the microcontroller"""
- # Synchronize with the MCU
- while True:
- # Send a ?
- self._uart.write(b"?")
- self._uart.flush()
- if verbose:
- print("?")
- # Receive a response
- try:
- s = self.readline()
- except RecvTimeout:
- continue
- # If we got the right response, break
- if s == b"Synchronized\r\n":
- break
- # Tell the MCU we've synchronized
- s = self.send_command_raw(b"Synchronized\r\n")
- # Next, it should say OK, at which point we're done synchronizing
- if s != b"OK\r\n":
- raise ISPError("Wrong response during synchronization")
-
- # Send clock frequency in kHz
- s = self.send_command_raw("{:d}\r\n".format(self.clock).encode("utf-8"))
- # Next, it should say OK
- if s != b"OK\r\n":
- raise ISPError("Wrong response during synchronization")
-
- def close(self):
- """Close the serial port"""
- self._uart.close()
-
- def unlock(self, code="23130"):
- """Unlock the flash write, erase, and go commands"""
- return self.send_command("U {}\r\n".format(code).encode("utf-8"))
-
- def setbaudrate(self, baudrate, stopbits):
- """Update the baud rate and number of stop bits"""
- r = self.send_command("B {} {}\r\n".format(baudrate, stopbits).encode(
- "utf-8"))
- # Update the baud rate and number of stop bits for our UART connection
- if r[0] == ReturnCode.CMD_SUCCESS:
- self._uart.baudrate = baudrate
- self._uart.stopbits = stopbits
- return r
-
- def echo(self, setting):
- """Set whether echo is enabled or disabled"""
- r = self.send_command("A {}\r\n".format(int(setting)).encode("utf-8"))
- self._echo = setting
- return r
-
-
- class ReturnCode(Enum):
- """LPC ISP return codes
-
- From UM10800, section 25.6.1.16.
- """
- CMD_SUCCESS = 0
- INVALID_COMMAND = 1
- SRC_ADDR_ERROR = 2
- DST_ADDR_ERROR = 3
- SRC_ADDR_NOT_MAPPED = 4
- DST_ADDR_NOT_MAPPED = 5
- COUNT_ERROR = 6
- INVALID_SECTOR = 7
- SECTOR_NOT_BLANK = 8
- SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION = 9
- COMPARE_ERROR = 10
- BUSY = 11
- PARAM_ERROR = 12
- ADDR_ERROR = 13
- ADDR_NOT_MAPPED = 14
- CMD_LOCKED = 15
- INVALID_CODE = 16
- INVALID_BAUD_RATE = 17
- INVALID_STOP_BIT = 18
- CODE_READ_PROTECTION_ENABLED = 19
-
-
- class ISPError(IOError):
- """Generic error for ISP"""
-
-
- class RecvTimeout(ISPError):
- """Timeout while receiving a command"""
|