NXP JN5169 唤醒定时器

一、唤醒定时器介绍

二、实现代码

  • 1、中断模式 1
  • 2、中断模式 2
  • 3、轮询模式

一、唤醒定时器介绍

有关 32kHz 时钟见:低速(32kHz)系统时钟

        JN5169 上有两个 41 位唤醒定时器,由 32 kHz 时钟(该时钟可源自内部或外部)驱动。它们可能会在设备其余大部分设备掉电时的睡眠周期内运行,以计时睡眠周期或应用程序可能需要的其他长时间周期。唤醒定时器不在深度睡眠期间运行,可以选择通过软件控制在睡眠模式下禁用。当唤醒定时器到期时,它通常会产生一个中断。如果设备处于睡眠状态,则该中断可以用作结束睡眠时间的事件。功能包括:

  • 41位递减计数器
  • (可选)在睡眠期间运行
  • 由 32 kHz 系统时钟提供时钟; 32 kHz RC 振荡器,32 kHz 晶振或 32 kHz 时钟输入

        唤醒定时器包括一个从所选 32 kHz 时钟开始计时的 41 位递减计数器。当计数器达到零时,会产生中断或唤醒事件。达到零时,计数器将继续递减计数直到停止,这允许测量响应中断的等待时间。如果需要中断或唤醒事件,则应在装入该期间的计数值之前使能定时器中断。一旦加载了计数器值并启动了计数器,便开始递减计数。计数器可以通过软件控制随时停止——计数器将保持其停止时所包含的值,并且不会产生中断。可以读取计时器的状态以指示计时器是否正在运行或已到期;当定时器中断被屏蔽时,这很有用。此操作将重置所有过期的状态标志。

唤醒定时器时钟:

Android实现定时休眠唤醒_时钟周期

二、实现代码

1、中断模式 1

#include <AppHardwareApi.h>
#include <AppQueueApi.h>

#define UART					E_AHI_UART_0

PRIVATE void vPutChar(unsigned char c);
PRIVATE void vPutStrs(unsigned char *str);
PRIVATE void vUartInit(void);
PRIVATE void vWakeTimerInit(void);

PRIVATE uint32 u32WakeTimerClockCycle;		//定时 T 秒所需的 32kHz 时钟周期数

#define DURATION_SECONDS	2				//WakeTimer 定时时间(以秒计算),这里示例2秒


PUBLIC void AppColdStart (void)
{
	/*等待系统时钟切换为外部32MHz晶振*/
	while (bAHI_GetClkSource() == TRUE);
	/*优化闪存等待状态*/
	vAHI_OptimiseWaitStates();

	vAHI_WatchdogStop();
	(void)u32AHI_Init();

	u32WakeTimerClockCycle = 0;

	vUartInit();
	vWakeTimerInit();


    while (1) {

        vAHI_CpuDoze();     /* Doze */
    }
}

PUBLIC void AppWarmStart (void)
{
    AppColdStart();
}

PRIVATE void vCbWakeTimer (uint32 u32Device, uint32 u32ItemBitmap)
{
	if(E_AHI_DEVICE_SYSCTRL == u32Device){		//系统中断
		switch(u32ItemBitmap){
			case E_AHI_SYSCTRL_WK1_MASK:		//WakeTimer1
				vPutStrs((uint8*)"E_AHI_SYSCTRL_WK1_MASK\n");
				break;
			case E_AHI_SYSCTRL_WK0_MASK:		//WakeTimer0
				vPutStrs((uint8*)"E_AHI_SYSCTRL_WK0_MASK\n");
				break;
			default:
				break;
		}
	}
	/**
	 * WakeTimer 计数在到达 0 时,定时器触发,翻转到 0x1FFFFFFFFFF,并继续递减。
	 * 如果使能,在到达0 时产生唤醒定时器中断。
	 * 每次触发中断之后需要重新设置 32KHz 时钟周期数,不然默认会翻转到 0x1FFFFFFFFFF,并继续递减。
	 */
	vAHI_WakeTimerStartLarge(E_AHI_WAKE_TIMER_0, u32WakeTimerClockCycle);
}

PRIVATE void vWakeTimerInit(void)
{
	/**
	 * 如果 32KHz 时钟的时钟源是(默认)内部 32KHz RC 振荡器,
	 * 那么唤醒定时器的运行速度可能快 18%或 慢 18%
	 * 为了得到更精确的定时,建议先校准时钟,并相应调整指定的计数值
	 * 通过时钟校准计算所需的唤醒定时器持续时间的 32KHz 时钟周期数 N
	 * 唤醒定时器 32 个时钟周期等于 1ms
	 * n = u32AHI_WakeTimerCalibrate()
	 * 定时时间 T (单位秒)
	 * 时钟周期数 N = (10000.0 / n) * 32000 * T
	 */
	vAHI_WakeTimerStop(E_AHI_WAKE_TIMER_0);	//使用 u32AHI_WakeTimerCalibrate() 之前需要停止相应的唤醒定时器
	u32WakeTimerClockCycle = (uint32)DURATION_SECONDS * 32000 * (10000.0 / u32AHI_WakeTimerCalibrate());
	vAHI_WakeTimerEnable(E_AHI_WAKE_TIMER_0, TRUE);		//唤醒定时器启动时启用中断
	vAHI_WakeTimerStartLarge(E_AHI_WAKE_TIMER_0, u32WakeTimerClockCycle);	//启动唤醒定时器
	vAHI_SysCtrlRegisterCallback(vCbWakeTimer);			//注册中断回调函数
}


/*发送单个字符*/
PRIVATE void vPutChar(unsigned char c)
{
    while (!(u8AHI_UartReadLineStatus(UART) & E_AHI_UART_LS_THRE));    /*发送FIFO为空*/
    vAHI_UartWriteData(UART, c);   /*写入要发送的字符*/
    /*
       发送移位寄存器为空或者发送FIFO为空,即等待发送完毕
       E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT = 0x20 | 0x40 = 0x60
    */
    while ((u8AHI_UartReadLineStatus(UART) & (E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT))
            != (E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT));
}
/*发送字符串*/
PRIVATE void vPutStrs(unsigned char *str)
{
    while(*str){
    	vPutChar(*str++);
    }
}

/*初始化串口*/
PRIVATE void vUartInit(void)
{
#if (UART == E_AHI_UART_0)
    vAHI_UartSetRTSCTS(UART, FALSE); /* UART0 2线模式。Disable use of CTS/RTS       */
#endif
    vAHI_UartEnable(UART);
    //复位指定UART的发送和接收FIFO,并将FIFO触发级别设置为单字节触发
    vAHI_UartReset(UART,
                     TRUE, /* 复位收发FIFO*/
                     TRUE);
    vAHI_UartSetBaudRate(UART, E_AHI_UART_RATE_115200); /* 设置波特率*/
}

效果演示:

Android实现定时休眠唤醒_nxp_02

2、中断模式 2

与模式 1 相比,少了中断回调函数。

#include <AppHardwareApi.h>
#include <AppQueueApi.h>

#define UART					E_AHI_UART_0

PRIVATE void vPutChar(unsigned char c);
PRIVATE void vPutStrs(unsigned char *str);
PRIVATE void vUartInit(void);
PRIVATE void vWakeTimerInit(void);

PRIVATE uint32 u32WakeTimerClockCycle;		//定时 T 秒所需的 32KHz 时钟周期数

#define DURATION_SECONDS	2				//WakeTimer 定时时间(以秒计算),这里示例2秒


PUBLIC void AppColdStart (void)
{
	/*等待系统时钟切换为外部32MHz晶振*/
	while (bAHI_GetClkSource() == TRUE);
	/*优化闪存等待状态*/
	vAHI_OptimiseWaitStates();

	vAHI_WatchdogStop();
	(void)u32AHI_Init();

	u32WakeTimerClockCycle = 0;

	vUartInit();
	vWakeTimerInit();


    while (1) {
        vAHI_CpuDoze();     /* Doze */

        //唤醒定时器中断发生后唤醒设备,重新装载计数时钟周期数,然后进入 Doze 模式
        /**
         * WakeTimer 计数在到达 0 时,定时器触发,翻转到 0x1FFFFFFFFFF,并继续递减。
         * 如果使能,在到达0 时产生唤醒定时器中断。
         * 每次触发中断之后需要重新设置 32KHz 时钟周期数,不然默认会翻转到 0x1FFFFFFFFFF,并继续递减。
         */
        vAHI_WakeTimerStartLarge(E_AHI_WAKE_TIMER_0, u32WakeTimerClockCycle);
        vPutStrs((uint8*)"Interrupt Mode 2:E_AHI_SYSCTRL_WK0_MASK\n");
    }
}

PUBLIC void AppWarmStart (void)
{
    AppColdStart();
}

PRIVATE void vWakeTimerInit(void)
{
	/**
	 * 如果 32KHz 时钟的时钟源是(默认)内部 32KHz RC 振荡器,
	 * 那么唤醒定时器的运行速度可能快 18%或 慢 18%
	 * 为了得到更精确的定时,建议先校准时钟,并相应调整指定的计数值
	 * 通过时钟校准计算所需的唤醒定时器持续时间的 32KHz 时钟周期数 N
	 * 唤醒定时器 32 个时钟周期等于 1ms
	 * n = u32AHI_WakeTimerCalibrate()
	 * 定时时间 T (单位秒)
	 * 时钟周期数 N = (10000.0 / n) * 32000 * T
	 */
	vAHI_WakeTimerStop(E_AHI_WAKE_TIMER_0);	//使用 u32AHI_WakeTimerCalibrate() 之前需要停止相应的唤醒定时器
	u32WakeTimerClockCycle = (uint32)DURATION_SECONDS * 32000 * (10000.0 / u32AHI_WakeTimerCalibrate());
	vAHI_WakeTimerEnable(E_AHI_WAKE_TIMER_0, TRUE);		//唤醒定时器启动时启用中断
	vAHI_WakeTimerStartLarge(E_AHI_WAKE_TIMER_0, u32WakeTimerClockCycle);	//启动唤醒定时器
}


/*发送单个字符*/
PRIVATE void vPutChar(unsigned char c)
{
    while (!(u8AHI_UartReadLineStatus(UART) & E_AHI_UART_LS_THRE));    /*发送FIFO为空*/
    vAHI_UartWriteData(UART, c);   /*写入要发送的字符*/
    /*
       发送移位寄存器为空或者发送FIFO为空,即等待发送完毕
       E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT = 0x20 | 0x40 = 0x60
    */
    while ((u8AHI_UartReadLineStatus(UART) & (E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT))
            != (E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT));
}
/*发送字符串*/
PRIVATE void vPutStrs(unsigned char *str)
{
    while(*str){
    	vPutChar(*str++);
    }
}

/*初始化串口*/
PRIVATE void vUartInit(void)
{
#if (UART == E_AHI_UART_0)
    vAHI_UartSetRTSCTS(UART, FALSE); /* UART0 2线模式。Disable use of CTS/RTS       */
#endif
    vAHI_UartEnable(UART);
    //复位指定UART的发送和接收FIFO,并将FIFO触发级别设置为单字节触发
    vAHI_UartReset(UART,
                     TRUE, /* 复位收发FIFO*/
                     TRUE);
    vAHI_UartSetBaudRate(UART, E_AHI_UART_RATE_115200); /* 设置波特率*/
}

效果演示:

Android实现定时休眠唤醒_zigbee_03

3、轮询模式

注意!轮询模式下设备不能进入 休眠(doze)模式 ,因为关闭了唤醒定时器中断,无法唤醒进入休眠模式的设备!

#include <AppHardwareApi.h>
#include <AppQueueApi.h>

#define UART					E_AHI_UART_0

PRIVATE void vPutChar(unsigned char c);
PRIVATE void vPutStrs(unsigned char *str);
PRIVATE void vUartInit(void);
PRIVATE void vWakeTimerInit(void);

PRIVATE uint32 u32WakeTimerClockCycle;		//定时 T 秒所需的 32KHz 时钟周期数

#define DURATION_SECONDS	2				//WakeTimer 定时时间(以秒计算),这里示例2秒


PUBLIC void AppColdStart (void)
{
	/*等待系统时钟切换为外部32MHz晶振*/
	while (bAHI_GetClkSource() == TRUE);
	/*优化闪存等待状态*/
	vAHI_OptimiseWaitStates();

	vAHI_WatchdogStop();
	(void)u32AHI_Init();

	u32WakeTimerClockCycle = 0;

	vUartInit();
	vWakeTimerInit();


    while (1) {
    	while(u64AHI_WakeTimerReadLarge(E_AHI_WAKE_TIMER_0) == 0){
    		vPutStrs((uint8*)"E_AHI_SYSCTRL_WK0_MASK\n");
    		/**
    		 * WakeTimer 计数在到达 0 时,定时器触发,翻转到 0x1FFFFFFFFFF,并继续递减。
    		 * 如果使能,在到达0 时产生唤醒定时器中断。
    		 * 每次触发中断之后需要重新设置 32KHz 时钟周期数,不然默认会翻转到 0x1FFFFFFFFFF,并继续递减。
    		 */
    		vAHI_WakeTimerStartLarge(E_AHI_WAKE_TIMER_0, u32WakeTimerClockCycle);
    	}
    }
}

PUBLIC void AppWarmStart (void)
{
    AppColdStart();
}


PRIVATE void vWakeTimerInit(void)
{
	/**
	 * 如果 32KHz 时钟的时钟源是(默认)内部 32KHz RC 振荡器,
	 * 那么唤醒定时器的运行速度可能快 18%或 慢 18%
	 * 为了得到更精确的定时,建议先校准时钟,并相应调整指定的计数值
	 * 通过时钟校准计算所需的唤醒定时器持续时间的 32KHz 时钟周期数 N
	 * 唤醒定时器 32 个时钟周期等于 1ms
	 * n = u32AHI_WakeTimerCalibrate()
	 * 定时时间 T (单位秒)
	 * 时钟周期数 N = (10000.0 / n) * 32000 * T
	 */
	vAHI_WakeTimerStop(E_AHI_WAKE_TIMER_0);	//使用 u32AHI_WakeTimerCalibrate() 之前需要停止相应的唤醒定时器
	u32WakeTimerClockCycle = (uint32)DURATION_SECONDS * 32000 * (10000.0 / u32AHI_WakeTimerCalibrate());
	vAHI_WakeTimerEnable(E_AHI_WAKE_TIMER_0, FALSE);		//唤醒定时器启动时关闭中断
	vAHI_WakeTimerStartLarge(E_AHI_WAKE_TIMER_0, u32WakeTimerClockCycle);	//启动唤醒定时器
}


/*发送单个字符*/
PRIVATE void vPutChar(unsigned char c)
{
    while (!(u8AHI_UartReadLineStatus(UART) & E_AHI_UART_LS_THRE));    /*发送FIFO为空*/
    vAHI_UartWriteData(UART, c);   /*写入要发送的字符*/
    /*
       发送移位寄存器为空或者发送FIFO为空,即等待发送完毕
       E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT = 0x20 | 0x40 = 0x60
    */
    while ((u8AHI_UartReadLineStatus(UART) & (E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT))
            != (E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT));
}
/*发送字符串*/
PRIVATE void vPutStrs(unsigned char *str)
{
    while(*str){
    	vPutChar(*str++);
    }
}

/*初始化串口*/
PRIVATE void vUartInit(void)
{
#if (UART == E_AHI_UART_0)
    vAHI_UartSetRTSCTS(UART, FALSE); /* UART0 2线模式。Disable use of CTS/RTS       */
#endif
    vAHI_UartEnable(UART);
    //复位指定UART的发送和接收FIFO,并将FIFO触发级别设置为单字节触发
    vAHI_UartReset(UART,
                     TRUE, /* 复位收发FIFO*/
                     TRUE);
    vAHI_UartSetBaudRate(UART, E_AHI_UART_RATE_115200); /* 设置波特率*/
}

效果演示:

Android实现定时休眠唤醒_时钟周期_04