From 7b596416bf2cf533a514b4d1f7b95c6de6efa7d5 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Thu, 29 Dec 2011 12:02:49 +0000 Subject: Gigabeat S: Update RDS processing to use asynchronous I2C rather than thread. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31462 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/rds.c | 39 +++++++++++++- firmware/drivers/tuner/si4700.c | 29 ++++++++++ firmware/export/config/gigabeats.h | 3 +- firmware/export/si4700.h | 12 ++++- .../arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c | 63 ++++++++++++++-------- 5 files changed, 119 insertions(+), 27 deletions(-) (limited to 'firmware') diff --git a/firmware/drivers/rds.c b/firmware/drivers/rds.c index 09bc33807c..828c28b672 100644 --- a/firmware/drivers/rds.c +++ b/firmware/drivers/rds.c @@ -36,14 +36,46 @@ static char rt_copy[65]; static int rt_segment; static int rt_abflag; +#ifdef SI4700_RDS_ASYNC +/* Functions are called in ISR context */ +#define rds_disable_irq_save() disable_irq_save() +#define rds_restore_irq(old) restore_irq(old) +/* Need triple buffer so string isn't clobbered while caller is using it */ +static inline char * get_ps(void) +{ + static char ps_out[9]; + int oldlevel = rds_disable_irq_save(); + strcpy(ps_out, ps_copy); + rds_restore_irq(oldlevel); + return ps_out; +} +static inline char * get_rt(void) +{ + static char rt_out[65]; + int oldlevel = rds_disable_irq_save(); + strcpy(rt_out, rt_copy); + rds_restore_irq(oldlevel); + return rt_out; +} +#else /* ndef SI4700_RDS_ASYNC */ +#define rds_disable_irq_save() 0 +#define rds_restore_irq(old) ((void)(old)) +static inline char * get_ps(void) { return ps_copy; } +static inline char * get_rt(void) { return rt_copy; } +#endif /* SI4700_RDS_ASYNC */ + /* resets the rds parser */ void rds_reset(void) { + int oldlevel = rds_disable_irq_save(); + ps_copy[0] = '\0'; ps_segment = 0; rt_copy[0] = '\0'; rt_segment = 0; pi = 0; + + rds_restore_irq(oldlevel); } /* initialises the rds parser */ @@ -172,6 +204,9 @@ bool rds_process(uint16_t data[4]) return false; } +/* TODO: The caller really should provide the buffer in order to regulate + access */ + /* returns the programme identification code */ uint16_t rds_get_pi(void) { @@ -181,12 +216,12 @@ uint16_t rds_get_pi(void) /* returns the most recent valid programme service name */ char* rds_get_ps(void) { - return ps_copy; + return get_ps(); } /* returns the most recent valid RadioText message */ char* rds_get_rt(void) { - return rt_copy; + return get_rt(); } diff --git a/firmware/drivers/tuner/si4700.c b/firmware/drivers/tuner/si4700.c index bebbd0c881..0684d2042f 100644 --- a/firmware/drivers/tuner/si4700.c +++ b/firmware/drivers/tuner/si4700.c @@ -556,6 +556,34 @@ void si4700_dbg_info(struct si4700_dbg_info *nfo) } #ifdef HAVE_RDS_CAP + +#ifdef SI4700_RDS_ASYNC +/* Read raw RDS info for processing - asynchronously */ + +/* Assumes regbuf is 32 bytes */ +void si4700_rds_read_raw_async(void) +{ + si4700_read_raw_async((RDSD - STATUSRSSI + 1) * 2); +} + +void si4700_rds_read_raw_async_complete(unsigned char *regbuf, + uint16_t data[4]) +{ + const int index = (RDSA - STATUSRSSI) * 2; + + for (int i = 0; i < 4; i++) { + data[i] = regbuf[index] << 8 | regbuf[index + 1]; + regbuf += 2; + } +} + +/* Set the event flag */ +void si4700_rds_set_event(void) +{ + rds_event = 1; +} + +#else /* Read raw RDS info for processing */ bool si4700_rds_read_raw(uint16_t data[4]) { @@ -582,6 +610,7 @@ void si4700_rds_set_event(void) rds_event = 1; mutex_unlock(&fmr_mutex); } +#endif /* SI4700_RDS_ASYNC */ char * si4700_get_rds_info(int setting) { diff --git a/firmware/export/config/gigabeats.h b/firmware/export/config/gigabeats.h index 04e7b156b6..9a34791ab1 100644 --- a/firmware/export/config/gigabeats.h +++ b/firmware/export/config/gigabeats.h @@ -90,6 +90,7 @@ #define CONFIG_TUNER SI4700 #define HAVE_RDS_CAP +#define SI4700_RDS_ASYNC /* Define this if you have the WM8978 audio codec */ #define HAVE_WM8978 @@ -163,7 +164,7 @@ #define GPIO_EVENT_MASK (USE_GPIO1_EVENTS) /* Define this if target has an additional number of threads specific to it */ -#define TARGET_EXTRA_THREADS 3 +#define TARGET_EXTRA_THREADS 2 /* Type of mobile power - check this out */ #define BATTERY_CAPACITY_DEFAULT 700 /* default battery capacity */ diff --git a/firmware/export/si4700.h b/firmware/export/si4700.h index 761ad1ca24..fe55dd3853 100644 --- a/firmware/export/si4700.h +++ b/firmware/export/si4700.h @@ -44,10 +44,18 @@ bool si4700_st(void); /** RDS support **/ void si4700_rds_init(void); -/* Read raw RDS info for processing */ -bool si4700_rds_read_raw(uint16_t data[4]); /* Radio is fully powered up or about to be powered down */ void si4700_rds_powerup(bool on); +#ifdef SI4700_RDS_ASYNC +/* Read raw RDS info for processing - asynchronously */ +void si4700_read_raw_async(int count); +void si4700_rds_read_raw_async(void); +void si4700_rds_read_raw_async_complete(unsigned char *regbuf, + uint16_t data[4]); +#else +/* Read raw RDS info for processing */ +bool si4700_rds_read_raw(uint16_t data[4]); +#endif /* Obtain specified string */ char* si4700_get_rds_info(int setting); /* Set the event flag */ diff --git a/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c index e0457e367a..a7b9bc21da 100644 --- a/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c @@ -128,15 +128,52 @@ bool si4700_st(void) /* Low-level RDS Support */ -static struct semaphore rds_sema; -static uint32_t rds_stack[DEFAULT_STACK_SIZE/sizeof(uint32_t)]; -/* RDS GPIO interrupt handler */ +/* Transfer descriptor for RDS async operations */ +struct si4700_i2c_transfer_desc +{ + struct i2c_transfer_desc xfer; + unsigned char regbuf[32]; +} si4700_xfer = +{ + .xfer = { .node = &si4700_i2c_node } +}; + +static void si4700_rds_read_raw_callback(struct i2c_transfer_desc *xfer) +{ + struct si4700_i2c_transfer_desc *xf = + (struct si4700_i2c_transfer_desc *)xfer; + + if (xfer->rxcount != 0) + return; /* Read didn't finish */ + + uint16_t rds_data[4]; + + si4700_rds_read_raw_async_complete(xf->regbuf, rds_data); + + if (rds_process(rds_data)) + si4700_rds_set_event(); +} + +/* Callback from si4700_rds_read_raw to execute the read */ +void si4700_read_raw_async(int count) +{ + si4700_xfer.xfer.txdata = NULL; + si4700_xfer.xfer.txcount = 0; + si4700_xfer.xfer.rxdata = si4700_xfer.regbuf; + si4700_xfer.xfer.rxcount = count; + si4700_xfer.xfer.callback = si4700_rds_read_raw_callback; + si4700_xfer.xfer.next = NULL; + + i2c_transfer(&si4700_xfer.xfer); +} + +/* RDS GPIO interrupt handler - start RDS data read */ void si4700_stc_rds_event(void) { /* read and clear the interrupt */ SI4700_GPIO_STC_RDS_ISR = (1ul << SI4700_GPIO_STC_RDS_LINE); - semaphore_release(&rds_sema); + si4700_rds_read_raw_async(); } /* Called with on=true after full radio power up, and with on=false before @@ -152,26 +189,8 @@ void si4700_rds_powerup(bool on) } } -/* Captures RDS data and processes it */ -/* Use of a thread here is likely temporary */ -static void NORETURN_ATTR rds_thread(void) -{ - uint16_t rds_data[4]; - - while (1) - { - semaphore_wait(&rds_sema, TIMEOUT_BLOCK); - - if (si4700_rds_read_raw(rds_data) && rds_process(rds_data)) - si4700_rds_set_event(); - } -} - /* One-time RDS init at startup */ void si4700_rds_init(void) { - semaphore_init(&rds_sema, 1, 0); rds_init(); - create_thread(rds_thread, rds_stack, sizeof(rds_stack), 0, "rds" - IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU)); } -- cgit v1.2.3