diff --git a/ex00/main.c b/ex00/main.c index 65207e8..62d8906 100644 --- a/ex00/main.c +++ b/ex00/main.c @@ -9,10 +9,10 @@ #define D4 PORTB4 int main(void) { - DDRB |= _BV(D1); + DDRB |= _BV(D2); while (true) { - PORTB ^= _BV(D1); + PORTB ^= _BV(D2); delay_ms(500); }; } diff --git a/ex01/main.c b/ex01/main.c index f514ef9..23c01e3 100644 --- a/ex01/main.c +++ b/ex01/main.c @@ -20,14 +20,14 @@ // // all these information are on page ~140 void timer1_init(void) { - // Set PB2 (OC1B) as output - DDRB |= _BV(PB2); + // Set PB1 (OC1A) as output + DDRB |= _BV(PB1); // CTC mode (WGM12 = 1) TCCR1B |= _BV(WGM12); // Toggle OC1B on compare match (COM1B0 = 1) - TCCR1A |= _BV(COM1B0); + TCCR1A |= _BV(COM1A0); // Set compare values OCR1A = TIMER_FREQ / 2; diff --git a/ex02/Makefile b/ex02/Makefile new file mode 100644 index 0000000..d64d0a1 --- /dev/null +++ b/ex02/Makefile @@ -0,0 +1,43 @@ +# Makefile +MCU=atmega328p +F_CPU=16000000 +CC=avr-gcc +OBJCOPY=avr-objcopy +CFLAGS=-std=c99 -Wall -Wextra -g -Os -mmcu=$(MCU) -DF_CPU=$(F_CPU) -Iinclude +TARGET=main +SERIAL=-P /dev/ttyUSB0 -b 115200 + + +SRC_DIR=. +OBJ_DIR=build + +SRC_FILES=main.c utils.c +OBJ_FILES=$(patsubst %.c,%.o,$(SRC_FILES)) + +SRC=$(addprefix $(SRC_DIR)/,$(SRC_FILES)) +OBJ=$(addprefix $(OBJ_DIR)/,$(OBJ_FILES)) + +all: flash + +re: fclean all + +fclean: clean +clean: + rm -rf $(OBJ_DIR) + rm -f $(TARGET).hex + +hex: $(TARGET).hex + +flash: hex + avrdude -p $(MCU) -c arduino -U flash:w:$(TARGET).hex:i $(SERIAL) + +$(OBJ_DIR)/$(TARGET).bin: $(OBJ) + $(CC) $(CFLAGS) $(OBJ) -o $@ + +$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c + mkdir -p $(shell dirname $@) + $(CC) $(CFLAGS) -c $< -o $@ + + +$(TARGET).hex: $(OBJ_DIR)/$(TARGET).bin + $(OBJCOPY) -j .text -j .data -O ihex $< $@ diff --git a/ex02/include/mystd.h b/ex02/include/mystd.h new file mode 100644 index 0000000..5d880c5 --- /dev/null +++ b/ex02/include/mystd.h @@ -0,0 +1,15 @@ +#ifndef MYSTDINT_H +#define MYSTDINT_H + +typedef unsigned int uint16_t; +typedef signed int int16_t; + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef uint8_t bool; + +#define true (1) +#define false (0) + +#endif /* MYSTDINT_H */ diff --git a/ex02/include/utils.h b/ex02/include/utils.h new file mode 100644 index 0000000..a9ab05f --- /dev/null +++ b/ex02/include/utils.h @@ -0,0 +1,8 @@ +#ifndef UTILS_H +#define UTILS_H + +#include "mystd.h" + +void delay_ms(uint16_t count); + +#endif /* UTILS_H */ diff --git a/ex02/main.c b/ex02/main.c new file mode 100644 index 0000000..0b12ad9 --- /dev/null +++ b/ex02/main.c @@ -0,0 +1,45 @@ +#include +#include "mystd.h" +#include "utils.h" + +#define D1 PORTB0 +#define D2 PORTB1 +#define D3 PORTB2 +#define D4 PORTB4 + +#define PRESCALER 256 +#define TIMER_FREQ (F_CPU / PRESCALER) + +#define DUTY_CYCLE 1 + +// the PWM is something that counts from 0 to TOP +// when it reached the value i'll name TOGGLE, it'll set the OUTPUT high +// when it reaches TOP it'll reset COUNTER and set OUTPUT to low +// +// this means we have a clock that reaches TOP every X +// and during this, we can set TOGGLE such that we set OUTPUT high +void timer1_init(void) { + // Set PB1 (OC1A) as output + DDRB |= _BV(PB1); + + // Non-inverting OC1B -> the OC1B is set to low on TOP reached + TCCR1A |= _BV(COM1A1); + + // set to PWM-fast with ICR1 as TOP + TCCR1A |= _BV(WGM11); + TCCR1B |= _BV(WGM13) | _BV(WGM12); + + // TOP => 1hz + ICR1 = TIMER_FREQ - 1; + // TOGGLE => 1/10th of ICR1 + OCR1A = ((TIMER_FREQ / 10) * DUTY_CYCLE); + + // Start timer with prescaler 256 (CS12) + TCCR1B |= _BV(CS12); +} + +int main(void) { + timer1_init(); + while (1) + ; +} diff --git a/ex02/utils.c b/ex02/utils.c new file mode 100644 index 0000000..96efa11 --- /dev/null +++ b/ex02/utils.c @@ -0,0 +1,19 @@ +#include "utils.h" + +// this just burns cycles. +// the volatile is important, it means that the cpu can't optimize any +// read/writes for the value +static inline void spin_loop(volatile uint16_t counts) { + while (counts) + counts--; +} + +void delay_ms(uint16_t ms) { + while (ms) { + // this value was taken using a delay of 500ms, and just recording the led + // blinking. it seems to be high enough such that each loop of delay_loop + // takes 1ms :D + spin_loop((F_CPU) / 5000); + ms--; + } +} diff --git a/ex03/Makefile b/ex03/Makefile new file mode 100644 index 0000000..d64d0a1 --- /dev/null +++ b/ex03/Makefile @@ -0,0 +1,43 @@ +# Makefile +MCU=atmega328p +F_CPU=16000000 +CC=avr-gcc +OBJCOPY=avr-objcopy +CFLAGS=-std=c99 -Wall -Wextra -g -Os -mmcu=$(MCU) -DF_CPU=$(F_CPU) -Iinclude +TARGET=main +SERIAL=-P /dev/ttyUSB0 -b 115200 + + +SRC_DIR=. +OBJ_DIR=build + +SRC_FILES=main.c utils.c +OBJ_FILES=$(patsubst %.c,%.o,$(SRC_FILES)) + +SRC=$(addprefix $(SRC_DIR)/,$(SRC_FILES)) +OBJ=$(addprefix $(OBJ_DIR)/,$(OBJ_FILES)) + +all: flash + +re: fclean all + +fclean: clean +clean: + rm -rf $(OBJ_DIR) + rm -f $(TARGET).hex + +hex: $(TARGET).hex + +flash: hex + avrdude -p $(MCU) -c arduino -U flash:w:$(TARGET).hex:i $(SERIAL) + +$(OBJ_DIR)/$(TARGET).bin: $(OBJ) + $(CC) $(CFLAGS) $(OBJ) -o $@ + +$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c + mkdir -p $(shell dirname $@) + $(CC) $(CFLAGS) -c $< -o $@ + + +$(TARGET).hex: $(OBJ_DIR)/$(TARGET).bin + $(OBJCOPY) -j .text -j .data -O ihex $< $@ diff --git a/ex03/include/mystd.h b/ex03/include/mystd.h new file mode 100644 index 0000000..5d880c5 --- /dev/null +++ b/ex03/include/mystd.h @@ -0,0 +1,15 @@ +#ifndef MYSTDINT_H +#define MYSTDINT_H + +typedef unsigned int uint16_t; +typedef signed int int16_t; + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef uint8_t bool; + +#define true (1) +#define false (0) + +#endif /* MYSTDINT_H */ diff --git a/ex03/include/utils.h b/ex03/include/utils.h new file mode 100644 index 0000000..a9ab05f --- /dev/null +++ b/ex03/include/utils.h @@ -0,0 +1,8 @@ +#ifndef UTILS_H +#define UTILS_H + +#include "mystd.h" + +void delay_ms(uint16_t count); + +#endif /* UTILS_H */ diff --git a/ex03/main.c b/ex03/main.c new file mode 100644 index 0000000..f2dc8aa --- /dev/null +++ b/ex03/main.c @@ -0,0 +1,70 @@ +#include +#include "mystd.h" +#include "utils.h" + +#define D1 PORTB0 +#define D2 PORTB1 +#define D3 PORTB2 +#define D4 PORTB4 + +#define PRESCALER 256 +#define TIMER_FREQ (F_CPU / PRESCALER) + +// the PWM is something that counts from 0 to TOP +// when it reached the value i'll name TOGGLE, it'll set the OUTPUT high +// when it reaches TOP it'll reset COUNTER and set OUTPUT to low +// +// this means we have a clock that reaches TOP every X +// and during this, we can set TOGGLE such that we set OUTPUT high +void timer1_init(uint8_t duty) { + // Set PB1 (OC1A) as output + DDRB |= _BV(PB1); + + // Non-inverting OC1B -> the OC1B is set to low on TOP reached + TCCR1A |= _BV(COM1A1); + + // set to PWM-fast with ICR1 as TOP + TCCR1A |= _BV(WGM11); + TCCR1B |= _BV(WGM13) | _BV(WGM12); + + // TOP => 1hz + ICR1 = TIMER_FREQ - 1; + // TOGGLE => 1/10th of ICR1 + OCR1A = ((TIMER_FREQ / 10) * duty); + + // Start timer with prescaler 256 (CS12) + TCCR1B |= _BV(CS12); +} + +#define SW1 PD2 +#define SW2 PD4 + +int main(void) { + uint8_t prev = 0; + uint8_t duty_cycle = 1; + timer1_init(duty_cycle); + while (1) { + bool has_changed = false; + // lets read both button in a single byte, and keep track of that too + uint8_t cur = (PIND & (_BV(SW1) | _BV(SW2))); + // check for button SW1 + if (prev & (_BV(SW1)) && !(cur & (_BV(SW1)))) { + duty_cycle++; + has_changed = true; + } + // check for button SW2 + if (prev & (_BV(SW2)) && !(cur & (_BV(SW2)))) { + duty_cycle--; + has_changed = true; + } + prev = cur; + if (has_changed) { + if (duty_cycle > 10) + duty_cycle = 10; + if (duty_cycle < 1) + duty_cycle = 1; + timer1_init(duty_cycle); + } + delay_ms(10); + } +} diff --git a/ex03/utils.c b/ex03/utils.c new file mode 100644 index 0000000..96efa11 --- /dev/null +++ b/ex03/utils.c @@ -0,0 +1,19 @@ +#include "utils.h" + +// this just burns cycles. +// the volatile is important, it means that the cpu can't optimize any +// read/writes for the value +static inline void spin_loop(volatile uint16_t counts) { + while (counts) + counts--; +} + +void delay_ms(uint16_t ms) { + while (ms) { + // this value was taken using a delay of 500ms, and just recording the led + // blinking. it seems to be high enough such that each loop of delay_loop + // takes 1ms :D + spin_loop((F_CPU) / 5000); + ms--; + } +}