Compare commits

..

No commits in common. "c0f8cac065634bf5ff77950bfd32578e56f9f1e9" and "52e161f43ba7cfdb0d2ee515967882baa02c359b" have entirely different histories.

View file

@ -2,7 +2,6 @@
#include <avr/io.h> #include <avr/io.h>
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include <util/delay.h> #include <util/delay.h>
#include <util/twi.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
@ -18,12 +17,6 @@
#define ENC_A (PINB & (1 << PB6)) #define ENC_A (PINB & (1 << PB6))
#define ENC_B (PINB & (1 << PB7)) #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 } #define SYM_ENTRY(SYM) { SYM, sizeof(SYM) / 2 }
static uint8_t EEMEM eeprom_contrast = 8; static uint8_t EEMEM eeprom_contrast = 8;
@ -95,9 +88,6 @@ 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, static const __flash uint8_t sym_u[] = { 0xFC, 0xFC, 0x00, 0x00, 0xFC, 0xFC,
0x3F, 0x3F, 0x30, 0x30, 0x3F, 0x3F }; 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, static const __flash uint8_t sym_invalid[] = { 0x80, 0xE0, 0x98, 0xCC, 0x4C, 0x18, 0xE0, 0x80,
0x01, 0x07, 0x1F, 0x24, 0x25, 0x1F, 0x07, 0x01}; 0x01, 0x07, 0x1F, 0x24, 0x25, 0x1F, 0x07, 0x01};
@ -143,18 +133,7 @@ static const struct symbol symbol_table[] = { SYM_ENTRY(sym_0),
SYM_ENTRY(sym_r), SYM_ENTRY(sym_r),
SYM_ENTRY(sym_s), SYM_ENTRY(sym_s),
SYM_ENTRY(sym_t), 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 }; enum input { cw, ccw, click, hold };
@ -187,7 +166,6 @@ static void lcd_write(const uint8_t data) {
} }
static void lcd_init(void) { static void lcd_init(void) {
// TODO: Optimize waiting times
SPI_DDR |= (1 << LCD_CD) | (1 << LCD_RST); SPI_DDR |= (1 << LCD_CD) | (1 << LCD_RST);
_delay_ms(1); _delay_ms(1);
SPI_PORT |= (1 << LCD_RST); SPI_PORT |= (1 << LCD_RST);
@ -222,12 +200,12 @@ static void lcd_update_backlight(void) {
case 3: case 3:
case 4: case 4:
case 5: case 5:
TCCR0B = 0x0C; // Prescaler = 256; TCCR0B = 0x0C; // prescaler = 256;
DDRD |= (1 << PD5); DDRD |= (1 << PD5);
OCR0B = value_backlight - 1; OCR0B = value_backlight - 1;
break; break;
default: default:
TCCR0B = 0x0B; // Prescaler = 64; TCCR0B = 0x0B; // prescaler = 64;
DDRD |= (1 << PD5); DDRD |= (1 << PD5);
OCR0B = value_backlight - 4; OCR0B = value_backlight - 4;
break; break;
@ -302,7 +280,6 @@ static void lcd_write_integer_page(const uint8_t integer,
uint16_t comperator = 1; uint16_t comperator = 1;
for (; comperator <= integer; comperator *= 10, input_digits++); for (; comperator <= integer; comperator *= 10, input_digits++);
for (int8_t i = digits - input_digits; i > 0; i--) { for (int8_t i = digits - input_digits; i > 0; i--) {
lcd_write_kerning(2, invert); lcd_write_kerning(2, invert);
lcd_write_digit_page(0, page, invert); lcd_write_digit_page(0, page, invert);
@ -335,98 +312,7 @@ static void lcd_splash(void) {
} }
} }
static void twi_error(void) { static void lcd_home(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); lcd_fill(0x00);
bool ch1_selected = false; bool ch1_selected = false;
@ -468,7 +354,7 @@ static void draw_home(void) {
} }
} }
static void draw_setup(void) { static void lcd_setup(void) {
lcd_fill(0x00); lcd_fill(0x00);
bool contrast_selected = false; bool contrast_selected = false;
@ -507,8 +393,7 @@ static void draw_setup(void) {
lcd_write_string_page("CONTRAST:\0", i, contrast_selected); lcd_write_string_page("CONTRAST:\0", i, contrast_selected);
lcd_write_kerning(2, contrast_selected); lcd_write_kerning(2, contrast_selected);
lcd_write_kerning(16, false); lcd_write_kerning(16, false);
lcd_write_integer_page(value_contrast, 2, i, lcd_write_integer_page(value_contrast, 2, i, change_contrast_selected);
change_contrast_selected);
lcd_write_kerning(2, change_contrast_selected); lcd_write_kerning(2, change_contrast_selected);
} }
@ -517,8 +402,7 @@ static void draw_setup(void) {
lcd_write_string_page("BACKLIGHT:\0", i, backlight_selected); lcd_write_string_page("BACKLIGHT:\0", i, backlight_selected);
lcd_write_kerning(2, backlight_selected); lcd_write_kerning(2, backlight_selected);
lcd_write_kerning(5, false); lcd_write_kerning(5, false);
lcd_write_integer_page(value_backlight, 3, i, lcd_write_integer_page(value_backlight, 3, i, change_backlight_selected);
change_backlight_selected);
lcd_write_kerning(2, change_backlight_selected); lcd_write_kerning(2, change_backlight_selected);
} }
@ -532,7 +416,7 @@ static void draw_setup(void) {
static void change_state(const enum state new_state) { static void change_state(const enum state new_state) {
switch (new_state) { switch (new_state) {
case home: case home:
draw_home(); lcd_home();
current_state = home; current_state = home;
break; break;
case ch1: case ch1:
@ -543,7 +427,7 @@ static void change_state(const enum state new_state) {
break; break;
case setup: case setup:
setup_state = contrast; setup_state = contrast;
draw_setup(); lcd_setup();
current_state = setup; current_state = setup;
break; break;
} }
@ -555,13 +439,13 @@ static void update_home(const enum input event) {
home_state++; home_state++;
if (home_state > setup) if (home_state > setup)
home_state = ch1; home_state = ch1;
draw_home(); lcd_home();
break; break;
case ccw: case ccw:
home_state--; home_state--;
if (home_state > setup) if (home_state > setup)
home_state = setup; home_state = setup;
draw_home(); lcd_home();
break; break;
case click: case click:
change_state(home_state); change_state(home_state);
@ -595,7 +479,7 @@ static void update_setup(const enum input event) {
} }
break; break;
} }
draw_setup(); lcd_setup();
break; break;
case ccw: case ccw:
switch (setup_state) { switch (setup_state) {
@ -619,17 +503,17 @@ static void update_setup(const enum input event) {
} }
break; break;
} }
draw_setup(); lcd_setup();
break; break;
case click: case click:
switch (setup_state) { switch (setup_state) {
case contrast: case contrast:
setup_state = change_contrast; setup_state = change_contrast;
draw_setup(); lcd_setup();
break; break;
case backlight: case backlight:
setup_state = change_backlight; setup_state = change_backlight;
draw_setup(); lcd_setup();
break; break;
case back: case back:
change_state(home); change_state(home);
@ -637,12 +521,12 @@ static void update_setup(const enum input event) {
case change_contrast: case change_contrast:
eeprom_update_byte(&eeprom_contrast, value_contrast); eeprom_update_byte(&eeprom_contrast, value_contrast);
setup_state = contrast; setup_state = contrast;
draw_setup(); lcd_setup();
break; break;
case change_backlight: case change_backlight:
eeprom_update_byte(&eeprom_backlight, value_backlight); eeprom_update_byte(&eeprom_backlight, value_backlight);
setup_state = backlight; setup_state = backlight;
draw_setup(); lcd_setup();
break; break;
} }
break; break;
@ -657,13 +541,13 @@ static void update_setup(const enum input event) {
setup_state = contrast; setup_state = contrast;
value_contrast = eeprom_read_byte(&eeprom_contrast); value_contrast = eeprom_read_byte(&eeprom_contrast);
lcd_update_contrast(); lcd_update_contrast();
draw_setup(); lcd_setup();
break; break;
case change_backlight: case change_backlight:
setup_state = backlight; setup_state = backlight;
value_backlight = eeprom_read_byte(&eeprom_backlight); value_backlight = eeprom_read_byte(&eeprom_backlight);
lcd_update_backlight(); lcd_update_backlight();
draw_setup(); lcd_setup();
break; break;
} }
break; break;
@ -691,9 +575,6 @@ static void update_state(const enum input event) {
ISR(PCINT0_vect) { ISR(PCINT0_vect) {
cli(); cli();
// Dechatter
_delay_ms(3);
switch (enc) { switch (enc) {
case 0: case 0:
if (ENC_A && !ENC_B) if (ENC_A && !ENC_B)
@ -727,16 +608,16 @@ ISR(PCINT0_vect) {
break; break;
} }
// TODO: proper dechattering
_delay_ms(3);
sei(); sei();
} }
// Encoder button interrupt // encoder button interrupt
ISR(PCINT1_vect) { ISR(PCINT1_vect) {
cli(); cli();
// Debounce
_delay_ms(2);
if (PINC & (1 << PC0)) { // Release if (PINC & (1 << PC0)) { // Release
if (TCCR1B & (1 << CS10)) // If release before hold if (TCCR1B & (1 << CS10)) // If release before hold
update_state(click); // Switch to selected state update_state(click); // Switch to selected state
@ -748,6 +629,9 @@ ISR(PCINT1_vect) {
TCCR1B |= (1 << CS11) | (1 << CS10); // Enable Timer/Counter1 TCCR1B |= (1 << CS11) | (1 << CS10); // Enable Timer/Counter1
} }
// TODO: Proper debouncing
_delay_ms(3);
sei(); sei();
} }
@ -766,12 +650,13 @@ int main(void) {
value_contrast = eeprom_read_byte(&eeprom_contrast); value_contrast = eeprom_read_byte(&eeprom_contrast);
value_backlight = eeprom_read_byte(&eeprom_backlight); value_backlight = eeprom_read_byte(&eeprom_backlight);
// Init backlight // Init backlight: FastPWM: 1.25kHz
// TODO: Try to get the backlit even more dim
TCCR0A |= (1 << WGM01) | (1 << WGM00) | (1 << COM0B1); TCCR0A |= (1 << WGM01) | (1 << WGM00) | (1 << COM0B1);
OCR0A = 255; OCR0A = 255;
lcd_update_backlight(); lcd_update_backlight();
// SPI and LCD init // SPI setup
spi_init(); spi_init();
lcd_init(); lcd_init();
@ -789,19 +674,11 @@ int main(void) {
OCR1A = 65535; OCR1A = 65535;
TIMSK1 |= (1 << OCIE1A); // Enable match compare A TIMSK1 |= (1 << OCIE1A); // Enable match compare A
// Show splash screen // Show splash screen and load the menu
lcd_splash(); lcd_splash();
_delay_ms(2000); _delay_ms(2000);
// Load the menu
change_state(current_state); change_state(current_state);
// Set TWI bit rate to 200kHz
TWBR = 12;
(void) &twi_read_register;
(void) &twi_write_register;
// Enable interrupts // Enable interrupts
sei(); sei();