diff --git a/Makefile b/Makefile index aeb205a..87827af 100644 --- a/Makefile +++ b/Makefile @@ -74,6 +74,9 @@ flash: restore: avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(DUMP_ORI) +dump: + avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:r:dump.hex + clean: rm -f main.hex main.bin *.o diff --git a/module04/ex01/bitmanip.h b/module04/ex01/bitmanip.h index ce33649..0808aec 100644 --- a/module04/ex01/bitmanip.h +++ b/module04/ex01/bitmanip.h @@ -36,16 +36,16 @@ #define PULLUP_ON(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem)) #define PULLUP_OFF(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem)) -// Bit definitions -#define D1 0 -#define D2 1 -#define D3 2 -#define D4 4 -#define SW1 2 -#define SW2 4 -#define D5B 3 -#define D5R 5 -#define D5G 6 +// Bit definitions ( // ) +#define D1 0 // PB0 +#define D2 1 // PB1 +#define D3 2 // PB2 +#define D4 4 // PB4 +#define SW1 2 // PD2 +#define SW2 4 // PD4 +#define D5B 3 // PD3 +#define D5R 5 // PD5 +#define D5G 6 // PD6 // Elements (port, bit) #define LED1 (B, D1) diff --git a/module04/ex01/header.h b/module04/ex01/header.h index 5934f5d..b4d8b56 100644 --- a/module04/ex01/header.h +++ b/module04/ex01/header.h @@ -14,5 +14,7 @@ // PROTOTYPES // // main.c +void blink_led_1(); +void vary_duty(); #endif // HEADER_H \ No newline at end of file diff --git a/module04/ex01/main.c b/module04/ex01/main.c index 48ffb91..696726a 100644 --- a/module04/ex01/main.c +++ b/module04/ex01/main.c @@ -27,11 +27,62 @@ // - if i choose prescaler 64 for a duration of 0.01 seconds, i need to restart the clock after how many cycles : // - (16000000 / 64) * 0.01 = 2500 ticks -> set ICR1 = 2500 +// alternatively, can use the default values : +// - Fast PWM, 8-bit, TOP 0x00FF (255) +// - Fast PWM, 9-bit, TOP 0x01FF (511) +// - Fast PWM, 10-bit, TOP 0x03FF (1023) + +// no need to set a second for the "blinking" with PWM and duty cycle : +// only need to use a top value convenient, like a multiple of 100 +// if choose top value of 100 : +// - at prescaler 1 : 100 / 16000000 = 0.00000625s (it takes this time to do a cycle) +// - at prescaler 8 : (100 * 8) / 16000000 = 0.00005s +// - at prescaler 64 : (100 * 64) / 16000000 = 0.0004s +// - at prescaler 256 : (100 * 256) / 16000000 = 0.0016s +// - at prescaler 1024 : (100 * 1024) / 16000000 = 0.0064s +// if choose top value of 1000 : +// - at prescaler 1 : 1000 / 16000000 = 0.0000625s (it takes this time to do a cycle) +// - at prescaler 8 : (1000 * 8) / 16000000 = 0.0005s +// - at prescaler 64 : (1000 * 64) / 16000000 = 0.004s +// - at prescaler 256 : (1000 * 256) / 16000000 = 0.016s +// - at prescaler 1024 : (1000 * 1024) / 16000000 = 0.064s + // 16.9.3 : timer1 fast PWM -#define LED1_PWM_PRESCALER 8 // can be 1, 8, 64, 256, 1024 +#define LED1_PWM_PRESCALER 256 // can be 1, 8, 64, 256, 1024 #define DUTY_CYCLE_PERCENT 9 -#define FRQUENCY_MS 1 +#define FREQUENCY_MS 1 +#define TOP_VALUE 1000 + +volatile uint8_t duty_cycle = DUTY_CYCLE_PERCENT; + +void blink_led_1() { + TCCR1A = (1 << WGM11); // Table 16-4 : set timer1 in fast PWM mode 14, with TOP ICR1, so we can use OCR1A for duty cycle and keep ICR1 for frequency + TCCR1B = (1 << WGM13) | (1 << WGM12); // mode 15 with OCR1A TOP prevent using duty cycle trigger on OC1A (OCR1B is free but triggers OC1B -> PB2) + // other fast PWM modes 5, 6, and 7 uses predefined TOP, preventing to define a multiple of 100 for percent accuracy + + TCCR1A |= (1 << COM1A1); // Table 16-2 : set non-inverting mode to trigger OC1A on fast PWM (14.3.1 : OC1A is alternate function of PB1) + + TCCR1B |= PRESCALE_SET(LED1_PWM_PRESCALER); // Table 16-5 : set the appropriate prescale values + + // ICR1 = TIME_MS(FREQUENCY_MS, LED1_PWM_PRESCALER); // top value for Xms + ICR1 = TOP_VALUE; + OCR1A = PERCENT(duty_cycle, ICR1); // 16.9.3 : duty cycle +} + +vary_duty() { + // TCCR0A = (1 << WGM11); // Table 15-8 : set timer0 in CTC mode, with TOP OCRA + // TCCR1B = (1 << WGM13) | (1 << WGM12); + + // TCCR1A |= (1 << COM1A1); // Table 16-2 : set non-inverting mode to trigger OC1A on fast PWM (14.3.1 : OC1A is alternate function of PB1) + + // TCCR1B |= PRESCALE_SET(LED1_PWM_PRESCALER); // Table 16-5 : set the appropriate prescale values + + // // ICR1 = TIME_MS(FREQUENCY_MS, LED1_PWM_PRESCALER); // top value for Xms + // ICR1 = TOP_VALUE; + // OCR1A = PERCENT(duty_cycle, ICR1); // 16.9.3 : duty cycle + +} // use timers interruptions to varie led1 intensity using duty cycle, from 0% to 100% to 0% in 1 second // timer1 sets the led duty cycle, timer0 change the duty cycle percentage @@ -40,19 +91,15 @@ int main() { CLEAR_ELEM(LED1); MODE_OUTPUT(LED2); CLEAR_ELEM(LED2); + MODE_OUTPUT(LED3); + CLEAR_ELEM(LED3); + MODE_OUTPUT(LED4); + CLEAR_ELEM(LED4); SREG |= ENABLE_GLOBAL_INTERRUPT; - TCCR1A = (1 << WGM11); // Table 16-4 : set fast PWM mode with TOP ICR1, so we can use OCR1A for duty cycle and keep ICR1 for frequency - TCCR1B = (1 << WGM13) | (1 << WGM12); - - TCCR1A |= (1 << COM1A1); // Table 16-2 : set non-inverting mode to trigger OC1A on fast PWM - - TCCR1B |= PRESCALE_SET(LED1_PWM_PRESCALER); // Table 16-5 : set the appropriate prescale values - - ICR1 = TIME_MS(FRQUENCY_MS, LED1_PWM_PRESCALER); // top value for Xms - - OCR1A = PERCENT(DUTY_CYCLE_PERCENT, ICR1); // duty cycle frequence + blink_led_1(); + vary_duty(); while (1); }