Implement switches and rotary encoder
This commit is contained in:
		
							parent
							
								
									f71c65106f
								
							
						
					
					
						commit
						09bc6979e9
					
				| @ -1,10 +1,9 @@ | ||||
| MCU=atmega88 | ||||
| CFLAGS=-g -Wall -mcall-prologues -mmcu=$(MCU) -Os -DF_CPU=8000000 -IAVR-SSD1306/Files/ | ||||
| CFLAGS=-g -Wall -Wno-multichar -Wno-overflow -mcall-prologues -mmcu=$(MCU) -O2 -DF_CPU=8000000 -IAVR-SSD1306/Files/ | ||||
| LDFLAGS=-Wl,-gc-sections -Wl,-relax | ||||
| CC=avr-gcc | ||||
| TARGET=main | ||||
| _OBJECT_FILES=main.o AVR-SSD1306/Files/SSD1306.c AVR-SSD1306/Files/TWI.c | ||||
| OBJECT_FILES=main.o oled-display/font.o oled-display/i2c.o oled-display/lcd.o | ||||
| OBJECT_FILES=main.o input.o systick.o oled-display/font.o oled-display/i2c.o oled-display/lcd.o | ||||
| 
 | ||||
| all: $(TARGET).hex | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										98
									
								
								firmware/input.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								firmware/input.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | ||||
| #include <avr/io.h> | ||||
| #include <util/delay.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include "input.h" | ||||
| #include "systick.h" | ||||
| 
 | ||||
| static volatile int8_t rotary_delta = 0; | ||||
| static volatile uint8_t sw_event = 0; | ||||
| 
 | ||||
| void input_init() | ||||
| { | ||||
| 	PORT_ROTARY(DDR) &= ~(PIN_ROTARY_A | PIN_ROTARY_B); // Configure as input
 | ||||
| 	PORT_ROTARY(PORT) &= ~(PIN_ROTARY_A | PIN_ROTARY_B); // Set pullups
 | ||||
| 
 | ||||
| 	PORT_KEYPAD(DDR) &= ~(PIN_KEYPAD_MASK); // Key inputs
 | ||||
| 	PORT_KEYPAD(PORT) |= PIN_KEYPAD_MASK; // Key pullups
 | ||||
| } | ||||
| 
 | ||||
| int8_t get_rotary_delta() | ||||
| { | ||||
| 	int8_t temp = rotary_delta; | ||||
| 	//rotary_delta = 0;
 | ||||
| 	return temp; | ||||
| } | ||||
| 
 | ||||
| static inline void input_proc_rotary() | ||||
| { | ||||
| 	static int8_t last_a; | ||||
| 	int8_t a; | ||||
| 	int8_t b; | ||||
| 	int8_t p; | ||||
| 
 | ||||
| 	p = PORT_ROTARY(PIN); | ||||
| 	a = (p & PIN_ROTARY_A); | ||||
| 	b = (p & PIN_ROTARY_B); | ||||
| 	a = !a; | ||||
| 	b = !b; | ||||
| 
 | ||||
| 	if (a == 1 && last_a == 0) { | ||||
| 		_delay_ms(1); // TODO
 | ||||
| 		rotary_delta += !!(a ^ b); | ||||
| 	} | ||||
| 	if (a == 0 && last_a == 1) { | ||||
| 		_delay_ms(1); // TODO
 | ||||
| 		rotary_delta -= !(a ^ b); | ||||
| 	} | ||||
| 
 | ||||
| 	last_a = a; | ||||
| } | ||||
| 
 | ||||
| // TODO: Pressing two keys at the same time can lead to unfortunate behavior.
 | ||||
| void input_proc_switches() | ||||
| { | ||||
| 	uint8_t sw; | ||||
| 	uint8_t ev; | ||||
| 	uint8_t i; | ||||
| 	static uint8_t sw_last = 0xFF; | ||||
| 	uint8_t delta; | ||||
| 
 | ||||
| 	sw = PORT_KEYPAD(PIN) & PIN_KEYPAD_MASK; | ||||
| 	ev = sw ^ sw_last; | ||||
| 
 | ||||
| 	if (ev) { | ||||
| 		if (timer_expired(TIMID_SW_DEBOUNCE)) { // If we read a value, wait for the debounce time before we process any other state
 | ||||
| 			for (i=0; i < 8; ++i) { | ||||
| 				if (ev & (1 << i)) { | ||||
| 					if (sw & (1 << i)) { // Key release
 | ||||
| 						if (timer_expired(TIMID_SW_LONGPRESS)) | ||||
| 							i |= (1 << 7) | (1 << 6); | ||||
| 						else | ||||
| 							i |= (1 << 7); | ||||
| 						sw_event = i; | ||||
| 					} else { // Key push
 | ||||
| 						sw_event = 0; // To be honest, I don't have a f*cking clue why I need this...
 | ||||
| 						timer_set(TIMID_SW_LONGPRESS, MS_TO_TICKS(1000)); | ||||
| 					} | ||||
| 					timer_set(TIMID_SW_DEBOUNCE, MS_TO_TICKS(250)); | ||||
| 					break; // We can only process one event at a time anyway, so let's quit it here
 | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		sw_last = sw; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| uint8_t get_switch_event() | ||||
| { | ||||
| 	uint8_t temp = sw_event; | ||||
| 	sw_event = 0; | ||||
| 	return temp; | ||||
| } | ||||
| 
 | ||||
| // Need to call timer_proc() before calling this function!
 | ||||
| void input_proc() | ||||
| { | ||||
| 	input_proc_rotary(); | ||||
| 	input_proc_switches(); | ||||
| } | ||||
							
								
								
									
										19
									
								
								firmware/input.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								firmware/input.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| #ifndef INPUT_H | ||||
| #define INPUT_H | ||||
| 
 | ||||
| #define PORT_KEYPAD(t) t##D // Keys connected to: 0,1,2(INT0->POWER),5,6,7
 | ||||
| #define PIN_KEYPAD_MASK 0b11100111 | ||||
| #define PORT_KEYAUX(t) t##B | ||||
| #define PIN_ROTARY_PUSH (1 << 0) | ||||
| 
 | ||||
| #define PORT_ROTARY(t) t##D | ||||
| #define PIN_ROTARY_A (1 << 3) // INT1
 | ||||
| #define PIN_ROTARY_B (1 << 4) | ||||
| 
 | ||||
| void input_init(); | ||||
| void input_proc(); | ||||
| int8_t get_rotary_delta(); | ||||
| uint8_t get_switch_event(); | ||||
| extern uint8_t ctime; | ||||
| 
 | ||||
| #endif // INPUT_H
 | ||||
| @ -1,22 +1,37 @@ | ||||
| #include <avr/io.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include <avr/pgmspace.h> | ||||
| #include <avr/delay.h> | ||||
| #include <util/delay.h> | ||||
| #include "oled-display/lcd.h" | ||||
| #include "input.h" | ||||
| #include "systick.h" | ||||
| 
 | ||||
| #define PORT_SPI(t) t##B | ||||
| #define PIN_SPI_CS (1 << 2) | ||||
| 
 | ||||
| void spi_proc() | ||||
| int dbg = 0; | ||||
| 
 | ||||
| void spi_init() | ||||
| { | ||||
| 	SPCR = (1 << SPE); | ||||
| 	SPSR = (1 << SPI2X); | ||||
| 	DDRB |= (1 << 4); | ||||
| } | ||||
| 
 | ||||
| uint8_t spi_proc() | ||||
| { | ||||
| 	static uint8_t new_data = 0; | ||||
| 	static uint8_t x = 0; | ||||
| 	static uint8_t y = DISPLAY_HEIGHT / 8 - 1; | ||||
| 	uint8_t spi_cs; | ||||
| 	 | ||||
| 
 | ||||
| 	spi_cs = !(PORT_SPI(PIN) & PIN_SPI_CS); | ||||
| 	 | ||||
| 
 | ||||
| 	if (spi_cs) { | ||||
| 		if (SPSR & (1 << SPIF)) { | ||||
| 			//SPDR = get_rotary_delta();
 | ||||
| 			SPDR = get_switch_event(); | ||||
| 			//SPDR = dbg;
 | ||||
| 			lcd_set_buffer(x, y, SPDR); | ||||
| 			if (y == 0) { | ||||
| 				y = DISPLAY_HEIGHT / 8 - 1; | ||||
| @ -37,10 +52,12 @@ void spi_proc() | ||||
| 		x = 0; | ||||
| 		y = DISPLAY_HEIGHT / 8 - 1; | ||||
| 	} | ||||
| 
 | ||||
| 	return spi_cs; | ||||
| } | ||||
| 
 | ||||
| int main() | ||||
| {	 | ||||
| void lcd_startup() | ||||
| { | ||||
| 	lcd_init(LCD_DISP_ON); | ||||
| 	lcd_gotoxy(0, 0); | ||||
| 	lcd_puts_p(PSTR("== Internet Radio ==")); | ||||
| @ -50,13 +67,24 @@ int main() | ||||
| 	lcd_gotoxy(0, 3); | ||||
| 	lcd_puts_p(PSTR("Please wait...")); | ||||
| 	lcd_display(); | ||||
| 	 | ||||
| 	SPCR = (1 << SPE); | ||||
| 	 | ||||
| } | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
| 	cli(); | ||||
| 
 | ||||
| 	lcd_startup(); | ||||
| 	spi_init(); | ||||
| 	systick_init(); | ||||
| 	input_init(); | ||||
| 
 | ||||
| 	_delay_ms(10); | ||||
| 	 | ||||
| 
 | ||||
| 	while (1) { | ||||
| 		spi_proc(); | ||||
| 		if (!spi_proc()) { | ||||
| 			timer_proc(); | ||||
| 			input_proc(); | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
							
								
								
									
										66
									
								
								firmware/systick.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								firmware/systick.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,66 @@ | ||||
| #include <avr/io.h> | ||||
| #include "systick.h" | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| uint8_t ctime; | ||||
| 
 | ||||
| static uint8_t tims[NTIM]; | ||||
| 
 | ||||
| void systick_init() | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	TCCR1A = 0; | ||||
| 	TCCR1B = (1 << CS10) | (1 << CS12); // f_tim = f_clk / 256 -> TCNT1H counts with 8ms / tick
 | ||||
| 	TCCR1C = 0; | ||||
| 	OCR1A = 0x7FFF; | ||||
| 
 | ||||
| 	for (i=0; i < NTIM; ++i) { | ||||
| 		tims[i] = 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void timer_proc() | ||||
| { | ||||
| 	uint8_t now; | ||||
| 	uint8_t delta; | ||||
| 	uint8_t i; | ||||
| 
 | ||||
| 	now = TCNT1L; | ||||
| 	now = TCNT1H; | ||||
| 
 | ||||
| 	if (now == ctime) | ||||
| 		return; | ||||
| 	delta = now - ctime; | ||||
| 	if (delta > 127) | ||||
| 		delta -= 128; | ||||
| 
 | ||||
| 	for (i=0; i < NTIM; ++i) { | ||||
| 		if (tims[i] > delta) { | ||||
| 			tims[i] -= delta; | ||||
| 		} else { | ||||
| 			tims[i] = 0; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ctime = now; | ||||
| } | ||||
| 
 | ||||
| uint8_t timer_expired(uint8_t tim_id) | ||||
| { | ||||
| 	return !tims[tim_id]; | ||||
| } | ||||
| 
 | ||||
| void timer_set(uint8_t tim_id, uint8_t ticks) | ||||
| { | ||||
| 	tims[tim_id] = ticks; | ||||
| } | ||||
| 
 | ||||
| uint8_t block_for(uint8_t tim_id, uint8_t ticks) | ||||
| { | ||||
| 	if (timer_expired(tim_id)) { | ||||
| 		timer_set(tim_id, ticks); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										19
									
								
								firmware/systick.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								firmware/systick.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| #ifndef SYSTICK_H | ||||
| #define SYSTICK_H | ||||
| #include <avr/io.h> | ||||
| 
 | ||||
| #define TIMID_SW_DEBOUNCE 0 | ||||
| #define TIMID_SW_LONGPRESS 1 | ||||
| #define NTIM 2 | ||||
| 
 | ||||
| #define MS_TO_TICKS(ms) (((ms/1000 * F_CPU/1024) / 256)) | ||||
| 
 | ||||
| #define SYSTICK_VAL TCNT1H | ||||
| 
 | ||||
| void timer_proc(); | ||||
| void systick_init(); | ||||
| uint8_t timer_expired(uint8_t tim_id); | ||||
| void timer_set(uint8_t tim_id, uint8_t ticks); | ||||
| uint8_t block_for(uint8_t tim_id, uint8_t ticks); | ||||
| 
 | ||||
| #endif // SYSTICK_H
 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user