指令名 |
功能描述 |
DMB |
数据存储器隔离。DMB 指令保证: 仅当所有在它前面的存储器访问操作 都执行完毕后,才提交(commit)在它后面的存储器访问操作。回写ram |
DSB |
数据同步隔离。比 DMB 严格: 仅当所有在它前面的存储器访问操作 回写ram和清空cache 都执行完毕后,才执行在它后面的指令(亦即任何指令都要等待存储器访 问操作——译者注) |
ISB |
指令同步隔离。最严格:它会清洗流水线,以保证所有它前面的指令都执 行完毕之后,才执行它后面的指令。回写ram和清空cache,清洗流水线 |
注意:dma的使用,要加唤醒锁。
当某时刻所有优先级高于 Idle 任务的任务处于被阻塞或者被挂起的状态,此刻调度器会调度 Idle 任务运行,它的执行函数为:
static portTASK_FUNCTION( prvIdleTask, pvParameters )
{
/* Stop warnings. */
( void ) pvParameters;
/** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE
SCHEDULER IS STARTED. **/
/* In case a task that has a secure context deletes itself, in which case
the idle task is responsible for deleting the task's secure context, if
any. */
portTASK_CALLS_SECURE_FUNCTIONS();
for( ;; )
{
/* See if any tasks have deleted themselves - if so then the idle task
is responsible for freeing the deleted task's TCB and stack. */
prvCheckTasksWaitingTermination(); //判断是否有需要 Task 自己删除自己,如果有,那么在 Idle 任务中来回收这种类型的场景
#if ( configUSE_PREEMPTION == 0 )
{
/* If we are not using preemption we keep forcing a task switch to
see if any other task has become available. If we are using
preemption we don't need to do this as any task becoming available
will automatically get the processor anyway. */
taskYIELD();
}
#endif /* configUSE_PREEMPTION */
#if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
{
/* When using preemption tasks of equal priority will be
timesliced. If a task that is sharing the idle priority is ready
to run then the idle task should yield before the end of the
timeslice.
A critical region is not required here as we are just reading from
the list, and an occasional incorrect value will not matter. If
the ready list at the idle priority contains more than one task
then a task other than the idle task is ready to execute. */
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 )
{
taskYIELD();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */
#if ( configUSE_IDLE_HOOK == 1 )
{
extern void vApplicationIdleHook( void );
/* Call the user defined function from within the idle task. This
allows the application designer to add background functionality
without the overhead of a separate task.
NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
CALL A FUNCTION THAT MIGHT BLOCK. */
vApplicationIdleHook();
}
#endif /* configUSE_IDLE_HOOK */
/* This conditional compilation should use inequality to 0, not equality
to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when
user defined low power mode implementations require
configUSE_TICKLESS_IDLE to be set to a value other than 1. */
#if ( configUSE_TICKLESS_IDLE != 0 )
{
TickType_t xExpectedIdleTime;
/* It is not desirable to suspend then resume the scheduler on
each iteration of the idle task. Therefore, a preliminary
test of the expected idle time is performed without the
scheduler suspended. The result here is not necessarily
valid. */
xExpectedIdleTime = prvGetExpectedIdleTime();
if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
{
vTaskSuspendAll();
{
/* Now the scheduler is suspended, the expected idle
time can be sampled again, and this time its value can
be used. */
configASSERT( xNextTaskUnblockTime >= xTickCount );
xExpectedIdleTime = prvGetExpectedIdleTime();
/* Define the following macro to set xExpectedIdleTime to 0
if the application does not want
portSUPPRESS_TICKS_AND_SLEEP() to be called. */
configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( xExpectedIdleTime );
if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
{
traceLOW_POWER_IDLE_BEGIN();
portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
traceLOW_POWER_IDLE_END();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
( void ) xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_TICKLESS_IDLE */
}
}
extern void osiIdleSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) osiIdleSleep( xExpectedIdleTime )
static void prv32KSleep(osiPmContext_t *d, int64_t sleep_ms)
{
OSI_LOGI(0, "32K sleep sleep/%u", (unsigned)sleep_ms);
#ifdef CONFIG_QUEC_PROJECT_FEATURE_SLEEP
osiPmSource_t *p;
TAILQ_FOREACH(p, &d->resume_list, resume_iter)
{
if ( p->ops.suspend && \
(p->tag == DRV_NAME_PWT || p->tag == DRV_NAME_LPG))
{
OSI_LOGD(0, "suspend cb %4c", p->tag);
p->ops.suspend(p->cb_ctx, 0);
}
}
quec_enter_sleep_cb(); //1.关硬件外设(led、流控、gnss);2.客户自定义关闭
#endif
osiProfileEnter(PROFCODE_DEEP_SLEEP);
halSysWdtStop(); //关看门狗
WDT_ENTER_DEEPSLEEP(OSI_MIN(int64_t, osiCpDeepSleepTime(), sleep_ms) + SUSPEND_WDT_MARGIN_TIME);
uint32_t source = osiChip32KSleep(sleep_ms);
OSI_LOGI(0, "suspend resume source 0x%08x", source);
#ifdef CONFIG_QUEC_PROJECT_FEATURE_SLEEP
TAILQ_FOREACH(p, &d->resume_list, resume_iter)
{
if (p->ops.resume != NULL && \
(p->tag == DRV_NAME_PWT || p->tag == DRV_NAME_LPG))
{
OSI_LOGD(0, "resume cb %4c", p->tag);
p->ops.resume(p->cb_ctx, 0, source);
}
}
quec_exit_sleep_cb(source); //1.回复硬件外设(led、流控、gnss);2.客户自定义的打开
#endif
halSysWdtStart(); //开关门狗
WDT_EXIT_DEEPSLEEP(); //
osiProfileExit(PROFCODE_DEEP_SLEEP);
}
uint32_t osiChip32KSleep(int64_t sleep_ms)
{
//1.关闭硬件定时器
osiChipTimerDisable();
//2.开启idel的定时器
prvSetIdleTimerForSleep(sleep_ms);
//3.保存tick
prvSaveTickRef32K();
extern char __svc_stack_end[];
uint32_t source = osiCallWithStack(__svc_stack_end, prv32KSleepSram, 0, 0);
//4.记录tick
prvRestoreTickRef32K();
//5.定时器唤醒处理
osiTimerWakeupProcess();
return source; //返回唤醒原因
}
栈 从psram移到sram中运行,
prv32KSleepSram()
{
//1.关闭cp(协处理器,流媒体加速器)的时钟
REG_SYS_CTRL_CLK_OTHERS_DISABLE_T clk_others_disable = {.b.disable_oc_id_cp_a5 = 1};
hwp_sysCtrl->clk_others_disable = clk_others_disable.v;
//2.usb检测使能
REGT_FIELD_CHANGE(hwp_analogReg->usb_reg3,
REG_ANALOG_REG_USB_REG3_T,
usb_det_en, 1);
hwp_analogReg->usb_reserved |= 0x20;
//3.保持ap和aon_lp在深度睡眠继续打开电源
REGT_FIELD_CHANGE(hwp_pwrctrl->pwr_hwen,
REG_CP_PWRCTRL_PWR_HWEN_T,
ap_pwr_en, 0,
aon_lp_pon_en, 0);
//4.禁止分支预测
__set_SCTLR(__get_SCTLR() & (~SCTLR_Z_Msk));
__ISB(); //清洗流水线
//5.关闭MMU,因为页表(TTB)在psram
__set_SCTLR(__get_SCTLR() & ~1);
__ISB();
//6.psram进入低电压模式(psram不能被访问了)
REGT_FIELD_CHANGE(hwp_sysCtrl->cfg_force_lp_mode_lp,
REG_SYS_CTRL_CFG_FORCE_LP_MODE_LP_T,
cfg_force_lp_psram, 1);
//7.psram进入了自刷新模式
REGT_FIELD_CHANGE(hwp_pwrctrl->ddr_slp_req_hwen,
REG_CP_PWRCTRL_DDR_SLP_REQ_HWEN_T,
ddrslpreq_hwen, 0);
REGT_FIELD_CHANGE(hwp_pwrctrl->ddr_slp_req_sw,
REG_CP_PWRCTRL_DDR_SLP_REQ_SW_T,
ddrslpreq, 1);
REGT_WAIT_FIELD_NEZ(hwp_pwrctrl->ddr_slp_ack,
REG_CP_PWRCTRL_DDR_SLP_ACK_T,
ddrslpack);
//8.设置gpio9输入、高电平唤醒
REG_IOMUX_PAD_GPIO_9_CFG_REG_T gpio_9_cfg = {};
gpio_9_cfg.b.pad_gpio_9_sel = 0;
hwp_iomux->pad_gpio_9_cfg_reg = gpio_9_cfg.v;
//9.设置gpio1
hwp_gpio1->gpio_oen_set_in = (1 << CONFIG_SLEEP32K_GPIO);
hwp_gpio1->gpint_mode_set_reg = (1 << CONFIG_SLEEP32K_GPIO);
hwp_gpio1->gpint_ctrl_r_clr_reg = (1 << CONFIG_SLEEP32K_GPIO);
hwp_gpio1->gpint_ctrl_f_clr_reg = (1 << CONFIG_SLEEP32K_GPIO);
hwp_gpio1->gpint_ctrl_r_set_reg = (1 << CONFIG_SLEEP32K_GPIO);
//10.刷cache
__DSB();
__ISB();
//11.读取usb的状态
gusbcfg.v = hwp_usbc->gusbcfg;
//12.时间查看
unsigned tick16k = hwp_timer2->hwtimer_curval;
//13.wfi:等待usb接入,中断,定时器唤醒
for (int count = 0;;)
{
// 获取IRQ
uint32_t isr = __get_ISR();
if ((isr & (CPSR_I_Msk | CPSR_F_Msk | CPSR_A_Msk)) != 0)
break;
// 610us
if ((unsigned)(hwp_timer2->hwtimer_curval - tick16k) > SLEEP32K_POLL_PLL_START)
{
REG_SYS_CTRL_SEL_CLOCK_T sel_clock = {hwp_sysCtrl->sel_clock};
if (sel_clock.b.apll_locked_h)
break;
}
// usb接入
if (gusbcfg.b.physel)
{
ggpio.v = hwp_usbc->ggpio;
count = (ggpio.b.gpi == 2) ? count + 1 : 0;
}
else
{
usb_mon.v = hwp_analogReg->usb_mon;
count = (usb_mon.b.usb_dm_chr == 0 && usb_mon.b.usb_dp_chr == 1) ? count + 1 : 0;
}
if (count >= USB_MON_DET_COUNT)
{
source = HAL_RESUME_SRC_USB_MON;
break;
}
}
//14.gpio9输出高
gpio_9_cfg.b.pad_gpio_9_oen_frc = 1;
gpio_9_cfg.b.pad_gpio_9_out_frc = 1;
gpio_9_cfg.b.pad_gpio_9_out_reg = 1;
hwp_iomux->pad_gpio_9_cfg_reg = gpio_9_cfg.v;
//15.gpio1设置
hwp_gpio1->gpint_ctrl_r_clr_reg = (1 << CONFIG_SLEEP32K_GPIO);
hwp_gpio1->gpint_ctrl_f_clr_reg = (1 << CONFIG_SLEEP32K_GPIO);
//16.usb使能关闭
REGT_FIELD_CHANGE(hwp_analogReg->usb_reg3,
REG_ANALOG_REG_USB_REG3_T,
usb_det_en, 0);
hwp_analogReg->usb_reserved &= ~0x20;
//17.退出自刷新
REGT_FIELD_CHANGE(hwp_pwrctrl->ddr_slp_req_sw,
REG_CP_PWRCTRL_DDR_SLP_REQ_SW_T,
ddrslpreq, 0);
REGT_FIELD_CHANGE(hwp_pwrctrl->ddr_slp_req_hwen,
REG_CP_PWRCTRL_DDR_SLP_REQ_HWEN_T,
ddrslpreq_hwen, 1);
//18.恢复电压
REGT_FIELD_CHANGE(hwp_sysCtrl->cfg_force_lp_mode_lp,
REG_SYS_CTRL_CFG_FORCE_LP_MODE_LP_T,
cfg_force_lp_psram, 0);
//19.使能mmu
__set_SCTLR((__get_SCTLR() & ~(1 << 28) & ~(1 << 1)) | 1 | (1 << 29));
__ISB();
//20.清除唤醒的记录
REG_CP_IDLE_IDL_AWK_ST_T awk_st = {hwp_idle->idl_awk_st};
REG_CP_IDLE_IDL_AWK_ST_T awk_st_clr = {
.b.awk0_awk_stat = 1, // pmic
.b.awk1_awk_stat = 0, // vad_int
.b.awk2_awk_stat = 1, // key
.b.awk3_awk_stat = 1, // gpio1
.b.awk4_awk_stat = 1, // uart1
.b.awk5_awk_stat = 1, // pad uart1_rxd
.b.awk6_awk_stat = 1, // wcn2sys
.b.awk7_awk_stat = 1, // pad wcn_osc_en
.b.awk_osw2_stat = 1};
hwp_idle->idl_awk_st = awk_st_clr.v;
//21.记录唤醒
if (awk_st.b.awk0_awk_stat)
source |= HAL_RESUME_SRC_PMIC;
if (awk_st.b.awk1_awk_stat)
source |= HAL_RESUME_SRC_VAD;
if (awk_st.b.awk2_awk_stat)
source |= HAL_RESUME_SRC_KEY;
if (awk_st.b.awk3_awk_stat)
source |= HAL_RESUME_SRC_GPIO1;
if (awk_st.b.awk4_awk_stat)
source |= HAL_RESUME_SRC_UART1;
if (awk_st.b.awk5_awk_stat)
source |= HAL_RESUME_SRC_UART1_RXD;
if (awk_st.b.awk6_awk_stat)
source |= HAL_RESUME_SRC_WCN2SYS;
if (awk_st.b.awk7_awk_stat)
source |= HAL_RESUME_SRC_WCN_OSC;
if (awk_st.b.awk_osw1_stat)
source |= HAL_RESUME_SRC_IDLE_TIMER1;
if (awk_st.b.awk_osw2_stat)
source |= HAL_RESUME_SRC_IDLE_TIMER2;
if (awk_st.b.awk_self_stat)
source |= HAL_RESUME_SRC_SELF;
//22.打开协处理器的时钟
REG_SYS_CTRL_CLK_OTHERS_ENABLE_T clk_others_enable = {.b.enable_oc_id_cp_a5 = 1};
hwp_sysCtrl->clk_others_enable = clk_others_enable.v;
//23.打开分支预测
__set_SCTLR(__get_SCTLR() | SCTLR_Z_Msk);
__ISB();
//24. ap和aon_lp在深度睡眠关闭电源
REGT_FIELD_CHANGE(hwp_pwrctrl->pwr_hwen,
REG_CP_PWRCTRL_PWR_HWEN_T,
ap_pwr_en, 1,
aon_lp_pon_en, 1);
return source;//返回唤醒原因
}