.Z80 ASEG ; absolute addressing ORG 100h ; skip CP/M CR EQU 0Dh ; carriage return LF EQU 0Ah ; new line BDOS EQU 0005h ; BDOS entry point PSTR EQU 09h ; print string CRED EQU 01h ; read console OLED EQU 50h ; base addr of OLED card ORST EQU 04h ; reset command (H) OBUF EQU 02h ; chip select (L), buffer (H) ODB EQU 01h ; display byte (H) OCMD EQU 00h ; command (L) ; 4 rows of display OROWA EQU 0B0h ; select top row OROWB EQU 0B1h ; select second row OROWC EQU 0B2h ; select third row OROWD EQU 0B3h ; select bottom row OCOL0 EQU 04h ; left most column OSELC EQU 10h ; select column command OCOLL EQU 80h ; column count: 128 columns ; 128 columns from 4 to 131 ; 1Xh, 0Yh - XY = 04h to 83h ; MAIN CALL OINIT ; init OLED CALL OCLS ; clear screen CALL PROMPT ; print prompt CALL OCSTART ; go to start CALL READLINE ; read row A CALL READLINE ; read row B CALL READLINE ; read row C CALL READLINE ; read row D RET ; exit to CP/M READLINE: LD D,OCOLL ; number of columns READLINE1: PUSH DE CALL READHEX ; read hex input from console CALL ODATA ; write to OLED POP DE DEC D ; count donw columns JP NZ,READLINE1 ; next column RET OINIT: CALL ORESET ; reset OLED LD HL,OINITSEQ ; commands to send OINITLOOP: LD A,(HL) ; load command byte to A CP 0FFh ; check if we are done RET Z ; marker reached CALL OCOMMAND ; send command from A INC HL ; next command JR OINITLOOP ; send next command ORESET: LD C,OLED ; base I/O address LD B,ORST OR OBUF ; RST H, /CS H, DB L OUT (C),A ; write any A, to (C) + B REPT 4 NOP ; delay ENDM LD B,OBUF ; clear RST OUT (C),A ; send REPT 20 NOP ; long delay ENDM RET OCLS: CALL OCSTART ; set start CALL OCLSROW ; clear row A CALL OCLSROW ; clear row B CALL OCLSROW ; clear row C CALL OCLSROW ; clear row D RET ; set cursor to start OCSTART: LD A,OSELC ; select column CALL OCOMMAND LD A,OCOL0 ; column 0 CALL OCOMMAND LD A,OROWA ; select first row CALL OCOMMAND RET OCLSROW: ;XOR A ; display byte to write (0) LD A,0FFh ; turn on all pixels LD D,OCOLL ; count columns in D OCLSROW1: CALL ODATA ; write A to displey DEC D ; next column JR NZ,OCLSROW1 RET ; A = command to send to OLED OCOMMAND: LD C,OLED ; base I/O LD B,OCMD ; send command OUT (C),A ; send REPT 4 NOP ENDM LD B,OCMD OR OBUF OUT (C),A ; send REPT 10 NOP ENDM RET ; Write to OLED memory ; A = graphic byte to dispaly memory ODATA: LD C,OLED ; base I/O LD B,ODB ; select Data Byte mode OUT (C),A ; output byte REPT 4 NOP ENDM LD B,OBUF OR ODB OUT (C),A ; output byte NOP NOP RET ; Read byte from console READ: LD C,CRED ; read from console CALL BDOS ; call CP/M RET ; A=CHAR ; Reads 4 bit value (0-F) READNIB: CALL READ LD B,41h ; compare with 'A' (10) CP B JP NC,RNB1 ; A>=B SUB 30h ; sub '0' RET RNB1: SUB 41h-10 ; sub 'A'-10 AND 0Fh ; clear to 4 bits so 'a-f' also work RET ; Reads two bytes (0-F) from console ; A = byte read READHEX: CALL READNIB ; read MSD nibble SLA A ; shift 4 bits SLA A SLA A SLA A LD B,A ; B=A PUSH BC ; save B CALL READNIB ; read LSD nibble POP BC ; restore B OR B ; OR B to A RET PROMPT: LD C,PSTR ; load function number LD DE,PROMPTMSG ; load string addr CALL BDOS ; call CP/M RET PROMPTMSG: DB 'OLED:>', CR, LF,'$' ; string terminated with $ ; Initialization sequence ; 081h,080h - set contrast (080h full) ; 020h,000h - set horizontal window wrapping ; 021h,004h,083h - window full width ; 022h,000h,003h - window full height OINITSEQ: DB 0AEh,0D5h,0A0h,0A8h DB 01Fh,0D3h,000h,0ADh DB 08Eh,0D8h,005h,0A1h DB 0C8h,0DAh,012h,091h DB 03Fh,03Fh,03Fh,03Fh DB 081h,070h,0D9h,0D2h DB 0DBh,034h,0A6h,0A4h DB 0AFh,020h,000h,021h DB 004h,083h,000h,003h DB 0FFh ; end marker END