Reply - Raw
This is a reply to WgDDY-Da
Replies:
// 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ø <oddstr13@openshell.no>
// 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_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;
/*
  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 '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 '\r':
      case '\n':
        break;
      default:
        Serial.print("Unknown command: ");
        Serial.println(c);
    }
  }
}