×
单片机 > 单片机程序设计 > 详情

s3c2440 省电模式开发详解

发布时间:2024-05-24 发布时间:
|

1、源码包
Kernel:linux-2.6.18.2
Uboot:u-boot-1.1.4
Gcc:arm-linux-gcc-3.4.1.tar.bz2

开发流程及详细步骤
1、休眠部分

1.电源管理守护进程
省略

2.内核接口文件(arch/arm/kernel/apm.c)
电源守护进程通过apm.c的ioctl函数来使内核开始进入sleep模式。
case APM_IOC_SUSPEND:
as->suspend_result = -EINTR;
if (as->suspend_state == SUSPEND_READ) {
as->suspend_state = SUSPEND_ACKED;
suspends_pending--;
} else {
queue_event(APM_USER_SUSPEND, as);
}
if (suspends_pending == 0)
apm_suspend(); //由此进入sleep
调用的顺序如下:


3.进sleep前的准备工作
A.关闭系统进程(kernel/power/ console.c)
int pm_prepare_console(void) //该函数使所有系统进程休眠或关闭。
B.关闭外设驱动电源(drivers/base/power/suspend.c)
int device_power_down(pm_message_t state) //该函数使所有设备驱动sleep

4.进入sleep前的设置(arch/arm/mach-s3c2410/pm.c)
static int s3c2410_pm_enter(suspend_state_t state) //该函数引导进sleep前的设置

static int s3c2410_pm_enter(suspend_state_t state)
{
unsigned long regs_save[16];
unsigned long tmp;

s3c2410_pm_debug_init(); //sleep中uart不能再用,此函数实现uart重新初始化用来调试

DBG("s3c2410_pm_enter(%d)n", state); //打印信息

if (state != PM_SUSPEND_MEM) {
printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supportedn");
return -EINVAL;
} //判断是否是休眠只用ram实现,应为该项目不支持硬盘休眠功能。

if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
!any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
printk(KERN_ERR PFX "No sources enabled for wake-up!n");
printk(KERN_ERR PFX "Aborting sleepn");
return -EINVAL;
} //判断中断唤醒是否允许,不允许则不能进入休眠。


s3c2410_pm_check_prepare(); //如果需要在sleep前检查ram则此函数会运行,否则此函数为空,即如果CONFIG_S3C2410_PM_CHECK被定义。


s3c2410_sleep_save_phys = virt_to_phys(regs_save);
//将用来保存系统寄存器的数组地址转为物理地址,以供后面调用。
DBG("s3c2410_sleep_save_phys=0x%08lxn", s3c2410_sleep_save_phys); //打印信息
__raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
//将系统唤醒时需要调用的函数地址写入GSTATUS3寄存器。
DBG("GSTATUS3 0x%08xn", __raw_readl(S3C2410_GSTATUS3)); //打印信息
DBG("GSTATUS4 0x%08xn", __raw_readl(S3C2410_GSTATUS4)); //打印信息

s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save)); //保存io口配置状态
s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); //保存中断配置状态
s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save)); //保存核心配置状态
s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); //保存串口配置状态

s3c2410_pm_configure_extint(); //配置外部中断唤醒,使系统休眠中可以按键唤醒

DBG("sleep: irq wakeup masks: %08lx,%08lxn",
s3c_irqwake_intmask, s3c_irqwake_eintmask); //打印信息

__raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK); //屏蔽系统定义中断
__raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); //打开外部唤醒中断

__raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
//通过写已经被申请的位,将中断请求寄存器清空

arm920_flush_kern_cache_all(); //清缓冲区

s3c2410_pm_check_store();//如果需要在sleep前检查ram则此函数会运行,否则此函数为空,即如果CONFIG_S3C2410_PM_CHECK被定义。

__raw_writel(0x00, S3C2410_CLKCON); //关闭所有外设时钟

s3c2410_cpu_suspend(regs_save); //调用汇编函数s3c2410_cpu_suspend 进入sleep。
/************************************************************************/
上为进入休眠部分,下为唤醒部分。
/************************************************************************/
cpu_init(); //CPU初始化

tmp = __raw_readl(S3C2410_GSTATUS2);
tmp &= S3C2410_GSTATUS2_OFFRESET;
__raw_writel(tmp, S3C2410_GSTATUS2); //清除唤醒复位标记

s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); //恢复核心配置
s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save)); //恢复io口配置
s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); //恢复中断配置
s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); //恢复串口配置

s3c2410_pm_debug_init(); //串口调试函数初始化

DBG("post sleep: IRQs 0x%08x, 0x%08xn",
__raw_readl(S3C2410_SRCPND),
__raw_readl(S3C2410_EINTPEND)); //打印信息

s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
s3c_irqwake_intmask); //查看中断唤醒源信息
s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
s3c_irqwake_eintmask); //查看中断唤醒源信息

DBG("post sleep, preparing to returnn");

s3c2410_pm_check_restore();//如果需要在sleep前检查ram则此函数会运行,否则此函数为空,即如果CONFIG_S3C2410_PM_CHECK被定义。

DBG("S3C2410 PM Resume (post-restore)n");
return 0;
}


5.进休眠前的最后汇编段程序(arch/arm/mach-s3c2410/sleep.s)
ENTRY(s3c2410_cpu_suspend)
stmfd sp!, { r4 - r12, lr }

@@ store co-processor registers

mrc p15, 0, r4, c15, c1, 0 @ CP access register
mrc p15, 0, r5, c13, c0, 0 @ PID
mrc p15, 0, r6, c3, c0, 0 @ Domain ID
mrc p15, 0, r7, c2, c0, 0 @ translation table base address
mrc p15, 0, r8, c1, c0, 0 @ control register

stmia r0, { r4 - r13 }

@@ flush the caches to ensure everything is back out to
@@ SDRAM before the core powers down

#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
bl arm920_flush_kern_cache_all
#endif

@@ prepare cpu to sleep

ldr r4, =S3C2410_REFRESH
ldr r5, =S3C24XX_MISCCR
ldr r6, =S3C2410_CLKCON
ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB)

orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
orr r8, r8, #(S3C2410_MISCCR_USBSUSPND0 | S3C2410_MISCCR_USBSUSPND1) @suspend usb
orr r8, r8, #(S3C2400_MISCCR_SPUCR_LDIS | S3C2400_MISCCR_SPUCR_HDIS) @suspend d(0-31)
orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
orr r9, r9, #S3C2410_CLKCON_POWER @ power down command

teq pc, #0 @ first as a trial-run to load cache
bl s3c2410_do_sleep
teq r0, r0 @ now do it for real
b s3c2410_do_sleep @

@@ align next bit of code to cache line
.align 8
s3c2410_do_sleep:
streq r7, [ r4 ] @ SDRAM sleep command
mov r0, #0x1000

1: subs r0, r0, #1 @wait until the SelfRefresh is released
bne 1b
streq r8, [ r5 ] @ SDRAM power-down config
streq r9, [ r6 ] @ CPU sleep
1: beq 1b
mov pc, r14


2、唤醒部分
1、Uboot部分(u-boot-1.1.4/cpu/arm920t/start.s)
reset:
#if 0
mrs r0, cpsr /* Set the cpu to SVC32 mode */
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
#endif

/* disable watchdog timer */
mov r0, #WTCON_BASE
ldr r1, =0x0
str r1, [r0, #oWTCON]
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r0, #INT_BASE
ldr r1, =0xffffffff
str r1, [r0, #oINTMSK]

ldr r1, =0x7ff
str r1, [r0, #oINTSUBMSK]

[1] [2]
s3c2440省电模式休眠部分

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
51单片机的数码管动态扫描方法