PWM LED driving

Change-Id: Ic3eb3c13e5a0f35e13caf96039304647b2363bd2
This commit is contained in:
Romain Goyet
2016-08-05 18:44:12 +02:00
parent 197333c83b
commit ada53fed0d
6 changed files with 197 additions and 1 deletions

20
ion/include/ion/led.h Normal file
View File

@@ -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 <stdint.h>
typedef uint16_t ion_color_t;
void ion_led_set_color(ion_color_t color);
#endif

View File

@@ -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\

View File

@@ -19,6 +19,7 @@ void enable_fpu() {
void init_platform() {
enable_fpu();
init_keyboard();
ion_led_init();
init_display();
}

89
ion/src/device/led.c Normal file
View File

@@ -0,0 +1,89 @@
#include <ion/led.h>
#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) {
}

View File

@@ -25,4 +25,5 @@
#include "spi.h"
#include "dma.h"
#include "cm4.h"
#include "tim.h"
//#include "ltdc.h"

View File

@@ -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