diff options
Diffstat (limited to 'firmware')
| -rw-r--r-- | firmware/SOURCES | 1 | ||||
| -rw-r--r-- | firmware/backlight.c | 101 | ||||
| -rw-r--r-- | firmware/export/backlight.h | 3 | ||||
| -rw-r--r-- | firmware/export/timer.h | 34 | ||||
| -rw-r--r-- | firmware/timer.c | 181 |
5 files changed, 261 insertions, 59 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES index 5fbe6be..06b4ce0 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -101,6 +101,7 @@ hwcompat.c kernel.c rolo.c thread.c +timer.c crt0.S #endif mp3_playback.c diff --git a/firmware/backlight.c b/firmware/backlight.c index e997cca..25cc045 100644 --- a/firmware/backlight.c +++ b/firmware/backlight.c @@ -27,6 +27,7 @@ #include "usb.h" #include "power.h" #include "system.h" +#include "timer.h" #ifdef HAVE_REMOTE_LCD #include "lcd-remote.h" @@ -66,7 +67,6 @@ static unsigned int remote_backlight_timeout = 5; static const char backlight_fade_value[8] = { 0, 1, 2, 4, 6, 8, 10, 20 }; static int fade_in_count = 1; static int fade_out_count = 4; -static bool timer_allowed = true; static bool bl_timer_active = false; static int bl_dim_current = BL_PWM_COUNT; @@ -75,44 +75,20 @@ static int bl_pwm_counter = 0; static volatile int bl_cycle_counter = 0; static enum {DIM_STATE_START, DIM_STATE_MAIN} bl_dim_state = DIM_STATE_START; -void backlight_start_timer(void) -{ - unsigned int count; - - if (bl_timer_active) - return ; - - /* Prevent cpu frequency changes while dimming. */ - cpu_boost(true); - count = 1; - bl_timer_active = true; - - /* We are using timer 1 */ - TRR1 = count; /* The reference count */ - TCN1 = 0; /* reset the timer */ - TMR1 = 0x011d; /* prescaler=2, restart, CLK/16, enabled */ - - TER1 = 0xff; /* Clear all events */ - - /* ICR2 (Timer2) */ - ICR0 = (ICR0 & 0xffff00ff) | 0x00009000; /* Interrupt on level 4.0 */ - IMR &= ~(1<<10); -} - -void TIMER1(void) __attribute__ ((interrupt_handler)); -void TIMER1(void) +static void backlight_isr(void) { int timer_period; bool idle = false; - - timer_period = FREQ / 2000 * BL_PWM_INTERVAL / 1000 / 32; - switch (bl_dim_state) { + + timer_period = FREQ / 1000 * BL_PWM_INTERVAL / 1000; + switch (bl_dim_state) + { /* New cycle */ case DIM_STATE_START: bl_pwm_counter = 0; bl_cycle_counter++; - if (bl_dim_current > 0 && bl_dim_current < BL_PWM_COUNT) + if (bl_dim_current > 0 && bl_dim_current < BL_PWM_COUNT) { and_l(~0x00020000, &GPIO1_OUT); bl_pwm_counter = bl_dim_current; @@ -125,6 +101,7 @@ void TIMER1(void) and_l(~0x00020000, &GPIO1_OUT); else or_l(0x00020000, &GPIO1_OUT); + if (bl_dim_current == bl_dim_target) idle = true; } @@ -137,9 +114,8 @@ void TIMER1(void) bl_dim_state = DIM_STATE_START; timer_period = timer_period * (BL_PWM_COUNT - bl_pwm_counter) / BL_PWM_COUNT; break ; - } - + if ((bl_dim_target > bl_dim_current) && (bl_cycle_counter >= fade_in_count)) { bl_dim_current++; @@ -155,37 +131,50 @@ void TIMER1(void) if (idle) { cpu_boost(false); + timer_unregister(); bl_timer_active = false; - TMR1 = 0; } + else + timer_set_period(timer_period); +} - TRR1 = timer_period; - TCN1 = 0; - TER1 = 0xff; /* Clear all events */ +static void backlight_switch(void) +{ + if (bl_dim_target > (BL_PWM_COUNT/2)) + { + and_l(~0x00020000, &GPIO1_OUT); + bl_dim_current = BL_PWM_COUNT; + } + else + { + or_l(0x00020000, &GPIO1_OUT); + bl_dim_current = 0; + } } -static void __backlight_dim(int value) +static void backlight_release_timer(void) { - bl_dim_target = value; - backlight_start_timer(); + cpu_boost(false); + timer_unregister(); + bl_timer_active = false; + backlight_switch(); } -void backlight_allow_timer(bool on) +static void backlight_dim(int value) { - timer_allowed = on; + bl_dim_target = value; - if (!timer_allowed && bl_timer_active) - { - cpu_boost(false); - bl_dim_current = bl_dim_target; - bl_timer_active = false; - TMR1 = 0; + if (bl_timer_active) + return ; - if (bl_dim_current) - and_l(~0x00020000, &GPIO1_OUT); - else - or_l(0x00020000, &GPIO1_OUT); + if (timer_register(0, backlight_release_timer, 1, 0, backlight_isr)) + { + /* Prevent cpu frequency changes while dimming. */ + cpu_boost(true); + bl_timer_active = true; } + else + backlight_switch(); } void backlight_set_fade_in(int index) @@ -202,8 +191,8 @@ void backlight_set_fade_out(int index) static void __backlight_off(void) { #if CONFIG_BACKLIGHT == BL_IRIVER - if (timer_allowed && (fade_out_count > 0)) - __backlight_dim(0); + if (fade_out_count > 0) + backlight_dim(0); else { bl_dim_target = bl_dim_current = 0; @@ -224,8 +213,8 @@ static void __backlight_off(void) static void __backlight_on(void) { #if CONFIG_BACKLIGHT == BL_IRIVER - if (timer_allowed && (fade_in_count > 0)) - __backlight_dim(BL_PWM_COUNT); + if (fade_in_count > 0) + backlight_dim(BL_PWM_COUNT); else { bl_dim_target = bl_dim_current = BL_PWM_COUNT; diff --git a/firmware/export/backlight.h b/firmware/export/backlight.h index 8d1b56c..b2a2448 100644 --- a/firmware/export/backlight.h +++ b/firmware/export/backlight.h @@ -30,9 +30,6 @@ void backlight_set_timeout(int index); #if CONFIG_BACKLIGHT == BL_IRIVER void backlight_set_fade_in(int index); void backlight_set_fade_out(int index); -void backlight_allow_timer(bool on); -#else -#define backlight_allow_timer(on) #endif bool backlight_get_on_when_charging(void); void backlight_set_on_when_charging(bool yesno); diff --git a/firmware/export/timer.h b/firmware/export/timer.h new file mode 100644 index 0000000..73936ca --- /dev/null +++ b/firmware/export/timer.h @@ -0,0 +1,34 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id$ +* +* Copyright (C) 2005 Jens Arnold +* +* All files in this archive are subject to the GNU General Public License. +* See the file COPYING in the source tree root for full license agreement. +* +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +* KIND, either express or implied. +* +****************************************************************************/ + +#ifndef __TIMER_H__ +#define __TIMER_H__ + +#include <stdbool.h> +#include "config.h" + +#ifndef SIMULATOR + +bool timer_register(int reg_prio, void (*unregister_callback)(void), + long cycles, int int_prio, void (*timer_callback)(void)); +bool timer_set_period(long cycles); +void timer_unregister(void); + +#endif /* !SIMULATOR */ +#endif /* __TIMER_H__ */ diff --git a/firmware/timer.c b/firmware/timer.c new file mode 100644 index 0000000..3e524ac --- /dev/null +++ b/firmware/timer.c @@ -0,0 +1,181 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id$ +* +* Copyright (C) 2005 Jens Arnold +* +* All files in this archive are subject to the GNU General Public License. +* See the file COPYING in the source tree root for full license agreement. +* +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +* KIND, either express or implied. +* +****************************************************************************/ + +#include <stdbool.h> +#include "config.h" +#include "cpu.h" +#include "system.h" +#include "timer.h" + +#ifndef SIMULATOR + +static int timer_prio = -1; +static void (*pfn_timer)(void) = NULL; /* timer callback */ +static void (*pfn_unregister)(void) = NULL; /* unregister callback */ + + +/* interrupt handler */ +#if CONFIG_CPU == SH7034 +void IMIA4(void) __attribute__((interrupt_handler)); +void IMIA4(void) +{ + if (pfn_timer != NULL) + pfn_timer(); + and_b(~0x01, &TSR4); /* clear the interrupt */ +} +#elif defined CPU_COLDFIRE +void TIMER1(void) __attribute__ ((interrupt_handler)); +void TIMER1(void) +{ + if (pfn_timer != NULL) + pfn_timer(); + TER1 = 0xff; /* clear all events */ +} +#endif /* CONFIG_CPU */ + +static bool timer_set(long cycles, bool start) +{ + int phi = 0; /* bits for the prescaler */ + int prescale = 1; + +#ifdef CPU_COLDFIRE + cycles >>= 1; /* the coldfire timer works on busclk == cpuclk/2 */ +#endif + + while (cycles > 0x10000) + { /* work out the smallest prescaler that makes it fit */ +#if CONFIG_CPU == SH7034 + phi++; +#endif + prescale *= 2; + cycles >>= 1; + } + +#if CONFIG_CPU == SH7034 + if (prescale > 8) + return false; + + if (start) + { + if (pfn_unregister != NULL) + { + pfn_unregister(); + pfn_unregister = NULL; + } + + and_b(~0x10, &TSTR); /* Stop the timer 4 */ + and_b(~0x10, &TSNC); /* No synchronization */ + and_b(~0x10, &TMDR); /* Operate normally */ + + TIER4 = 0xF9; /* Enable GRA match interrupt */ + } + + TCR4 = 0x20 | phi; /* clear at GRA match, set prescaler */ + GRA4 = (unsigned short)(cycles - 1); + if (start || (TCNT4 >= GRA4)) + TCNT4 = 0; + and_b(~0x01, &TSR4); /* clear an eventual interrupt */ + +#elif defined CPU_COLDFIRE + if (prescale > 4096) + return false; + + if (prescale > 256) + { + phi = 0x05; /* prescale sysclk/16, timer enabled */ + prescale >>= 4; + } + else + phi = 0x03; /* prescale sysclk, timer enabled */ + + if (start) + { + if (pfn_unregister != NULL) + { + pfn_unregister(); + pfn_unregister = NULL; + } + phi &= ~1; /* timer disabled at start */ + } + + /* We are using timer 1 */ + TMR1 = 0x0018 | (unsigned short)phi | ((unsigned short)(prescale - 1) << 8); + TRR1 = (unsigned short)(cycles - 1); + if (start || (TCN1 >= TRR1)) + TCN1 = 0; /* reset the timer */ + TER1 = 0xff; /* clear all events */ + +#endif /* CONFIG_CPU */ + return true; +} + +/* Register a user timer, called every <count> CPU cycles */ +bool timer_register(int reg_prio, void (*unregister_callback)(void), + long cycles, int int_prio, void (*timer_callback)(void)) +{ + if (reg_prio <= timer_prio || cycles == 0) + return false; + +#if CONFIG_CPU == SH7034 + if (int_prio < 1 || int_prio > 15) + return false; +#elif defined CPU_COLDFIRE + (void)int_prio; +#endif + + if (!timer_set(cycles, true)) + return false; + + pfn_timer = timer_callback; + pfn_unregister = unregister_callback; + timer_prio = reg_prio; + +#if CONFIG_CPU == SH7034 + IPRD = (IPRD & 0xFF0F) | int_prio << 4; /* interrupt priority */ + or_b(0x10, &TSTR); /* start timer 4 */ +#elif defined CPU_COLDFIRE + /* ICR2 (Timer1) */ + ICR0 = (ICR0 & 0xffff00ff) | 0x00009000; /* interrupt on level 4.0 */ + and_l(~(1<<10), &IMR); + TMR1 |= 1; /* start timer */ +#endif + + return true; +} + +bool timer_set_period(long cycles) +{ + return timer_set(cycles, false); +} + +void timer_unregister(void) +{ +#if CONFIG_CPU == SH7034 + and_b(~0x10, &TSTR); /* stop the timer 4 */ + IPRD = (IPRD & 0xFF0F); /* disable interrupt */ +#elif defined CPU_COLDFIRE + TMR1 = 0; /* disable timer 1 */ + or_l((1<<10), &IMR); /* disable interrupt */ +#endif + pfn_timer = NULL; + pfn_unregister = NULL; + timer_prio = -1; +} + +#endif /* !SIMULATOR */ |