From 6746d34b2f7aba60b3fb6b9733aa8d5d79528cec Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 9 Sep 2021 20:19:40 +0200 Subject: [PATCH 1/3] Handle switch input The `input` enum is extended with `click` and `hold` values and all dependencies are adapted to that. In order to handle the `click` input an interrupt is used. Further, for handling held button input with the switch the Timer/Counter1 compare match interrupt with OCR1A is used. --- firmware/src/main.c | 50 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/firmware/src/main.c b/firmware/src/main.c index f70b58d..93515ff 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -58,7 +58,7 @@ static const struct symbol sym_9 = { 5, { 0xF8, 0xFC, 0x8C, 0xFC, 0xF8, static const struct symbol sym_setup = { 19, { 0xF8, 0x98, 0xB8, 0x00, 0xF8, 0x98, 0x18, 0x00, 0x18, 0xF8, 0x18, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x98, 0xF8, 0x1D, 0x19, 0x1F, 0x00, 0x1F, 0x19, 0x18, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x00, 0x1F, 0x01, 0x01 } }; -enum input {cw, ccw}; +enum input {cw, ccw, click, hold}; static enum state {home} current_state = home; static enum home_state {ch1, ch2, ch3, setup} current_home_state = ch1; @@ -253,6 +253,10 @@ static void update_home(enum input event) { current_home_state = setup; lcd_home(); break; + case click: + break; + case hold: + break; } } @@ -310,12 +314,45 @@ ISR(PCINT0_vect) { break; } - // TODO: proper debounce and dechattering + // TODO: proper dechattering _delay_us(100); sei(); } +// encoder button interrupt +ISR(PCINT1_vect) { + cli(); + + if (PINC & (1 << PC0)) { // release + TCCR1B &= (0 << CS11) & (0 << CS10); // Disable Timer/Counter1 + if (TCNT1 != 0) { + update_state(click); // Switch to selected state + TCNT1 = 0; + } + } else { // press + if (!(TCCR1B & (1 << CS10))) { + TCCR1B |= (1 << CS11) | (1 << CS10); // Enable Timer/Counter1 + } + } + + // TODO: proper debouncing + _delay_us(70); + + sei(); +} + +// Timer/Counter1 compare match A +ISR(TIMER1_COMPA_vect) { + cli(); + + TCCR1B &= (0 << CS11) & (0 << CS10); // Disable Timer/Counter1 + TCNT1 = 0; + update_state(hold); + + sei(); +} + int main(void) { // FastPWM: 1.25kHz // TODO: Try to get the backlit even more dim @@ -334,6 +371,15 @@ int main(void) { PCICR |= (1 << PCIE0); PCMSK0 |= (1 << PCINT6) | (1 << PCINT7); + // Encoder switch setup + PORTC |= (1 << PC0); + PCICR |= (1 << PCIE1); + PCMSK1 |= (1 << PCINT8); + + // Timer1 setup to recognize held button + OCR1A = 8192; + TIMSK1 |= (1 << OCIE1A); // Enable match compare A + // Show splash screen and load the menu lcd_splash(); _delay_ms(250); From 9c496e765d4750e813e356920d1aff8f81c5e837 Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 9 Sep 2021 20:40:50 +0200 Subject: [PATCH 2/3] Refactor state handling In order to improve the handling of states the `state` enum is also used for saving the `home_state`, which was previously called `current_home_state`. All dependent functions were adapted to the change. The `volatile` keyword was added to some variables. --- firmware/src/main.c | 53 ++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/firmware/src/main.c b/firmware/src/main.c index 93515ff..b7ac373 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -60,10 +60,10 @@ static const struct symbol sym_setup = { 19, { 0xF8, 0x98, 0xB8, 0x00, 0xF8, 0x9 enum input {cw, ccw, click, hold}; -static enum state {home} current_state = home; -static enum home_state {ch1, ch2, ch3, setup} current_home_state = ch1; +static volatile enum state {home, ch1, ch2, ch3, setup} current_state = home; +static volatile enum state home_state = ch1; -static uint8_t enc = 0; +static volatile uint8_t enc = 0; void spi_init(void) { SPI_DDR |= (1 << SPI_SCK) | (1 << SPI_MOSI) | (1 << SPI_SS); @@ -169,7 +169,7 @@ static void lcd_home(void) { bool ch3_selected = false; bool setup_selected = false; - switch(current_home_state) { + switch(home_state) { case ch1: ch1_selected = true; break; @@ -239,21 +239,39 @@ static void lcd_home(void) { } } +static void change_state(enum state new_state) { + switch(new_state) { + case home: + lcd_home(); + current_state = home; + break; + case ch1: + break; + case ch2: + break; + case ch3: + break; + case setup: + break; + } +} + static void update_home(enum input event) { switch (event) { case cw: - current_home_state++; - if (current_home_state > setup) - current_home_state = ch1; + home_state++; + if (home_state > setup) + home_state = ch1; lcd_home(); break; case ccw: - current_home_state--; - if (current_home_state > setup) - current_home_state = setup; + home_state--; + if (home_state > setup) + home_state = setup; lcd_home(); break; case click: + change_state(home_state); break; case hold: break; @@ -265,14 +283,13 @@ static void update_state(enum input event) { case home: update_home(event); break; - } -} - -static void change_state(enum state new_state) { - switch(new_state) { - case home: - lcd_home(); - current_state = home; + case ch1: + break; + case ch2: + break; + case ch3: + break; + case setup: break; } } From 19c0f141a496d1f3b9a7ee62e8c1e5c53a6c794c Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 9 Sep 2021 20:50:52 +0200 Subject: [PATCH 3/3] Add setup screen In order to draw the setup screen, several character symbols are added. The `lcd_setup` function, which draws the setup screen, as well as the `update_setup` function, that updates the setup screens state, are added. --- firmware/src/main.c | 144 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/firmware/src/main.c b/firmware/src/main.c index b7ac373..99d9146 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -29,10 +29,38 @@ struct symbol { uint8_t symbol[]; }; +static const struct symbol sym_a = { 6, { 0xC0, 0xF0, 0x3C, 0x3C, 0xF0, 0xC0, + 0x3F, 0x3F, 0x06, 0x06, 0x3F, 0x3F } }; +static const struct symbol sym_b = { 6, { 0xFC, 0xFC, 0x8C, 0x8C, 0xFC, 0x78, + 0x3F, 0x3F, 0x31, 0x31, 0x3F, 0x1E } }; static const struct symbol sym_c = { 5, { 0xF8, 0xFC, 0x0C, 0x1C, 0x18, 0x1F, 0x3F, 0x30, 0x38, 0x18 } }; +static const struct symbol sym_e = { 5, { 0xFC, 0xFC, 0x8C, 0x8C, 0x0C, + 0x3F, 0x3F, 0x31, 0x31, 0x30 } }; +static const struct symbol sym_g = { 6, { 0xF8, 0xFC, 0x0C, 0x0C, 0x3C, 0x38, + 0x1F, 0x3F, 0x30, 0x33, 0x3F, 0x1F } }; static const struct symbol sym_h = { 6, { 0xFC, 0xFC, 0x80, 0x80, 0xFC, 0xFC, 0x3F, 0x3F, 0x01, 0x01, 0x3F, 0x3F } }; +static const struct symbol sym_i = { 4, { 0x0C, 0xFC, 0xFC, 0x0C, + 0x30, 0x3F, 0x3F, 0x30 } }; +static const struct symbol sym_k = { 6, { 0xFC, 0xFC, 0xC0, 0xF0, 0x7C, 0x1C, + 0x3F, 0x3F, 0x03, 0x0F, 0x3E, 0x38 } }; +static const struct symbol sym_l = { 5, { 0xFC, 0xFC, 0x00, 0x00, 0x00, + 0x3F, 0x3F, 0x30, 0x30, 0x30 } }; +static const struct symbol sym_n = { 7, { 0xFC, 0xFC, 0xF0, 0xC0, 0x00, 0xFC, 0xFC, + 0x3F, 0x3F, 0x00, 0x03, 0x0F, 0x3F, 0x3F } }; +static const struct symbol sym_o = { 6, { 0xF8, 0xFC, 0x0C, 0x0C, 0xFC, 0xF8, + 0x1F, 0x3F, 0x30, 0x30, 0x3F, 0x1F } }; +static const struct symbol sym_p = { 6, { 0xFC, 0xFC, 0x8C, 0x8C, 0xFC, 0xF8, + 0x3F, 0x3F, 0x01, 0x01, 0x01, 0x00 } }; +static const struct symbol sym_r = { 6, { 0xFC, 0xFC, 0x8C, 0x8C, 0xFC, 0xF8, + 0x3F, 0x3F, 0x01, 0x03, 0x3F, 0x3E } }; +static const struct symbol sym_s = { 6, { 0xF8, 0xFC, 0x8C, 0x8C, 0x9C, 0x18, + 0x18, 0x39, 0x31, 0x31, 0x3F, 0x1F } }; +static const struct symbol sym_t = { 6, { 0x0C, 0x0C, 0xFC, 0xFC, 0x0C, 0x0C, + 0x00, 0x00, 0x3F, 0x3F, 0x00, 0x00 } }; +static const struct symbol sym_u = { 6, { 0xFC, 0xFC, 0x00, 0x00, 0xFC, 0xFC, + 0x3F, 0x3F, 0x30, 0x30, 0x3F, 0x3F } }; static const struct symbol sym_0 = { 5, { 0xF8, 0xFC, 0x0C, 0xFC, 0xF8, 0x1F, 0x3F, 0x30, 0x3F, 0x1F } }; @@ -55,6 +83,9 @@ static const struct symbol sym_8 = { 5, { 0x78, 0xFC, 0x8C, 0xFC, 0x78, static const struct symbol sym_9 = { 5, { 0xF8, 0xFC, 0x8C, 0xFC, 0xF8, 0x1C, 0x3D, 0x31, 0x3F, 0x1F } }; +static const struct symbol sym_colon = { 2, { 0x30, 0x30, + 0x0C, 0x0C } }; + static const struct symbol sym_setup = { 19, { 0xF8, 0x98, 0xB8, 0x00, 0xF8, 0x98, 0x18, 0x00, 0x18, 0xF8, 0x18, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x98, 0xF8, 0x1D, 0x19, 0x1F, 0x00, 0x1F, 0x19, 0x18, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x00, 0x1F, 0x01, 0x01 } }; @@ -239,6 +270,102 @@ static void lcd_home(void) { } } +static void lcd_setup(void) { + lcd_fill(0x00); + + for (uint8_t i = 0; i < 2; i++) { + SPI_PORT &= ~(1 << LCD_CD); + lcd_write(0x00); + lcd_write(0x10); + lcd_write(0xB0 + i); + SPI_PORT |= (1 << LCD_CD); + + lcd_write_kerning(32, true); + lcd_write_symbol_page(&sym_s, i, true); + lcd_write_kerning(2, true); + lcd_write_symbol_page(&sym_e, i, true); + lcd_write_kerning(2, true); + lcd_write_symbol_page(&sym_t, i, true); + lcd_write_kerning(2, true); + lcd_write_symbol_page(&sym_u, i, true); + lcd_write_kerning(2, true); + lcd_write_symbol_page(&sym_p, i, true); + lcd_write_kerning(33, true); + } + + for (uint8_t i = 0; i < 2; i++) { + SPI_PORT &= ~(1 << LCD_CD); + lcd_write(0x02); + lcd_write(0x10); + lcd_write(0xB2 + i); + SPI_PORT |= (1 << LCD_CD); + + lcd_write_symbol_page(&sym_c, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_o, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_n, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_t, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_r, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_a, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_s, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_t, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_colon, i, false); + lcd_write_kerning(13, false); + } + + for (uint8_t i = 0; i < 2; i++) { + SPI_PORT &= ~(1 << LCD_CD); + lcd_write(0x02); + lcd_write(0x10); + lcd_write(0xB4 + i); + SPI_PORT |= (1 << LCD_CD); + + lcd_write_symbol_page(&sym_b, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_a, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_c, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_k, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_l, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_i, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_g, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_h, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_t, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_colon, i, false); + lcd_write_kerning(9, false); + } + + for (uint8_t i = 0; i < 2; i++) { + SPI_PORT &= ~(1 << LCD_CD); + lcd_write(0x03); + lcd_write(0x12); + lcd_write(0xB6 + i); + SPI_PORT |= (1 << LCD_CD); + + lcd_write_symbol_page(&sym_b, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_a, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_c, i, false); + lcd_write_kerning(2, false); + lcd_write_symbol_page(&sym_k, i, false); + } +} + static void change_state(enum state new_state) { switch(new_state) { case home: @@ -252,6 +379,8 @@ static void change_state(enum state new_state) { case ch3: break; case setup: + lcd_setup(); + current_state = setup; break; } } @@ -278,6 +407,20 @@ static void update_home(enum input event) { } } +static void update_setup(enum input event) { + switch (event) { + case cw: + break; + case ccw: + break; + case click: + break; + case hold: + change_state(home); + break; + } +} + static void update_state(enum input event) { switch (current_state) { case home: @@ -290,6 +433,7 @@ static void update_state(enum input event) { case ch3: break; case setup: + update_setup(event); break; } }