Hardware test – 2nd phase

With the PCB’s in and the initial hardware check finished and me delaying far too long on getting back to this project, it was time to move on to verifying that my intended hardware functionality did, in fact, work as planned.  There are several functional blocks that need to be tested, both on the AVR and the Z80 support circuitry.

For this post, I’ll focus on three specific functional blocks:

  • AVR as the Z80 system clock
  • AVR interface with the DS3231 RTC module
  • AVR interface with the system, data and address buses

On past projects, especially when acquiring and evaluating various OEM samples to be used with a microcontroller, I’ve always found it time consuming to write different test programs over and over again.  Always having to configure, reconfigure, flash, test, debug, fix code, re-flash and do it all over again.  Those real-time debug cycles on any FLASH-based MCU can be very time consuming, which I sought out ways to cut the time.  To that end, I ran across Dick CappelsAttoBASIC back in 2011.  With some modifications to the code, I was able to fully support the TWI and SPI interfaces for the project I was working on at the time.  Since then, I have found it to be indispensable in evaluating new hardware devices and initial hardware testing when an AVR is the embedded microcontroller on a particular project, such as this Z80 SBC.  It also helps to be the AttoBASIC maintainer (since 2011) as I know the program well enough to add support for any feature if I find I have a need for it.  For the following initial hardware testing, I have been using AttoBASIC and to provide others with examples, I will provide each program listing that was used for the  testing.

With all the I/O ports that the ATMEL AT90USB1286 provides, I still found myself a little bit shy in ports.  I wanted to leave the JTAG interface and some A/D channels available, thus PORTF was not fully accessible.  I ended up using a 74HC299 to interface to the Z80 databus.  The 74HC299 is an “8-bit universal shift register with 3-state outputs“.  Its a nice part that comes in a 20-pin package.  I chose to use the DIP package for this project.  From the 74HC299 datasheet:

The 74HC299; 74HCT299 contain eight edge-triggered D-type flip-flops and the
interstage logic necessary to perform synchronous shift-right, shift-left, parallel load and
hold operations. An operation is determined by the mode select inputs S0 and S1, as
shown in Table 3.

Pins I/O0 to I/O7 are flip-flop 3-state buffer outputs which allow them to operate as data
inputs in parallel load mode. The serial outputs Q0 and Q7 are used for expansion in
serial shifting of longer words.

1st test, Z80 clock:  I had already tested this function on my breadboard using an assembly language program but that was with an ATmega328P.  It should work the same on the AT90USB1286 but I wanted to be sure … and it did.  Its a simple program; initialize all ports to their proper state,  setup TIMER 2 as the Z80 clock source and generate a pulse on the Z80 CLK pin.  The majority of the program listing is for documentation.   Here’s the AttoBASIC program listing:

5 REM Z80 POWER-UP INIT
10 REM PD2=IORQ, PD3=MREQ, PD4=WR, PD5=RD
15 REM PF1/PF0 = S1/S0 FOR WS-GEN
20 REM PB0=HC299_CS, PB6=HC299_OE, PB7=HC299_S1
25 REM PB4=Z80CLK, PE2=Z80RST, PD6=Z80BUSRQ
30 OPA $FF, OPC $FF         # SET ADDRESS PORT AS INPUTS W/ PUPS (C=A[15:8], A=A[7:0])
35 OPB $D0; ODB $D0         # SET PORTS
40 OPD $FF; ODD 0           # SET PORTS
45 OPE $F3; ODE $04         # SET PORTS
50 OPF $00; ODF $03         # SET PORTS
55 REM SETUP TMR2: TCCR2A(@$B0)=$42, TCCR2B(@$B1)=$01, OCR2A($B3)=$07
60 X:= PEEK 0 $64; X:= X AND $BF; POKE X 0 $64      # TMR2 ENABLE IN PRR0
65 POKE $3F 0 $B3; POKE $42 0 $B0; POKE $01 0 $B1   # SETUP TMR2 AS 125KHZ Z80 CLK
70 PBE2                                             # GENERATE A RESET PULSE TO CYCLE REGISTERS
75 END

2nd test, RAM R/W test:  To test the address, data and system control buses, I initially wrote a program to set the AVR’s I/O ports, then with the Z80 removed from the circuit, I wrote data to the RAM, read the data back from the RAM, incremented the address bus and repeated the cycle for all 65,536 bytes of RAM.  I then decided to expand upon that by testing the RAM with the Z80 in-circuit.  After all, that will be the final goal, to use the AVR as a host controller with the Z80 in-circuit.  Below is the logic analyzer’s capture of the AttoBASIC program that is testing RAM.  What is important to note here is that in testing the memory, I am also testing the AT16V8 address decoder.

I only have 16 channels available on my logic analyzer so I chose to capture the Z80’s DATA[7:0], ADDR[2:0], RD, WR, MREQ, BUSREQ and BUSACK, triggering on the falling edge of the BUSACK signal.  In doing so, I could test that the Z80 responds to a request for the bus, relinquishes the bus and acknowledges it.  During the test, the Z80’s clock was active and a reset pulse was applied before dropping the BUSREQ line and waiting for the BUSACK line to drop active low.  Once BUSACK was detected low, the program proceeded to sequentially test each RAM location. The address can be seen incrementing and although the scale is too large to see the contents of the data bus, a 0x55 is being written and read back then complimented so that a 0xAA is written and read back from the next location.  The state of the MREQ, RD and WR lines can also be seen.

screenshot-ram_test

RAM Test w/ AttoBASIC

I would not say that AttoBASIC was speedy when it came to testing, as sequential memory accesses took about 15.88 mS, which was about 63 bytes per second. As calculated, it would take 17 minutes and 19.4 seconds to complete the test if there were no errors to report.  In actuality, the AttoBASIC program reported that it took 17 minutes and 9.3 seconds to complete and there were no errors.  However slow it may be compared to pure assembly or “C” code, it served it’s purpose. The AttoBASIC program code is listed below:

5 REM Z80 RAM ERROR TEST
10 REM PD2=IORQ, PD3=MREQ, PD4=WR, PD5=RD
15 REM PB4=Z80CLK, PE2=Z80RST, PD6=Z80BUSRQ
20 REM PF1/PF0 = S1/S0 FOR WS-GEN
25 REM PB0=HC299_CS, PB6=HC299_OE, PB7=HC299_S1
30 SPM 2# SPI TO MODE 2
35 D:= $55; Z:=0                  # DATA TO WRITE=$55, Z HOLDS '0'
40 GOSUB 220                      # INSURE ALL PORTS AS INPUTS
45 GOSUB 225                      # START Z80 CLOCK AND INITIATE A Z80 RST
50 SDD6; CBD6                     # INITIATE Z80 BUSRQ
55 IF 1 = IBE0                    # WAIT FOR Z80 BUSACK
60 GOTO 55                        # LOOP TILL Z80 BUSACK
65 ODA $FF; OPA $00               # SET PORTA OUTPUT AND ADDRESS A[7:0] =0x00
70 ODC $FF; OPC $00               # SET PORTC OUTPUT AND ADDRESS A[15:8] =0x00
75 OPB '11010001; ODB '11010111   # SS=1 (SEL HC299), OE=1 (HI-Z), (S0=1/S1=1)
80 ODD '11111100; OPD '10111111   # CONTROL PORT TO OUTPUTS, ALL HIGH
85 ODE '00000100; OPE '11111111   # SET PORTE, INPUTS W/ PULL-UPS
90 ODF '00000011; OPF '11111100   # SET S0/S1 OUTPUTS FOR 0 WS
95 RTI 2; RTR                     # SET 100MS RTC INTERVAL AND RESET THE RTC
100 FOR U=0 255; FOR L=0 255      # SET UP THE UPPER AND LOWER ADDRESS LOOPS
105 OPC U; OPA L                  # OUTPUT CURRENT ADDRESS ONTO BUS
110 GOSUB 165                     # WRITE DATA TO THE RAM ADDRESS
115 GOSUB 180                     # READ DATA FROM THE RAM ADDRESS AND PRINT IT
120 SBD5; SBD3                    # RAISE THE Z80 RD AND MREQ SIGNAL
125 IF X != D                     # RESULT = EXECTED?
130 GOSUB 195                     # ERROR, INFORM USER
135 D:= COM D                     # COMPLIMENT DATA TO WRITE (ODD/EVEN ADDR)
140 NEXT L; NEXT U                # CONTINUE INCREMENT LOOP
145 PRI PEEK VPG@RTC1; PRI PEEK VPG@RTC0  # PRINT THE CONTENTS OF THE RTC (IN 0.1 SEC)
150 ODA $FF; ODB $FF; ODC $FF; ODD $FF    # SET ALL PORTS TO INPUTS
155 END
160# *** WRITE DATA TO DATA BUS ***
165 CBB7; SPW D; CBB6; CBD3            # SHIFT ENABLE, WRITE DATA='D', ENABLE DATA ONTO                                                                                   #  BUS, DROP Z80 MREQ
170 CBD4; SBD4; SBD3; SBB6; SBB7; RET  # PULSE Z80 WR, RAISE Z80 MREQ, OE=1,S1=1 THEN RETURN
175# *** READ DATA FROM DATA BUS ***
180 CBD3; CBD5; SPW 0; SBD5; SBD3      # DROP Z80 MREQ, DROP Z80 RD, DUMMY WRITE TO                                                                                            # LOAD, RAISE Z80 RD, RAISE Z80 MREQ
185 CBB7; X:= SPR; SBB7; RET           # S1=0, 'X'=READ DATA, S1=1 THEN RETURN
190# *** PRINT ERROR MESSAGE *** ;
195 PRI "ERROR DETECTED AT:~"          # INFORM USER OF ERROR IN TESTING
200 PRI "A[15:8]="; PRX U              # INFORM USER OF UPPER ADDRESS
205 PRI "A[ 7:0]="; PRX L              # INFORM USER OF LOWER ADDRESS
210 PRI "EXPECTED= "; PRX D; PRI "RESULT = "; PRX X
215 PRINT "~"; RET                     # INSERT CR/LF BETWEEN ADDRESSES
220 ODA Z; ODB Z; ODC Z; ODD Z; ODE Z; ODF Z; RET   # ALL PORTS TO INPUTS
222 REM SETUP TMR2: TCCR2A(@$B0)=$42, TCCR2B(@$B1)=$01, OCR2A($B3)=$07
225 X:= PEEK 0 $64; X:= X AND $BF; POKE X 0 $64     # TMR2 ENABLE IN PRR0
230 SDB4; POKE 63 0 $B3; POKE $42 0 $B0; POKE 1 0 $B1  # SETUP TMR2 AS 1MHZ Z80 CLK
235 SDE2; SBE2; PBE2; RET              # GENERATE A RESET PULSE TO CYCLE REGISTERS AND RETURN

DS3231 RTC test:  The AVR is directly connected to the DS3231 RTC via the I2C (TWI) bus.  I had already written a program to interface with a TEXAS INSTRUMENTS bq32000, which is also a real-time clock with a nearly identical register set as the DS3231.  It took only a slight modification to that program and I was able to test the DS3231.  The program sets the date and time to a set value, waits 4 second, reads it back again and displays the result. The AttoBASIC program code is listed below:

5 REM DS3231 RTC TEST
10 TWI 1                               # INIT TWI @100kbps
15 A:= $D0 ; B:= $D1                   # WRITE AND READ ADDRESSES FOR BQ32000 RTC
20# *** CONFIGURE THE DS3231
25 TWS ; TWW A $E 0; TWP               # write config register
30# *** INITIALIZE TIME AND DATE DATA TO RTC REGISTERS
35 DATA $00 $00 $60 $00 $22 $12 $16    # setup RTC's time and date
40 FOR Z=0 6                           # set data registers 0 to 6
45 R:=Z ; D:= READ                     # set register and data
50 TWS; TWW A R D; TWP                 # Write data to a register
55 NEXT                                                                   # end of loop
60# *** WAIT A BIT FOR THE SECONDS TO CHANGE THEN READ THE REGISTERS BACK
65 PRINT "Wait 4 sec~" ; SLP 8         # wait 4 seconds to see if the clock is running
70 TWS; TWW A 0                        # Select register 0, no STOP
75 TWS; TWW B; TWR 7; TWP              # slave to read and retrieve 7 bytes
80# *** LOOP AND PRINT EACH REGISTER'S VALUE
85 FOR R=0 6                           # Loop from register 0 to 6
90 PRINT "R:" ; PRI R                  # print the register
95 PRINT "D=" ; PRX READ               # print the data in the register
100 NEXT                               # end of loop
105 END

I did not test the wait-state generator as it was previously tested on the breadboard circuit, thus I already know it works.

An additional note: the overall current consumption is measured at ≈250 ma.

This completes the testing of the major functional blocks on the Z80 SBC.  The next phase is to start writing the AVR host controller firmware.

Peace and blessings.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s