The code on this page presents examples of Armpit Scheme consoles whereby a PS/2 keyboard and on- or off-board LCD can be used as input-output ports for standalone systems. The examples are updates from previous versions that incorporate version-specific aspects such as the use of inexact->exact in the LCD drawing examples (below) and also provide ARMSchembly source code. Output to LCD includes pixel setting, area fills and text that scrolls when the bottom of the screen is reached. The PS/2 keyboard data is obtained via an Interrupt Service Routine (ISR) that echoes entered characters to the attached LCD output port. Both the LCD and PS/2 routines include assembled machine code installed above the heap that provides for nice performance. The code has been tested on a total of five boards: 1) Olimex LPC2478-STK (320x240, 24-bit color, within-MCU controller, on-board LCD); 2) Luminary Micros IDM-L35 (320x240, 16-bit color, SSD2119 controller, on-board LCD) and, 3),4),5) SparkFun Electronics Nokia-like LCD (128x128, 8-bit color, S1D15G00 controller) on Olimex LPC-H2214 and NewMicros Tiny2106 and Tiny2138. On the PS/2 side, both a Microsoft keyboard with USB-to-PS/2 converter and an i-concepts Classic Keyboard (native PS/2, $10.49 from K-mart) were found to work properly while a WK-610 USB mini-keyboard with USB-PS/2 converter did not work (Keyboard LEDs flashed, dimmed or stayed on -- indicating potential power-up issues).
The LCD output port is compatible with Armpit Scheme built-in character output ports, especially the uart port. It is an improper list in which the car is a list of port information and the cdr is a vector of port type and action primitives:
((address status font) . #(type close write-chr/str write/dsp putc lcdptc lcdcmd restor scrollup))This LCD full output port is named lcop in the code below. The port information list contains a useful port address (or zero), a port status vector and a font vector (if needed, i.e. if characters will be written to the LCD). The address is set to the start of the in-RAM screen buffer on the LPC2478 (within MCU LCD controller) and to zero on the IDM-L35 and nokia-like LCD that have screen buffers within the LCD controller (external to the MCU realm). The status vector contains the current row and column for character writing, the top and bottom row of the screen (for scrolling), the foreground and background text colors and the number of text rows and columns of the screen. The font vector (if used) contains a 30-bit font for 96 printable characters, each in a 6 pixel rows x 5 pixel columns character box format. The font for each character is stored as a single 30-bit integer and its MSb is the top-left pixel of the character, the second MSb is the pixel to the right of the top-left pixel, and so on.
The LCD primitive port vector contains one port type integer and up to 8 primitives. The port type, and the close, write-char/string, and write/display primitives are copied from the uart output port built into Armpit Scheme. The putc function is adapted to LCD use and calls helper primitive functions lcdptc, lcdcmd and/or scrollup as needed (restor is not used). On the IDM-L35 and systems using the nokia-like LCD, the lcdcmd primitive is also used to send commands to the LCD controller during LCD initialization and by drawing functions such as (pixel ...) and (fill ...). On these systems, the Scheme primitive (wlcd ...) is used to call lcdcmd from Scheme.
The code of the LCD subsystem of the console is separated into two parts. The first part enabled the LCD and allows the user to perform drawing functions (pixel setting, area filling) and is stored in an on-chip file named "init-lcd-draw". The second-part of the code is stored in an on-chip file named "init-lcd-write" and adds font, character writing and screen scrolling to the output port. Both parts are needed for a console but only the first is needed to run the drawing examples below. The Corresponding Armpit Scheme code files are: Nokia-like LCD Draw, Nokia-like LCD Write, LPC2478-STK LCD Draw, LPC2478-STK LCD Write, IDM-L35 LCD Draw, IDM-L35 LCD Write. In the case of the nokia-like LCD, one can select the appropriate connection pins between MCU board and LCD at the top of the DRAW file (the pins are gpios as a bit-bang interface is implemented).
When both the draw and write files are loaded, one can write text to the LCD, or even set the LCD as the current output port. For example:
armpit> (write 100 lcop) armpit> (display "hello" lcop) armpit> (define ocop (current-output-port)) ; save the current output-port armpit> (define (current-output-port) lcop) ; set default output to LCD armpit> 100 armpit> "hello"LCD text status is obtained from (cadar lcop) and vector-ref and vector-set! operations on (cadar lcop) can be used to modify foreground and background colors (among others). The function (cls) clears the screen to its background color.
The code below is a test of LCD drawing functions. It is saved in a file named "init-lcd-test" and can be executed by loading the file. Each test ends by pressing a key on the keyboard. The tests include a cosine wave, grid, checkerboard and moving rectangle (with wait loop). They are designed for a 128x128 LCD with 8-bit color but also work on the larger LCDs. Be sure to paste only one of the 2 color definitions: 8-bit for a Nokia-type LCD or 24-bit for corresponding LCDs. The tests mainly give an idea of the performance of the interface.
;------------------------------------------------------------- ; TESTING LCD draw functions ;------------------------------------------------------------- ; open an output file for the tests (define p (open-output-file "init-lcd-test")) ; define colors -- 8-bit (write '(begin (define color1 #x1c) (define color2 #x07) (define color3 #xe0) (define color4 #xe0) (define color5 #x1c)) p) ; define colors -- 24-bit (write '(begin (define color1 #xff00) (define color2 #xff0000) (define color3 #xff) (define color4 #xff) (define color5 #xff00)) p) ; cosine (write '(begin (cls) (let loop ((x 0)) (if (> x 129) #t (begin (pixel x (inexact->exact (round (+ 64 (* -50 (cos (/ x 10)))))) color1) (loop (+ x 1))))) (read-char) (cls)) p) ; grid (write '(begin (cls) (let vlin ((x 0)) (if (> x 128) #t (begin (fill x 2 x 130 color2) (vlin (+ x 8))))) (let hlin ((y 2)) (if (> y 130) #t (begin (fill 0 y 127 y color2) (hlin (+ y 8))))) (read-char) (cls)) p) ; checkerboard (write '(begin (cls) (let rlop ((y 3)) (if (> y 123) #t (let clop ((x 1)) (if (> x 121) (rlop (+ y 32)) (begin (fill x y (+ x 15) (+ y 15) color3) (clop (+ x 32))))))) (let rlop ((y 19)) (if (> y 123) #t (let clop ((x 16)) (if (> x 121) (rlop (+ y 32)) (begin (fill x y (+ x 15) (+ y 15) color3) (clop (+ x 32))))))) (read-char) (cls)) p) ; moving rectangle (write '(begin (cls) (let mlop () (if (char-ready?) (read-char) (begin (fill 0 60 40 70 #xe0) (let rlop ((x 0)) (let wlop ((n 100)) (if (zero? n) #t (wlop (- n 1)))) (if (> x 88) #t (begin (fill (+ x 41) 60 (+ x 41) 70 color4) (fill x 60 x 70 #x00) (rlop (+ x 1))))) (let rlop ((x 88)) (let wlop ((n 100)) (if (zero? n) #t (wlop (- n 1)))) (if (< x 0) #t (begin (fill (+ x 41) 60 (+ x 41) 70 #x00) (fill x 60 x 70 color5) (rlop (- x 1))))) (mlop)))) (cls)) p) ; close the file (close-output-port p)
The PS/2 keyboard Interrupt Service Routine (ISR) is used to complete the standalone Armpit Scheme console with keyboard input. The PS/2 keyboard requires a regulated 5 Volt power supply which can come from the board in most of the test systems but needs to be supplied externally on the LPC-H2214. Three types of ISRs are used. On systems that have appropriate timer/counters (LPC2478-STK and Tiny2138), the counter functionality is used to acquire keyboard scan code bits. On the IDM-L35, gpio edge detection interrupts are used for that same purpose. On the Tiny-2106 and LPC-H2214, level-triggered external interrupts are used to clock the keyboard data in. The ISRs are otherwise nearly identical in the way they convert scan codes to ASCII characters and process backspaces and breaks (ctrl-c). All ISRs are also linked at install time to echo characters to the LCD and store them in the readbuffer for evaluation by the rep.
The PS/2 keyboard ISR code files are: PS/2 Keyboard ISR via Counter, PS/2 Keyboard ISR via External Interrupt, PS/2 Keyboard ISR via GPIO Edge Interrupt (Cortex-M3). Each code file applicable to multiple MCUs contains MCU-specific definitions at the top of the code only. The code writes the ISR, pin configuration and initialization to an on-chip file named "init-lcd-ps2". The file also sets the current-output-port to be the LCD port such that a standalone Armpit Scheme console results from loading "init-lcd-draw", "init-lcd-write" and "init-lcd-ps2" in sequence. A sample boot file performing this function can be defined using (note: on the LPC-H2214, P0.3 must be at 3.3V for the boot file to be read at startup and it seems that attaching an LCD somehow tends to pull P0.3 low):
(let ((p (open-output-file "boot"))) (write '(begin (load "init-lcd-draw") (load "init-lcd-write") (load "init-lcd-ps2")) p) (close-output-port p))