diff --git a/ion/include/ion/led.h b/ion/include/ion/led.h new file mode 100644 index 000000000..fbed450ea --- /dev/null +++ b/ion/include/ion/led.h @@ -0,0 +1,20 @@ +#ifndef ION_LED_H +#define ION_LED_H + +/* ION abstracts pushing pixels to the screen. + * + * There could be a single entry point, set_pixel, but setting pixels one by one + * incurs quite a large overhead because you need to send the coordinate of each + * pixel to the screen. + * + * Many displays support sending contiguous pixels without having to repeat the + * pixel coordinates every time. We're therefore leveraging this capability + * which results in a very consequent speedup (up to ~10x faster). */ + +#include + +typedef uint16_t ion_color_t; + +void ion_led_set_color(ion_color_t color); + +#endif diff --git a/ion/src/device/Makefile b/ion/src/device/Makefile index 4a80badfe..101bfe104 100644 --- a/ion/src/device/Makefile +++ b/ion/src/device/Makefile @@ -1,5 +1,5 @@ include ion/src/device/boot/Makefile -objs += $(addprefix ion/src/device/, init.o heap.o) +objs += $(addprefix ion/src/device/, init.o heap.o led.o) objs += $(addprefix ion/src/device/display/,\ display.o\ gpio.o\ diff --git a/ion/src/device/init.c b/ion/src/device/init.c index 33a93b222..0012237b3 100644 --- a/ion/src/device/init.c +++ b/ion/src/device/init.c @@ -19,6 +19,7 @@ void enable_fpu() { void init_platform() { enable_fpu(); init_keyboard(); + ion_led_init(); init_display(); } diff --git a/ion/src/device/led.c b/ion/src/device/led.c new file mode 100644 index 000000000..5aaaf3e29 --- /dev/null +++ b/ion/src/device/led.c @@ -0,0 +1,89 @@ +#include +#include "registers/registers.h" + +/* Pin used : + * PA8 - Red LED - TIM1_CH1 + * PA9 - Green LED - TIM1_CH2 + * PA10 - Blue LED -TIM1_CH3 + */ + +void sleep() { + for (volatile int i=0;i<100000; i++) { + } +} + +void ion_led_gpio_init() { + // We are using GPIOA, which live on the AHB1 bus. Let's enable its clock. + RCC_AHB1ENR |= GPIOAEN; + +#if 0 + + for (int i=8; i<=8; i++) { + REGISTER_SET_VALUE(GPIO_MODER(GPIOA), MODER(i), GPIO_MODE_OUTPUT); + } + char value = 1; + while (1) { + value = !value; + for (int i=8; i<=10; i++) { + REGISTER_SET_VALUE(GPIO_ODR(GPIOA), ODR(i), value); + } + for (volatile int i=0; i<100000; i++) { + } + } +#else + + /* RED_LED(PA8), GREEN_LED(PA9), BLUE_LED(PA10) are driven using a timer, + * which is an alternate function. */ + REGISTER_SET_VALUE(GPIO_MODER(GPIOA), MODER(8), GPIO_MODE_ALTERNATE_FUNCTION); + REGISTER_SET_VALUE(GPIO_MODER(GPIOA), MODER(9), GPIO_MODE_ALTERNATE_FUNCTION); + REGISTER_SET_VALUE(GPIO_MODER(GPIOA), MODER(10), GPIO_MODE_ALTERNATE_FUNCTION); + + /* More precisely, we will use AF01, which maps PA8 to TIM1_CH1, PA9 to + * TIM1_CH2 and PA10 to TIM1_CH3. */ + REGISTER_SET_VALUE(GPIO_AFR(GPIOA, 8), AFR(8), 1); + REGISTER_SET_VALUE(GPIO_AFR(GPIOA, 9), AFR(9), 1); + REGISTER_SET_VALUE(GPIO_AFR(GPIOA, 10), AFR(10), 1); +#endif +} + +void ion_led_timer_init() { + /* TIM1 lives on the APB2 bus. Let's enable its clock. */ + RCC_APB2ENR |= TIM1EN; + TIM_PSC(TIM1) = 1000; + + /* Pulse width modulation mode allows you to generate a signal with a + * frequency determined by the value of the TIMx_ARR register and a duty cycle + * determined by the value of the TIMx_CCRx register. */ + TIM_ARR(TIM1) = 40000; + TIM_CCR1(TIM1) = 20000; + TIM_CCR2(TIM1) = 20000; + + + // Set Channel 1 as output, PWM mode 1 + REGISTER_SET_VALUE(TIM_CCMR1(TIM1), TIM_OC1M, 6); + // Set Channel 2 as output, PWM mode 2 + REGISTER_SET_VALUE(TIM_CCMR1(TIM1), TIM_OC2M, 6); + //REGISTER_SET_VALUE(TIM_CCMR2(TIM1), TIM_OC3M, 6); + + // Output preload enable for channel 1 and 2 + TIM_CCMR1(TIM1) |= (TIM_OC1PE | TIM_OC2PE); + + // Auto-reload preload enable + TIM_CR1(TIM1) |= TIM_ARPE; + + // Enable Capture/Compare channel 1 and channel 2 + TIM_CCER(TIM1) |= (TIM_CC1E | TIM_CC2E); + + TIM_BDTR(TIM1) |= (TIM_MOE); + + TIM_CR1(TIM1) |= (TIM_CEN); // Enable the counter +} + +void ion_led_init() { + ion_led_gpio_init(); + ion_led_timer_init(); +} + + +void ion_led_set_color(ion_color_t color) { +} diff --git a/ion/src/device/registers/registers.h b/ion/src/device/registers/registers.h index abc385184..2a2f1a524 100644 --- a/ion/src/device/registers/registers.h +++ b/ion/src/device/registers/registers.h @@ -25,4 +25,5 @@ #include "spi.h" #include "dma.h" #include "cm4.h" +#include "tim.h" //#include "ltdc.h" diff --git a/ion/src/device/registers/tim.h b/ion/src/device/registers/tim.h new file mode 100644 index 000000000..4fb9cde75 --- /dev/null +++ b/ion/src/device/registers/tim.h @@ -0,0 +1,85 @@ +#ifndef STM32_REGISTERS_TIM_H +#define STM32_REGISTERS_TIM_H 1 + +#define TIM1_BASE 0x40010000 +#define TIM2_BASE 0x40000000 +#define TIM3_BASE 0x40000400 +#define TIM4_BASE 0x40000800 + +#define TIM_REGISTER_AT(timer,offset) (*(volatile uint16_t *)(timer##_BASE+offset)) + +// TIM control registers 1 + +#define TIM_CR1(timer) TIM_REGISTER_AT(timer, 0x00) + +#define TIM_CEN (1<<0) +#define TIM_UDIS (1<<1) +#define TIM_URS (1<<2) +#define TIM_OPM (1<<3) +#define TIM_DIR (1<<4) +//#define TIM_CMS +#define TIM_ARPE (1<<7) +#define TIM_CKD_1 0 +#define TIM_CKD_2 1 +#define TIM_CKD_4 2 + +// TIM control registers 2 + +#define TIM_CR2(timer) TIM_REGISTER_AT(timer, 0x04) + +#define TIM_CDDS (1<<3) +#define TIM_MMS_RESET 0 +#define TIM_MMS_ENABLE 1 +#define TIM_MMS_UPDATE 2 +#define TIM_MMS_COMPARE_PULSE 3 +#define TIM_TI1S (1<<7) + +// TIM capture/compare mode register 1 + +#define TIM_CCMR1(timer) TIM_REGISTER_AT(timer, 0x18) + +//#define LOW_BIT_TIM_CC1S 0 +//#define HIGH_BIT_TIM_CC1S 1 +#define TIM_OC1PE (1<<3) +#define LOW_BIT_TIM_OC1M 4 +#define HIGH_BIT_TIM_OC1M 6 +#define TIM_OC2PE (1<<11) +#define LOW_BIT_TIM_OC2M 12 +#define HIGH_BIT_TIM_OC2M 14 + +#define TIM_CCMR2(timer) TIM_REGISTER_AT(timer, 0x1C) + +#define LOW_BIT_TIM_OC3M 4 +#define HIGH_BIT_TIM_OC3M 6 + +// TIM capture/compare enable register +#define TIM_CCER(timer) TIM_REGISTER_AT(timer, 0x20) + +#define TIM_CC1E (1<<0) +#define TIM_CC1P (1<<1) +#define TIM_CC1NE (1<<2) +#define TIM_CC2E (1<<4) +#define TIM_CC2P (1<<5) +#define TIM_CC2NE (1<<6) + +#define TIM_CNT(timer) TIM_REGISTER_AT(timer, 0x24) +#define TIM_PSC(timer) TIM_REGISTER_AT(timer, 0x28) + +// TIM auto-reload register +#define TIM_ARR(timer) TIM_REGISTER_AT(timer, 0x2C) + +// TIM capture/compare register 1 +#define TIM_CCR1(timer) TIM_REGISTER_AT(timer, 0x34) + +// TIM capture/compare register 2 +#define TIM_CCR2(timer) TIM_REGISTER_AT(timer, 0x38) + + +// TIM break and dead-time register + +#define TIM_BDTR(timer) TIM_REGISTER_AT(timer, 0x44) + + +#define TIM_MOE (1<<15) + +#endif