drv_pm.c 3.5 KB
Newer Older
A
ACM32_MCU 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
/*
 * Copyright (c) 2006-2022, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date         Author        Notes
 * 2021-10-13   AisinoChip    first add to bsp
 */

#include "board.h"
#include <rtdevice.h>

#if defined(RT_USING_PM)

#define IWDT_SRC_CLK        32000
#define IWDT_CLK_PRESCALER  IWDT_CLOCK_PRESCALER_32
#define IWDT_CLK            (IWDT_SRC_CLK / (4<<IWDT_CLK_PRESCALER))

static IWDT_HandleTypeDef hiwdt;

static rt_tick_t get_pm_tick_from_os_tick(rt_tick_t tick)
{
    return (rt_tick_t)(IWDT_CLK * tick / RT_TICK_PER_SECOND);
}

static rt_tick_t get_os_tick_from_pm_tick(rt_tick_t tick)
{
    static rt_uint32_t os_tick_remain = 0;
    rt_uint32_t ret;

    ret = (tick * RT_TICK_PER_SECOND + os_tick_remain) / IWDT_CLK;

    os_tick_remain += (tick * RT_TICK_PER_SECOND);
    os_tick_remain %= IWDT_CLK;

    return ret;
}

static void _pm_sleep(struct rt_pm *pm, rt_uint8_t mode)
{
    RT_ASSERT(pm != RT_NULL);

    switch(mode)
    {
    case PM_SLEEP_MODE_NONE:
        break;

    case PM_SLEEP_MODE_IDLE:
        break;

    case PM_SLEEP_MODE_LIGHT:
        System_Enter_Sleep_Mode(SLEEPENTRY_WFI);
        break;

    case PM_SLEEP_MODE_DEEP:
        System_Enter_Stop_Mode(STOPENTRY_WFI);
        break;

    case PM_SLEEP_MODE_STANDBY:
        System_Enter_Standby_Mode();
        break;

    case PM_SLEEP_MODE_SHUTDOWN:
        break;

    default:
        return;
    }
}

static void _pm_run(struct rt_pm *pm, rt_uint8_t mode)
{
    static rt_uint8_t prev_mode = 0;

    RT_ASSERT(pm != RT_NULL);

    if(prev_mode == mode)
    {
        return;
    }

    switch(mode)
    {
    case PM_RUN_MODE_HIGH_SPEED: /* 64Mhz */
    case PM_RUN_MODE_NORMAL_SPEED: /* 64Mhz */
        System_Clock_Init(64000000);
        break;

    case PM_RUN_MODE_MEDIUM_SPEED: /* 32Mhz */
        System_Clock_Init(32000000);
        break;

    case PM_RUN_MODE_LOW_SPEED: /* 8Mhz */
        System_Clock_Init(8000000);
        break;

    default:
        return;
    }

    SysTick_Config(System_Get_SystemClock() / RT_TICK_PER_SECOND);
    prev_mode = mode;
}

static void _pm_timer_start(struct rt_pm *pm, rt_uint32_t timeout)
{
    int tick;

    RT_ASSERT(pm != RT_NULL);
    IWDT_HandleTypeDef *phiwdt = (IWDT_HandleTypeDef *)(pm->parent.user_data);

    if(timeout != RT_TICK_MAX)
    {
        tick = get_pm_tick_from_os_tick(timeout);
        phiwdt->Instance = IWDT;
        phiwdt->Init.Prescaler = IWDT_CLK_PRESCALER;
        phiwdt->Init.Reload = tick;
        phiwdt->Init.Window = tick;  /* window function disabled when window >= reload */
        phiwdt->Init.Wakeup = tick - 1;  /* wakeup function disabled when wakeup >= reload */
        HAL_IWDT_Init(phiwdt);
    }
}

static void _pm_timer_stop(struct rt_pm *pm)
{
    RT_ASSERT(pm != RT_NULL);

    IWDT_HandleTypeDef *phiwdt = (IWDT_HandleTypeDef *)(pm->parent.user_data);

    phiwdt->Instance->CMDR = 0xFFFF;
}

static rt_tick_t _pm_timer_get_tick(struct rt_pm *pm)
{
    rt_tick_t tick;
    RT_ASSERT(pm != RT_NULL);

    return get_os_tick_from_pm_tick(tick);
}

static const struct rt_pm_ops _pm_ops =
{
    _pm_sleep,
    _pm_run,
    _pm_timer_start,
    _pm_timer_stop,
    _pm_timer_get_tick
};

/**
 * This function initialize the power manager
 */
int drv_pm_hw_init(void)
{

    rt_uint8_t timer_mask = 0;

    /* initialize timer mask */
    timer_mask = (1UL << PM_SLEEP_MODE_DEEP) | (1UL << PM_SLEEP_MODE_STANDBY);

    /* initialize system pm module */
    rt_system_pm_init(&_pm_ops, timer_mask, &hiwdt);

    return 0;
}
INIT_BOARD_EXPORT(drv_pm_hw_init);

#endif /* RT_USING_PM */