forked from len0rd/rockbox
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
This commit is contained in:
parent
3648e87054
commit
89da4328a0
8 changed files with 141 additions and 24 deletions
|
@ -130,7 +130,7 @@ static int get_action_worker(int context, int timeout,
|
||||||
/* Produce keyclick */
|
/* Produce keyclick */
|
||||||
if (global_settings.keyclick && !(button & BUTTON_REL))
|
if (global_settings.keyclick && !(button & BUTTON_REL))
|
||||||
if (!(button & BUTTON_REPEAT) || global_settings.keyclick_repeats)
|
if (!(button & BUTTON_REPEAT) || global_settings.keyclick_repeats)
|
||||||
pcmbuf_beep(5000, 2, 2500*global_settings.keyclick);
|
pcmbuf_beep(4000, 2, 2500*global_settings.keyclick);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((context != last_context) && ((last_button & BUTTON_REL) == 0))
|
if ((context != last_context) && ((last_button & BUTTON_REL) == 0))
|
||||||
|
|
|
@ -954,14 +954,15 @@ bool pcmbuf_insert_buffer(char *buf, int count)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_HARDWARE_BEEP
|
||||||
/* Generates a constant square wave sound with a given frequency
|
/* Generates a constant square wave sound with a given frequency
|
||||||
in Hertz for a duration in milliseconds. */
|
in Hertz for a duration in milliseconds. */
|
||||||
void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
|
void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
|
||||||
{
|
{
|
||||||
unsigned int count = 0;
|
int i;
|
||||||
unsigned int i;
|
unsigned int step = 0xffffffffu / NATIVE_FREQUENCY * frequency;
|
||||||
unsigned int interval = NATIVE_FREQUENCY / frequency;
|
int32_t phase = 0;
|
||||||
unsigned int samples = NATIVE_FREQUENCY / 1000 * duration;
|
int samples = NATIVE_FREQUENCY / 1000 * duration;
|
||||||
int32_t sample;
|
int32_t sample;
|
||||||
int16_t *bufstart;
|
int16_t *bufstart;
|
||||||
int16_t *bufptr;
|
int16_t *bufptr;
|
||||||
|
@ -986,21 +987,17 @@ void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
|
||||||
bufptr = bufstart;
|
bufptr = bufstart;
|
||||||
for (i = 0; i < samples; ++i)
|
for (i = 0; i < samples; ++i)
|
||||||
{
|
{
|
||||||
|
int32_t amp = (phase >> 31) ^ (int32_t)amplitude;
|
||||||
sample = mix ? *bufptr : 0;
|
sample = mix ? *bufptr : 0;
|
||||||
*bufptr++ = clip_sample_16(sample + amplitude);
|
*bufptr++ = clip_sample_16(sample + amp);
|
||||||
if (bufptr > pcmbuf_end)
|
if (bufptr >= pcmbuf_end)
|
||||||
bufptr = (int16_t *)audiobuffer;
|
bufptr = (int16_t *)audiobuffer;
|
||||||
sample = mix ? *bufptr : 0;
|
sample = mix ? *bufptr : 0;
|
||||||
*bufptr++ = clip_sample_16(sample + amplitude);
|
*bufptr++ = clip_sample_16(sample + amp);
|
||||||
if (bufptr > pcmbuf_end)
|
if (bufptr >= pcmbuf_end)
|
||||||
bufptr = (int16_t *)audiobuffer;
|
bufptr = (int16_t *)audiobuffer;
|
||||||
|
|
||||||
/* Toggle square wave edge */
|
phase += step;
|
||||||
if (++count >= interval)
|
|
||||||
{
|
|
||||||
count = 0;
|
|
||||||
amplitude = -amplitude;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Kick off playback if required */
|
/* Kick off playback if required */
|
||||||
|
@ -1009,7 +1006,7 @@ void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
|
||||||
pcm_play_data(NULL, (unsigned char *)bufstart, samples * 4);
|
pcm_play_data(NULL, (unsigned char *)bufstart, samples * 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif /* HAVE_HARDWARE_BEEP */
|
||||||
|
|
||||||
/* Returns pcm buffer usage in percents (0 to 100). */
|
/* Returns pcm buffer usage in percents (0 to 100). */
|
||||||
int pcmbuf_usage(void)
|
int pcmbuf_usage(void)
|
||||||
|
|
|
@ -694,7 +694,7 @@ static void audio_skip(int direction)
|
||||||
if (playlist_check(ci.new_track + wps_offset + direction))
|
if (playlist_check(ci.new_track + wps_offset + direction))
|
||||||
{
|
{
|
||||||
if (global_settings.beep)
|
if (global_settings.beep)
|
||||||
pcmbuf_beep(5000, 100, 2500*global_settings.beep);
|
pcmbuf_beep(2000, 100, 2500*global_settings.beep);
|
||||||
|
|
||||||
LOGFQUEUE("audio > audio Q_AUDIO_SKIP %d", direction);
|
LOGFQUEUE("audio > audio Q_AUDIO_SKIP %d", direction);
|
||||||
queue_post(&audio_queue, Q_AUDIO_SKIP, direction);
|
queue_post(&audio_queue, Q_AUDIO_SKIP, direction);
|
||||||
|
@ -706,7 +706,7 @@ static void audio_skip(int direction)
|
||||||
{
|
{
|
||||||
/* No more tracks. */
|
/* No more tracks. */
|
||||||
if (global_settings.beep)
|
if (global_settings.beep)
|
||||||
pcmbuf_beep(1000, 100, 1000*global_settings.beep);
|
pcmbuf_beep(1000, 100, 1500*global_settings.beep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,6 +152,17 @@ void audiohw_postinit(void)
|
||||||
wmcodec_write(LEFTMIX1, LEFTMIX1_LD2LO | LEFTMIX1_LI2LO_DEFAULT);
|
wmcodec_write(LEFTMIX1, LEFTMIX1_LD2LO | LEFTMIX1_LI2LO_DEFAULT);
|
||||||
wmcodec_write(RIGHTMIX2, RIGHTMIX2_RD2RO | RIGHTMIX2_RI2RO_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);
|
audiohw_mute(false);
|
||||||
|
|
||||||
#ifdef MROBE_100
|
#ifdef MROBE_100
|
||||||
|
|
|
@ -52,6 +52,11 @@
|
||||||
#define LCD_SLEEP_TIMEOUT (5*HZ)
|
#define LCD_SLEEP_TIMEOUT (5*HZ)
|
||||||
|
|
||||||
#define HAVE_TOUCHPAD_SENSITIVITY_SETTING
|
#define HAVE_TOUCHPAD_SENSITIVITY_SETTING
|
||||||
|
|
||||||
|
#ifndef SIMULATOR
|
||||||
|
#define HAVE_HARDWARE_BEEP
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* BOOTLOADER */
|
#endif /* BOOTLOADER */
|
||||||
|
|
||||||
#define CONFIG_KEYPAD GIGABEAT_PAD
|
#define CONFIG_KEYPAD GIGABEAT_PAD
|
||||||
|
|
|
@ -32,18 +32,18 @@ void tick_start(unsigned int interval_in_ms)
|
||||||
* Timer input clock frequency =
|
* Timer input clock frequency =
|
||||||
* fPCLK / {prescaler value+1} / {divider value}
|
* fPCLK / {prescaler value+1} / {divider value}
|
||||||
* TIMER_FREQ = 49156800 / 2
|
* TIMER_FREQ = 49156800 / 2
|
||||||
* 13300 = TIMER_FREQ / 231 / 8
|
* 146300 = TIMER_FREQ / 21 / 8
|
||||||
* 49156800 = 19*(11)*(7)*7*5*5*(3)*2*2*2*2*2*2
|
* 49156800 = 19*11*(7)*7*5*5*(3)*2*2*2*2*2*2
|
||||||
* 231 = 11*7*3
|
* 21 = 7*3
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* stop timer 4 */
|
/* stop timer 4 */
|
||||||
TCON &= ~(1 << 20);
|
TCON &= ~(1 << 20);
|
||||||
/* Set the count for timer 4 */
|
/* 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 */
|
/* Set the the prescaler value for timers 2,3, and 4 */
|
||||||
TCFG0 = (TCFG0 & ~0xff00) | ((231-1) << 8);
|
TCFG0 = (TCFG0 & ~0xff00) | ((TIMER234_PRESCALE-1) << 8);
|
||||||
/* MUX4 = 1/16 */
|
/* DMA mode off, MUX4 = 1/16 */
|
||||||
TCFG1 = (TCFG1 & ~0xff0000) | 0x030000;
|
TCFG1 = (TCFG1 & ~0xff0000) | 0x030000;
|
||||||
/* set manual bit */
|
/* set manual bit */
|
||||||
TCON |= 1 << 21;
|
TCON |= 1 << 21;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
/* timer is based on PCLK and minimum division is 2 */
|
/* timer is based on PCLK and minimum division is 2 */
|
||||||
#define TIMER_FREQ (49156800/2)
|
#define TIMER_FREQ (49156800/2)
|
||||||
|
#define TIMER234_PRESCALE 21
|
||||||
|
|
||||||
bool __timer_set(long cycles, bool set);
|
bool __timer_set(long cycles, bool set);
|
||||||
bool __timer_register(void);
|
bool __timer_register(void);
|
||||||
|
|
|
@ -29,8 +29,14 @@
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "i2c-meg-fx.h"
|
#include "i2c-meg-fx.h"
|
||||||
|
#include "system-target.h"
|
||||||
|
#include "timer-target.h"
|
||||||
#include "wmcodec.h"
|
#include "wmcodec.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_HARDWARE_BEEP
|
||||||
|
static void beep_stop(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
void audiohw_init(void)
|
void audiohw_init(void)
|
||||||
{
|
{
|
||||||
/* GPC5 controls headphone output */
|
/* GPC5 controls headphone output */
|
||||||
|
@ -39,6 +45,14 @@ void audiohw_init(void)
|
||||||
GPCDAT |= (1 << 5);
|
GPCDAT |= (1 << 5);
|
||||||
|
|
||||||
audiohw_preinit();
|
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)
|
void wmcodec_write(int reg, int data)
|
||||||
|
@ -48,3 +62,92 @@ void wmcodec_write(int reg, int data)
|
||||||
d[1] = data;
|
d[1] = data;
|
||||||
i2c_write(0x34, d, 2);
|
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 */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue