diff options
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | main.c | 22 | ||||
-rw-r--r-- | pwm.c | 81 | ||||
-rw-r--r-- | pwm.h | 11 |
4 files changed, 103 insertions, 16 deletions
@@ -1,9 +1,10 @@ MCU = atmega88 +CFLAGS=-Os all: sanduhr.hex -sanduhr.elf: main.c i2c.c i2c.h uart.c uart.h timer.c timer.h gyro.c gyro.h accel.c accel.h common.h speaker.c speaker.h - avr-gcc -std=gnu99 -mmcu=$(MCU) -Os -o $@ $^ +sanduhr.elf: main.c i2c.c i2c.h uart.c uart.h timer.c timer.h gyro.c gyro.h accel.c accel.h common.h speaker.c speaker.h pwm.c pwm.h + avr-gcc -std=gnu99 -mmcu=$(MCU) $(CFLAGS) -o $@ $^ sanduhr.hex: sanduhr.elf avr-objcopy -O ihex -R .eeprom $< $@ @@ -14,19 +14,7 @@ #include "gyro.h" #include "accel.h" #include "speaker.h" - -static void ledInit () { - /* set led1,led2 to output */ - DDRB |= (1 << PB6) | (1 << PB7); - /* set led3,led4,led5,led6 to output */ - DDRD |= (1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5); -} - -/* show data with leds */ -static void ledShow (const unsigned char val) { - PORTB = (PORTB & ~((1 << PB6) | (1 << PB7))) | ((val & 0x3) << PB6); - PORTD = (PORTD & ~((1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5))) | (((val >> 2) & 0xf) << PD2); -} +#include "pwm.h" static void cpuInit () { /* enter change prescaler mode */ @@ -45,12 +33,12 @@ static void cpuInit () { int main () { cpuInit (); - ledInit (); twInit (); uartInit (); gyroInit (); accelInit (); speakerInit (); + pwmInit (); set_sleep_mode (SLEEP_MODE_IDLE); printf ("initialization done\n"); @@ -59,6 +47,7 @@ int main () { sei (); gyroStart (); accelStart (); + pwmStart (); #if 0 speakerStart (); @@ -70,6 +59,10 @@ int main () { bool checkGyro = false; while (1) { while (!timerHit ()) { + for (uint8_t i = 0; i < 6; i++) { + pwmSetBrightness (i, abs (gyroGetZTicks ())); + } + /* round-robin to prevent starvation */ if (checkGyro) { gyroProcess (); @@ -97,6 +90,7 @@ int main () { #endif } timerStop (); + pwmStop (); printf ("stopped\n"); @@ -0,0 +1,81 @@ +/* LED pwm, uses timer0 + * XXX: this works, but we should use non-linear steps + */ + +#include <avr/io.h> +#include <avr/interrupt.h> +#include <stdbool.h> + +#include "speaker.h" + +#define PWM_STEPS 16 + +/* inverse brightness; 0 is max brightness, PWM_STEPS off */ +static uint8_t invbrightness[6]; +static uint8_t count = 0; + +ISR(TIMER0_COMPA_vect) { + if (count == 0) { + /* switch off all LEDs */ + PORTB = PORTB & ~((1 << PB6) | (1 << PB7)); + PORTD = PORTD & ~((1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5)); + } else { + uint8_t pb = 0, pd = 0; + if (count > invbrightness[0]) { + pb |= (1 << PB6); + } + if (count > invbrightness[1]) { + pb |= (1 << PB7); + } + if (count > invbrightness[2]) { + pd |= (1 << PD2); + } + if (count > invbrightness[3]) { + pd |= (1 << PD3); + } + if (count > invbrightness[4]) { + pd |= (1 << PD4); + } + if (count > invbrightness[5]) { + pd |= (1 << PD5); + } + /* actually set them */ + PORTB |= pb; + PORTD |= pd; + } + ++count; + if (count >= PWM_STEPS) { + count = 0; + } +} + +void pwmInit () { + /* set led1,led2 to output */ + DDRB |= (1 << PB6) | (1 << PB7); + /* set led3,led4,led5,led6 to output */ + DDRD |= (1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5); +} + +void pwmStart () { + /* reset timer value */ + TCNT0 = 0; + /* set ctc timer0 (part 1) */ + TCCR0A = 0; + /* enable compare match interrupt */ + TIMSK0 = (1 << OCIE0A); + /* compare value; interrupt on every tick */ + OCR0A = 0; + /* io clock with 8 prescaler (>8 is too slow and starts flickering); ctc + * (part 2) */ + TCCR0B = (1 << CS01) | (1 << WGM02); +} + +void pwmStop () { + /* zero clock source */ + TCCR0B = 0; +} + +void pwmSetBrightness (const uint8_t i, const uint8_t b) { + invbrightness[i] = b; +} + @@ -0,0 +1,11 @@ +#ifndef PWM_H +#define PWM_H + +#include <stdint.h> +void pwmInit (); +void pwmStart (); +void pwmStop (); +void pwmSetBrightness (const uint8_t i, const uint8_t b); + +#endif /* PWM_H */ + |