summaryrefslogtreecommitdiff
path: root/bsp/samd21/board/sleep_timer.c
blob: a676d5bc859e0e37751afa5259d443439a3aa962 (plain)
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
// From module: RTC - Real Time Counter in Count Mode (Polled APIs)
#include <rtc_count.h>
#include <rtc_count_interrupt.h>
// #include <rtc_tamper.h>
#include <power.h>
#include <port.h>

#include <rtthread.h>

/* RTC module instance */
static struct rtc_module rtc_instance;

static void _rtc_timer_int_cb(void)
{
	port_pin_toggle_output_level(PIN_PB30);
}

/* Init RTC as ADC sample timer */
static void _rtc_timer_init(void)
{
	struct rtc_count_config conf;

	rtc_count_get_config_defaults(&conf);

	conf.prescaler         = RTC_COUNT_PRESCALER_DIV_1;
	conf.mode              = RTC_COUNT_MODE_32BIT;
	conf.clear_on_match    = false;
	conf.compare_values[0] = 0;

	// struct rtc_count_events evconfig;
	// evconfig.generate_event_on_compare[0] = true;

	rtc_count_init(&rtc_instance, RTC, &conf);
	// rtc_count_enable_events(&rtc_instance, &evconfig);
    // rtc_count_enable(&rtc_instance);
	rtc_count_set_count(&rtc_instance, 0);
	rtc_count_register_callback(&rtc_instance, _rtc_timer_int_cb, RTC_COUNT_CALLBACK_COMPARE_0);
	// rtc_count_enable_callback(&rtc_instance, RTC_COUNT_CALLBACK_COMPARE_0);
}

static void _rtc_timer_start(uint32_t ms)
{
	uint32_t compare = 0;

	compare = (uint32_t)(32.768 * ms);

	// rtc_count_register_callback(&rtc_instance, _rtc_timer_int_cb, RTC_COUNT_CALLBACK_COMPARE_0);
	rtc_count_enable_callback(&rtc_instance, RTC_COUNT_CALLBACK_COMPARE_0);

	rtc_count_set_count(&rtc_instance, 0);
	rtc_count_set_compare(&rtc_instance, compare, RTC_COUNT_COMPARE_0);
	rtc_count_enable(&rtc_instance);
}

static void sleep_tick_adjust(uint32_t ms)
{
	uint32_t diff;

	diff = rt_tick_from_millisecond(ms);

	rt_tick_set(rt_tick_get() + diff);
	{
		struct rt_thread *thread;

		/* check time slice */
		thread = rt_thread_self();

		if (thread->remaining_tick <= diff)
		{
			/* change to initialized tick */
			thread->remaining_tick = thread->init_tick;

			/* yield */
			rt_thread_yield();
		}
		else
		{
			thread->remaining_tick -= diff;
		}

		/* check timer */
		rt_timer_check();
	}
}

static void _sleep_entry(void)
{
	rt_tick_t timeout;
	rt_uint32_t ms;
	rt_uint32_t count;

	system_set_sleepmode(SYSTEM_SLEEPMODE_STANDBY);
	timeout = rt_timer_next_timeout_tick() - rt_tick_get();

	ms = timeout * (1000 / RT_TICK_PER_SECOND);
	rt_kprintf("os tick:%u entry sleep:%u tick\r\n", rt_tick_get(), timeout);

	_rtc_timer_start(ms);

	system_sleep();

	rt_enter_critical();
	count = rtc_count_get_count(&rtc_instance);
	ms = (count + 32) / 32.768;
	rtc_count_disable(&rtc_instance);
	sleep_tick_adjust(ms);
	timeout = rt_tick_get();
	rt_exit_critical();
	rt_kprintf("sleep exited, os tick:%u\n", timeout);
}

void sleep_timer_init(void)
{
	_rtc_timer_init();
	rt_thread_idle_sethook(_sleep_entry);
}

void sleep_timer_start(uint32_t ms)
{
	_rtc_timer_start(ms);
}

void sleep_timer_stop(void)
{
	rtc_count_disable(&rtc_instance);
}