Documentation for “Zerocat Chipflasher” as of Wed, 24 Jun 2026 07:28:14 +0200
Repository: git://zerocat.org/zerocat/projects/chipflasher.git
Version: v3.0.0-0-b445ef922
Branch: master

pcb.spin.nointerface.html

{{

______________________________________________________________________________
********************************************************* File starts here ***
Zerocat Chipflasher --- Flash free firmware, kick the Management Engine.

Copyright (C) 2020, 2021, 2022, 2024, 2025, 2026  Kai Mertens 

File pcb.spin --- Check PCB features.

This file is part of the Zerocat Chipflasher.

See end of file for terms of use.

******************************************************************************
}}



''
''
''# Included Compiler Configuration
# ifndef __PCB_SPIN_CFG__
#   include "./pcb.spin.cfg"
# endif



''
''
''# Object Summary
OBJ     'This directive triggers the compiler to insert a summary.



''
''
''# Loaded Objects
                                              ''
        time           : "time"               ''* time object



''
''
''# Included Files



''
''
''# Constants
CON
        ''


        ''## Sections in respect to PCB version
        ''
        ''* PCBv2.1, PCBv2.2
        ''* PCBv2.0
        ''* PCBv2
        ''* PCBv1.1
        ''* PCBv1.0
        ''* PCBv1
        ''* Common
        ''
        ''The PCB version is detected during runtime, that is why this object should
        ''set RAM locations to appropriate values:
        ''
        ''* RAM_PCB_VERSION
        ''* RAM_RST_INIHIBIT
        ''* RAM_ISMON_VSPI
        ''* RAM_ISMON_RPULL
        ''* RAM_ISMON_RST
        ''* RAM_MASK_CEn_AVAIL


        ''
        ''## PCBv2.1, PCBv2.2
        ''

        ''* SPI_CEn1_PCBv2_1      -- Second Enable Pin, active low
        SPI_CEn1_PCBv2_1        = 1

        ''* SPI_RPULL             -- Used to load C_pull and to read R_pull value
        SPI_RPULL               = 0

        ''* Hardcoded RC decay values for C_pull = 22nF, R_pull = 83..570 Ohm
        RPULL_MIN               = 83
        RPULL_MAX               = 570
        'RPULL_MIN_22nF          = 1133
        'RPULL_MAX_22nF          = 1975
        'RPULL_MIN_22nF_X7R      = 1122      'raw values range between 1119..1125
        'RPULL_MAX_22nF_X7R      = 1807      'raw values range between 1794..1819
        'RPULL_MIN_22nF_X7R_3    = 3366      'raw values range between 3362..3370
        'RPULL_MAX_22nF_X7R_3    = 5423      'raw values range between 5414..5432
        RPULL_MIN_22nF_X7R_10   = 11221     'raw values range between 11216..11226
        RPULL_MAX_22nF_X7R_10   = 18055     'raw values range between 18031..18098


        ''
        ''## PCBv2.0
        ''

        ''* SPI_CEn1_PCBv2_0      -- Second Enable Pin, active low
        SPI_CEn1_PCBv2_0        = 0


        ''
        ''## PCBv2
        ''

        ''* RS232_RST             -- Sense RST input from host
        ''* RST_INHIBIT           -- Inhibit signal pin on board v2 for net RS232_RST
        ''* ADC_OUT               -- Sigma-delta ADC circuit, counter output
        ''* ADC_CALIBRATION       -- Sigma-delta ADC circuit, calibration pin, providing 0V/3.3V, tri-state when idle
        ''* ADC_IN                -- Sigma-delta ADC circuit, counter input
        ''
        RS232_RST               = 24
        RST_INHIBIT             = 11
        ADC_OUT                 = 27
        ADC_CALIBRATION         = 26
        ADC_IN                  = 25

        ''* DIP Switch 1: RS232 Baudrate
        ''
        ''    open = H, closed = L
        ''
        ''    RS232 Baudrate  |  SWDIP_1
        ''    ----------------|-----------
        ''             57600  |        H
        ''            115200  |        L
        ''
        SWDIP_1                 = 18

        ''* DIP Switch 2: SPI Power-up Type
        ''
        ''    open = H, closed = L
        ''
        ''    Power-up Type   |  SWDIP_2
        ''    ----------------|-----------
        ''        one shot    |        H
        ''        pulses      |        L
        ''
        SWDIP_2                 = 19

        ''* DIP Switch 3: SPI Power-off Type
        ''
        ''    open = H, closed = L
        ''
        ''    Power-off Type  |  SWDIP_3
        ''    ----------------|-----------
        ''             auto   |        H
        ''             user   |        L
        ''
        SWDIP_3                 = 20

        ''* DIP Switch 4: SPI Mode
        ''
        ''    open = H, closed = L
        ''
        ''    SPI Mode  |  SWDIP_4
        ''    ----------|-----------
        ''           0  |        H
        ''           3  |        L
        ''
        SWDIP_4                 = 21

        ''* DIP Switches 5..6: SPI Clock Driver
        ''
        ''    open = H, closed = L
        ''
        ''    SPI Clock Driver  |  SWDIP_5  |  SWDIP_6
        ''    ------------------|-----------|-----------
        ''                 25%  |        H  |        H
        ''                 50%  |        L  |        H
        ''                 75%  |        H  |        L
        ''                100%  |        L  |        L
        ''
        SWDIP_5                 = 22
        SWDIP_6                 = 23


        ''
        ''## PCBv1.1
        ''
        SPI_CABLEn_PCBv1_1      = 9               'This pin is used to detect the SPI cable since board-v1.1.0


        ''
        ''## PCBv1.0
        ''
        SPI_CABLEn_PCBv1_0      = 10              'This pin is used to detect the SPI cable prior to board-v1.1.0


        ''
        ''## PCBv1
        ''

        ''* SPI_CEn1_PCBv1        -- Second Chip Enable Pin, active low
        ''
        SPI_CEn1_PCBv1          = 0

        ''* RST_DISABLE           -- Inhibit signal pin on board v1 for net RS232_RST
        ''
        RST_DISABLE             = 16

        ''* PCBv1_CONFIG          -- Hardcoded DIP switch configuration for PCBv1 aka board-v1
        ''
        ''    This configuration can also be set per menu.
        ''
        ''    - RS232 baudrate: 115200
        ''    - SPI power-on: one shot
        ''    - SPI power-off: auto
        ''    - SPI clock: mode 3
        ''    - clock driver strength: 50%
        ''
        PCBv1_CONFIG            = %011001


        ''
        ''## Common
        ''

        ''* DIP Switches A and B: Board Version
        ''
        ''    Devkit: open = H, closed straight = L, closed angular = H
        ''
        ''    open = H, closed = L
        ''
        ''    Board Version  |  SWDIP_B  |  SWDIP_A
        ''    ---------------|-----------|-----------
        ''             V1    |        L  |        L
        ''             V2    |        L  |        H
        ''             V2.1  |        L  |        H_delayed_40
        ''             V2.2  |        L  |        H_delayed_20
        ''             V3    |        H  |        L
        ''             V4    |        H  |        H
        ''
        ''    On PCBv1, SWDIP_A is connected to GND via resistor.
        ''
        ''    On PCBv1, SWDIP_B is not connected but will hopefully read low at start.
        ''
        ''    On PCBv2.1 and PCBv2.2, SWDIP_A is connected to an RC network.
        ''    It can be detected by driving SWDIP_A low and then waiting for a low-to-high transition.
        ''
        SWDIP_A                 = 16
        SWDIP_B                 = 17

        ''* SPI Pins
        SPI_CEn0                = 1               'First Chip Enable Pin

        ''* RS232 Pins
        RS232_TX                = 30              'RS232 TX (Transmit to Host) Pin
        RS232_RX                = 31              'RS232 RX (Receive from Host) Pin

        ''* SPI Modes
        SPI_MODE_0              = 0
        SPI_MODE_3              = 3



''
''
''# Globals
VAR


        BYTE g_pcbversion
        BYTE g_pcbconfig



''
''
''# Functions


PUB     set_pcbversion (v)

        '' Setter method for g_pcbversion.

        g_pcbversion := v


PUB     get_pcbversion : r

        '' Getter method for g_pcbversion

        RETURN g_pcbversion


PUB     set_pcbconfig (v)

        '' Setter method for g_pcbconfig.

        g_pcbconfig := v


PUB     get_pcbconfig : r

        '' Getter method for g_pcbconfig

        RETURN g_pcbconfig


PUB     check_cable_SPI : r

        '' Check SPI Cable:
        ''
        '' FALSE = a) Cable not present or b) twisted plug
        '' TRUE  = Cable present

        CASE g_pcbversion
            $01:    r := !(INA[SPI_CABLEn_PCBv1_0] <> FALSE)
            OTHER:  r := !(INA[SPI_CABLEn_PCBv1_1] <> FALSE)


PUB     is_monitor_VSPI

        '' Is SPI voltage monitor hardware available?

        CASE g_pcbversion
            $01, $11:     RETURN FALSE
            OTHER:        RETURN TRUE


PUB     is_monitor_RPULL

        '' Is SPI R_pull monitor hardware available?

        'Is monitor hardware available for SPI R_pull?
        CASE g_pcbversion
            $01, $11, $02:    RETURN FALSE
            OTHER:            RETURN TRUE


PUB     is_monitor_RST

        '' Is pin RS232_RST monitored?

        CASE g_pcbversion
            $02:      RETURN TRUE
            OTHER:    RETURN FALSE


PUB     is_RS232_CTS

        '' Is pin RS232_CTS available?

        CASE g_pcbversion
            $01, $11, $02:    RETURN FALSE
            OTHER:            RETURN TRUE


PUB     get_RST_INHIBIT

        '' Which pin is used to inhibit net RS232_RST?

        'Which pin is used to inhibit net RS232_RST?
        CASE g_pcbversion
            $01, $11:     RETURN RST_DISABLE
            OTHER:        RETURN RST_INHIBIT


PUB     get_MASK_CEn_AVAIL

        '' Which pins are used to enable SPI CE#?

        CASE g_pcbversion
            $01, $11:     RETURN (|<SPI_CEn0 | |<SPI_CEn1_PCBv1)
            $02:          RETURN (|<SPI_CEn0 | |<SPI_CEn1_PCBv2_0)
            $12:          RETURN (|<SPI_CEn0 | |<SPI_CEn1_PCBv2_1)
            OTHER:        RETURN |<SPI_CEn0


PUB     get_RPULL : r

        '' Check value of R_pull,
        ''   which must not be smaller than 83 Ohm if driven by one pin.

        'set up Counter A for Pos. Detection on SPI_RPULL
        FRQA := 0
        PHSA := 0
        CTRA := %0_01000_000 << 23 + 0 << 9 + SPI_RPULL

        'prepare SPI_RPULL
        OUTA[SPI_RPULL]~~

        REPEAT 10
            'load C_pull for 10us
            DIRA |= (|<SPI_RPULL | get_MASK_CEn_AVAIL)
            time.sleep_10us

            'stop loading, count decay time
            FRQA := 1
            DIRA &= !(|<SPI_RPULL)            'take this execution time into account
            time.sleep_50us
            FRQA := 0
            DIRA &= !get_MASK_CEn_AVAIL

        'restore SPI_RPULL
        OUTA[SPI_RPULL]~

        'stop Counter A
        CTRA := %0_00000_000 << 23 + 0 << 9 + SPI_RPULL

        'adjust result, or ...
        'r := ((PHSA - RPULL_MIN_22nF_X7R) * (RPULL_MAX - RPULL_MIN) / (RPULL_MAX_22nF_X7R - RPULL_MIN_22nF_X7R)) + RPULL_MIN
        'r := ((PHSA - RPULL_MIN_22nF_X7R_3) * (RPULL_MAX - RPULL_MIN) / (RPULL_MAX_22nF_X7R_3 - RPULL_MIN_22nF_X7R_3)) + RPULL_MIN
        r := ((PHSA - RPULL_MIN_22nF_X7R_10) * (RPULL_MAX - RPULL_MIN) / (RPULL_MAX_22nF_X7R_10 - RPULL_MIN_22nF_X7R_10)) + RPULL_MIN

        '... calibrate:
        'r := PHSA


PUB     sample_pcbversion : vboard | sw

        '' Retrieve board version from PCB, read SWDIP_A and SWDIP_B:
        ''
        ''  Devkit: open = H, closed straight = L, closed angular = H
        ''
        ''  open = H, closed = L
        ''
        ''  SWDIP_B  |  SWDIP_A         | PCB version   | Return Value    | device
        ''  ---------|------------------|---------------|-----------------|---------------------------------
        ''        L  |  L               | board-v1      | $0001           |                                 
        ''        L  |  L               | board-v1.1    | $0011           |  Chipflasher `board-edition-1  ''
        ''        L  |  H               | board-v2.0    | $0002           |  Chipflasher v2                 
        ''        L  |  H_delayed_40    | board-v2.1    | $0012           |                                 
        ''        L  |  H_delayed_20    | board-v2.2    | $0022           |  Chipflasher v2.1               
        ''        H  |  L               | board-v3      | $0003           |                                 
        ''        H  |  H               | board-v4      | $0004           |                                 
        ''
        ''  On board-v1, SWDIP_A is connected to GND via resistor.
        ''
        ''  On board-v1, SWDIP_B is not connected but will hopefully read low at start.
        ''
        ''  On board-v2.1 and board-v2.2, SWDIP_A is connected to an RC network.
        ''  It can be detected by driving SWDIP_A low and then waiting for a low-to-high transition.

        'drive SWDIP_A low
        DIRA[SWDIP_A]~~
        time.sleep_husec(10)

        'read SWDIP_A: sample #0, delay, sample #1, delay, sample #2
        DIRA[SWDIP_A]~

        'sample #0
        sw := INA[SWDIP_A] << 2

        'sample #1
        'delay must be bigger than 1.2msec with 23.5k and 100nF
        'delay must be smaller than 2.5msec with 47k and 100nF
        time.sleep_husec(20)
        sw |= INA[SWDIP_A] << 1

        'sample #2
        time.sleep_husec(20)
        sw |= INA[SWDIP_A] << 0

        'get major board version
        vboard := INA[SWDIP_B..SWDIP_A] + 1

        'set minor board version
        CASE vboard
            1:
                'test for board version below v1.1
                CASE INA[10..9]
                    %01:                      'cable on board-v1.0
                    OTHER:                    'a) no cable or b) cable twisted or c) cable on board-v1.1
                        vboard |= 1 << 4    'set v1 subversion to 1
            2:
                CASE sw
                    %000:   vboard |= 0 << 4
                    %001:   vboard |= 1 << 4
                    %011:   vboard |= 2 << 4


PUB     sample_pcbconfig : cfg

        '' Return six configuration bits in respect to parameter `vboard':
        '' If `vboard' is 1, return the value of `PCBv1_CONFIG',
        ''   otherwise read DIP switches on PCB.

        CASE g_pcbversion
            $01, $11:   cfg := PCBv1_CONFIG                       'PCBv1: hardcode DIP switch
            OTHER:      cfg := (!INA[SWDIP_6..SWDIP_1])           'PCBv2: read DIP switch


PUB     get_SPI_power_on_type

        '' Return TRUE or FALSE according to bit position 2 of parameter `cfg',
        ''   corresponding to this translation:
        ''
        '' bp2
        '' ---
        ''  0    = one shot SPI power-up (FALSE)
        ''  1    = pulsed SPI power-up (TRUE)

#   ifdef _CFG_SPIPWRON_ONESHOT
        RETURN FALSE
#   endif
#   ifdef _CFG_SPIPWRON_PULSES
        RETURN TRUE
#   endif
#   ifdef _CFG_SPIPWRON_DIPSW
        RETURN (g_pcbconfig & %000010) <> FALSE
#   endif


PUB     get_SPI_power_off_type

        '' Return TRUE or FALSE according to bit postion 3 of parameter `cfg',
        ''   corresponding to this translation:
        ''
        '' bp3
        '' ---
        ''  0    = automatic suspend, if required (FALSE)
        ''  1    = static power, suspend inhibited (TRUE)

#   ifdef _CFG_SPIPWROFF_AUTO
        RETURN FALSE
#   endif
#   ifdef _CFG_SPIPWROFF_USER
        RETURN TRUE
#   endif
#   ifdef _CFG_SPIPWROFF_DIPSW
        RETURN (g_pcbconfig & %000100) <> FALSE
#   endif


PUB     get_SPI_power_config

        '' Return value 0..3 according to bit positions 2 and 3 of parameter `cfg',
        ''   corresponding to this translation table:
        ''
        '' bp2 | bp3
        '' ----|----
        ''  0  |  0    = one shot, auto
        ''  1  |  0    = pulses, auto
        ''  0  |  1    = one shot, static
        ''  1  |  1    = pulses, static

        RETURN (g_pcbconfig & %000110) >> 1


PUB     get_SPI_mode

        '' Return SPI Mode according to bit position 4 of parameter `cfg':
        ''   0 -> Mode 0, 1 -> Mode 3
        '' Alternatively, return modes according to preprocessor directive.

#   ifdef _CFG_SPIMODE_0
        RETURN SPI_MODE_0
#   endif
#   ifdef _CFG_SPIMODE_3
        RETURN SPI_MODE_3
#   endif
#   ifdef _CFG_SPIMODE_DIPSW
        CASE (g_pcbconfig & %001000) >> 3
            0:  RETURN SPI_MODE_0
            1:  RETURN SPI_MODE_3
#   endif


PUB     get_clk_driver

        '' Return 0..3 according to bit positions 5 and 6 of parameter `cfg'.
        '' Return values correspond to 25%(0)..100%(3) SPI clock driver strength.
        '' Alternatively, return values according to preprocessor directive.

#   ifdef _CFG_SPICLK_100
        RETURN %11
#   endif
#   ifdef _CFG_SPICLK_75
        RETURN %10
#   endif
#   ifdef _CFG_SPICLK_50
        RETURN %01
#   endif
#   ifdef _CFG_SPICLK_25
        RETURN %00
#   endif
#   ifdef _CFG_SPICLK_DIPSW
        RETURN (g_pcbconfig & %110000) >> 4
#   endif


PUB     get_baudrate

        '' Return baudrate according to bit position 1 of parameter `cfg':
        ''   0 -> 57600, 1 -> 115200
        '' Alternatively, return baudrate according to preprocessor directive:
        ''   38400, 230400

#   ifdef _CFG_RS232_230400
        RETURN 230400
#   endif
#   ifdef _CFG_RS232_115200
        CASE g_pcbconfig & %000001
            0:  RETURN 57600
            1:  RETURN 115200
#   endif
#   ifdef _CFG_RS232_57600
        CASE g_pcbconfig & %000001
            0:  RETURN 57600
            1:  RETURN 115200
#   endif
#   ifdef _CFG_RS232_38400
        RETURN 38400
#   endif



{{


******************************************************************************
Terms of Use:

Zerocat Chipflasher is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Zerocat Chipflasher is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License along
with Zerocat Chipflasher.  If not, see <http://www.gnu.org/licenses/>.

************************************************************** End of File ***
}}