Compare commits
5 commits
52e161f43b
...
c0f8cac065
Author | SHA1 | Date | |
---|---|---|---|
c0f8cac065 | |||
3aa458c4bc | |||
2579ae3686 | |||
664aa4bad5 | |||
99175efc8c |
1 changed files with 153 additions and 30 deletions
|
@ -2,6 +2,7 @@
|
|||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <util/delay.h>
|
||||
#include <util/twi.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
@ -17,6 +18,12 @@
|
|||
#define ENC_A (PINB & (1 << PB6))
|
||||
#define ENC_B (PINB & (1 << PB7))
|
||||
|
||||
#define TWI_PORT PORTC
|
||||
#define TWI_SDA PC4
|
||||
#define TWI_SCL PC5
|
||||
|
||||
#define SI5351_ADDRESS (0x60 << 1)
|
||||
|
||||
#define SYM_ENTRY(SYM) { SYM, sizeof(SYM) / 2 }
|
||||
|
||||
static uint8_t EEMEM eeprom_contrast = 8;
|
||||
|
@ -88,6 +95,9 @@ static const __flash uint8_t sym_t[] = { 0x0C, 0x0C, 0xFC, 0xFC, 0x0C, 0x0C,
|
|||
static const __flash uint8_t sym_u[] = { 0xFC, 0xFC, 0x00, 0x00, 0xFC, 0xFC,
|
||||
0x3F, 0x3F, 0x30, 0x30, 0x3F, 0x3F };
|
||||
|
||||
static const __flash uint8_t sym_underscore[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20 };
|
||||
|
||||
static const __flash uint8_t sym_invalid[] = { 0x80, 0xE0, 0x98, 0xCC, 0x4C, 0x18, 0xE0, 0x80,
|
||||
0x01, 0x07, 0x1F, 0x24, 0x25, 0x1F, 0x07, 0x01};
|
||||
|
||||
|
@ -133,7 +143,18 @@ static const struct symbol symbol_table[] = { SYM_ENTRY(sym_0),
|
|||
SYM_ENTRY(sym_r),
|
||||
SYM_ENTRY(sym_s),
|
||||
SYM_ENTRY(sym_t),
|
||||
SYM_ENTRY(sym_u) };
|
||||
SYM_ENTRY(sym_u),
|
||||
SYM_ENTRY(sym_invalid),
|
||||
SYM_ENTRY(sym_invalid),
|
||||
SYM_ENTRY(sym_invalid),
|
||||
SYM_ENTRY(sym_invalid),
|
||||
SYM_ENTRY(sym_invalid),
|
||||
SYM_ENTRY(sym_invalid),
|
||||
SYM_ENTRY(sym_invalid),
|
||||
SYM_ENTRY(sym_invalid),
|
||||
SYM_ENTRY(sym_invalid),
|
||||
SYM_ENTRY(sym_underscore),
|
||||
};
|
||||
|
||||
enum input { cw, ccw, click, hold };
|
||||
|
||||
|
@ -166,6 +187,7 @@ static void lcd_write(const uint8_t data) {
|
|||
}
|
||||
|
||||
static void lcd_init(void) {
|
||||
// TODO: Optimize waiting times
|
||||
SPI_DDR |= (1 << LCD_CD) | (1 << LCD_RST);
|
||||
_delay_ms(1);
|
||||
SPI_PORT |= (1 << LCD_RST);
|
||||
|
@ -200,12 +222,12 @@ static void lcd_update_backlight(void) {
|
|||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
TCCR0B = 0x0C; // prescaler = 256;
|
||||
TCCR0B = 0x0C; // Prescaler = 256;
|
||||
DDRD |= (1 << PD5);
|
||||
OCR0B = value_backlight - 1;
|
||||
break;
|
||||
default:
|
||||
TCCR0B = 0x0B; // prescaler = 64;
|
||||
TCCR0B = 0x0B; // Prescaler = 64;
|
||||
DDRD |= (1 << PD5);
|
||||
OCR0B = value_backlight - 4;
|
||||
break;
|
||||
|
@ -280,6 +302,7 @@ static void lcd_write_integer_page(const uint8_t integer,
|
|||
uint16_t comperator = 1;
|
||||
|
||||
for (; comperator <= integer; comperator *= 10, input_digits++);
|
||||
|
||||
for (int8_t i = digits - input_digits; i > 0; i--) {
|
||||
lcd_write_kerning(2, invert);
|
||||
lcd_write_digit_page(0, page, invert);
|
||||
|
@ -312,7 +335,98 @@ static void lcd_splash(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void lcd_home(void) {
|
||||
static void twi_error(void) {
|
||||
lcd_fill(0xFF);
|
||||
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
lcd_move_cursor(0, i);
|
||||
lcd_write_string_page("TW_STATUS:\0", i, true);
|
||||
lcd_write_kerning(2, true);
|
||||
lcd_write_integer_page(TW_STATUS, 3, i, true);
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
lcd_move_cursor(0, i + 2);
|
||||
lcd_write_string_page("TW_DATA:\0", i, true);
|
||||
lcd_write_kerning(16, true);
|
||||
lcd_write_integer_page(TWDR, 3, i, true);
|
||||
}
|
||||
|
||||
for (;;);
|
||||
}
|
||||
|
||||
static void twi_start(void) {
|
||||
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // Start transmission
|
||||
while (!(TWCR & (1 << TWINT))); // Wait until start is transmitted
|
||||
|
||||
if (TW_STATUS != TW_START) // Check status
|
||||
twi_error();
|
||||
}
|
||||
|
||||
static uint8_t twi_transmit(const uint8_t data) {
|
||||
TWDR = data;
|
||||
TWCR = (1 << TWINT) | (1 << TWEN); // Transmit data
|
||||
while (!(TWCR & (1 << TWINT))); // Wait until data is transmitted
|
||||
|
||||
return TW_STATUS;
|
||||
}
|
||||
|
||||
static uint8_t twi_receive(void) {
|
||||
TWCR = (1 << TWINT) | (1 << TWEN); // Receive data
|
||||
while (!(TWCR & (1 << TWINT))); // Wait until data is received
|
||||
|
||||
return TW_STATUS;
|
||||
}
|
||||
|
||||
static void twi_stop(void) {
|
||||
TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
|
||||
}
|
||||
|
||||
static uint8_t twi_read_register(const uint8_t address,
|
||||
const uint8_t reg) {
|
||||
twi_start();
|
||||
|
||||
if (twi_transmit(address) != TW_MT_SLA_ACK)
|
||||
twi_error();
|
||||
|
||||
if (twi_transmit(reg) != TW_MT_DATA_ACK)
|
||||
twi_error();
|
||||
|
||||
twi_stop();
|
||||
|
||||
_delay_us(2);
|
||||
|
||||
twi_start();
|
||||
|
||||
if (twi_transmit(address + 1) != TW_MR_SLA_ACK)
|
||||
twi_error();
|
||||
|
||||
if (twi_receive() != TW_MR_DATA_NACK)
|
||||
twi_error();
|
||||
|
||||
twi_stop();
|
||||
|
||||
return TWDR;
|
||||
}
|
||||
|
||||
static void twi_write_register(const uint8_t address,
|
||||
const uint8_t reg,
|
||||
const uint8_t data) {
|
||||
twi_start();
|
||||
|
||||
if (twi_transmit(address) != TW_MT_SLA_ACK)
|
||||
twi_error();
|
||||
|
||||
if (twi_transmit(reg) != TW_MT_DATA_ACK)
|
||||
twi_error();
|
||||
|
||||
if (twi_transmit(data) != TW_MT_DATA_ACK)
|
||||
twi_error();
|
||||
|
||||
twi_stop();
|
||||
}
|
||||
|
||||
static void draw_home(void) {
|
||||
lcd_fill(0x00);
|
||||
|
||||
bool ch1_selected = false;
|
||||
|
@ -354,7 +468,7 @@ static void lcd_home(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void lcd_setup(void) {
|
||||
static void draw_setup(void) {
|
||||
lcd_fill(0x00);
|
||||
|
||||
bool contrast_selected = false;
|
||||
|
@ -393,7 +507,8 @@ static void lcd_setup(void) {
|
|||
lcd_write_string_page("CONTRAST:\0", i, contrast_selected);
|
||||
lcd_write_kerning(2, contrast_selected);
|
||||
lcd_write_kerning(16, false);
|
||||
lcd_write_integer_page(value_contrast, 2, i, change_contrast_selected);
|
||||
lcd_write_integer_page(value_contrast, 2, i,
|
||||
change_contrast_selected);
|
||||
lcd_write_kerning(2, change_contrast_selected);
|
||||
}
|
||||
|
||||
|
@ -402,7 +517,8 @@ static void lcd_setup(void) {
|
|||
lcd_write_string_page("BACKLIGHT:\0", i, backlight_selected);
|
||||
lcd_write_kerning(2, backlight_selected);
|
||||
lcd_write_kerning(5, false);
|
||||
lcd_write_integer_page(value_backlight, 3, i, change_backlight_selected);
|
||||
lcd_write_integer_page(value_backlight, 3, i,
|
||||
change_backlight_selected);
|
||||
lcd_write_kerning(2, change_backlight_selected);
|
||||
}
|
||||
|
||||
|
@ -416,7 +532,7 @@ static void lcd_setup(void) {
|
|||
static void change_state(const enum state new_state) {
|
||||
switch (new_state) {
|
||||
case home:
|
||||
lcd_home();
|
||||
draw_home();
|
||||
current_state = home;
|
||||
break;
|
||||
case ch1:
|
||||
|
@ -427,7 +543,7 @@ static void change_state(const enum state new_state) {
|
|||
break;
|
||||
case setup:
|
||||
setup_state = contrast;
|
||||
lcd_setup();
|
||||
draw_setup();
|
||||
current_state = setup;
|
||||
break;
|
||||
}
|
||||
|
@ -439,13 +555,13 @@ static void update_home(const enum input event) {
|
|||
home_state++;
|
||||
if (home_state > setup)
|
||||
home_state = ch1;
|
||||
lcd_home();
|
||||
draw_home();
|
||||
break;
|
||||
case ccw:
|
||||
home_state--;
|
||||
if (home_state > setup)
|
||||
home_state = setup;
|
||||
lcd_home();
|
||||
draw_home();
|
||||
break;
|
||||
case click:
|
||||
change_state(home_state);
|
||||
|
@ -479,7 +595,7 @@ static void update_setup(const enum input event) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
lcd_setup();
|
||||
draw_setup();
|
||||
break;
|
||||
case ccw:
|
||||
switch (setup_state) {
|
||||
|
@ -503,17 +619,17 @@ static void update_setup(const enum input event) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
lcd_setup();
|
||||
draw_setup();
|
||||
break;
|
||||
case click:
|
||||
switch (setup_state) {
|
||||
case contrast:
|
||||
setup_state = change_contrast;
|
||||
lcd_setup();
|
||||
draw_setup();
|
||||
break;
|
||||
case backlight:
|
||||
setup_state = change_backlight;
|
||||
lcd_setup();
|
||||
draw_setup();
|
||||
break;
|
||||
case back:
|
||||
change_state(home);
|
||||
|
@ -521,12 +637,12 @@ static void update_setup(const enum input event) {
|
|||
case change_contrast:
|
||||
eeprom_update_byte(&eeprom_contrast, value_contrast);
|
||||
setup_state = contrast;
|
||||
lcd_setup();
|
||||
draw_setup();
|
||||
break;
|
||||
case change_backlight:
|
||||
eeprom_update_byte(&eeprom_backlight, value_backlight);
|
||||
setup_state = backlight;
|
||||
lcd_setup();
|
||||
draw_setup();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -541,13 +657,13 @@ static void update_setup(const enum input event) {
|
|||
setup_state = contrast;
|
||||
value_contrast = eeprom_read_byte(&eeprom_contrast);
|
||||
lcd_update_contrast();
|
||||
lcd_setup();
|
||||
draw_setup();
|
||||
break;
|
||||
case change_backlight:
|
||||
setup_state = backlight;
|
||||
value_backlight = eeprom_read_byte(&eeprom_backlight);
|
||||
lcd_update_backlight();
|
||||
lcd_setup();
|
||||
draw_setup();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -575,6 +691,9 @@ static void update_state(const enum input event) {
|
|||
ISR(PCINT0_vect) {
|
||||
cli();
|
||||
|
||||
// Dechatter
|
||||
_delay_ms(3);
|
||||
|
||||
switch (enc) {
|
||||
case 0:
|
||||
if (ENC_A && !ENC_B)
|
||||
|
@ -608,16 +727,16 @@ ISR(PCINT0_vect) {
|
|||
break;
|
||||
}
|
||||
|
||||
// TODO: proper dechattering
|
||||
_delay_ms(3);
|
||||
|
||||
sei();
|
||||
}
|
||||
|
||||
// encoder button interrupt
|
||||
// Encoder button interrupt
|
||||
ISR(PCINT1_vect) {
|
||||
cli();
|
||||
|
||||
// Debounce
|
||||
_delay_ms(2);
|
||||
|
||||
if (PINC & (1 << PC0)) { // Release
|
||||
if (TCCR1B & (1 << CS10)) // If release before hold
|
||||
update_state(click); // Switch to selected state
|
||||
|
@ -629,9 +748,6 @@ ISR(PCINT1_vect) {
|
|||
TCCR1B |= (1 << CS11) | (1 << CS10); // Enable Timer/Counter1
|
||||
}
|
||||
|
||||
// TODO: Proper debouncing
|
||||
_delay_ms(3);
|
||||
|
||||
sei();
|
||||
}
|
||||
|
||||
|
@ -650,13 +766,12 @@ int main(void) {
|
|||
value_contrast = eeprom_read_byte(&eeprom_contrast);
|
||||
value_backlight = eeprom_read_byte(&eeprom_backlight);
|
||||
|
||||
// Init backlight: FastPWM: 1.25kHz
|
||||
// TODO: Try to get the backlit even more dim
|
||||
// Init backlight
|
||||
TCCR0A |= (1 << WGM01) | (1 << WGM00) | (1 << COM0B1);
|
||||
OCR0A = 255;
|
||||
lcd_update_backlight();
|
||||
|
||||
// SPI setup
|
||||
// SPI and LCD init
|
||||
spi_init();
|
||||
lcd_init();
|
||||
|
||||
|
@ -674,11 +789,19 @@ int main(void) {
|
|||
OCR1A = 65535;
|
||||
TIMSK1 |= (1 << OCIE1A); // Enable match compare A
|
||||
|
||||
// Show splash screen and load the menu
|
||||
// Show splash screen
|
||||
lcd_splash();
|
||||
_delay_ms(2000);
|
||||
|
||||
// Load the menu
|
||||
change_state(current_state);
|
||||
|
||||
// Set TWI bit rate to 200kHz
|
||||
TWBR = 12;
|
||||
|
||||
(void) &twi_read_register;
|
||||
(void) &twi_write_register;
|
||||
|
||||
// Enable interrupts
|
||||
sei();
|
||||
|
||||
|
|
Loading…
Reference in a new issue