From a777f9ac5e0ad6d130a2fda4e3a86b694cbfdfe8 Mon Sep 17 00:00:00 2001 From: Maix0 <39835848+Maix0@users.noreply.github.com> Date: Thu, 16 Apr 2026 16:43:23 +0200 Subject: [PATCH] feat(ex02): done --- .clang-format | 58 ++++++++++++++++++- ex02/Makefile | 55 ++++++++++++++++++ ex02/include/mystd.h | 15 +++++ ex02/include/timer0.h | 112 ++++++++++++++++++++++++++++++++++++ ex02/include/timer2.h | 112 ++++++++++++++++++++++++++++++++++++ ex02/include/timer_global.h | 25 ++++++++ ex02/include/utils.h | 10 ++++ ex02/src/main.c | 96 +++++++++++++++++++++++++++++++ ex02/src/utils.c | 28 +++++++++ 9 files changed, 510 insertions(+), 1 deletion(-) create mode 100644 ex02/Makefile create mode 100644 ex02/include/mystd.h create mode 100644 ex02/include/timer0.h create mode 100644 ex02/include/timer2.h create mode 100644 ex02/include/timer_global.h create mode 100644 ex02/include/utils.h create mode 100644 ex02/src/main.c create mode 100644 ex02/src/utils.c diff --git a/.clang-format b/.clang-format index fd608c9..beb2561 100644 --- a/.clang-format +++ b/.clang-format @@ -1 +1,57 @@ -git@vogsphere.42paris.fr:vogsphere/intra-uuid-daecd842-c910-4973-b9ff-efcdd4424883-7368496-macaruan +BasedOnStyle: Chromium +AccessModifierOffset: 0 +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCompound: true + AlignFunctionPointers: true + PadOperators: false +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCompound: true + AlignFunctionPointers: true + PadOperators: true +AlignConsecutiveDeclarations: + Enabled: true + AcrossComments: true + AlignCompound: true + AlignFunctionPointers: true + PadOperators: true +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCompound: true + AlignFunctionPointers: true + PadOperators: true +AlignConsecutiveShortCaseStatements: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCaseArrows: true + AlignCaseColons: true +ColumnLimit: 100 +NamespaceIndentation: All +CommentPragmas: "" +IncludeCategories: + - Regex: ^<.*\.h> + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: ^<.* + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: .* + Priority: 3 + SortPriority: 0 + CaseSensitive: false +IndentPPDirectives: AfterHash +IndentWidth: 4 +TabWidth: 4 +UseTab: Always +Language: Cpp +IndentAccessModifiers: true diff --git a/ex02/Makefile b/ex02/Makefile new file mode 100644 index 0000000..1234920 --- /dev/null +++ b/ex02/Makefile @@ -0,0 +1,55 @@ +# 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 +IFLAGS= +TARGET=main +SERIAL=-P /dev/ttyUSB0 -b 115200 + + +SRC_DIR=src +OBJ_DIR=build + +SRC_FILES=main.c utils.c timer.c +OBJ_FILES=$(patsubst %.c,%.o,$(SRC_FILES)) + +SRC=$(addprefix $(SRC_DIR)/,$(SRC_FILES)) +OBJ=$(addprefix $(OBJ_DIR)/,$(OBJ_FILES)) + +ELF_FILE=$(OBJ_DIR)/$(TARGET).elf +HEX_FILE=$(OBJ_DIR)/$(TARGET).hex + +all: flash + +re: fclean all + +fclean: clean + rm -f $(HEX_FILE) + rm -f $(ELF_FILE) +clean: + rm -rf $(OBJ_DIR) + +hex: $(HEX_FILE) + +flash: hex + avrdude -p $(MCU) -c arduino -U flash:w:$(HEX_FILE):i $(SERIAL) + + +$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c + @mkdir -p $(shell dirname $@) + $(CC) $(CFLAGS) $(IFLAGS) -c $< -o $@ + +$(ELF_FILE): $(OBJ) + $(CC) $(CFLAGS) $(OBJ) -o $@ + +$(HEX_FILE): $(ELF_FILE) + $(OBJCOPY) -j .text -j .data -O ihex $< $@ + +print: + @echo $(SRC) + @echo $(OBJ) + @echo $(ELF_FILE) + @echo $(HEX_FILE) + 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/timer0.h b/ex02/include/timer0.h new file mode 100644 index 0000000..43ce95f --- /dev/null +++ b/ex02/include/timer0.h @@ -0,0 +1,112 @@ +#ifndef TIMER0_H +# define TIMER0_H + +# include +# include "mystd.h" + +# include "timer_global.h" + +static inline void t0_init_fpwm_3(e_timer_prescaler prescaler) { + // Fast PWM (8-bit): WGM22:0 = 0b011 + TCCR0A = _BV(WGM00) | _BV(WGM01); + + // reset to zero -> timer off + TCCR0B &= ~(_BV(CS02) | _BV(CS01) | _BV(CS00)); + // set the correct prescaler + switch (prescaler) { + case (PRESCALER_1): { + TCCR0B |= (_BV(CS00)); + break; + } + case (PRESCALER_8): { + TCCR0B |= (_BV(CS01)); + break; + } + case (PRESCALER_64): { + TCCR0B |= (_BV(CS01) | _BV(CS00)); + break; + } + case (PRESCALER_256): { + TCCR0B |= (_BV(CS02)); + break; + } + case (PRESCALER_1024): { + TCCR0B |= (_BV(CS02) | _BV(CS00)); + break; + } + case (PRESCALER_OFF): { + break; + } + } +} + +static inline void t0_set_ocr(enum e_timer_output output, uint8_t value) { + if (output & TO_A) + OCR0A = value; + if (output & TO_B) + OCR0B = value; +} + +static inline void t0_set_out_mode(enum e_timer_output output, enum e_timer_output_mode mode) { + if (output & TO_A) { + TCCR0A &= ~(_BV(COM0A1) | _BV(COM0A0)); + switch (mode) { + case (TOM_00): { + break; + } + case (TOM_10): { + TCCR0A |= (_BV(COM0A1)); + break; + } + case (TOM_01): { + TCCR0A |= (_BV(COM0A0)); + break; + } + case (TOM_11): { + TCCR0A |= (_BV(COM0A1) | _BV(COM0A0)); + break; + } + } + } + if (output & TO_B) { + TCCR0A &= ~(_BV(COM0B1) | _BV(COM0B0)); + switch (mode) { + case (TOM_00): { + break; + } + case (TOM_10): { + TCCR0A |= (_BV(COM0B1)); + break; + } + case (TOM_01): { + TCCR0A |= (_BV(COM0B0)); + break; + } + case (TOM_11): { + TCCR0A |= (_BV(COM0B1) | _BV(COM0B0)); + break; + } + } + } +} + +// OC2B => RED => PD3 +// OC0B => GREEN => PD5 +// OC0A => BLUE => PD6 + +#endif /* TIMER0_H */ + + /* + // OC2B = PD3 → output + DDRD |= _BV(DDD3) | _BV(DDD5) | _BV(DDD6); + + // Fast PWM (8-bit): WGM22:0 = 0b011 + TCCR0A = _BV(WGM00) | _BV(WGM01); + TCCR0A |= _BV(COM0B1); + + // 50% duty cycle + OCR0B = 128; + + // Start timer, prescaler = 64 + TCCR0B = _BV(CS02); + */ diff --git a/ex02/include/timer2.h b/ex02/include/timer2.h new file mode 100644 index 0000000..3a97258 --- /dev/null +++ b/ex02/include/timer2.h @@ -0,0 +1,112 @@ +#ifndef TIMER2_H +# define TIMER2_H + +# include +# include "mystd.h" + +# include "timer_global.h" + +static inline void t2_init_fpwm_3(e_timer_prescaler prescaler) { + // Fast PWM (8-bit): WGM22:0 = 0b011 + TCCR2A = _BV(WGM20) | _BV(WGM21); + + // reset to zero -> timer off + TCCR2B &= ~(_BV(CS22) | _BV(CS21) | _BV(CS20)); + // set the correct prescaler + switch (prescaler) { + case (PRESCALER_1): { + TCCR2B |= (_BV(CS20)); + break; + } + case (PRESCALER_8): { + TCCR2B |= (_BV(CS21)); + break; + } + case (PRESCALER_64): { + TCCR2B |= (_BV(CS21) | _BV(CS20)); + break; + } + case (PRESCALER_256): { + TCCR2B |= (_BV(CS22)); + break; + } + case (PRESCALER_1024): { + TCCR2B |= (_BV(CS22) | _BV(CS20)); + break; + } + case (PRESCALER_OFF): { + break; + } + } +} + +static inline void t2_set_ocr(enum e_timer_output output, uint8_t value) { + if (output & TO_A) + OCR2A = value; + if (output & TO_B) + OCR2B = value; +} + +static inline void t2_set_out_mode(enum e_timer_output output, enum e_timer_output_mode mode) { + if (output & TO_A) { + TCCR2A &= ~(_BV(COM2A1) | _BV(COM2A0)); + switch (mode) { + case (TOM_00): { + break; + } + case (TOM_10): { + TCCR2A |= (_BV(COM2A1)); + break; + } + case (TOM_01): { + TCCR2A |= (_BV(COM2A0)); + break; + } + case (TOM_11): { + TCCR2A |= (_BV(COM2A1) | _BV(COM2A0)); + break; + } + } + } + if (output & TO_B) { + TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0)); + switch (mode) { + case (TOM_00): { + break; + } + case (TOM_10): { + TCCR2A |= (_BV(COM2B1)); + break; + } + case (TOM_01): { + TCCR2A |= (_BV(COM2B0)); + break; + } + case (TOM_11): { + TCCR2A |= (_BV(COM2B1) | _BV(COM2B0)); + break; + } + } + } +} + +// OC2B => RED => PD3 +// OC0B => GREEN => PD5 +// OC0A => BLUE => PD6 + +#endif /* TIMER0_H */ + + /* + // OC2B = PD3 → output + DDRD |= _BV(DDD3) | _BV(DDD5) | _BV(DDD6); + + // Fast PWM (8-bit): WGM22:0 = 0b011 + TCCR2A = _BV(GM20) | _BV(GM21); + TCCR2A |= _BV(COM2B1); + + // 50% duty cycle + OCR0B = 128; + + // Start timer, prescaler = 64 + TCCR2B = _BV(CS22); + */ diff --git a/ex02/include/timer_global.h b/ex02/include/timer_global.h new file mode 100644 index 0000000..7e1833a --- /dev/null +++ b/ex02/include/timer_global.h @@ -0,0 +1,25 @@ +#ifndef TIMER_GLOBAL_H +#define TIMER_GLOBAL_H + +typedef enum e_timer_prescaler { + PRESCALER_OFF = 0, + PRESCALER_1 = 1, + PRESCALER_8 = 8, + PRESCALER_64 = 64, + PRESCALER_256 = 256, + PRESCALER_1024 = 1024, +} e_timer_prescaler; + +typedef enum e_timer_output { + TO_A = (1 << 0), + TO_B = (1 << 1), +} e_timer_output; + +typedef enum e_timer_output_mode { + TOM_00, + TOM_01, + TOM_10, + TOM_11, +} e_timer_output_mode; + +#endif /* TIMER_GLOBAL_H */ diff --git a/ex02/include/utils.h b/ex02/include/utils.h new file mode 100644 index 0000000..22d70d1 --- /dev/null +++ b/ex02/include/utils.h @@ -0,0 +1,10 @@ +#ifndef UTILS_H +#define UTILS_H + +#include "mystd.h" + +void delay_ms(uint16_t count); + +void ft_bzero(void *data, uint16_t size); + +#endif /* UTILS_H */ diff --git a/ex02/src/main.c b/ex02/src/main.c new file mode 100644 index 0000000..074391e --- /dev/null +++ b/ex02/src/main.c @@ -0,0 +1,96 @@ +#include + +#include "mystd.h" +#include "timer_global.h" +#include "utils.h" + +#include "timer0.h" +#include "timer2.h" + +#define D5_R PD5 +#define D5_G PD6 +#define D5_B PD3 + +#define RGB_MASK (_BV(D5_R) | _BV(D5_G) | _BV(D5_B)) + +/* +name R# G# B# +red ff 0 0 +green 0 ff 0 +blue 0 0 ff + +yellow ff ff 0 +cyan 0 ff ff +magenta ff 0 ff + +white ff ff ff +*/ +#define COL_RED (_BV(D5_R)) +#define COL_GREEN (_BV(D5_G)) +#define COL_BLUE (_BV(D5_B)) + +#define COL_YELLOW (_BV(D5_R) | _BV(D5_G)) +#define COL_CYAN (_BV(D5_G) | _BV(D5_B)) +#define COL_MAGENTA (_BV(D5_R) | _BV(D5_B)) + +#define COL_WHITE (_BV(D5_R) | _BV(D5_G) | _BV(D5_B)) + +// OC2B => BLUE => PD3 | 2 +// OC0B => RED => PD5 | 0 +// OC0A => GREEN => PD6 | 0 + +void set_rgb(uint8_t r, uint8_t g, uint8_t b) { + if (r == 0x00) { + t0_set_out_mode(TO_B, TOM_00); + PORTD = (PORTD & ~_BV(PD5)); + } else { + t0_set_out_mode(TO_B, TOM_10); + t0_set_ocr(TO_B, r); + } + + if (g == 0x00) { + t0_set_out_mode(TO_A, TOM_00); + PORTD = (PORTD & ~_BV(PD6)); + } else { + t0_set_out_mode(TO_A, TOM_10); + t0_set_ocr(TO_A, g); + } + + if (b == 0x00) { + t2_set_out_mode(TO_B, TOM_00); + PORTD = (PORTD & ~_BV(PD3)); + } else { + t2_set_out_mode(TO_B, TOM_10); + t2_set_ocr(TO_B, b); + } +} + +void wheel(uint8_t pos) { + pos = 255 - pos; + if (pos < 85) { + set_rgb(255 - pos * 3, 0, pos * 3); + } else if (pos < 170) { + pos = pos - 85; + set_rgb(0, pos * 3, 255 - pos * 3); + } else { + pos = pos - 170; + set_rgb(pos * 3, 255 - pos * 3, 0); + } +} + +int main(void) { + // OC2B = PD3 → output + DDRD |= RGB_MASK; + + t0_init_fpwm_3(PRESCALER_64); + t2_init_fpwm_3(PRESCALER_64); + + t0_set_out_mode(TO_A | TO_B, TOM_00); + t2_set_out_mode(TO_B, TOM_00); + + uint8_t pos = 0; + while (1) { + wheel(pos++); + delay_ms(10); + } +} diff --git a/ex02/src/utils.c b/ex02/src/utils.c new file mode 100644 index 0000000..25b0d93 --- /dev/null +++ b/ex02/src/utils.c @@ -0,0 +1,28 @@ +#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--; + } +} + +void ft_bzero(void* data, uint16_t size) { + char* d = data; + while (size) { + *d = 0; + d++; + size--; + } +}