3-Chip Z80 Design

Combining a Z80 retro design with a modern PSoC CPU.

Similar projects worth following
Starting from
land_boards has 826 orders / 20reviews
Ships from United States of America
A Z80 CPU, 512K SRAM and a Programmable System on a Chip make a functional retro-future CPU card

This project uses a Z80, 512KB SRAM and a Cypress Semiconductor (now Infineon) Programmable System on a Chip (PSoC) to make a 3-chip Z80 retro-future computer All of the I/O and SRAM control is performed by the PSoC which emulates Z80 serial and parallel I/O peripherals.

Why Use a PSoC?

The PSoC has the following advantages:

  • 5V I/O which lets the PSoC interface directly with the Z80
  • Programmable Logic array to implement Z80 glue logic and peripherals
  • 32-bit ARM core
  • PSoC can download the program to the SRAM so there's no need for EPROM


A three chip Z80 design schematic is something like:

This has three parts - a 512KB SRAM, the Z80 and the PSoC.

The oscillator is optional unless precise serial connections are required. This is not necessary in most applications since the PSoC has a USB interface.

The PSoC emulates the control/status registers of a 6850 ACIA.


Additional parallel I/O is via an optional MCP23017 chip which connects to I2C pins on the PSoC. This is slower than a PIO chip, but probably still OK for most applications. This is similar to the Z80-MBC2 board without requiring the complications of the ATMEGA interface. In that design, the ATMEGA interfaces to the CPU force feeding it instructions with boot sequences. And this is one less IC.

The PSoC SPI interface connects to an optional external SD card.

An optional Front Panel card was also created which connects via I2C to the PSoC.

Booting Software Builds

In this design, the PSoC downloads the software to the SRAM and takes the Z80 out of reset. Hardware/software implementations which have both EPROM and RAM could be "emulated" by banking the SRAM. Control of upper RAM address bits allows a bank of the SRAM to work as an EEPROM. The program can be downloaded from the emulated SRAM into the SRAM itself.

512KB MultiOS Multicomp

Card runs CP/M 2.2, CP/M 3.0, BASIC.

Z80 Peripheral Emulation

The Z80 peripherals are emulated insider the PSoC - mostly in hardware. For instance, the DART/SIO consist of data and control/status registers which are I/O mapped to the Z80 and memory mapped to the PSoC. An 8-bit mailbox interfaceis used for all peripherals and the I/O address is latched in a register in the PSoC.

Counter/Timers could also easily be simulated in PSoC hardware.

The PCB would be less expensive (than my previous design) since it could easily be built in a board that is smaller (95x95mm which is the sweet spot for PCB costs. PCBWay or JLCPCB wants $14 for 10 boards that are larger than 100x100mm but only $5 for 10 boards which are less than 100x100mm or less.

Design Logs

See the 90+ logs here for the card which provide excruciating details on the design process.

  • 1 × Z80 - 20 Mhz runs at 12.5 MHz
  • 1 × PSOC5LP - Programamble System on a Chip - 100 pin TQFP
  • 1 × AS6C4008-55PCN 512KB SRAM
  • 1 × Optional MCP23017 I/O Expander
  • 1 × Optional SD Card Adapter (needed for CP/M)

View all 6 components

  • Updates to Boot Menu on PSoC

    land-boards.com09/17/2022 at 14:23 0 comments

    It's been a while. I plugged in the board USB and forgot how to run it. I even forgot which button I needed to press on the front panel to get Multiboot to run. This Hackaday page helped me remember. Glad I made it.

    Decided to add hints to the PSoC monitor menu. Got a bit carried away but it's really easy now.

    The PSoC now boots to the following screen showing what the Front Panel buttons do:

    Z80_PSoC - Running Front Panel
    SW25 SW26 SW27 SW28 SW29 SW30 SW31 SW32
    Run  Mon  N/A  N/A  N/A  LDAD STOR INCA
    SW17 SW18 SW19 SW20 SW21 SW22 SW23 SW24
    A15  A14  A13  A12  A11  A10  A9   A8
    SW9  SW10 SW11 SW12 SW13 SW14 SW15 SW16
    A7   A6   A5   A4   A3   A2   A1   A0
    SW1  SW2  SW3  SW4  SW5  SW6  SW7  SW7
    D7   D6   D5   D4   D3   D2   D1   D0
    Press SW25 (upper left button) to exit Front Panel and run Z80
    Press SW26 to run Monitor/Test Code

    Pressing the upper left button on the Front Panel (SW25) goes directly to Multiboot. 

    The next button in boots the monitor. The monitor looks like:

    Land Boards, LLC - Z80_PSoC monitor
    I - Initialize SD Card
    B - Blink LED
    F - Read Front Panel
    Rxxxxxxxx - Read sector xxxxxxxx from the SD Card
    N - Read next sector from the SD Card
    W - Write to the SD Card at 2GB - 1 sector
    X - eXit Monitor and run Z80
    ? - Print this menu

    Pressing X goes to Multiboot. 

    The PSoC waits until the USB terminal (PuTTY) is running. Now I feel like I could plug the card in anytime and just use it. Added P-Touch labels to SW25, SW26 to remind me what they do.

    Also noted that the USB Serial port can be set to any baud rate since the PSoC automatically adjusts. Tried 230.4 kb and it worked just fine.

  • SD Card Adapter

    land-boards.com02/21/2020 at 14:34 0 comments

    Made my own SD Card adapter to use with my Z80_PSOC card. Works great. Made this card because I wanted good mounting holes. Also, didn't like the series resistor method of shifting the 5V of the Z80_PSOC to 3.3V of the SD Card that most cards use in their design

    Here's the SD Card. Uses a TXS0104E level shifter to convert the 5V of the Z80 to the 3.3V used by the SD Card.

    Here's the card mounted to a carrier which lets it stack up with the other 95x95mm cards.

  • Pics of New Board

    land-boards.com12/08/2019 at 17:57 0 comments

    Here is a picture of the new Rev 3 card. The card runs fine and there are no wires.

    Here's the stackup with the Front Panel, JoyPad and SD Card.

  • New Board Spin

    land-boards.com12/04/2019 at 14:25 0 comments

    There were some things I wanted to add/change on the first rev of the card. Got the PCBs back from PCBs fabrication but haven't assembled the cards yet. This change:

    • Adds Z80 expansion connector (J5)
    • Fixes labeling on the Programming connector (H2)
    • Adds control signal labels for SRAM debugging (WR*, RD*, and CS*)
    • Adds a pin 1 indicator for the PSoC "Small dot >" (at U4)
    • Adds I/O Connector (H4)
    • Rotate I2C connector to allow horizontal header to be used
    • Might want to use right angle connectors at J4, H2, H3, and H4

    Z80 Bus Expansion Connector
    The primary feature added is the 40-pin bus expansion connector which brings out the Z80 bus. Here's the connector pinout:
    Most of the signals are directly from the Z80.  Some of them are hard driven from the PSoC and would need to be changed to Open Drain outputs with pull-ups if there was an expansion card attached to this connector. I mostly want the connector to aid in debugging. Getting all those little chip clips on the Z80 pins and making them stay is just too hard. It's much easier to push the female pin from the Logic Analyzer onto a header.

    H4 I/O Connector
    Also added a 6-pin connector for additional I/O (maybe an RS-232 port?). Pxx are PSoC pins.

  • Front Panel Card Change

    land-boards.com11/19/2019 at 12:38 0 comments

    Removed the straight connector for I2C and replaced it with a dual row right angle connector. One of the pins is deliberately left out on the 2x5 connector. That is because other cards that connect to the I2C bus won't use the same interrupt line as the Front Panel.

    This provides a more robust connection to the Front Panel card. It is less likely to come loose and provides additional clearance down to card below (Z80_PSOC card).

    Also, took apart the staggered stack-up and rebuilt it using 1/4" standoffs that are #6-32 M-F parts for the standoffs below the Z80_PSOC CPU card. Using 1" standoffs between the Front Panel and CPU cards and used #6-32 nuts at the top of the Front Panel Card. This makes the entire stackup less than 1-1/2" tall with buttons and switches at the top of the stack (Picture with taller standoffs at the bottom).

    The SD Card and JoyPad cards are cabled out to external cards. Going to make a 49x49mm card which has an SD card socket. The SD card will be used with a 95x95mm to 49x49mm adapter card which will allow the SD card to be stacked easily in a mechanically sound manner. The SD card can have a right angle connector and will be routed to the Z80_PSOC CPU card. The card could be mounted on the bottom of the 95-49mm adapter card so that the cable route down but then the I2C cable from the Front Panel to the Z80_PSOC card would route down around the card.  Another possibility is making a version of the adapter card with a slot on the side for cable routing.

  • Multi-boot Multicomp (Part 3)

    land-boards.com11/16/2019 at 20:07 0 comments

    In the last log we got the Multi-boot monitor to run however, when BASIC was run it hung.

    The Z80 is trying to access I/O address 0x39 which isn't implemented yet. That's the swap back to the original BIOS code. Since it was never swapped out it can be swapped right back in with an ackIO( ).

    After adding back in the BIOS, BASIC now works as launched from Multi-boot with the S5 command.

    Cold or Warm?
    Memory top?
    Z80 BASIC Ver 4.7b
    Copyright (C) 1978 by Microsoft
    57694 Bytes free
    10 print "HI"
    10 PRINT "HI"

    Added in code that when the 0x39 (swapped back) is received then goes and causes a BUSREQ*, waits for a BUSACK* and copies the BIOS back into SRAM.

    Back to Debugging CP/M

    The CP/M code is in and the BIOS code looks like this:

    ; Disable the ROM, pop the boot disk and IOBYTE from the stack 
    ; (supplied by monitor), then start the OS
    ;    org 0FFB0h
        ld A,01h 
        out (38h),A        ; kick ROM
        pop AF            ; Monitor gives physical boot volume
        ld (mnttab),A        ; ignore 8 bit volume number
        pop AF            ; Monitor gives the IOBYTE ...
        ld (IOBYTE),A
        ld HL,mnttab
        ld (0FFFEh),HL        ; put mounttab vector in FFFE
        ld HL,backdoor
        ld (0FFFCh),HL        ; put backdoor vector above that
        ld A,0C3h
        ld (0FFFBh),A        ; and a JP opcode above that
        ld C,0
        jp BIOS

    S2 also works.

    Z80 CP/M BIOS 2.20
    Based on MULTICOMP by G. Searle 2007-13
    CP/M 2.2 (c) 1979 by Digital Research
    A:   Volume 002 : ASM      COM : DDT      COM : DISPLAY  COM
    A: DOWNLOAD COM : DUMP     COM : DUTIL    COM : ED       COM
    A: LOAD     COM : MOUNT    COM : PIP      COM : RDINIT   COM
    A: RESET    COM : STAT     COM : SUBMIT   COM : TIME     COM

    S3 also works.

    CP/M V3.0 Loader
    Copyright (C) 1998, Caldera Inc.
     BNKBIOS3 SPR  FA00  0600
     BNKBIOS3 SPR  7400  0C00
     RESBDOS3 SPR  F400  0600
     BNKBDOS3 SPR  4600  2E00
     61K TPA
    CP/M Version 3.0 BIOS (2016/9/13)
    FPGA-Z80 Multicomputer
    Original concept by Grant Searle

     S4 boots but hangs.

    MP/M II V2.1 Loader
    Copyright (C) 1981, Digital Research
    Nmb of consoles     =  4
    Breakpoint RST #    =  6
    Memory Segment Table:
    SYSTEM  DAT  FF00H  0100H
    TMPD    DAT  FE00H  0100H
    USERSYS STK  FC00H  0200H
    XIOSJMP TBL  FB00H  0100H
    XDOS    SPR  CD00H  2200H
    BNKXIOS SPR  C200H  0B00H
    BNKBDOS SPR  9F00H  2300H
    BNKXDOS SPR  9D00H  0200H
    TMP     SPR  9900H  0400H
    LCKLSTS DAT  9600H  0300H
    CONSOLE DAT  9200H  0400H
    MP/M II Sys  9200H  6E00H  Bank 0
    Memseg  Usr  0000H  C000H  Bank 1
    Memseg  Usr  0000H  C000H  Bank 2
    Memseg  Usr  0000H  C000H  Bank 3
    Memseg  Usr  0000H  C000H  Bank 4
    Memseg  Usr  0000H  C000H  Bank 5
    Memseg  Usr  0000H  C000H  Bank 6
    Memseg  Usr  0000H  9200H  Bank 0

    S6 doesn't boot.

    S7 boots.

    > S7
    CP/M V3.0 LoaderBIOS for Grant Searle's Multicomputer
     Loading ZPM3...
     BNKBIOS3 SPR  FA00  0600
     BNKBIOS3 SPR  7400  0C00
     RESBDOS3 SPR  F400  0600
     BNKBDOS3 SPR  4600  2E00
     61K TPA
    CP/M Version 3.0 BIOS (2016/9/13)
    FPGA-Z80 Multicomputer
    Original concept by Grant Searle
        ZCPR compatible system for CP/M+ by Simeon Cran
    Loading NAMES.NDR
    RamDisk: Initialized
    00:00 A0:SYS>

    Tried S1 twice and it booted on the second try.

    Z80 CP/M BIOS 2.20
    Based on MULTICOMP by G. Searle 2007-13
    Dos+ 2.5  Copyright 1986 (c) by C.B. Falconer
    CCP+ Ver. 2.2

    zexall runs on S1.

    Z80 instruction exerciser
    <adc,sbc> hl,<bc,de,hl,sp>....  OK
    add hl,<bc,de,hl,sp>..........  OK
    add ix,<bc,de,ix,sp>..........  OK
    add iy,<bc,de,iy,sp>..........  OK
    aluop a,nn....................  OK
    aluop a,<b,c,d,e,h,l,(hl),a>..  OK
    aluop a,<ixh,ixl,iyh,iyl>.....  OK
    aluop a,(<ix,iy>+1)...........  OK
    bit n,(<ix,iy>+1).............  OK
    bit n,<b,c,d,e,h,l,(hl),a>....  OK
    cpd<r>........................  OK
    cpi<r>........................  OK
    <daa,cpl,scf,ccf>.............  OK
    <inc,dec> a...................  OK
    <inc,dec> b...................  OK
    <inc,dec> bc..................  OK
    <inc,dec> c......................
    Read more »

  • Multi-boot Multicomp (Part 2)

    land-boards.com11/14/2019 at 15:45 0 comments

    I've got the BIOS loading for Multi-boot Multicomp. It boots up to the Multi-boot prompt.

      Available Commands:
      :ccxxxxiibbbbbb Load Intel-Hex file record
      Rxxxx           Run from address xxxx
      Sddd            System boot
      Iddd            Init: Format directory
      Pddd[,xxxx]     PutSys: write system image[,loadaddress]
                      (No address: re-use last loadaddress)
      Gddd[,xxxx]     GetSys: load system track
      Dxxxx[,yyyy]  Dump memory from xxxx [,to yyyy]
                    D (no address) shows next block
      Cxxxx         Change/show memory at xxxx
                    CR advances "," quits
      ddd is a decimal volume number,
      xxxx, yyyy is a hexadecimal address.
      Leading zeros may be omitted.
      ESC or ^C aborts.

     When I enter "S1" it hangs. I single stepped through the SD code from the PSoC side and it looks like the SD card is working the same as Grant's CP/M boot (build tested earlier).

    At the least the PSoC is not hung but there's no more I/O requests from the Z80.

    Bank Switching vs MMU

    The previous CP/M design does a bank switch with a write to I/O address 0x38. There is no bank switching with the MMU so it's not the case that it needs to swap out the banks. But I'm not sure what the effect of not having an actual EPROM would be in this case. The BIOS gets loaded into the first 2K of SRAM.

    The FPGA version of this design had two addresses for switching ROM and SRAM in/out of the first 2KB. That could be done in this instance by re-copying the monitor program into the SRAM, but probably is unnecessary. There's also no writes in the BIOS to the switching although there has to be something somewhere in the code to do the switching otherwise the bottom 2KB would not be accessible. This command won't work:

    When you type "reset" you enact a cold reset, 
    returning you to the ROM monitor.

    SYSRUN Routine

    The SYSRUN routine is short:

    ; SYSRUN - boot (load and run) from system track of selected volume
    sysrun:    call getargs   ; get volume and loadaddress
        call setDskIO
        call readsys          ; read disk contents to loadaddress
        call getlen           ; find loadaddress and length
        ldir                  ; move buffer to image
        ld A,(aciaCtl)        ; message bootdisk and console to 
        and 02h               ; main program - 2 methods, on stack
        rrca                  ; and in alternate BC registers
        xor 01h               ; convert to iobyte...
        push AF               ; save bytes in BIOS
        ld C,A
        ld A,(volume)         ; tell BIOS which is ...
        push AF               ; ...the active bootvolume
        ld B,A
        exx                   ; also make b'=bootdisk, c'=console
        ld HL,(0FFFEh)        ; pop and run location
        jp (HL)               ; bye bye

    Limited Ability to Monitor Z80 Activity

    It's a pain to hook up the logic analyzer to the Z80. Rev 3 of this board will make it much easier because it brings out all Z80 signals to a 40 pin header.

    All of these signals already go to the Z80. It would be nice to be able to break into the PSoC monitor and single step through Z80 code or at least capture the address/data of the bus.

    Stuff I Tried

    Also tried G1,4000 to read the SD card for image 1 into memory at 0x4000. It hung PuTTY.

    - Command G performs the same service, but stops when the 
    image is loaded and returns to the monitor prompt. 
    This command is useful to examine the image, 
    or prepare it for loading onto a volume.

    I am able to Change and Dump memory which makes me conclude that the MMU must be functioning correctly.

    > C4000
    4000 00 40
    4001 01 00
    > C8000
    8000 00 80
    8001 01 00
    > CC000
    C000 00 C0
    C001 01 00
    > D4000
    4000  40 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F       @...............
    > D8000
    8000  80 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F       ................
    > DC000
    C000  C0 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F       @...............

    SD Card Sector Map

    S1 attempts to load sector 0x4000.

    Card layout:
    sector  --------------------------------------------------------------
    0       the first 8 Mbytes unused:  \    Put partition table here
    16384   8MB volume 1                |    if desired.
    32768   8MB volume 2                |
    49152   8MB volume 3                |
            =    .                      |
            =    .                      | 2 Gbyte maximum reserved memory
    1949696 end of 1 GB card, or...
    Read more »

  • Multi-boot Multicomp

    land-boards.com11/11/2019 at 13:51 0 comments

    I tried out the Multi-boot Multicomp build over the last couple of days on my Multicomp FPGA build and it is really sweet (compliments to the author/compiler - Rienk H. Koolstra). It would be a nice port to this card since it's a superset of all of the builds that I have done so far. From the features list of the page - the system's main specifications are:

    • New ROM monitor with multi-boot capability, Format, Getsys and Putsys tools and debug capabilities. No BASIC in ROM.
    • SD-HC capable card controller. Init at 250 kHz, running at 25 MHz.
    • Improved keyboard definition featuring external keymap and added key functionality.
    • Multi volume disk system, which currently supports upto 253 8MB disk volumes (which uses 2GB+ on the SD-card). All these volumes can be loaded with a separate OS bootimage.
    • OSes configured with 3 drives: A:, B: and C:. A: for the system drive (holding the volume booted from) while B: and C: can be assigned and re-assigned one of the remaining volumes. Also a RAM disk is available for CP/M 2 and CP/M 3 systems.
    • Y2k compatible system clock (date and time) for all OSes.
    • Included are CP/M 2.2, Dos+ 2.5, CP/M 3.0, MPMII 2.1, ZSDOS 1.1/ZCPR2, ZPM3/ZCCP and NASCOM ROM Basic

    There are two possible hurdles to overcome. The first is the MMU and the second potential hurdle is the SD card interface.

    MMU Design

    There are differences between the MMU in this implementation and the one currently in the PSoC. The current bank switch is for a single bank with selectable size. The MMU design has 4 banks which select one of 64 16KB banks. The base address for each of the bank is written by first writing to an offset register and then writing to the particular map register. The VHDL code for the MMU is here.

    This can be implemented as a pair Z80 I/O addresses with one for the register select and another for the table value at that offset. The table consists of four registers which are 6 bits each (or 5 bits for 512KB).

    The hardware seems fairly straightforward. The MMU logic is labeled as MMU4 and looks like:

    This adds another level of multiplexer to the SRAM address lines.
    The current page that drives the MMU1 gets changed to go through the new level of multiplexer. My assumption is that PSOC Creator will reduce the logic automatically.
    The HEX file from Multiboot Multicomp gets converted into a C array with srec_cat as previously done and added to the project. The Z80 IO handler gets updated to add handlers for the new Memory Mapper. The Harware_Config.h file gets updated to add the new Memory Map (USING_MEM_MAP_4) and top level design (MULTIBOOT_CPM). This is very similar to the 9-Chip CP/M design described in a previous blog.

    Can't test it with real hardware at the moment but it did compile and I checked it into the Project GitHub.
    That did eat up some PSoC resources (mostly in the additional control registers), but there's still room.

  • Interrupts on the PSoC

    land-boards.com11/05/2019 at 15:43 0 comments

    In the last log we added support for interrupts on the PSoC. To summarize:

    • There are (5) MCP23017 parts which connect to the PSoC
      • MCP23017 parts communicate with the PSoC using I2C
      • (1) Expansion MC23017 on the main board
        • Port A and Port B have pull-ups enabled
        • Port A and Port B inputs set to inverting
        • Pulling input pin to ground causes a "1" to be read for the pin
        • Connected to a JOYPAD on Port A
        • Expansion MCP23017 ports are initialized as inputs
          • Ports can be configured by Z80 writes (PIO control register format)
      • (4) MCP23017 parts on the Front Panel
        • Half of the pins on each MCP23017 are configured as inputs from pushbuttons and half as outputs for LEDs
        • Ports can be read from the Z80
    • The MCP23017 has two interrupt pins; one for A Port and one for B Port
    • The (2) interrupt pins on each of the MCP23017 parts are wired together
    • MCP23017 parts are set to Open Drain outputs on the Interrupt lines
    • All [five] MCP23017 ports are Wire-OR tied together into one line - I2CINT*
    • MCP23017 parts are set to interrupt on change of the input pins
      • Any change (H>L or L>H) causes the interrupt lines to be asserted on the port's interrupt pin
        • Every button press causes two interrupts one when the button is pressed, the other when the button is released
    • The PSoC has to poll each MCP23017 to determine which MCP23017 part caused the interrupt
    • The I2CINT* line is connected to pin 68 (P12[3]) on the PSoC
    • An inverter inside the PSoC changes the active low signal into an active high signal
    • The I2CINT* pin on the PSoC is connected to an interrupt function in the PSoC
      • InterruptType is set to LEVEL
    • PSOC Creator generates the API for the interrupt function which corresponds to I2CINT*
      • API functions that can be called from "anywhere" include:
        • I2CINT_ISR_Start( ) - Start up the function and enable interrupts
        • I2CINT_ISR_Disable( ) - Disable interrupts from the I2CINT* pin
        • I2CINT_ISR_Enable( ) - Enable interrupts from the I2CINT* pin
    • Had to manually create a function to handle the Interrupt
      • I2CIntISR( ) - Read the Interrupt capture registers into variables
        • Reads the six INTCAP registers (two in the Expansion MCP23017 and the four halves from the switches of the Front Panel MCP23017 parts)
    • The Z80 reset was tied to the MCP23017 reset line
      • The MCP23017 couldn't t be initialized while it is held in reset
      • The PSoC monitor couldn't be used to test the interrupt function
      • Reworked the reset line to access interrupts from the PSoC Monitor
        • Cut etch
        • Add pull-up resistor since MCP23017 part doesn't have internal pull-up

    After Reworking RESET* to the Expansion MCP23017

    After doing the rework to the card, it now processes interrupts consistently. The ARM Core no longer gets heap errors, etc. However, the bounce of the switches is now a problem. If the code is set with a breakpoint at the end of the I2CINT_ISR routine it shows all key presses and releases are being received. If the ARM is running full speed it looks like some presses are being missed.

    Possible Ways to Debounce and Have Interrupts

    One way might be to disable interrupts when the interrupt is received and then use a timer to only enable interrupts again after some number of mSecs have gone by. That has the potential to be relatively simple. Would be the first time I've explicitly used timers, though.

  • Interrupts from the MCP23017

    land-boards.com11/03/2019 at 23:40 0 comments

    The MCP23017 has two interrupt modes. One is to interrupt on level. The pin is compared to a default value and causes an interrupt when different. The interrupt will persist as long as the signal is different than the default value that was set. Reading the GPIO or INTCAP clears the interrupt . But, in this mode another interrupt will happen immediately if the pin is still different That is the mode I was running and and explains why interrupts hang around until the button (front panel or Expansion MCP23017) is released.

    The other mode causes an interrupt on change of the pin. That's the mode I switched to and it works. Interrupts are generated when there's a change. The only downside is there is an interrupt when the button is pressed and another interrupt is generated when the key is released. There's no edge selection for the interrupt but that's easy enough to do in the PSoC software. It could possibly be useful to know when a button is released

    The interrupt takes a bit over 500 uS total time. That's due to the 400 KHz I2C bus speed and the number of ports (6x2) that need to be read. No biggie really.

    At this point it would be helpful to read the values from the ports and create three values from them. One would be a long value which is the state of the Front  Panelswitches. The other would be two bytes which indicate the value of the Expansion MCP23017 ports. The same caveats about debouncing apply here that applied when getting the Front Panel to work.

    Here's the Polled mode reads of the JOYPAD from basic. The Z80 is reading the PIO Port A (that's where the JOYPAD is connected) and printing the value if it changes. This mode does not require interrupts since it's actually doing a read of the PIO.

    Interrupts are funny things. When they happen at the wrong time bad things happen. The program above worked pretty good - some of the time.  Then they would kill the program on the Z80. Difficult to debug in this setup since I don't have visibility into the Z80 code without hooking up the logic analyzer.

    Allowing Interrupts in a Time Slot

    There's a fix for this issue by limiting time interrupts to only happen in a window. And the main( ) program loop is a convenient place to do that. The code looks something like this.

                // Give the I2CInt a time slot

    This opens a short window for the interrupts and it cleared up the Z80 hangs. The BASIC program does a constant read of the PIO port so it's likely the interrupt was messing up that read by interrupting the I2C transfer for the polled read. Doing the interrupt in a time that the Z80 port is guaranteed to not being handled is a fairly clean solution.

    The 2uS delay is not necessary. Just enabling the interrupt would let it sneak through. I tested it and it worked fine without it.


    The PIO should not be directly read. No need to do that. The ISR can load the value of the port when the interrupt happens. After all, it is only reading the port when it needs to be read - when a button is pressed.

    In the next log we'll take a look at Interrupts from the MCP23017 seen from the perspective of the PSoC and attempt to solve a problem that I am seeing.

View all 94 project logs

Enjoy this project?



Martin Lukasek wrote 04/19/2020 at 21:35 point

Nice, I did pretty similar design with PSoC 4200L and Signetics 2650 some time ago

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates