资源描述
LM3S 系列单片机休眠与深度休眠应用笔记(一)
LM3S 系列单片机休眠与深度休眠应用笔记
1 处理器的3 种模式
Contex-M3 处理器除支持正常运行模式外,还支持睡眠模式和深度睡眠模式,用来实现低功耗。
处理器在运行模式中控制器积极执行代码;睡眠模式中器件的时钟不变,但控制器不再执行代码(并且也不再需要时钟);在深度睡眠模式中,器件的时钟可以改变,并且控制器不再执行代码(也不需要时钟)。
z 运行模式
运行模式下,处理器和所有当前被RCGCn 寄存器使能的外设均可以正常运行。系统时钟可以由包括PLL 在内的所有可用时钟源提供。
z 睡眠模式
睡眠模式下,Cortex-M3 处理器内核和存储器子系统都不使用时钟。外设仅在相应的时钟门控在SCGCn 寄存器中使能且Auto Clock Gating (见RCC 寄存器)使能时,或者在相应的时钟门控在RCGCn 寄存器中使能且Auto Clock Gating 被禁能时,才使用时钟。睡眠模式下,系统时钟源和频率均与运行模式下相同。
z 深度睡眠模式
深度睡眠模式下,Cortex-M3 处理器内核和存储器子系统都不使用时钟。外设仅在相应的时钟门控在DCGCn 寄存器中使能且Auto Clock Gating (见RCC 寄存器)使能时,或者在相应的时钟门控在RCGCn 寄存器中使能且Auto Clock Gating 被禁能时,才使用时钟。在睡眠模式下,系统时钟源默认为主振荡器。但如果DSLPCLKCFG 寄存器中的IOSC 位被置位,那么系统时钟源也可以是内部振荡器。在使用DSLPCLKCFG 寄存器时,如有必要,可以让内部振荡器上电,同时让主振荡器开始断电。如果PLL 在执行WFI 指令时工作,硬件将会让主振荡器断电,并将激活的RCC 寄存器中的SYSDIV 字段变为1/16 。当发生深度睡眠退出事件时,在使能深度睡眠期间被停止的时钟前,硬件先将系统时钟的时钟源和频率变回到开始进入深度睡眠模式时的值。
在VDD = 3.3V,LDO = 2.5V ,温度 = 2 5℃,系统时钟 = 20MHZ(带PLL),内核处理器无活动外设条件下,芯片厂家给出各种模式的功率规范如表 1 所示。
表 1 功率规范
参数
参数名称
最小值
额定值
最大值
单位
IDD_RUN
运行模式
-
40
45
mA
IDD_SLEEP
睡眠模式
-
17
20
mA
IDD_DEEPSLEEP
深度睡眠模式
-
800
1000
μA
1.2 睡眠机制及睡眠模式进入条件
Contex-M3 处理器由3 种睡眠机制:立即睡眠、退出后睡眠和深度睡眠。
表 2 睡眠机制
睡眠机制
描叙
立即睡眠
处理器可通过等待中断(WFI) 和等待事件(WFE) 指令来请求进入立即睡眠模式。WFI 和WFE 指令使处理器进入低功耗模式,等待一个异常来唤醒。
退出后睡眠
如果系统控制寄存器的SLEEPONEXIT位置位,当处理器退出最低优先级的中断服务程序进入用户程序时,处理器进入低功耗模式,内核处于低功耗模式直到下一个异常发生。一般来说,使用这种模式的用户程序是一个空循环后空线程。
深度睡眠
如果系统控制寄存器的SLEEPDEEP 位置位,当处理器进入立即睡眠或退出后睡眠模式时,系统进入深度睡眠模式。
由上表我们可以知道有3 种方式可以进入睡眠模式:
1. 处理器通过WFI 指令请求进入睡眠模。
WFI(Wait For Interrupt) ,顾名思义,该指令等待中断异常发生。程序运行该指令后,程序挂起,不再往下执行,直到发生中断异常唤醒CPU。我们提供的试验例程就是使用此方式进入睡眠模式的。
注意:当在中断程序执行该指令时,更高优先级的中断才能唤醒。例如:中断A 的优先级为5,当在中断A 中运行WFI 指令时,只有优先级高于A 的中断程序(如优先级4,数字越小优先级越高)才能唤醒CPU。
2. 处理器通过WFE 指令请求进入睡眠模。
WFI(Wait For Event) ,顾名思义,该指令等待事件唤醒。该方式用于双核或多核的处理器,不适合一般的单CPU 系统。
3. 处理器通过置位SLEEPONEXIT 进入睡眠模。
该方式一般只是调试时用,这种模式的用户程序一般是一个空循环后空线程,所以用户正常使用,不推荐此模式。
1.3 与深度睡眠和睡眠相关的寄存器
Contex-M3 处理器的低功耗设置和唤醒机制相当灵活。系统有三种工作模式:正常工作模式、睡眠模式和深度睡眠模式,每种模式的各种接口、功能模块、或单元的时钟可以单独使能。在深度睡眠模式下,系统的主振荡器可以切换成内部振荡器来实现极低的功耗要求。
z深度睡眠位SLEEPDEEP
深度睡眠位SLEEPDEEP 为系统控制寄存器(SYS_CTL_REG) 的第2 位。
系统控制寄存器地址:0XE000ED10
当深度睡眠位:=1 时,向系统指示可以停止Cortex-M3 时钟;=0 时不适合将系统时
钟关闭。
当处理器请求进入睡眠模式时,如果该位已经置位,处理器进入深度睡眠模式,否则处理器进入睡眠模式。
z自动时钟门控位AGC 自动时钟门控位AGC 为运行模式时钟配置寄存器(RCC)的第27 位。系统控制寄存器地址:0x400FE000 + 0X060 该位规定在控制器进入睡眠或深度睡眠模式时,系统是否分别使用睡眠模式时钟门控控
制(SCGCn)寄存器和深度睡眠模式时钟门控控制(DCGCn)寄存器。如果该位置位,则当控制器处于睡眠模式时使用SCGCn 或DCGCn 寄存器来控制分配给外设的时钟。否则,当控制器进入睡眠模式时使用运行模式时钟门控控制(RCGCn )寄存器。RCGCn 寄存器始终用来控制运行模式下的时钟。
这样,可以在控制器处于睡眠模式并且不需要使用外设时降低外设的功耗。
z深度睡眠时钟配置寄存器DSLPCLKCFG 深度睡眠时钟配置寄存器地址:0x400FE000 + 0X144 该寄存器只有最低位(IOSC)有用。
该寄存器用于在进入深度睡眠模式时自动从主振荡器切换成内部振荡器。系统时钟源默认情况下是主振荡器。在该寄存器置位时,内部振荡器开始上电,主振荡器开始断电。当发生深度-睡眠退出事件时,硬件会将系统时钟变回到刚进入深度-睡眠模式时的时钟源和频率。
IOSC 位允许在运行深度-睡眠模式时选择主振荡器。置位时,该位在深度-睡眠模式期间会将内部振荡器强制变为时钟源。否则,主振荡器将始终作为默认的系统时钟源。
z运行-模式时钟门控寄存器组、睡眠-模式时钟门控寄存器组和深度-睡眠-模式时钟门控
寄存器组。运行-模式时钟门控寄存器0(RCGC0) 地址:0x400FE000 + 0X100 运行-模式时钟门控寄存器1(RCGC1) 地址:0x400FE000 + 0X104 运行-模式时钟门控寄存器2(RCGC2) 地址:0x400FE000 + 0X108 睡眠-模式时钟门控寄存器0(SCGC0) 地址:0x400FE000 + 0X110 睡眠-模式时钟门控寄存器1(SCGC1) 地址:0x400FE000 + 0X114 睡眠-模式时钟门控寄存器2(SCGC2) 地址:0x400FE000 + 0X118 深度睡眠-模式时钟门控寄存器0(DCGC0)地址:0x400FE000 + 0X120 深度睡眠-模式时钟门控寄存器1(DCGC1)地址:0x400FE000 + 0X124 深度睡眠-模式时钟门控寄存器2(DCGC2)地址:0x400FE000 + 0X128
这几个寄存器用来控制时钟选通逻辑。每个位控制一个给定接口、功能、或单元的时钟使能,详情请参考表 3、表 4 和表 5。如果置位,则对应的单元接收时钟并运行。否则,对应的单元不使用时钟并禁止(节能)。如果功能单元不使用时钟,那么在对该单元进行读或写操作时都将返回总线故障。除非特别说明,否则这些位的复位状态都为0(不使用时钟), 即所有功能单元都禁止。应用所需的端口需通过软件来使能。
表 3 RCGC0 、SCGC0 和DCGC0 位段对应控制的功能模块
位/字段
名称
类型
复位
描述
31:21
保留
RO
0
保留位,返回不确定的值,并且应永不改变
20
PWM
R/W
0
该位控制PWM 模块的时钟选通。如果该位置位,PWM 接收
时钟并运行。否则,PWM 不使用时钟并禁止。
19:17
保留
RO
0
保留位,返回不确定的值,并且应永不改变
16
ADC
R/W
0
该位控制ADC 模块的时钟选通。如果该位置位,ADC 接收
时钟并运行。否则,ADC 不使用时钟并禁止。
15:12
保留
RO
0
保留位,返回不确定的值,并且应永不改变
该字段设置ADC 采样数据的速率。该字段为0x2 时,表示采
样速率最大,为500,000 采样/秒(即每秒采样50 万次)
你可将采样速率设置为低于最大速率,这可以通过设置
MAXADCSPD 位来实现:
11:8
MAXADCSPD
R/W
0
值采样速率
0x0 125K 采样/秒
0x1 250K 采样/秒
0x2 500K 采样/秒
0x3 1000K 采样/秒
7:4
保留
RO
0
保留位,返回不确定的值,并且应永不改变
3
WDT
R/W
0
该位控制WDT 模块的时钟选通。如果该位置位,WDT 接收
时钟并运行。否则,WDT 不使用时钟并禁止。
2
SWO
R/W
0
该位控制SWO 模块的时钟选通。如果该位置位,SWO 接收
时钟并运行。否则,SWO 不使用时钟并禁止。
1
SWD
R/W
0
该位控制SWD 模块的时钟选通。如果该位置位,SWD 接收
时钟并运行。否则,SWD 不使用时钟并禁止。
0
JTAG
R/W
0
该位控制JTAG 模块的时钟选通。如果该位置位,JTAG 接收
时钟并运行。否则,JTAG 不使用时钟并禁止。
表 4 RCGC1 、SCGC1 和DCGC1 位段对应控制的功能模块
位
名称
类型
复位
描述
31:27
保留
RO
0
保留位返回一个不确定的值,并且应该永不改变
26
COMP2
R/W
0
该位控制模拟比较器2 模块的时钟门控。若置位,则接收时钟并运行。否则,不使用时钟并且不运行。
25
COMP1
R/W
0
该位控制模拟比较器1 模块的时钟门控。若置位,则接收时钟并运行。否则,不使用时钟并且不运行。
24
COMP0
R/W
0
该位控制模拟比较器0 模块的时钟门控。若置位,则接收时钟并运行。否则,不使用时钟并且不运行。
23:19
保留
RO
0
保留位返回一个不确定的值,并且应该永不改变
18
GPTM2
R/W
0
该位控制通用定时器2 模块的时钟门控。若置位,则接收时钟并运行。否则,不使用时钟并且不运行。
17
GPTM1
R/W
0
该位控制通用定时器1 模块的时钟门控。若置位,则接收时钟并运行。否则,不使用时钟并且不运行。
16
GPTM0
R/W
0
该位控制通用定时器0 模块的时钟门控。若置位,则接收时钟并运行。否则,不使用时钟并且不运行。
15:13
保留
RO
0
保留位返回一个不确定的值,并且应该永不改变
12
I2C
R/W
0
该位控制I2C 模块的时钟门控。若置位,则接收时钟并运行。否则,不使用时钟并且不运行。
11:9
保留
RO
0
保留位返回一个不确定的值,并且应该永不改变
8
QEI
R/W
0
该位控制QEI 模块的时钟门控。若置位,则QEI 接收时钟并运行。否则,不使用时钟并且不运行。
7:5
保留
RO
0
保留位返回一个不确定的值,并且应该永不改变
4
SSI
R/W
0
该位控制SSI 模块的时钟门控。若置位,则SSI 接收时钟并运行。否则,不使用时钟并且不运行。
3:2
保留
RO
0
保留位返回一个不确定的值,并且应该永不改变
1
UART1
R/W
0
该位控制UART1 模块的时钟门控。若置位,则UART1 接收时钟并运行。否则,不使用时钟并且不运行。
0
UART0
R/W
0
该位控制UART0 模块的时钟门控。若置位,则UART0 接收时钟并运行。否则,不使用时钟并且不运行。
表 5 RCGC2 、SCGC2 和DCGC2 位段对应控制的功能模块
位
名称
类型
复位
描述
31:5
保留
RO
0
保留位,返回不确定的值,并且应永不改变
4
PORTE
R/W
0
该位控制GPIO 端口E 模块的时钟选通。如果该位置位,对应单元接收时钟并运行。否则,不使用时钟并禁止。
3
PORTD
R/W
0
该位控制GPIO 端口D 模块的时钟选通。如果该位置位,对应单元接收时钟并运行。否则,不使用时钟并禁止。
2
PORTC
R/W
0
该位控制GPIO 端口C 模块的时钟选通。如果该位置位,对应单元接收时钟并运行。否则,不使用时钟并禁止。
1
PORTB
R/W
0
该位控制GPIO 端口B 模块的时钟选通。如果该位置位,对应单元接收时钟并运行。否则,不使用时钟并禁止。
0
PORTA
R/W
0
该位控制GPIO 端口A 模块的时钟选通。如果该位置位,对应单元接收时钟并运行。否则,不使用时钟并禁止。
1.4 深度睡眠模式设置步骤
处理通过调用WFI 指令即可进入睡眠模式,但要进入深度睡眠实现最低的功耗需要正确配置,其步骤如下:
1. 使能ACG 自动时钟门控。这样睡眠模式和深度睡眠模式的外设时钟可以单独控制。
2. 配置寄存器DCGC0、 DCGC1 和DCGC2,设置深度睡眠模式下允许时钟的外设。我们一般只给唤醒CPU 的外设使能时钟,因为允许时钟的外设越少,功耗越低。例如:我们的示例程序在进入深度睡眠模式后是通过PORTB 的外部中断唤醒的,因此在深度睡眠模式下必须允许PORTB 的时钟(置位DCGC2 寄存器的第1 位)。睡眠或深度睡眠模式下,必须设置最少一个唤醒条件,否则无法唤醒。另外值得注意的是,如果程序中设置了定时器中断,并且在睡眠或深度睡眠模式下允许了时钟,则在睡眠或深度睡眠模式下定时器正常工作,当定时器产生中断时,处理器就会被唤醒。
3. 使能深度睡眠位SLEEPDEEP ,使处理器休眠时进入深度睡眠模式。
4. 使能深度睡眠时钟配置寄存器DSLPCLKCFG 的IOSC 位,使处理器在深度睡眠期间将内部振荡器强制为时钟源。
5. 在完成上述配置后,如果想让处理区进入深度睡眠模式,调用WFI 指令即可。睡眠后,发生异常中断即可唤醒处理器。
1.5 示例程序说明
深度睡眠应用示例程序如程序清单 1 所示,在正常运行时时翻转LED 灯,按KEY1 键,进入深度睡眠,按KEY2 键唤醒处理区。程序清单 1(1)定义了深度睡眠需要操作的几个寄存器的地址,2 个按键和一个LED 灯。
程序清单 1(2)定义了函数WFI( ) ,此函数为C 语言内嵌汇编指令的函数。处理器请求休眠是通过汇编指令WFI 来实现的,用户应用程序只需调用函数WFI( ) ,即可请求休眠,关键字__asm 申明该函数内为汇编指令。
程序清单 1(3)定义了配置相关寄存器,使休眠时进入深度休眠,最大程度地实现低功耗的函数DeepSleepConfig( ) 。程序清单 1(4)为中断服务程序,示例程序在此请求休眠挂起。程序清单 1(5)也为中断服务程序,示例程序在此唤醒休眠。
程序清单 1 深度睡眠应用示例程序
#include "hw_memmap.h" #include "hw_types.h" #include "hw_ints.h" #include "sysctl.h" #include "systick.h" #include "gpio.h"#include "interrupt.h"
#define HWREG(x) (*((volatile unsigned long *)(x))) #define SYS_CTL_REG 0xe000ed10 (1)#define SYS_DSLPCLKCFG 0x400FE000 + 0X144 #define SYS_RCC 0x400FE000 + 0X060
#define KEY1 GPIO_PIN_4 // 定义KEY1 #define KEY2 GPIO_PIN_5 // 定义KEY1 #define LED1 GPIO_PIN_1 // 定义LED1
__asm void WFI(void) (2) { WFI }
void DeepSleepConfig() (3) { unsigned long temp;
// ACG 自动时钟门控,睡眠或深度睡眠时使用SCGC 或DCGC 来控制分配给外设的时钟temp = HWREG(SYS_RCC); HWREG(SYS_RCC) = temp|(1<<27);
// 设置深度睡眠下允许时钟外设 SysCtlPeripheralDeepSleepEnable(SYSCTL_PERIPH_GPIOB);
// 设置深度睡眠使能 HWREG(SYS_CTL_REG) = (1<<2);
// 深度睡眠期间将内部振荡器强制为时钟源HWREG(SYS_DSLPCLKCFG) = 1; }
void delay (unsigned int t) { unsigned int i;
do
{
i = 6000;
do{}
while(--i);
}while(--t); }
void InitPB(void)
{ // 使能PB 口 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
// 设置连接KEY2 的PB5 为输入GPIODirModeSet(GPIO_PORTB_BASE, KEY2, GPIO_DIR_MODE_IN);
// 设置KEY2 中断的触发方式为低电平触发 GPIOIntTypeSet(GPIO_PORTB_BASE, KEY2, GPIO_LOW_LEVEL);
// 设置PB 的优先级为1 IntPrioritySet(INT_GPIOB, (1<<5));
// 使能KEY2 中断 GPIOPinIntEnable(GPIO_PORTB_BASE, KEY2);
// 使能PB 口中断 IntEnable(INT_GPIOB); }
void InitPD(void)
{ // 使能PD 口 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
// 设置连接KEY1 的PD4 为输入GPIODirModeSet(GPIO_PORTD_BASE, KEY1, GPIO_DIR_MODE_IN);
// 设置连接LED1 的PD7 为输出 GPIODirModeSet(GPIO_PORTD_BASE, LED1, GPIO_DIR_MODE_OUT);
// 设置KEY1 中断的触发方式为低电平触发 GPIOIntTypeSet(GPIO_PORTD_BASE, KEY1, GPIO_LOW_LEVEL);
// 设置PB 的优先级为3 IntPrioritySet(INT_GPIOD, (3<<5));
// 使能KEY1 中断 GPIOPinIntEnable(GPIO_PORTD_BASE, KEY1);
// 使能PD 口中断 IntEnable(INT_GPIOD); }
void GPIO_Port_D_ISR(void) (4)
{ GPIOPinIntClear(GPIO_PORTD_BASE, KEY1); // 清除中断标志 WFI();
}
void GPIO_Port_B_ISR(void) (5) { GPIOPinIntClear(GPIO_PORTB_BASE, KEY2); // 清除中断标志}
int main(void)
{ InitPB (); InitPD (); DeepSleepConfig();
while (1)
{ GPIOPinWrite(GPIO_PORTD_BASE, LED1, ~LED1); // 点亮LED1 delay(100); GPIOPinWrite(GPIO_PORTD_BASE, LED1, LED1); // 熄灭LED1 delay(100);
} }
展开阅读全文