#include #include #include "display.h" void display_init() { // PC5, PC6, PC7: output (VFD RS, RW, E), RS=0, RW=1, E=1 // PD: output (VFD DB) - can be switched to input (pullup not needed) PORTC |= _BV(PC6) | _BV(PC7); DDRC |= _BV(PC5) | _BV(PC6) | _BV(PC7); PORTD = 0x00; DDRD = 0xff; } uint8_t display_read_ir() { // switch PD to input DDRD = 0x00; // E=0 (enable/clock) RS=0 (IR) RW=1 (read) PORTC = (PORTC & ~(_BV(PC5) | _BV(PC7))) | _BV(PC6); _delay_us(0.23); // E=1 (enable/clock) PORTC |= _BV(PC7); _delay_us(0.16); uint8_t data = PIND; _delay_us(0.23 - 0.16); // E=0 (enable/clock) PORTC &= ~_BV(PC7); _delay_us(0.01); // reset to idle PORTC = _BV(PC6) | _BV(PC7); DDRD = 0xff; return data; } uint8_t display_read_dr() { // switch PD to input DDRD = 0x00; // E=0 (enable/clock) RS=1 (IR) RW=1 (read) PORTC = (PORTC & ~_BV(PC7)) | (_BV(PC5) | _BV(PC6)); _delay_us(0.23); // E=1 (enable/clock) PORTC |= _BV(PC7); _delay_us(0.16); uint8_t data = PIND; _delay_us(0.23 - 0.16); // E=0 (enable/clock) PORTC &= ~_BV(PC7); _delay_us(0.01); // reset to idle PORTC = _BV(PC6) | _BV(PC7); DDRD = 0xff; return data; } void display_write_ir(uint8_t data) { // E=0 (enable/clock) RS=0 (IR) RW=0 (write) PORTC &= ~(_BV(PC5) | _BV(PC6) | _BV(PC7)); _delay_us(0.23); // E=1 (enable/clock) PORTC |= _BV(PC7); // data PORTD = data; _delay_us(0.23); // E=0 (enable/clock) PORTC &= ~_BV(PC7); _delay_us(0.01); // reset to idle PORTC = _BV(PC6) | _BV(PC7); PORTD = 0x00; } void display_write_dr(uint8_t data) { // E=0 (enable/clock) RS=1 (IR) RW=0 (write) PORTC = (PORTC & ~(_BV(PC6) | _BV(PC7))) | _BV(PC5); _delay_us(0.23); // E=1 (enable/clock) PORTC |= _BV(PC7); // data PORTD = data; _delay_us(0.23); // E=0 (enable/clock) PORTC &= ~_BV(PC7); _delay_us(0.01); // reset to idle PORTC = _BV(PC6) | _BV(PC7); PORTD = 0x00; } bool display_wait_ready() { // if the busy flag never goes high, we'll run into a deadlock here. // let's put a deadline on the wait loop. for (uint8_t i = 0; i < 100; i++) { // read_ir() takes about 500ns if (display_read_ir() & _BV(7)) return true; // wait 10us until the next status read _delay_us(10 - 0.5); } return false; } void display_write(uint8_t command, const uint8_t *data, uint8_t length) { if (display_wait_ready()) { display_write_ir(command); for (uint8_t i = 0; i < length; i++) { display_write_dr(data[i]); } } }