diff options
| author | Michael Sevakis <jethead71@rockbox.org> | 2008-12-07 00:07:47 +0000 |
|---|---|---|
| committer | Michael Sevakis <jethead71@rockbox.org> | 2008-12-07 00:07:47 +0000 |
| commit | 89da4328a07c8736c42843607a3f3bf91c17601d (patch) | |
| tree | cbd5d6580b2c62dad5830c043d9284ff15cf7bdf /firmware | |
| parent | 3648e8705402ce5a0af2125987f12c884b540eea (diff) | |
| download | rockbox-89da4328a07c8736c42843607a3f3bf91c17601d.zip rockbox-89da4328a07c8736c42843607a3f3bf91c17601d.tar.gz rockbox-89da4328a07c8736c42843607a3f3bf91c17601d.tar.bz2 rockbox-89da4328a07c8736c42843607a3f3bf91c17601d.tar.xz | |
Meg F/X can beep and click using a hardware timer so let us try it out. To match things up better, fix PCM beeping to give correct frequency (and get a pointer wrap bug too). Do some minor adjustments to compensate for corrections.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19355 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
| -rw-r--r-- | firmware/drivers/audio/wm8751.c | 11 | ||||
| -rw-r--r-- | firmware/export/config-gigabeat.h | 5 | ||||
| -rw-r--r-- | firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c | 12 | ||||
| -rw-r--r-- | firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h | 1 | ||||
| -rw-r--r-- | firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c | 103 |
5 files changed, 126 insertions, 6 deletions
diff --git a/firmware/drivers/audio/wm8751.c b/firmware/drivers/audio/wm8751.c index 9d552b5..2e0eb06 100644 --- a/firmware/drivers/audio/wm8751.c +++ b/firmware/drivers/audio/wm8751.c @@ -152,6 +152,17 @@ void audiohw_postinit(void) wmcodec_write(LEFTMIX1, LEFTMIX1_LD2LO | LEFTMIX1_LI2LO_DEFAULT); wmcodec_write(RIGHTMIX2, RIGHTMIX2_RD2RO | RIGHTMIX2_RI2RO_DEFAULT); +#ifdef TOSHIBA_GIGABEAT_F +#ifdef HAVE_HARDWARE_BEEP + /* Single-ended mono input */ + wmcodec_write(MONOMIX1, 0); + + /* Route mono input to both outputs at 0dB */ + wmcodec_write(LEFTMIX2, LEFTMIX2_MI2LO | LEFTMIX2_MI2LOVOL(2)); + wmcodec_write(RIGHTMIX1, RIGHTMIX1_MI2RO | RIGHTMIX1_MI2ROVOL(2)); +#endif +#endif + audiohw_mute(false); #ifdef MROBE_100 diff --git a/firmware/export/config-gigabeat.h b/firmware/export/config-gigabeat.h index 313bdad..664befd 100644 --- a/firmware/export/config-gigabeat.h +++ b/firmware/export/config-gigabeat.h @@ -52,6 +52,11 @@ #define LCD_SLEEP_TIMEOUT (5*HZ) #define HAVE_TOUCHPAD_SENSITIVITY_SETTING + +#ifndef SIMULATOR +#define HAVE_HARDWARE_BEEP +#endif + #endif /* BOOTLOADER */ #define CONFIG_KEYPAD GIGABEAT_PAD diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c index 76917c8..5ef8c80 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c @@ -32,18 +32,18 @@ void tick_start(unsigned int interval_in_ms) * Timer input clock frequency = * fPCLK / {prescaler value+1} / {divider value} * TIMER_FREQ = 49156800 / 2 - * 13300 = TIMER_FREQ / 231 / 8 - * 49156800 = 19*(11)*(7)*7*5*5*(3)*2*2*2*2*2*2 - * 231 = 11*7*3 + * 146300 = TIMER_FREQ / 21 / 8 + * 49156800 = 19*11*(7)*7*5*5*(3)*2*2*2*2*2*2 + * 21 = 7*3 */ /* stop timer 4 */ TCON &= ~(1 << 20); /* Set the count for timer 4 */ - TCNTB4 = (TIMER_FREQ / 231 / 8) * interval_in_ms / 1000; + TCNTB4 = (TIMER_FREQ / TIMER234_PRESCALE / 8) * interval_in_ms / 1000; /* Set the the prescaler value for timers 2,3, and 4 */ - TCFG0 = (TCFG0 & ~0xff00) | ((231-1) << 8); - /* MUX4 = 1/16 */ + TCFG0 = (TCFG0 & ~0xff00) | ((TIMER234_PRESCALE-1) << 8); + /* DMA mode off, MUX4 = 1/16 */ TCFG1 = (TCFG1 & ~0xff0000) | 0x030000; /* set manual bit */ TCON |= 1 << 21; diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h index ac195bf..b5652a3 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h +++ b/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h @@ -23,6 +23,7 @@ /* timer is based on PCLK and minimum division is 2 */ #define TIMER_FREQ (49156800/2) +#define TIMER234_PRESCALE 21 bool __timer_set(long cycles, bool set); bool __timer_register(void); diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c index 957d58b..de965f0 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c @@ -29,8 +29,14 @@ #include "kernel.h" #include "sound.h" #include "i2c-meg-fx.h" +#include "system-target.h" +#include "timer-target.h" #include "wmcodec.h" +#ifdef HAVE_HARDWARE_BEEP +static void beep_stop(void); +#endif + void audiohw_init(void) { /* GPC5 controls headphone output */ @@ -39,6 +45,14 @@ void audiohw_init(void) GPCDAT |= (1 << 5); audiohw_preinit(); + +#ifdef HAVE_HARDWARE_BEEP + /* pin pullup ON */ + GPBUP &= ~(1 << 3); + beep_stop(); + /* set pin to TIMER3 output (functional TOUT3) */ + GPBCON = (GPBCON & ~(0x3 << 6)) | (2 << 6); +#endif } void wmcodec_write(int reg, int data) @@ -48,3 +62,92 @@ void wmcodec_write(int reg, int data) d[1] = data; i2c_write(0x34, d, 2); } + +#ifdef HAVE_HARDWARE_BEEP +/** Beeping via TIMER3 output to codec MONO input **/ +static int beep_cycles = 0; +static int beep_cycle_count = 0; + +static void beep_stop(void) +{ + int oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS); + + /* stop interrupt */ + INTMSK |= TIMER3_MASK; + /* stop timer */ + TCON &= ~(1 << 16); + /* be sure timer PWM pin is LOW to avoid noise */ + TCON ^= (GPBDAT & (1 << 3)) << 15; + /* clear pending */ + SRCPND = TIMER3_MASK; + INTPND = TIMER3_MASK; + + restore_interrupt(oldstatus); +} + +/* Timer interrupt called on every cycle */ +void TIMER3(void) +{ + if (++beep_cycles >= beep_cycle_count) + { + /* beep is complete */ + beep_stop(); + } + + /* clear pending */ + SRCPND = TIMER3_MASK; + INTPND = TIMER3_MASK; +} + +void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude) +{ + #define TIMER3_TICK_SEC (TIMER_FREQ / TIMER234_PRESCALE) + + unsigned long tcnt, tcmp; + int oldstatus; + + if (amplitude <= 0) + { + beep_stop(); /* won't hear it anyway */ + return; + } + + /* pretend this is pcm */ + if (amplitude > 32767) + amplitude = 32767; + + /* limit frequency range to keep math in range */ + if (frequency > 19506) + frequency = 19506; + else if (frequency < 18) + frequency = 18; + + /* set timer */ + tcnt = TIMER3_TICK_SEC / frequency; + + oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS); + + beep_cycles = 0; + beep_cycle_count = TIMER3_TICK_SEC * duration / (tcnt*1000); + + /* divider = 1/2 */ + TCFG1 = (TCFG1 & ~(0xf << 12)) | (0 << 12); + /* stop TIMER3, inverter OFF */ + TCON &= ~((1 << 18) | (1 << 16)); + /* set countdown */ + TCNTB3 = tcnt; + /* set PWM counter - control volume with duty cycle. */ + tcmp = tcnt*amplitude / (65536*2 - 2*amplitude); + TCMPB3 = tcmp < 1 ? 1 : tcmp; + /* manual update: on (to reset count), interval mode (auto reload) */ + TCON |= (1 << 19) | (1 << 17); + /* clear manual bit */ + TCON &= ~(1 << 17); + /* start timer */ + TCON |= (1 << 16); + /* enable timer interrupt */ + INTMSK &= ~TIMER3_MASK; + + restore_interrupt(oldstatus); +} +#endif /* HAVE_HARDWARE_BEEP */ |