The power-saving SLEEP patch by Simon Elén.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3259 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index c1541cf..f272bea 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -1376,3 +1376,8 @@
desc: Display of recorded file size
eng: "Size:"
new:
+
+id: LANG_CPU_SLEEP
+desc: in system_settings_menu()
+eng: "Power Saving"
+new:
diff --git a/apps/main.c b/apps/main.c
index 614a7fc..e33e2bd 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -103,12 +103,12 @@
font_init();
show_logo();
+ set_irq_level(0);
#ifdef DEBUG
debug_init();
#else
serial_setup();
#endif
- set_irq_level(0);
i2c_init();
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c
index 8fb31d8..5196735 100644
--- a/apps/recorder/recording.c
+++ b/apps/recorder/recording.c
@@ -180,8 +180,7 @@
while(!done)
{
- yield();
- button = button_get(false);
+ button = button_get_w_tmo(HZ / peak_meter_fps);
switch(button)
{
case BUTTON_OFF:
diff --git a/apps/settings.c b/apps/settings.c
index bc78e82..c7ab9e4 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -21,6 +21,7 @@
#include <stdio.h>
#include "config.h"
#include "kernel.h"
+#include "thread.h"
#include "settings.h"
#include "disk.h"
#include "panic.h"
@@ -102,7 +103,7 @@
0x23 0x37 <rec. left gain (bit 0-3)>
0x24 0x38 <rec. right gain (bit 0-3)>
0x25 0x39 <disk poweroff flag (bit 0), MP3 buffer margin (bit 1-3),
- Trickle charge flag (bit 4)>
+ Trickle charge flag (bit 4), CPU sleep flag (bit 5)>
0x26 0x40 <runtime low byte>
0x27 0x41 <runtime high byte>
0x28 0x42 <topruntime low byte>
@@ -350,7 +351,8 @@
config_block[0x25] = (unsigned char)
((global_settings.disk_poweroff & 1) |
((global_settings.buffer_margin & 7) << 1) |
- ((global_settings.trickle_charge & 1) << 4));
+ ((global_settings.trickle_charge & 1) << 4) |
+ ((global_settings.cpu_sleep & 1) << 5));
{
static long lasttime = 0;
@@ -513,6 +515,8 @@
global_settings.lang_file);
lang_load(buf);
}
+
+ cpu_sleep(global_settings.cpu_sleep);
}
/*
@@ -636,6 +640,7 @@
global_settings.disk_poweroff = config_block[0x25] & 1;
global_settings.buffer_margin = (config_block[0x25] >> 1) & 7;
global_settings.trickle_charge = (config_block[0x25] >> 4) & 1;
+ global_settings.cpu_sleep = (config_block[0x25] >> 5) & 1;
}
if (config_block[0x27] != 0xff)
@@ -881,6 +886,7 @@
global_settings.lang_file[0] = 0;
global_settings.runtime = 0;
global_settings.topruntime = 0;
+ global_settings.cpu_sleep = true;
}
diff --git a/apps/settings.h b/apps/settings.h
index be41ef8..529797c 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -147,6 +147,8 @@
int bidir_limit; /* bidir scroll length limit */
int scroll_delay; /* delay (in 1/10s) before starting scroll */
int scroll_step; /* pixels to advance per update */
+
+ bool cpu_sleep; /* Use sleep instruction when idle? */
};
/* prototypes */
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index baffb81..37b2b09 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -27,6 +27,7 @@
#include "mpeg.h"
#include "button.h"
#include "kernel.h"
+#include "thread.h"
#include "sprintf.h"
#include "settings.h"
#include "settings_menu.h"
@@ -539,6 +540,13 @@
}
#endif
+static bool cpu_sleep_set(void)
+{
+ bool result = set_bool(str(LANG_CPU_SLEEP), &global_settings.cpu_sleep);
+ cpu_sleep(global_settings.cpu_sleep);
+ return result;
+}
+
static bool buffer_margin(void)
{
return set_int(str(LANG_MP3BUFFER_MARGIN), "s",
@@ -731,6 +739,7 @@
#ifdef HAVE_ATA_POWER_OFF
{ str(LANG_POWEROFF), poweroff },
#endif
+ { str(LANG_CPU_SLEEP), cpu_sleep_set },
#ifndef SIMULATOR
{ str(LANG_BATTERY_CAPACITY), battery_capacity },
#endif
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 79193d9..e65200e 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -111,7 +111,8 @@
{
int timeout = current_tick + HZ*10;
while (TIME_BEFORE(current_tick, timeout) && (ATA_ALT_STATUS & STATUS_BSY))
- yield();
+ sleep_thread();
+ wake_up_thread();
if (TIME_BEFORE(current_tick, timeout))
return 1;
@@ -131,7 +132,8 @@
while (TIME_BEFORE(current_tick, timeout) &&
!(ATA_ALT_STATUS & STATUS_RDY))
- yield();
+ sleep_thread();
+ wake_up_thread();
if (TIME_BEFORE(current_tick, timeout))
return STATUS_RDY;
diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c
index 2c33440..69d041f 100644
--- a/firmware/drivers/button.c
+++ b/firmware/drivers/button.c
@@ -163,19 +163,8 @@
int button_get_w_tmo(int ticks)
{
struct event ev;
- unsigned int timeout = current_tick + ticks;
-
- while (TIME_BEFORE( current_tick, timeout ))
- {
- if(!queue_empty(&button_queue))
- {
- queue_wait(&button_queue, &ev);
- return ev.id;
- }
- yield();
- }
-
- return BUTTON_NONE;
+ queue_wait_w_tmo(&button_queue, &ev, ticks);
+ return (ev.id != SYS_TIMEOUT)? ev.id: BUTTON_NONE;
}
#ifdef HAVE_RECORDER_KEYPAD
diff --git a/firmware/drivers/i2c.c b/firmware/drivers/i2c.c
index 97d7a51..f0b5907 100644
--- a/firmware/drivers/i2c.c
+++ b/firmware/drivers/i2c.c
@@ -19,6 +19,7 @@
#include "lcd.h"
#include "sh7034.h"
#include "kernel.h"
+#include "thread.h"
#include "debug.h"
#define PB13 0x2000
@@ -108,7 +109,8 @@
SCL_INPUT; /* Set the clock to input */
while(!SCL) /* and wait for the MAS to release it */
- yield();
+ sleep_thread();
+ wake_up_thread();
DELAY;
SCL_OUTPUT;
@@ -130,7 +132,8 @@
SDA_INPUT; /* And set to input */
SCL_INPUT; /* Set the clock to input */
while(!SCL) /* and wait for the MAS to release it */
- yield();
+ sleep_thread();
+ wake_up_thread();
if (SDA)
/* ack failed */
diff --git a/firmware/export/thread.h b/firmware/export/thread.h
index 7940ddf..7be58d0 100644
--- a/firmware/export/thread.h
+++ b/firmware/export/thread.h
@@ -19,12 +19,17 @@
#ifndef THREAD_H
#define THREAD_H
+#include <stdbool.h>
+
#define MAXTHREADS 16
#define DEFAULT_STACK_SIZE 0x400 /* Bytes */
int create_thread(void* function, void* stack, int stack_size, char *name);
void switch_thread(void);
+void sleep_thread(void);
+void wake_up_thread(void);
void init_threads(void);
int thread_stack_usage(int threadnum);
+void cpu_sleep(bool enabled);
#endif
diff --git a/firmware/kernel.c b/firmware/kernel.c
index 4d2f519..3255ba0 100644
--- a/firmware/kernel.c
+++ b/firmware/kernel.c
@@ -59,13 +59,15 @@
int timeout = current_tick + ticks + 1;
while (TIME_BEFORE( current_tick, timeout )) {
- yield();
+ sleep_thread();
}
+ wake_up_thread();
}
void yield(void)
{
switch_thread();
+ wake_up_thread();
}
/****************************************************************************
@@ -96,8 +98,9 @@
{
while(q->read == q->write)
{
- switch_thread();
+ sleep_thread();
}
+ wake_up_thread();
*ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
}
@@ -108,8 +111,9 @@
while(q->read == q->write && TIME_BEFORE( current_tick, timeout ))
{
- switch_thread();
+ sleep_thread();
}
+ wake_up_thread();
if(q->read != q->write)
{
@@ -201,6 +205,7 @@
}
current_tick++;
+ wake_up_thread();
TSR0 &= ~0x01;
}
@@ -257,7 +262,8 @@
{
/* Wait until the lock is open... */
while(m->locked)
- yield();
+ sleep_thread();
+ wake_up_thread();
/* ...and lock it */
m->locked = true;
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index 0518dd2..6fe60c9 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -845,6 +845,7 @@
{
saving = true;
queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
+ wake_up_thread();
}
}
}
@@ -948,6 +949,7 @@
}
CHCR3 &= ~0x0002; /* Clear DMA interrupt */
+ wake_up_thread();
}
#ifdef HAVE_MAS3587F
@@ -1791,9 +1793,10 @@
}
else
{
+ /* This doesn't look neccessary...
yield();
if(!queue_empty(&mpeg_queue))
- {
+ {*/
queue_wait(&mpeg_queue, &ev);
switch(ev.id)
{
@@ -1897,7 +1900,7 @@
init_playback_done = true;
break;
}
- }
+ /*}*/
}
#endif
}
@@ -1974,7 +1977,8 @@
queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL);
while(!init_recording_done)
- yield();
+ sleep_thread();
+ wake_up_thread();
}
void mpeg_init_playback(void)
@@ -1983,7 +1987,8 @@
queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL);
while(!init_playback_done)
- yield();
+ sleep_thread();
+ wake_up_thread();
}
static void init_recording(void)
diff --git a/firmware/test/fat/test.sh b/firmware/test/fat/test.sh
index 6a26e7f..44ff6bb 100644
--- a/firmware/test/fat/test.sh
+++ b/firmware/test/fat/test.sh
@@ -75,7 +75,6 @@
try mkfile /cpa.rock 0
check
try chkfile /cpa.rock
- try chkfile /apa.rock
try chkfile /bpa.rock
LOOP=50
diff --git a/firmware/thread.c b/firmware/thread.c
index 2651a4f..ea518ca 100644
--- a/firmware/thread.c
+++ b/firmware/thread.c
@@ -16,8 +16,11 @@
* KIND, either express or implied.
*
****************************************************************************/
+#include <stdbool.h>
#include "thread.h"
#include "panic.h"
+#include "kernel.h"
+#include "sh7034.h"
struct regs
{
@@ -30,6 +33,8 @@
};
int num_threads;
+bool cpu_sleep_enabled;
+static volatile int num_sleepers;
static int current_thread;
static struct regs thread_contexts[MAXTHREADS] __attribute__ ((section(".idata")));
char *thread_name[MAXTHREADS];
@@ -95,6 +100,18 @@
int next;
unsigned int *stackptr;
+#ifdef SIMULATOR
+ /* Do nothing */
+#else
+
+ while (cpu_sleep_enabled && num_sleepers == num_threads)
+ {
+ /* Enter sleep mode, woken up on interrupt */
+ SBYCR &= 0x7F;
+ asm volatile ("sleep");
+ }
+
+#endif
next = current = current_thread;
if (++next >= num_threads)
next = 0;
@@ -108,6 +125,22 @@
panicf("Stkov %s", thread_name[next]);
}
+void cpu_sleep(bool enabled)
+{
+ cpu_sleep_enabled = enabled;
+}
+
+void sleep_thread(void)
+{
+ ++num_sleepers;
+ switch_thread();
+}
+
+void wake_up_thread(void)
+{
+ num_sleepers = 0;
+}
+
/*---------------------------------------------------------------------------
* Create thread.
* Return 0 if context area could be allocated, else -1.
@@ -144,6 +177,7 @@
regs->sr = 0;
regs->pr = function;
}
+ wake_up_thread();
return 0;
}
@@ -154,6 +188,7 @@
thread_name[0] = main_thread_name;
thread_stack[0] = stackbegin;
thread_stack_size[0] = (int)stackend - (int)stackbegin;
+ num_sleepers = 0;
}
int thread_stack_usage(int threadnum)
diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c
index e25c3ec..cfef2b5 100644
--- a/uisimulator/common/stubs.c
+++ b/uisimulator/common/stubs.c
@@ -221,3 +221,8 @@
(void)ny;
}
#endif
+
+void cpu_sleep(bool enabled)
+{
+ (void)enabled;
+}