A Python script for programming Zilog MCUs – Z8F2480

Intro

Zilog may be a rather obscure MCU manufacturer nowadays, but for the ones who uses its MCUs, the script described here and published on GitHub may be useful.

This is a Python script developed to program Zilog MCUs through the COM port (RS232 or emulated with an USB-UART converter). It was specifically developed in order to be able program Z8F2480 MCUs through a COM port.

Z8F2480_bd_1319059115

The Z8F2480 is a 8-bit MCU with a nice set of features, including 24 kB Flash, internal oscillator (dispensing the use of crystal oscillators), SPI, I2C, ADC, an on-chip low power OpAmp and two integrated analog comparators.

For some unknown (and to me uncomprehensible) reason, Zilog decided to drop out support for the Serial Smart Cable in its Z8F2480/1680/0880 MCU line. In order to use them, the first option was to buy the rather expensive USB Smart Cable. An anachronism nowadays, in a world full of manufacturer-subsized development kits and tools.

So, I decided to find another way. The OCD (On-Chip Debugger) commands used during programming and debug are detailed described in the datasheet. Also, an application note by Zilog put some more light on how to develop a programmer. All the information available pointed out that it was possible to program the MCUs through a COM port. After spending some time, scratching my head a lot to develop and debug, the script was complete.

OCD interface

The hardware needed is a Serial Smart Cable or a DIY equivalent, which can be easily assembled. As it is stated on the datasheets, the minimum hardware is only composed of  a RS232 transceiver (or an USB-UART transceiver), a diode and a pull-up resistor.

Description

The script is divided in four parts:

  • programmer.py – the main application code.
  • intelhex2bin.py – converts a hex file to binary data.
  • crc_calc.py – calculates the CRC based on the algorithm used by Zilog (CCITT algorithm, input reflected, output reflected and output XOR’ed with 0xFFFF).
  • zilog_ocd.py – library of functions implementing OCD commands.

The main application input arguments are:

  • Firmware to be downloaded, as a hex file
  • COM port
  • MCU

For example, in order to program a Z8F2480 with firmware.hex through the COM1, the input arguments are:

python programmer.py firmware.hex COM1 Z8F2480

The execution sequence is:

  • Convert hex file to binary data
  • Open COM port
  • Enter debug mode: at this point, with the programmer attached to the MCU, the user is required to reset the MCU, either by pressing a reset button or power cycling the target board.
  • Read OCD revision
  • Check if MCU is in debug mode
  • Set Flash Programming Frequency registers
  • Mass erase Flash
  • Download code to Flash
  • Read Flash CRC and compare it with source CRC
  • If CRC is different, the all the Flash memory data is read back to the computer (Warning: this operation takes several minutes)

Zilog programmer

The project is published on my GitHub.

Requirements

  • Firmware in an Intel Hex file format – the ZDS must be configured to generate Intel Hex32 files (Project -> Settings -> Linker -> Output -> Executable formats).
  • Hardware – Serial Smart Cable or equivalent.
  • Python 3

Future improvements

This code is useful to me, but may be improved in some ways.

First, I have had problems reading Flash memory data back to the computer. Although the OCD command specifies that up to 65535 bytes may be read at once, in reality I was able to reliably read only 2 bytes at a time. So, the Flash read back operation is very slow and may take several minutes. After some hours spent debugging and not being able to correct this, I decided to look for alternatives and perform a CRC check to validate the memory integrity. The Flash read back is still executed, but only if the CRC check returns an error.

Second, it is being used only with Z8F2480 and Z8F082A MCUs. If you wish to use it with other Zilog MCUs, the could should be modified. The mods needed are easy: only change get_mcu_flash_size() and get_mcu_clock() functions to comply with the new MCU specifications.

Another interesting feature to add is a graphical interface, maybe built with the Qt framework.