Difference between revisions of "Stm32loader"

From emboxit
Jump to: navigation, search
 
m (1 revision)
 
(No difference)

Latest revision as of 07:41, 26 August 2017

<issues project="Stm32loader" search="false" filter="false" />


MODIFIED BY US

  • Tested and worked on VAS_DISP_CALL project
  • NiXal updates(2010) to original script for using DTR and RTS to control RESET and BOOT0
  • Prints the "Modified by us" banner
  • The most active repo today (01.2016) seems to be: jsnyder/stm32loader


Raspberry Pi

Free UART pins from OS

  • First make a backup of the file containing kernel parameters cmdline.txt as cmdline_bp.txt
sudo cp /boot/cmdline.txt /boot/cmdline_bp.txt
  • Edit the file cmdline.txt by removing the parameters containing ‘ttyAMA0‘. ie. ‘console=ttyAMA0,115200’ and ‘kgdboc=ttyAMA0,115200’
sudo nano /boot/cmdline.txt
  • The remaining file looks like,
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p6 rootfstype=ext4 elevator=deadline rootwait
  • Now edit inittab, file containing serial console data
sudo nano /etc/inittab
  • Comment out the line ‘2:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100’
#2:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100
  • Reboot Raspberry Pi
sudo reboot
  • Short the Rx and Tx pins on Pi (GPIO 14 and 15), such that it will receive the same data as it transmits.
  • Install minicom
sudo apt-get install minicom
  • And launching it
minicom -b 115200 -o -D /dev/ttyAMA0
  • Verify whether the pi is receiving the same data as it transmits
  • Install pySerial
sudo apt-get install python-serial
  • Test with a small python script

<python>

  1. Nikos tested with oscilloscope

import serial ser = serial.Serial ("/dev/ttyAMA0") #Open named port ser.baudrate = 9600 #Set baud rate to 9600

  1. data = ser.read(10) #Read ten characters from serial port to data

data = "1234567890" ser.write(data) #Send back the received data ser.close() </python>



  • TEST.CMD
stm32loader.py -e -w -v -z -p com1 -b 38400 -l 32000 VAS_DISP_CALL.bin

Stm32loader-console.JPG


  • stm32loader.py

<python>

  1. !/usr/bin/env python
  1. -*- coding: utf-8 -*-
  2. vim: sw=4:ts=4:si:et:enc=utf-8
  1. Author: Ivan A-R <ivan@tuxotronic.org>
  2. Project page: http://tuxotronic.org/wiki/projects/stm32loader
  3. This file is part of stm32loader.
  4. stm32loader is free software; you can redistribute it and/or modify it under
  5. the terms of the GNU General Public License as published by the Free
  6. Software Foundation; either version 3, or (at your option) any later
  7. version.
  8. stm32loader is distributed in the hope that it will be useful, but WITHOUT ANY
  9. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  11. for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with stm32loader; see the file COPYING3. If not see
  14. <http://www.gnu.org/licenses/>.

import sys, getopt import serial import time import Tkinter

try:

   from progressbar import *
   usepbar = 1

except:

   usepbar = 0
  1. Verbose level

QUIET = 1

def mdebug(level, message):

   if(QUIET >= level):
       print >> sys.stderr , message


class CmdException(Exception):

   pass

class CommandInterface:

   def open(self, aport='/dev/tty.usbserial-ftCYPMYJ', abaudrate=115200) :
       self.sp = serial.Serial(
           port=aport,
           baudrate=abaudrate, # baudrate
           bytesize=8, # number of databits
           parity=serial.PARITY_EVEN,
           stopbits=1,
           xonxoff=0, # enable software flow control
           rtscts=0, # disable RTS/CTS flow control
           timeout=5 # set a timeout value, None for waiting forever
       )


   def _wait_for_ask(self, info = ""):
       # wait for ask
       try:
           ask = ord(self.sp.read())
       except:
           raise CmdException("Can't read port or timeout")
       else:
           if ask == 0x79:
               # ACK
               return 1
           else:
               if ask == 0x1F:
                   # NACK
                   raise CmdException("NACK "+info)
               else:
                   # Unknow responce
                   raise CmdException("Unknow response. "+info+": "+hex(ask))


   def reset(self):
       self.sp.setDTR(1)
       time.sleep(0.1)
       self.sp.setDTR(0)
       time.sleep(0.5)
   def initChip(self):
       # Set boot
       self.sp.setRTS(1)
       self.reset()
       self.sp.write("\x7F") # Syncro
       return self._wait_for_ask("Syncro")
   def releaseChip(self):
       self.sp.setRTS(0)
       self.reset()
   def cmdGeneric(self, cmd):
       self.sp.write(chr(cmd))
       self.sp.write(chr(cmd ^ 0xFF)) # Control byte
       return self._wait_for_ask(hex(cmd))
   def cmdGet(self):
       if self.cmdGeneric(0x00):
           mdebug(10, "*** Get command");
           len = ord(self.sp.read())
           version = ord(self.sp.read())
           mdebug(10, " Bootloader version: "+hex(version))
           dat = map(lambda c: hex(ord(c)), self.sp.read(len))
           mdebug(10, " Available commands: "+str(dat))
           self._wait_for_ask("0x00 end")
           return version
       else:
           raise CmdException("Get (0x00) failed")
   def cmdGetVersion(self):
       if self.cmdGeneric(0x01):
           mdebug(10, "*** GetVersion command")
           version = ord(self.sp.read())
           self.sp.read(2)
           self._wait_for_ask("0x01 end")
           mdebug(10, " Bootloader version: "+hex(version))
           return version
       else:
           raise CmdException("GetVersion (0x01) failed")
   def cmdGetID(self):
       if self.cmdGeneric(0x02):
           mdebug(10, "*** GetID command")
           len = ord(self.sp.read())
           id = self.sp.read(len+1)
           self._wait_for_ask("0x02 end")
           return id
       else:
           raise CmdException("GetID (0x02) failed")


   def _encode_addr(self, addr):
       byte3 = (addr >> 0) & 0xFF
       byte2 = (addr >> 8) & 0xFF
       byte1 = (addr >> 16) & 0xFF
       byte0 = (addr >> 24) & 0xFF
       crc = byte0 ^ byte1 ^ byte2 ^ byte3
       return (chr(byte0) + chr(byte1) + chr(byte2) + chr(byte3) + chr(crc))


   def cmdReadMemory(self, addr, lng):
       assert(lng <= 256)
       if self.cmdGeneric(0x11):
           mdebug(10, "*** ReadMemory command")
           self.sp.write(self._encode_addr(addr))
           self._wait_for_ask("0x11 address failed")
           N = (lng - 1) & 0xFF
           crc = N ^ 0xFF
           self.sp.write(chr(N) + chr(crc))
           self._wait_for_ask("0x11 length failed")
           return map(lambda c: ord(c), self.sp.read(lng))
       else:
           raise CmdException("ReadMemory (0x11) failed")


   def cmdGo(self, addr):
       if self.cmdGeneric(0x21):
           mdebug(10, "*** Go command")
           self.sp.write(self._encode_addr(addr))
           self._wait_for_ask("0x21 go failed")
       else:
           raise CmdException("Go (0x21) failed")


   def cmdWriteMemory(self, addr, data):
       assert(len(data) <= 256)
       if self.cmdGeneric(0x31):
           mdebug(10, "*** Write memory command")
           self.sp.write(self._encode_addr(addr))
           self._wait_for_ask("0x31 address failed")
           #map(lambda c: hex(ord(c)), data)
           lng = (len(data)-1) & 0xFF
           mdebug(10, " %s bytes to write" % [lng+1]);
           self.sp.write(chr(lng)) # len really
           crc = 0xFF
           for c in data:
               crc = crc ^ c
               self.sp.write(chr(c))
           self.sp.write(chr(crc))
           self._wait_for_ask("0x31 programming failed")
           mdebug(10, " Write memory done")
       else:
           raise CmdException("Write memory (0x31) failed")


   def cmdEraseMemory(self, sectors = None):
       if self.cmdGeneric(0x43):
           mdebug(10, "*** Erase memory command")
           if sectors is None:
               # Global erase
               self.sp.write(chr(0xFF))
               self.sp.write(chr(0x00))
           else:
               # Sectors erase
               self.sp.write(chr((len(sectors)-1) & 0xFF))
               crc = 0xFF
               for c in sectors:
                   crc = crc ^ c
                   self.sp.write(chr(c))
               self.sp.write(chr(crc))
           self._wait_for_ask("0x43 erasing failed")
           mdebug(10, " Erase memory done")
       else:
           raise CmdException("Erase memory (0x43) failed")
   def cmdWriteProtect(self, sectors):
       if self.cmdGeneric(0x63):
           mdebug(10, "*** Write protect command")
           self.sp.write(chr((len(sectors)-1) & 0xFF))
           crc = 0xFF
           for c in sectors:
               crc = crc ^ c
               self.sp.write(chr(c))
           self.sp.write(chr(crc))
           self._wait_for_ask("0x63 write protect failed")
           mdebug(10, " Write protect done")
       else:
           raise CmdException("Write Protect memory (0x63) failed")
   def cmdWriteUnprotect(self):
       if self.cmdGeneric(0x73):
           mdebug(10, "*** Write Unprotect command")
           self._wait_for_ask("0x73 write unprotect failed")
           self._wait_for_ask("0x73 write unprotect 2 failed")
           mdebug(10, " Write Unprotect done")
       else:
           raise CmdException("Write Unprotect (0x73) failed")
   def cmdReadoutProtect(self):
       if self.cmdGeneric(0x82):
           mdebug(10, "*** Readout protect command")
           self._wait_for_ask("0x82 readout protect failed")
           self._wait_for_ask("0x82 readout protect 2 failed")
           mdebug(10, " Read protect done")
       else:
           raise CmdException("Readout protect (0x82) failed")
   def cmdReadoutUnprotect(self):
       if self.cmdGeneric(0x92):
           mdebug(10, "*** Readout Unprotect command")
           self._wait_for_ask("0x92 readout unprotect failed")
           self._wait_for_ask("0x92 readout unprotect 2 failed")
           mdebug(10, " Read Unprotect done")
       else:
           raise CmdException("Readout unprotect (0x92) failed")


  1. Complex commands section
   def readMemory(self, addr, lng):
       data = []
       if usepbar:
           widgets = ['Reading: ', Percentage(),', ', ETA(), ' ', Bar()]
           pbar = ProgressBar(widgets=widgets,maxval=lng, term_width=79).start()
       
       while lng > 256:
           if usepbar:
               pbar.update(pbar.maxval-lng)
           else:
               mdebug(5, "Read %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
           data = data + self.cmdReadMemory(addr, 256)
           addr = addr + 256
           lng = lng - 256
       if usepbar:
           pbar.update(pbar.maxval-lng)
           pbar.finish()
       else:
           mdebug(5, "Read %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
       data = data + self.cmdReadMemory(addr, lng)
       return data
   def writeMemory(self, addr, data):
       lng = len(data)
       if usepbar:
           widgets = ['Writing: ', Percentage(),' ', ETA(), ' ', Bar()]
           pbar = ProgressBar(widgets=widgets, maxval=lng, term_width=79).start()
       
       offs = 0
       while lng > 256:
           if usepbar:
               pbar.update(pbar.maxval-lng)
           else:
               mdebug(5, "Write %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
           self.cmdWriteMemory(addr, data[offs:offs+256])
           offs = offs + 256
           addr = addr + 256
           lng = lng - 256
       if usepbar:
           pbar.update(pbar.maxval-lng)
           pbar.finish()
       else:
           mdebug(5, "Write %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
       self.cmdWriteMemory(addr, data[offs:offs+lng] + ([0xFF] * (256-lng)) )



def __init__(self) :

       pass


def usage():

   print """Usage: %s [-hqVewvr] [-l length] [-p port] [-b baud] [-a addr] [file.bin]

-h This help -q Quiet -V Verbose -e Erase -w Write -v Verify -r Read -l length Length of read -p port Serial port (default: /dev/tty.usbserial-ftCYPMYJ) -b baud Baud speed (default: 115200) -a addr Target address

./stm32loader.py -e -w -v example/main.bin

""" % sys.argv[0]


if __name__ == "__main__":

   # Import Psyco if available
   try:
       import psyco
       psyco.full()
       print "Using Psyco..."
   except ImportError:
       pass
   conf = {
           'port': '/dev/tty.usbserial-ftCYPMYJ',
           'baud': 115200,
           'address': 0x08000000,
           'erase': 0,
           'write': 0,
           'verify': 0,
           'read': 0,
       }
  1. http://www.python.org/doc/2.5.2/lib/module-getopt.html
   try:
       opts, args = getopt.getopt(sys.argv[1:], "hqVzewvrp:b:a:l:")
   except getopt.GetoptError, err:
       # print help information and exit:
       print str(err) # will print something like "option -a not recognized"
       usage()
       sys.exit(2)
   QUIET = 5
   for o, a in opts:
       if o == '-V':
           QUIET = 10
       elif o == '-z':
           conf['protect'] = 1			
       elif o == '-q':
           QUIET = 0
       elif o == '-h':
           usage()
           sys.exit(0)
       elif o == '-e':
           conf['erase'] = 1
       elif o == '-w':
           conf['write'] = 1
       elif o == '-v':
           conf['verify'] = 1
       elif o == '-r':
           conf['read'] = 1
       elif o == '-p':
           conf['port'] = a
       elif o == '-b':
           conf['baud'] = eval(a)
       elif o == '-a':
           conf['address'] = eval(a)
       elif o == '-l':
           conf['len'] = eval(a)			
       else:
           assert False, "unhandled option"
   cmd = CommandInterface()
   cmd.open(conf['port'], conf['baud'])
   mdebug(10, "Open port %(port)s, baud %(baud)d" % {'port':conf['port'], 'baud':conf['baud']})
   try:
       try:
           cmd.initChip()
       except:
           print "Can't init. Ensure that BOOT0 is enabled and reset device"


       bootversion = cmd.cmdGet()

mdebug(0, "" ) mdebug(0, "-- Modified by us --" )

       mdebug(0, "Bootloader version %X" % bootversion)
       mdebug(0, "Chip id `%s'" % str(map(lambda c: hex(ord(c)), cmd.cmdGetID())))
  1. cmd.cmdGetVersion()
  2. cmd.cmdGetID()
  3. cmd.cmdReadoutUnprotect()
  4. cmd.cmdWriteUnprotect()
  5. cmd.cmdWriteProtect([0, 1])
       if (conf['write'] or conf['verify']):

# nikos added intelhex library # intelhex test below success! # from intelhex import IntelHex # h = IntelHex() # h.loadbin(args[0]) # nikos load binary file # print h[0] # print h[1] # print h[2] # print h[3] # print h[4] # print h[100] # h.dump() # print h.minaddr() # print h.maxaddr() # h.tobinfile("foo.bin") # nikos dump looks ok, maxaddress looks correct # nikos foo.bin is exact copy of input file # # nikos debug info printed mdebug(0, "-------------------reading data... " ) mdebug(0, "-------------------from file `%s'" % args[0])

           # data = map(lambda c: ord(c), file(args[0]).read())

data = map(lambda c: ord(c), file(args[0], 'rb').read()) mdebug(0, "-------------------length = %X" % len(data)) # nikos len(data)is wrong # I dont know if data is also wrong

       if conf['erase']:
           cmd.cmdEraseMemory()
       if conf['write']:
           cmd.writeMemory(conf['address'], data)
       if conf['protect']:
           cmd.cmdWriteProtect([0, 1])
       if conf['verify']:
           verify = cmd.readMemory(conf['address'], len(data))
           if(data == verify):
               print "Verification OK"
           else:
               print "Verification FAILED"
               print str(len(data)) + ' vs ' + str(len(verify))
               for i in xrange(0, len(data)):
                   if data[i] != verify[i]:
                       print hex(i) + ': ' + hex(data[i]) + ' vs ' + hex(verify[i])
       if not conf['write'] and conf['read']:

rdata = cmd.readMemory(conf['address'], conf['len'])

           file(args[0], 'wb').write(rdata)
           file(args[0], 'wb').write(.join(map(chr,rdata)))
  1. cmd.cmdGo(addr + 0x04)
   finally:
       cmd.releaseChip()

</python>