Skip to content

WiseEye2 Firmware Flashing Guide

Overview

This document outlines the procedure for programming a binary firmware image file into the WiseEye2 (WE2) MCU's quad-SPI flash. The process uses WE2’s in-system programming (ISP) mode via I²C, which enables the MCU to write data to its external flash. This procedure can be used on an unprogrammed or programmed WiseEye2 flash device.


Programming firmware via script

Firmware can be programmed onto the WiseEye2 by using the script cts_we2_util.py located in the src/ctsgen3 directory of the ctsgen3-x.x.x.tar.gz.

Example usage of the script alone:

poetry run python cts_we2_util.py flash-fw --bitfile=./path_to/firmware.bin

Example usage of flashing in a python script

import ctsgen3.cts_we2_util
import ft4222

deva = ft4222.openByDescription("FT4222 A")
device_A.i2cMaster_Init(ctsgen3.cts_we2_util.I2C_SPEED)
ctsgen3.cts_we2_util.slot_pb_start_programming(device_A, ctsgen3.cts_we2_util.ISP_I2C_MODE, firmware_filename)

Flash Procedure Details

This section provides more information about the procedure used in the script cts_we2_util.py. Details of each register and I2C functions used in the procedure can be found in the appendix.

ISP mode flashing uses an I²C interface on the WiseEye2 (slave ID = 0x28) to program the quad-SPI system flash connected to the device.

1. Initialize I²C Communication

  • The FT4222 is initialized as I²C master (maximum 1000 kbps).
  • Device with description "FT4222 A" is opened.

2. Enable ISP Test Mode

Enable ISP test mode via register ISP_ENABLE_REG_ADDR (0xD8) using function I2C_burst_write.

I2C_burst_write(
    ft4222_dev,
    ISP_CONTROL_I2C_SLVID,          # 0x28
    [ISP_ENABLE_REG_ADDR],          # [0xD8]
    [REG_D8_TEST_MODE]              # [0x02]
)

3. Read Clock Configuration

Read 32-bit value from ISP register ISP_SRC_PERI_CLK_CTRL (0x51010020) using the function i2c_single_read. Bits 12-15 determine the clock source (PLL, RC24, XTAL, etc.) and appropriate sclk/clkdiv values for the ISP settings.

ISP_SRC_PERI_CLK_CTRL[15:12] Clock Source sclk clkdiv
0x0 RC24 1 0
0xC PLL 0 10
0x4 RC9648 0 0
All other cases XTAL24 1 0

4. Disable ISP Test Mode

Restore ISP_ENABLE_REG_ADDR (0xD8) to 0x00 using function I2C_burst_write.

5. Construct and Send ispsetting Word

Build the 32-bit configuration word based on the clock settings from step 3. Typical setting values are shown below along with building the 32-bit ispsetting word.

crc_en     = 1
dummycycle = 0
endian     = 1
erasemode  = 0
ercmdset   = 0x20
ercmdseten = 0
fastread   = 0
flashtype  = 1
pp4en      = 1
ppen       = 1
qread      = 1

ispsetting = (
    0x01
    | (crc_en     << 1)
    | (sclk       << 2)
    | (ppen       << 3)
    | (erasemode  << 4)
    | (ercmdseten << 6)
    | (pp4en      << 7)
    | (ercmdset   << 8)
    | (clkdiv     << 16)
    | (qread      << 19)
    | (fastread   << 20)
    | (dummycycle << 21)
    | (flashtype  << 23)
    | (endian     << 25)
)

Write the ispsetting word to register ISP_CONTROL_ADDR (0x51010000) using the function i2c_single_write.


6. Enable ISP Mode

Enable ISP mode via register ISP_ENABLE_REG_ADDR (0xD8) using function I2C_burst_write.

I2C_burst_write(
    ft4222_dev,
    ISP_CONTROL_I2C_SLVID,          # 0x28
    [ISP_ENABLE_REG_ADDR],          # [0xD8]
    [REG_D8_ISP_EN]                 # [0x01]
)

7. Write Firmware in 256-Byte Blocks

  • Build a packet with a header of [0xFA] followed by a 4-byte address (starting at address ISP_MEM_OUT_ADDR (0x38000000))
  • Append 256 bytes of data from the bit-file to the packet.
  • Write the raw packet to the slave (no special I2C function is used).
  • Read the register ISP_PPDONE_COUNTER using the function i2c_single_read.
    • Verify the count value mask matches the current loop count.
    • Check CRC error bits. Assert an error if CRC fail is detected.
  • Repeat this procedure for the entire bit-file, incrementing the address and data slice accordingly.

8. Exit ISP Mode

Restore ISP_ENABLE_REG_ADDR (0xD8) to 0x00 using function I2C_burst_write.

9. Hard Reset

Execute a hard reset of the MCU to load the new firmware image from flash.

Appendix

ISP Enable Register

The ISP enable register 0xD8 is used at various times throughout the procedure. The bit definitions are below:

  • Register Address: 0xD8
Bit Position Mask Name Description
0 0x01 REG_D8_ISP_EN ISP enable: allows ISP commands to program/erase flash
1 0x02 REG_D8_TEST_MODE SCU test mode: unlocks SCU registers (e.g. clock config)
2 0x04 REG_D8_SPI_DO_EN SPI Data-Output enable: routes flash I/O over SPI DO pin
3–7 Reserved

ISP Control Register Map

Register Name Address Mask Description
ISP_CONTROL_ADDR 0x51010000 0x03FFFFFF ISP control address
0x00000001 Reserved
0x00000002 Enable CRC checks
0x00000004 Select clock source (sclk)
0x00000008 Enable page-program count
0x00000030 Erase mode: 0:sector, 1:32k, 2:64k, 3:chip
0x00000040 Erase command set enable
0x00000080 Enable 4-page program mode
0x0000FF00 Erase-command set value
0x00070000 Clock divider value
0x00080000 Enable quad-read
0x00100000 Enable fast-read
0x00E00000 dummy cycles - 0:8, 1:6, 2:8, 3:10
0x01800000 0:MXIC, 1:WINBOND
0x02000000 Data endianness (0:little, 1:big)
CRC_WOUT_ADDR 0x51010004 0xFFFFFFFF CRC write-out address pointer
CRC_ROUT_ADDR 0x51010008 0xFFFFFFFF CRC read-out address pointer
ISP_SRC_PERI_CLK_CTRL 0x51010020 0xFFFFFFFF ISP peripheral clock control
ISP_STATUS_CLR 0x51010030 0xFFFFFFFF Write-1-to-clear ISP/CRC status bits
ISP_PPDONE_COUNTER 0x51010040 0x300FFFFF Page-program done
0x000FFFFF Page-program done count
0x10000000 CRC error flag 0
0x20000000 CRC error flag 1
ISP_PPDONE 0x51010050 0xFFFFFFFF Page-program done/diagnostic conflict status

I²C Functions Overview

Summary Table (Cheat Sheet)

Function Input Address Type Data Width Use Case
I2C_burst_write 8-bit N × 8-bit Single/multiple register write
I2C_burst_read 8-bit N × 8-bit Sequential register read
i2c_single_write 32-bit 32-bit ISP config, control registers
i2c_single_read 32-bit 32-bit Clock source, CRC, status registers

I2C_burst_write(dev, slave_id, addr_list, data_list)

Purpose: Write one or more bytes to consecutive (or mapped) 8-bit I²C addresses.

Example:

I2C_burst_write(dev, 0x28, [0xD8], [0x02])
# → Writes 0x02 to address 0xD8 on slave 0x28.

Internals:

  • Concatenates the address and data bytes
  • Sends them together as one I²C write packet

I2C_burst_read(dev, slave_id, addr, size)

Purpose:
Reads a block of size bytes starting from the specified 8-bit address.

Example:

val = I2C_burst_read(dev, 0x28, [0xD8], 4)
# → Reads 4 bytes starting at address 0xD8.

Internals:

  • Issue an address‐phase write (START)
  • Perform a repeated start followed by a read

i2c_single_write(dev, slave_id, addr[4], data[4])

Purpose:
Write a 4-byte value to a 4-byte register address over I²C.

Transactions:

  • 8 × 2-byte writes + 1 × 2-byte ack.
  • Poll for completion.

Example:

i2c_single_write(
    dev,
    0x28,
    [0x00, 0x00, 0x10, 0x51],
    [0x12, 0x34, 0x56, 0x78]
)

Procedure:

Address and data are written in two byte chunks with each write consisting of an index byte and data byte.

Two-Byte Write Chunks

Order Index Byte Data Byte Description
1 0x00 A0 Address byte 0 (LSB)
2 0x01 A1 Address byte 1
3 0x02 A2 Address byte 2
4 0x03 A3 Address byte 3 (MSB)
5 0x04 D0 Data byte 0 (LSB)
6 0x05 D1 Data byte 1
7 0x06 D2 Data byte 2
8 0x07 D3 Data byte 3 (MSB)
9 0x0C 0x01 Write-ack command

Poll for Completion

  • Repeatedly write 0x0F
  • Then read 1-byte response:
    • 0x00 = write complete
    • Others = still busy
  • If 0x00 received within timeout, write succeeded

i2c_single_read(dev, slave_id, addr[4])

Purpose:
Read a 4-byte value from a 4-byte register address.

Transactions:

  • 4 × 2-byte writes + 1 × 2-byte ack
  • Poll for completion
  • 4 × 2-byte reads.

Example:

val = i2c_single_read(
    dev,
    0x28,
    [0x20, 0x00, 0x10, 0x51]
)

Procedure:

Two-Byte Write Chunks

Order Index Byte Data Byte Description
1 0x00 A0 Address byte 0 (LSB)
2 0x01 A1 Address byte 1
3 0x02 A2 Address byte 2
4 0x03 A3 Address byte 3 (MSB)

Read-Acknowledge Packet

Order Index Byte Data Byte Description
5 0x0C 0x00 Read-ack command

Poll for Completion
- Same as in i2c_single_write

Read Result (One Byte at a Time)

Step Operation Value Description
7 WRITE 0x08 Index byte 0
8 READ D0 Read byte 0
9 WRITE 0x09 Index byte 1
10 READ D1 Read byte 1
11 WRITE 0x0A Index byte 2
12 READ D2 Read byte 2
13 WRITE 0x0B Index byte 3
14 READ D3 Read byte 3
result = D0 + (D1 << 8) + (D2 << 16) + (D3 << 24)