Return to Section List Return to Menu
= = = 3. ADD PERIPHERALS = = =
Although your processor is now fully operational, it cannot store a lot of information, and it does not output human friendly text. In this section, you will add flash memory, a keypad, and an alphanumeric screen to your machine.
= BUY THE SECOND ROUND OF COMPONENTS =
Find the list of components on this page. Purchase all of the "second round" components. Be patient; delivery is not instantaneous!
= REMOVE DEBUG PORTS =
If you have been purchasing the components as instructed, you should only have 6 breadboards and 12 flip flops. This means you will not have enough parts or space to keep the debug ports. Unplug the debug input and debug output ports to allow for more exciting ports.
= HOOK UP THE SCREEN =
Plug in the "display data" and "display signal" flip flops as shown on the breadboard layout. You will need to connect the data bus to these display chips and other nearby flip flops. For convenience of wiring, consider plugging in some of the supporting flash flip flops and wiring them to the data bus. Use the schematic when wiring together the flip flops. "display data" should have mapped memory address 000C, while "display signal" should have address 100C.
Next you will need to do a bit of soldering. If you don't know how to solder, please refer to this video:
How and WHY to Solder Correctly
Connect a reasonably long wire to each of the pins on the alphanumeric screen. Be careful not to form bridges between different pins.
Attach the other end of each wire to the display flip flops. Look at the data sheet for both the flip flops and the screen, then follow this connection diagram:
If you don't use this wiring convention, the example programs will not work.
To test the screen connections, try this "hello world" program:
@@@ Move pointer forward by 1. P incrementPointer /P pointer_ [ N upperByte upperByte |<< second /pointer_ N lowerByte lowerByte |<< first /pointer_ lowerByte |<< increment /lowerByte_ ifNot /lowerByte_ [ upperByte |<< increment /upperByte_ ] incrementPointer |<< pair /lowerByte, upperByte_ ] @@@ I/O address for the alphanumeric screen. P screenDataAddress P screenSignalAddress screenDataAddress |<< pair /0, 192_ screenSignalAddress |<< pair /1, 192_ @@@ Send data and signals to the screen. V outputScreen /N data, N signal1, N signal2_ [ output /screenDataAddress, data_ output /screenSignalAddress, signal1_ output /screenSignalAddress, signal2_ ] @@@ Erase half of the screen. V clearScreenHalf /_ [ outputScreen /screen#1, 2, 0_ ] @@@ The bytes to send to the display in @@@ order to wake it up. C B}7 wakeDataSet wakeDataSet |<< /screen#48, screen#48, screen#48, screen#56, screen#8, screen#6, screen#12_ @@@ Wake up half of the screen. V wakeScreenHalf /_ [ P source source |<< reference /wakeDataSet_ N count count |<< ?wakeDataSet? while /count_ [ N data data |<< read /source_ outputScreen /data, 2, 0_ source |<< incrementPointer /source_ count |<< decrement /count_ ] ] @@@ Actually wake and clear half of the @@@ screen for the first time. wakeScreenHalf /_ clearScreenHalf /_ @@@ A test message to display. C B}20 testMessage testMessage |<< "HELLO WORLD!" @@@ Write each character of the test @@@ message to the screen. P testMessagePointer testMessagePointer |<< reference /testMessage_ N count count |<< ?testMessage? while /count_ [ N data data |<< read /testMessagePointer_ outputScreen /data, 6, 4_ testMessagePointer |<< incrementPointer /testMessagePointer_ count |<< decrement /count_ ]
Note that this is not machine code; it is Piston code. To compile Piston code into machine code, first navigate to this page to obtain Fabrication code, then use this page to assemble Fabrication code into machine code.
As you have in the past, convert the machine code into EEPROM programmer code, and then use your Arduino to enter the data. Sometimes the programmer code may be separated by line breaks. In this case, install each data block one at a time.
Run the "hello world" program using the slow clock. If everything worked OK, your machine should print "HELLO WORLD!" on the screen. If the program malfunctioned, add 1000 picofarad capacitors between the display flip flop WE pins and source. This will stabilize any noise in the circuit.
= HOOK UP THE KEYPAD =
Plug in and hook up another flip flop for the keypad. Let the keypad have address 900C in mapped memory. Connect the flip flop WE to the clock oscillator. This will ensure that input is frequently copied into the flip flop.
On an empty portion of breadboard, place 8 tactile push buttons. Attach each button to a keypad flip flop input:
Place a 100 kOhm resistor between each flip flop input and ground. This will ensure that the inputs default to a LOW state.
Test the keypad with this Piston program:
@@@ Move pointer forward by 1. P incrementPointer /P pointer_ [ N upperByte upperByte |<< second /pointer_ N lowerByte lowerByte |<< first /pointer_ lowerByte |<< increment /lowerByte_ ifNot /lowerByte_ [ upperByte |<< increment /upperByte_ ] incrementPointer |<< pair /lowerByte, upperByte_ ] @@@ I/O address for the alphanumeric screen. P screenDataAddress P screenSignalAddress screenDataAddress |<< pair /0, 192_ screenSignalAddress |<< pair /1, 192_ @@@ Send data and signals to the screen. V outputScreen /N data, N signal1, N signal2_ [ output /screenDataAddress, data_ output /screenSignalAddress, signal1_ output /screenSignalAddress, signal2_ ] @@@ Erase half of the screen. V clearScreenHalf /_ [ outputScreen /screen#1, 2, 0_ ] @@@ The bytes to send to the display in @@@ order to wake it up. C B}7 wakeDataSet wakeDataSet |<< /screen#48, screen#48, screen#48, screen#56, screen#8, screen#6, screen#12_ @@@ Wake up half of the screen. V wakeScreenHalf /_ [ P source source |<< reference /wakeDataSet_ N count count |<< ?wakeDataSet? while /count_ [ N data data |<< read /source_ outputScreen /data, 2, 0_ source |<< incrementPointer /source_ count |<< decrement /count_ ] ] @@@ Actually wake and clear half of the @@@ screen for the first time. wakeScreenHalf /_ clearScreenHalf /_ @@@ The I/O address of the keypad. P keyDataAddress keyDataAddress |<< pair /9, 192_ @@@ The main program loop. while /1_ [ N keyData keyData |<< 0 whileNot /keyData_ [ keyData |<< read /keyDataAddress_ ] outputScreen /screen#65, 6, 4_ while /keyData_ [ keyData |<< read /keyDataAddress_ ] ]
While the program is running, press any keypad button. Each time you press a button, the processor will print the letter "A" to the screen. If the program does not work, examine the keypad flip flop OE pin with an LED. If the LED does not periodically blink, the program is not reading keypad port data.
= HOOK UP FLASH MEMORY =
The flash memory requires several ports to operate. Plug in a flip flop for each port as shown on the breadboard layout. Attach each flip flop to the data bus and control signals. Feed the clock oscillator into the WE of the flash output port. This will constantly copy data from the flash chip to the flip flop.
Plug in the flash chip, and use this connection diagram for wiring:
This is the convention used by DUO OS.
Here is a test program for the flash chip:
@@@ XOR together the corresponding bits of two bytes. N xor /N data1, N data2_ [ N temp1 N temp2 temp1 |<< or /data1, data2_ temp2 |<< and /data1, data2_ temp2 |<< not /temp2_ xor |<< and /temp1, temp2_ ] @@@ Returns 1 if value is 0; returns 0 otherwise. N booleanNot /N value_ [ booleanNot |<< 1 if /value_ [ booleanNot |<< 0 ] ] @@@ Test equality of two bytes. N equal /N num1, N num2_ [ equal |<< xor /num1, num2_ equal |<< booleanNot /equal_ ] @@@ Move pointer forward by 1. P incrementPointer /P pointer_ [ N upperByte upperByte |<< second /pointer_ N lowerByte lowerByte |<< first /pointer_ lowerByte |<< increment /lowerByte_ ifNot /lowerByte_ [ upperByte |<< increment /upperByte_ ] incrementPointer |<< pair /lowerByte, upperByte_ ] @@@ I/O address for the alphanumeric screen. P screenDataAddress P screenSignalAddress screenDataAddress |<< pair /0, 192_ screenSignalAddress |<< pair /1, 192_ @@@ Send data and signals to the screen. V outputScreen /N data, N signal1, N signal2_ [ output /screenDataAddress, data_ output /screenSignalAddress, signal1_ output /screenSignalAddress, signal2_ ] @@@ Erase half of the screen. V clearScreenHalf /_ [ outputScreen /screen#1, 2, 0_ ] @@@ The bytes to send to the display in @@@ order to wake it up. C B}7 wakeDataSet wakeDataSet |<< /screen#48, screen#48, screen#48, screen#56, screen#8, screen#6, screen#12_ @@@ Wake up half of the screen. V wakeScreenHalf /_ [ P source source |<< reference /wakeDataSet_ N count count |<< ?wakeDataSet? while /count_ [ N data data |<< read /source_ outputScreen /data, 2, 0_ source |<< incrementPointer /source_ count |<< decrement /count_ ] ] @@@ Actually wake and clear half of the @@@ screen for the first time. wakeScreenHalf /_ clearScreenHalf /_ @@@ Pause for a short time. V sleep /N count_ [ while /count_ [ count |<< decrement /count_ ] ] @@@ I/O address for flash chip. P flashOutputAddress P flashInputAddress P bottomFlashAddressAddress P middleFlashAddressAddress P flashSignalAddress flashOutputAddress |<< pair /8, 192_ flashInputAddress |<< pair /2, 192_ bottomFlashAddressAddress |<< pair /3, 192_ middleFlashAddressAddress |<< pair /4, 192_ flashSignalAddress |<< pair /5, 192_ @@@ Store flash address and signal between @@@ function calls. N currentFlashSignal N currentTopFlashAddress currentFlashSignal |<< 224 currentTopFlashAddress |<< 0 @@@ Set the selected flash address @@@ without changing the signal. V selectFlashAddress /P address, N topAddress_ [ N data data |<< first /address_ output /bottomFlashAddressAddress, data_ data |<< second /address_ output /middleFlashAddressAddress, data_ currentTopFlashAddress |<< topAddress data |<< or /currentFlashSignal, currentTopFlashAddress_ output /flashSignalAddress, data_ ] @@@ Send a signal to flash while @@@ keeping the address constant. V signalFlash /N signal_ [ currentFlashSignal |<< signal N data data |<< or /currentFlashSignal, currentTopFlashAddress_ output /flashSignalAddress, data_ ] @@@ Set all flash operations to @@@ inactive. signalFlash /224_ @@@ Output a value to flash. This @@@ does not actually write a value @@@ unless you follow the chip @@@ security protocol. V outputFlash /P address, N topAddress, N value_ [ signalFlash /96_ output /flashInputAddress, value_ selectFlashAddress /address, topAddress_ signalFlash /64_ signalFlash /96_ ] @@@ Erases a sector in flash. A sector @@@ is 4096 bytes long. V eraseFlash /P address, N topAddress_ [ P tempAddress tempAddress |<< pair /58, 26_ outputFlash /tempAddress, 2, 170_ tempAddress |<< pair /197, 5_ outputFlash /tempAddress, 1, 85_ tempAddress |<< pair /58, 26_ outputFlash /tempAddress, 2, 128_ tempAddress |<< pair /58, 26_ outputFlash /tempAddress, 2, 170_ tempAddress |<< pair /197, 5_ outputFlash /tempAddress, 1, 85_ outputFlash /address, topAddress, 48_ sleep /255_ sleep /255_ ] @@@ Writes a value into flash. The @@@ sector must be erased first. V writeFlash /P address, N topAddress, N value_ [ P tempAddress tempAddress |<< pair /58, 26_ outputFlash /tempAddress, 2, 170_ tempAddress |<< pair /197, 5_ outputFlash /tempAddress, 1, 85_ tempAddress |<< pair /58, 26_ outputFlash /tempAddress, 2, 160_ outputFlash /address, topAddress, value_ ] @@@ Reads a value from flash. N readFlash /P address, N topAddress_ [ signalFlash /160_ selectFlashAddress /address, topAddress_ readFlash |<< read /flashOutputAddress_ ] @@@ Feedback messages for the test. C B}5 positiveFeedback C B}5 negativeFeedback positiveFeedback |<< "GOOD " negativeFeedback |<< "BAD " @@@ Write positive or negative feedback. V displayFeedback /N which_ [ P messagePointer if /which_ [ messagePointer |<< reference /positiveFeedback_ ] ifNot /which_ [ messagePointer |<< reference /negativeFeedback_ ] N count count |<< 5 while /count_ [ N data data |<< read /messagePointer_ outputScreen /data, 6, 4_ messagePointer |<< incrementPointer /messagePointer_ count |<< decrement /count_ ] ] @@@ The main program loop. P testSector P testAddress testSector |<< pair /0, 48_ testAddress |<< pair /17, 49_ N count count |<< 3 while /count_ [ eraseFlash /testSector, 1_ writeFlash /testAddress, 1, count_ N data data |<< readFlash /testAddress, 1_ N bool bool |<< equal /data, count_ displayFeedback /bool_ count |<< decrement /count_ ]
The program will attempt to write values to a flash sector. If the flash chip reads back the same values, the program will print "GOOD" to the screen; otherwise "BAD". The program must erase the sector each time by entering a security sequence. If the program does not work on your machine, make sure that your wiring matches the convention shown earlier. Incorrect wiring will cause the security sequence to fail.
= RUN AT FULL SPEED =
Now that you have checked all functionality of the CPU, you can use a faster clock oscillator. Create the circuit in the diagram below:
Whenever you are ready to run a program, attach the oscillator to the decade counter clock input. The code should run very quickly. If the program does not work properly, try placing 1000 picofarad capacitors between various WE pins and source. In addition, you can adjust the CPU speed by using different decade counter outputs.
Good job! You have finished constructing your DUO Compact!