From 98dcf81241c8ea176634617af8c4d3146c914eb3 Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 6 Jul 2011 21:18:34 +0000 Subject: Add support for the STM3210E-EVAL LCD backlight git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3748 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/arch/arm/src/stm32/stm32_tim.c | 2 +- nuttx/configs/stm3210e-eval/README.txt | 4 + nuttx/configs/stm3210e-eval/nx/defconfig | 5 + nuttx/configs/stm3210e-eval/src/up_lcd.c | 198 ++++++++++++++++++++++++++++--- 4 files changed, 192 insertions(+), 17 deletions(-) diff --git a/nuttx/arch/arm/src/stm32/stm32_tim.c b/nuttx/arch/arm/src/stm32/stm32_tim.c index d996a7af1..5ce495178 100644 --- a/nuttx/arch/arm/src/stm32/stm32_tim.c +++ b/nuttx/arch/arm/src/stm32/stm32_tim.c @@ -578,7 +578,7 @@ struct stm32_tim_priv_s stm32_tim7_priv = { #if STM32_NATIM > 0 -#if CONFIG_STM32_TIM7 +#if CONFIG_STM32_TIM1 struct stm32_tim_priv_s stm32_tim1_priv = { .ops = &stm32_tim_ops, .mode = STM32_TIM_MODE_UNUSED, diff --git a/nuttx/configs/stm3210e-eval/README.txt b/nuttx/configs/stm3210e-eval/README.txt index 848133b1b..3f050e32f 100755 --- a/nuttx/configs/stm3210e-eval/README.txt +++ b/nuttx/configs/stm3210e-eval/README.txt @@ -414,6 +414,9 @@ STM3210E-EVAL-specific Configuration Options Default is 320x240 (this setting is informative only... not used). CONFIG_LCD_PORTRAIT - Define for 240x320 display support. Default is 320x240. + CONFIG_LCD_BACKLIGHT - Define to support an adjustable backlight + using timer 1. The granularity of the settings is determined + by CONFIG_LCD_MAXPOWER. Requires CONFIG_STM32_TIM1. Configurations ============== @@ -465,6 +468,7 @@ Where is one of the following: uses the Nokia 6100 LCD driver. CONFIG_STM32_CODESOURCERYW=y : CodeSourcery under Windows + CONFIG_LCD_PORTRAIT=y : 240x320 ostest: ------ diff --git a/nuttx/configs/stm3210e-eval/nx/defconfig b/nuttx/configs/stm3210e-eval/nx/defconfig index 8210f04a5..63e362f32 100644 --- a/nuttx/configs/stm3210e-eval/nx/defconfig +++ b/nuttx/configs/stm3210e-eval/nx/defconfig @@ -326,6 +326,7 @@ CONFIG_HAVE_LIBM=n CONFIG_DEBUG=n CONFIG_DEBUG_VERBOSE=n CONFIG_DEBUG_GRAPHICS=n +CONFIG_DEBUG_LCD=n CONFIG_DEBUG_SYMBOLS=n CONFIG_MM_REGIONS=1 CONFIG_ARCH_LOWPUTC=y @@ -775,9 +776,13 @@ CONFIG_NX_MXCLIENTMSGS=16 # Default is 320x240 (this setting is informative only... not necessary). # CONFIG_LCD_PORTRAIT - Define for 240x320 display support. # Default is 320x240. +# CONFIG_LCD_BACKLIGHT - Define to support an adjustable backlight +# using timer 1. The granularity of the settings is determined +# by CONFIG_LCD_MAXPOWER. Requires CONFIG_STM32_TIM1. # CONFIG_LCD_LANDSCAPE=n CONFIG_LCD_PORTRAIT=y +CONFIG_LCD_BACKLIGHT=n # # Settings for examples/uip diff --git a/nuttx/configs/stm3210e-eval/src/up_lcd.c b/nuttx/configs/stm3210e-eval/src/up_lcd.c index fe2c6ac23..83c8fa693 100755 --- a/nuttx/configs/stm3210e-eval/src/up_lcd.c +++ b/nuttx/configs/stm3210e-eval/src/up_lcd.c @@ -52,6 +52,8 @@ #include #include "up_arch.h" +#include "stm32.h" +#include "stm32_internal.h" #include "stm3210e-internal.h" /************************************************************************************** @@ -67,14 +69,17 @@ /* Check power setting */ -#if !defined(CONFIG_LCD_MAXPOWER) -# define CONFIG_LCD_MAXPOWER 1 +#if !defined(CONFIG_LCD_MAXPOWER) || CONFIG_LCD_MAXPOWER < 1 +# undef CONFIG_LCD_MAXPOWER +# ifdef CONFIG_LCD_BACKLIGHT +# define CONFIG_LCD_MAXPOWER 100 +# else +# define CONFIG_LCD_MAXPOWER 1 +# endif #endif -#if CONFIG_LCD_MAXPOWER != 1 -# warning "CONFIG_LCD_MAXPOWER exceeds supported maximum" -# undef CONFIG_LCD_MAXPOWER -# define CONFIG_LCD_MAXPOWER 1 +#if CONFIG_LCD_MAXPOWER > 255 +# error "CONFIG_LCD_MAXPOWER must be less than 256 to fit in uint8_t" #endif /* Check orientation */ @@ -87,6 +92,21 @@ # define CONFIG_LCD_LANDSCAPE 1 #endif +/* Backlight */ + +#ifdef CONFIG_LCD_BACKLIGHT +# ifndef CONFIG_STM32_TIM1 +# error "CONFIG_STM32_TIM1 to use the LCD backlight controls" +# endif +# if CONFIG_LCD_MAXPOWER < 2 +# warning "A larger value of CONFIG_LCD_MAXPOWER is recommended" +# endif +#endif + +#if defined(CONFIG_STM32_TIM1_FULL_REMAP) +# error "PA8 cannot be configured as TIM1 CH1 with full remap" +#endif + /* Define CONFIG_DEBUG_LCD to enable detailed LCD debug output. Verbose debug must * also be enabled. */ @@ -233,6 +253,8 @@ #define LCD_REG_193 0xc1 #define LCD_REG_229 0xe5 +#define LCD_BL_TIMER_PERIOD 8999 + /* Debug ******************************************************************************/ #ifdef CONFIG_DEBUG_LCD @@ -263,8 +285,8 @@ struct stm3210e_dev_s /* Private LCD-specific information follows */ - bool spfd5408b; /* TRUE: LCD is SPFD5408B Controller */ - bool powered; /* TRUE: display on */ + bool spfd5408b; /* TRUE: LCD is SPFD5408B Controller */ + uint8_t power; /* Current power setting */ }; /************************************************************************************** @@ -316,6 +338,11 @@ static int stm3210e_setcontrast(struct lcd_dev_s *dev, unsigned int contrast); static inline void stm3210e_lcdinitialize(void); static inline void stm3210e_lcdclear(void); +#ifdef CONFIG_LCD_BACKLIGHT +static void stm3210e_backlight(void); +#else +# define stm3210e_backlight() +#endif /************************************************************************************** * Private Data @@ -489,9 +516,6 @@ static int stm3210e_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *bu size_t npixels) { FAR const uint16_t *src = (FAR const uint16_t*)buffer; -#ifndef CONFIG_LCD_LANDSCAPE - fb_coord_t tmp; -#endif int i; /* Buffer must be provided and aligned to a 16-bit address boundary */ @@ -664,7 +688,7 @@ static int stm3210e_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno static int stm3210e_getpower(struct lcd_dev_s *dev) { gvdbg("power: %d\n", 0); - return g_lcddev.powered ? 1 : 0; + return g_lcddev.power; } /************************************************************************************** @@ -683,17 +707,31 @@ static int stm3210e_setpower(struct lcd_dev_s *dev, int power) /* Set new power level */ - if (power) + if (power > 0) { - /* Turn the display on: 262K color and display ON */ + uint32_t duty; + + /* Caclulate the new backlight duty. It is a faction of the timer1 + * period based on the ration of the current power setting to the + * maximum power setting. + */ + + duty = ((uint32_t)LCD_BL_TIMER_PERIOD * (uint32_t)power) / CONFIG_LCD_MAXPOWER; + if (duty >= LCD_BL_TIMER_PERIOD) + { + duty = LCD_BL_TIMER_PERIOD - 1; + } + putreg16((uint16_t)duty, STM32_TIM1_CCR1); + + /* Then turn the display on */ stm3210e_writereg(LCD_REG_7, g_lcddev.spfd5408b ? 0x0112 : 0x0173); - g_lcddev.powered = true; + g_lcddev.power = power; } else { stm3210e_writereg(LCD_REG_7, 0); - g_lcddev.powered = false; + g_lcddev.power = 0; } return OK; @@ -948,6 +986,130 @@ static inline void stm3210e_lcdclear(void) } } +/************************************************************************************** + * Name: stm3210e_backlight + * + * Description: + * The LCD backlight is driven from PA8 which must be configured as TIM1 + * CH1. TIM1 must then be configured to output a clock on PA8; the duty + * of the clock determineds the backlight level. + * + **************************************************************************************/ + +#ifdef CONFIG_LCD_BACKLIGHT +static void stm3210e_backlight(void) +{ + uint16_t ccmr; + uint16_t ccer; + uint16_t cr2; + + /* Configure PA8 as TIM1 CH1 output */ + + stm32_configgpio(GPIO_TIM1_CH1OUT); + + /* Enabled timer 1 clocking */ + + modifyreg32(STM32_RCC_APB2ENR, 0, RCC_APB2ENR_TIM1EN); + + /* Reset timer 1 */ + + modifyreg32(STM32_RCC_APB2RSTR, 0, RCC_APB2RSTR_TIM1RST); + modifyreg32(STM32_RCC_APB2RSTR, RCC_APB2RSTR_TIM1RST, 0); + + /* Reset the Counter Mode and set the clock division */ + + putreg16(0, STM32_TIM1_CR1); + + /* Set the Autoreload value */ + + putreg16(LCD_BL_TIMER_PERIOD, STM32_TIM1_ARR); + + /* Set the Prescaler value */ + + putreg16(0, STM32_TIM1_PSC); + + /* Reset the Repetition Counter value */ + + putreg16(0, STM32_TIM1_RCR); + + /* Generate an update event to reload the Prescaler value immediatly */ + + putreg16(ATIM_EGR_UG, STM32_TIM1_EGR); + + /* Disable the Channel 1 */ + + ccer = getreg16(STM32_TIM1_CCER); + ccer &= ~ATIM_CCER_CC1E; + putreg16(ccer, STM32_TIM1_CCER); + + /* Get the TIM1 CR2 register value */ + + cr2 = getreg16(STM32_TIM1_CR2); + + /* Select the Output Compare Mode Bits */ + + ccmr = getreg16(STM32_TIM1_CCMR1); + ccmr &= ATIM_CCMR1_OC1M_MASK; + ccmr |= (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC1M_SHIFT); + + /* Set the capture compare register value (50% duty) */ + + g_lcddev.power = (CONFIG_LCD_MAXPOWER + 1) / 2; + putreg16((LCD_BL_TIMER_PERIOD + 1) / 2, STM32_TIM1_CCR1); + + /* Select the output polarity level == LOW and enable */ + + ccer |= (ATIM_CCER_CC1E | ATIM_CCER_CC1P); + + /* Reset the Output N Polarity level */ + + ccer &= ~(ATIM_CCER_CC1NP|ATIM_CCER_CC1NE); + + /* Reset the Ouput Compare and Output Compare N IDLE State */ + + cr2 &= ~(ATIM_CR2_OIS1|ATIM_CR2_OIS1N); + + /* Write the timer configuration */ + + putreg16(cr2, STM32_TIM1_CR2); + putreg16(ccmr, STM32_TIM1_CCMR1); + putreg16(ccer, STM32_TIM1_CCER); + + /* Set the auto preload enable bit */ + + modifyreg16(STM32_TIM1_CR1, 0, ATIM_CR1_ARPE); + + /* Enable Backlight Timer */ + + ccer |= ATIM_CR1_CEN; + putreg16(ccer, STM32_TIM1_CCER); + + /* Dump timer1 registers */ + + lcddbg("APB2ENR: %08x\n", getreg32(STM32_RCC_APB2ENR)); + lcddbg("CR1: %04x\n", getreg32(STM32_TIM1_CR1)); + lcddbg("CR2: %04x\n", getreg32(STM32_TIM1_CR2)); + lcddbg("SMCR: %04x\n", getreg32(STM32_TIM1_SMCR)); + lcddbg("DIER: %04x\n", getreg32(STM32_TIM1_DIER)); + lcddbg("SR: %04x\n", getreg32(STM32_TIM1_SR)); + lcddbg("EGR: %04x\n", getreg32(STM32_TIM1_EGR)); + lcddbg("CCMR1: %04x\n", getreg32(STM32_TIM1_CCMR1)); + lcddbg("CCMR2: %04x\n", getreg32(STM32_TIM1_CCMR2)); + lcddbg("CCER: %04x\n", getreg32(STM32_TIM1_CCER)); + lcddbg("CNT: %04x\n", getreg32(STM32_TIM1_CNT)); + lcddbg("PSC: %04x\n", getreg32(STM32_TIM1_PSC)); + lcddbg("ARR: %04x\n", getreg32(STM32_TIM1_ARR)); + lcddbg("RCR: %04x\n", getreg32(STM32_TIM1_RCR)); + lcddbg("CCR1: %04x\n", getreg32(STM32_TIM1_CCR1)); + lcddbg("CCR2: %04x\n", getreg32(STM32_TIM1_CCR2)); + lcddbg("CCR3: %04x\n", getreg32(STM32_TIM1_CCR3)); + lcddbg("CCR4: %04x\n", getreg32(STM32_TIM1_CCR4)); + lcddbg("CCR4: %04x\n", getreg32(STM32_TIM1_CCR4)); + lcddbg("CCR4: %04x\n", getreg32(STM32_TIM1_CCR4)); + lcddbg("DMAR: %04x\n", getreg32(STM32_TIM1_DMAR)); +} +#endif + /************************************************************************************** * Public Functions **************************************************************************************/ @@ -978,6 +1140,10 @@ int up_lcdinitialize(void) /* Clear the display */ stm3210e_lcdclear(); + + /* Configure the backlight */ + + stm3210e_backlight(); return OK; } -- cgit v1.2.3