diff --git a/main.c b/main.c index 120a23b..fd9ec7a 100644 --- a/main.c +++ b/main.c @@ -52,10 +52,26 @@ // the I²C address of this slave #define I2C_ADDR 0x28 +// the functions we can call over I²C enum i2c_mode_t { - MODE_INSTRUCTION, // read/write instruction/command - MODE_DATA, // read/write data - MODE_PORT, // read/write + // custom modes + MODE_CLEAR_DISPLAY, // clear display + MODE_LINE1, // write to line 1 + MODE_LINE2, // write to line 2 + MODE_DISPLAY_ON, // turn display on + MODE_DISPLAY_OFF, // turn display off + MODE_BRIGHTNESS, // set backlight brightness + + // raw instructions, directly mapping to HD44780 + MODE_DISPLAY, + MODE_RETURN_HOME, + MODE_ENTRY_MODE_SET, + MODE_CURSOR_DISPLAY_SHIFT, + MODE_FUNCTION_SET, + MODE_CGRAM_ADDR, + MODE_DDRAM_ADDR, + MODE_DATA, + MODE_COUNT, // number of modes }; @@ -269,7 +285,7 @@ void main(void) wait_10us(4 + 1); // wait 37 us (BF could be checked at this point) // we are now for sure in 8-bit more (and could switch do 4-bit). 8-bit mode is actually the default after power up IWDG_KR = IWDG_KR_KEY_REFRESH; // reset watchdog - hd44780_write_instruction(0x20); // function set: 4-bit mode + hd44780_write_instruction(0x28); // function set (DL=1: 4-bit mode, N=1: 2 lines, F=0: 5x8 dots) hd44780_write_instruction(0x08); // display off hd44780_write_instruction(0x01); // display clear hd44780_write_instruction(0x06); // entry mode set @@ -289,26 +305,63 @@ void main(void) if (i2c_input_new) { // this is the start of a transaction, the first byte indicates the mode to be used i2c_mode = input_data; // set user provided mode (no need to check since the undefined modes don't do anything) i2c_input_new = false; // clear flag + // process mode switch + switch (i2c_mode) { + case MODE_CLEAR_DISPLAY: // clear display + hd44780_write_instruction(0x01); // clear display instruction + break; + case MODE_LINE1: + hd44780_write_instruction(0x80); // set DDRAM address to 0 (line 1) + break; + case MODE_LINE2: + hd44780_write_instruction(0xc0); // set DDRAM address to 0x40 (line 2) + break; + case MODE_DISPLAY_ON: + hd44780_write_instruction(0x0c); // display on + break; + case MODE_DISPLAY_OFF: + hd44780_write_instruction(0x08); // display off + break; + case MODE_RETURN_HOME: + hd44780_write_instruction(0x02); // return home + break; + default: + break; // waiting for data + } } else { // process data // note set RS at every byte since read busy always switches it to instruction switch (i2c_mode) { - case MODE_PORT: + case MODE_LINE1: + case MODE_LINE2: + case MODE_DATA: + hd44780_write_data(input_data); + break; + case MODE_ENTRY_MODE_SET: + hd44780_write_instruction(0x04 | (input_data & 0x3)); + break; + case MODE_DISPLAY: + hd44780_write_instruction(0x08 | (input_data & 0x7)); + break; + case MODE_CURSOR_DISPLAY_SHIFT: + hd44780_write_instruction(0x10 | (input_data & 0xc)); + break; + case MODE_FUNCTION_SET: + hd44780_write_instruction(0x20 | (input_data & 0xc)); // keep DL=0 4-bit mode + break; + case MODE_CGRAM_ADDR: + hd44780_write_instruction(0x40 | (input_data & 0x3f)); + break; + case MODE_DDRAM_ADDR: + hd44780_write_instruction(0x80 | (input_data & 0x3f)); + break; + case MODE_BRIGHTNESS: if (input_data) { led_on(); } else { led_off(); } break; - case MODE_INSTRUCTION: - if (0x20 == (input_data & 0x20)) { // function set instruction - input_data &= ~(1 << 4); // ensure we stay in 4-bit mode - } - hd44780_write_instruction(input_data); - break; - case MODE_DATA: - hd44780_write_data(input_data); - break; default: // read values do not make sense break; }