// S6B0108/KS0108 LCD test code. // Arduino MEGA. // Data bus wired to PORT A. // Control signals wired to PORT C. // // Documents used for reference: // - http://www.pighixxx.com/test/pinouts/boards/mega.pdf // - http://www.cec-mc.ru/data/files/File/PDF/PG12864-H.PDF // - https://openlabpro.com/guide/ks0108-graphic-lcd-interfacing-pic18f4550-part-2/ // // Copyright (c) 2017 Odd Stråbø // License: MIT - https://opensource.org/licenses/MIT // const uint8_t DI_b = 0; const uint8_t RW_b = 1; const uint8_t E_b = 2; const uint8_t CS1_b = 3; const uint8_t CS2_b = 4; const uint8_t DI = _BV(DI_b); // HIGH == Data, LOW == Instruction const uint8_t RW = _BV(RW_b); // HIGH == Read, LOW == Write const uint8_t E = _BV(E_b); // LOW -> HIGH == Clock const uint8_t CS1 = _BV(CS1_b); // LOW == Select const uint8_t CS2 = _BV(CS2_b); // LOW == Select const bool REG_INSTRUCTION = 0; const bool REG_DATA = 1; const bool RW_READ = 1; const bool RW_WRITE = 0; const uint8_t STATUS_BUSY = _BV(7); const uint8_t STATUS_ONOFF = _BV(5); const uint8_t STATUS_RESET = _BV(4); const uint8_t DELAY = 10; void lcd_select_segment(uint8_t segment) { if (segment % 2 == 0) { // Select PORTC |= CS2; // Set CS2 HIGH PORTC &= ~CS1; // Set CS1 LOW } else { PORTC |= CS1; // Set CS1 HIGH PORTC &= ~CS2; // Set CS2 LOW } } void lcd_write(bool reg, const uint8_t data) { DDRA = 0; // Input // Clear everything but CS1 and CS2, then set DI(reg) PORTC = (PORTC & (CS1 | CS2)) | reg << DI_b; DDRA = 0xff; // Output PORTA = data; delayMicroseconds(DELAY); PORTC |= E; delayMicroseconds(DELAY); PORTC &= ~E; delayMicroseconds(DELAY); DDRA = 0; // Input } uint8_t lcd_read(bool reg) { DDRA = 0; // Input // Clear everything but CS1 and CS2, then set RW and DI(reg) PORTC = (PORTC & (CS1 | CS2)) | RW | reg << DI_b; delayMicroseconds(DELAY); PORTC |= E; delayMicroseconds(DELAY); uint8_t data = PINA; PORTC &= ~E; delayMicroseconds(DELAY); return data; } void lcd_read_ram(uint8_t *buf, uint8_t len) { DDRA = 0; // Input // Clear everything but CS1 and CS2, then set RW and DI(reg) PORTC = (PORTC & (CS1 | CS2)) | RW | REG_DATA << DI_b; for (uint8_t ptr=0; ptr < len; ptr++) { delayMicroseconds(DELAY); PORTC |= E; delayMicroseconds(DELAY); buf[ptr] = PINA; PORTC &= ~E; } delayMicroseconds(DELAY); } void lcd_write_ram(uint8_t *buf, uint8_t len) { DDRA = 0; // Input // Clear everything but CS1 and CS2, then set DI(reg) PORTC = (PORTC & (CS1 | CS2)) | REG_DATA << DI_b; DDRA = 0xff; // Output for (uint8_t ptr=0; ptr < len; ptr++) { PORTA = buf[ptr]; delayMicroseconds(DELAY); PORTC |= E; delayMicroseconds(DELAY); PORTC &= ~E; } delayMicroseconds(DELAY); DDRA = 0; // Input } void lcd_on() { lcd_write(REG_INSTRUCTION, 0b00111111); } void lcd_off() { lcd_write(REG_INSTRUCTION, 0b00111110); } uint8_t readStatus() { return lcd_read(REG_INSTRUCTION); } void lcd_set_page_address(uint8_t addr) { // address 0-63 lcd_write(REG_INSTRUCTION, 0b01000000 | (addr & 0b111111)); } void lcd_select_page(uint8_t page) { // page 0-7 lcd_write(REG_INSTRUCTION, 0b10111000 | (page & 0b111)); } /*** PAGE ***/ uint8_t pagebuf[64] = {}; void lcd_read_page() { lcd_set_page_address(0); // Dummy read. Data is moved from display RAM to output register on E falling edge. lcd_read(REG_DATA); lcd_read_ram(pagebuf, 64); } void lcd_read_page(uint8_t page) { lcd_select_page(page); lcd_read_page(); } void lcd_write_page() { lcd_set_page_address(0); lcd_write_ram(pagebuf, 64); } void lcd_write_page(uint8_t page) { lcd_select_page(page); lcd_write_page(); } /*** Application code ***/ void setup() { Serial.begin(115200); Serial.println("Setup start."); Serial.setTimeout(10); // put your setup code here, to run once: DDRA = 0; // PA Input DDRC = 0; PORTC = DI | CS1; // Default; Data Write on 2nd segment(CS2) DDRC = DI | RW | E | CS1 | CS2; lcd_on(); lcd_select_page(0); lcd_set_page_address(0); Serial.println("Setup end."); } uint8_t seq = 0; void loop() { static uint8_t page = 0; static uint8_t segment = 0; /* Serial.println(seq); lcd_set_page_address(seq); lcd_write(REG_DATA, seq); seq++; lcd_read_page(0); for (uint8_t i=0;i<64;i++) { Serial.print(i, DEC); Serial.print(": "); Serial.println(pagebuf[i], DEC); } delay(1000); */ if (Serial.available()) { char c = Serial.read(); switch (c) { case 'P': page = Serial.parseInt(); lcd_select_page(page); Serial.println("OK"); break; case 'S': segment = Serial.parseInt(); lcd_select_segment(segment); Serial.println("OK"); break; case 'I': // Page in lcd_read_page(page); Serial.write(pagebuf, 64); break; case 'O': Serial.readBytes(pagebuf, 64); lcd_write_page(page); Serial.println("OK"); break; case '1': lcd_on(); Serial.println("OK"); break; case '0': lcd_off(); Serial.println("OK"); break; case ' ': // Space and newline are not commands, silently skip. case '\r': case '\n': break; default: Serial.print("Unknown command: "); Serial.println(c); } } }