summaryrefslogtreecommitdiff
path: root/bsp/nrf52832/board/board.c
blob: 6b1befe16f37ac076ceb4bd95220340ee6326ae7 (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
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#include "board.h"
#include "uart.h"
#include "app_util_platform.h"
#include "nrf_drv_common.h"
#include "nrf_systick.h"
#include "nrf_rtc.h"
#include "nrf_drv_clock.h"
#include "softdevice_handler.h"
#include "nrf_drv_uart.h"
#include "nrf_gpio.h"

#include <rtthread.h>
#include <rthw.h>

#if 0

/*******************************************************************************
 * Function Name  : SysTick_Configuration
 * Description    : Configures the SysTick for OS tick.
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
void  SysTick_Configuration(void)
{
    nrf_drv_common_irq_enable(SysTick_IRQn, APP_TIMER_CONFIG_IRQ_PRIORITY);
    nrf_systick_load_set(SystemCoreClock / RT_TICK_PER_SECOND);
    nrf_systick_val_clear();
    nrf_systick_csr_set(NRF_SYSTICK_CSR_CLKSOURCE_CPU | NRF_SYSTICK_CSR_TICKINT_ENABLE
                        | NRF_SYSTICK_CSR_ENABLE);
}

/**
 * This is the timer interrupt service routine.
 *
 */


void SysTick_Handler(void)
{
    if (rt_thread_self() != RT_NULL)
    {
    	/* enter interrupt */
    	rt_interrupt_enter();

    	rt_tick_increase();

    	/* leave interrupt */
    	rt_interrupt_leave();
    }
}

#else

#define TICK_RATE_HZ  RT_TICK_PER_SECOND
#define SYSTICK_CLOCK_HZ  ( 32768UL )

#define NRF_RTC_REG        NRF_RTC1
    /* IRQn used by the selected RTC */
#define NRF_RTC_IRQn       RTC1_IRQn
    /* Constants required to manipulate the NVIC. */
#define NRF_RTC_PRESCALER  ( (uint32_t) (ROUNDED_DIV(SYSTICK_CLOCK_HZ, TICK_RATE_HZ) - 1) )
    /* Maximum RTC ticks */
#define NRF_RTC_MAXTICKS   ((1U<<24)-1U)

static volatile uint32_t m_tick_overflow_count = 0;
#define NRF_RTC_BITWIDTH 24
#define OSTick_Handler     RTC1_IRQHandler
#define EXPECTED_IDLE_TIME_BEFORE_SLEEP   2

void SysTick_Configuration(void)
{
    nrf_drv_clock_lfclk_request(NULL);

    /* Configure SysTick to interrupt at the requested rate. */
    nrf_rtc_prescaler_set(NRF_RTC_REG, NRF_RTC_PRESCALER);
    nrf_rtc_int_enable   (NRF_RTC_REG, RTC_INTENSET_TICK_Msk);
    nrf_rtc_task_trigger (NRF_RTC_REG, NRF_RTC_TASK_CLEAR);
    nrf_rtc_task_trigger (NRF_RTC_REG, NRF_RTC_TASK_START);
    nrf_rtc_event_enable(NRF_RTC_REG, RTC_EVTEN_OVRFLW_Msk);

    NVIC_SetPriority(NRF_RTC_IRQn, 0xF);
    NVIC_EnableIRQ(NRF_RTC_IRQn);
}

static rt_tick_t _tick_distance(void)
{
    nrf_rtc_event_clear(NRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0);

    uint32_t systick_counter = nrf_rtc_counter_get(NRF_RTC_REG);
    nrf_rtc_event_clear(NRF_RTC_REG, NRF_RTC_EVENT_TICK);

    /* check for overflow in TICK counter */
    if(nrf_rtc_event_pending(NRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW))
    {
        nrf_rtc_event_clear(NRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW);
        m_tick_overflow_count++;
    }

    return ((m_tick_overflow_count << NRF_RTC_BITWIDTH) + systick_counter) - rt_tick_get();
}

void OSTick_Handler( void )
{
    uint32_t diff;

	/* enter interrupt */
    rt_interrupt_enter();
    diff = _tick_distance();

    while((diff--) > 0)
    {
        if (rt_thread_self() != RT_NULL)
        {
          rt_tick_increase();
        }
    }
    /* leave interrupt */
    rt_interrupt_leave();
}

static void _wakeup_tick_adjust(void)
{
    uint32_t diff;
    uint32_t level;

    level = rt_hw_interrupt_disable();

    diff = _tick_distance();

    rt_tick_set(rt_tick_get() + diff);

    if (rt_thread_self() != RT_NULL)
    {
    	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();
    }

    rt_hw_interrupt_enable(level);
}

static void _sleep_ongo( uint32_t sleep_tick )
{
    uint32_t enterTime;
    uint32_t entry_tick;

    /* Make sure the SysTick reload value does not overflow the counter. */
    if ( sleep_tick > NRF_RTC_MAXTICKS - EXPECTED_IDLE_TIME_BEFORE_SLEEP )
    {
        sleep_tick = NRF_RTC_MAXTICKS - EXPECTED_IDLE_TIME_BEFORE_SLEEP;
    }

    rt_enter_critical();

    enterTime = nrf_rtc_counter_get(NRF_RTC_REG);

    {
        uint32_t wakeupTime = (enterTime + sleep_tick) & NRF_RTC_MAXTICKS;

        /* Stop tick events */
        nrf_rtc_int_disable(NRF_RTC_REG, NRF_RTC_INT_TICK_MASK);

        /* Configure CTC interrupt */
        nrf_rtc_cc_set(NRF_RTC_REG, 0, wakeupTime);
        nrf_rtc_event_clear(NRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0);
        nrf_rtc_int_enable(NRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK);

        entry_tick = rt_tick_get();

        __DSB();

        if ( sleep_tick > 0 )
        {
#ifdef SOFTDEVICE_PRESENT
            if (softdevice_handler_is_enabled())
            {
                uint32_t err_code = sd_app_evt_wait();
                APP_ERROR_CHECK(err_code);
            }
            else
#endif
            {
                /* No SD -  we would just block interrupts globally.
                * BASEPRI cannot be used for that because it would prevent WFE from wake up.
                */
                do{
                    __WFE();
                } while (0 == (NVIC->ISPR[0] | NVIC->ISPR[1]));
            }
        }

        nrf_rtc_int_disable(NRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK);
        nrf_rtc_event_clear(NRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0);

        _wakeup_tick_adjust();

        /* Correct the system ticks */
        {

            nrf_rtc_event_clear(NRF_RTC_REG, NRF_RTC_EVENT_TICK);
            nrf_rtc_int_enable (NRF_RTC_REG, NRF_RTC_INT_TICK_MASK);
            /* It is important that we clear pending here so that our corrections are latest and in sync with tick_interrupt handler */
            NVIC_ClearPendingIRQ(NRF_RTC_IRQn);
        }

        rt_kprintf("entry tick:%u, expected:%u, current tick:%u\n", entry_tick, sleep_tick, rt_tick_get());
    }

    rt_exit_critical();
}

#endif

void rt_hw_system_powersave(void)
{
    uint32_t sleep_tick;

    sleep_tick = rt_timer_next_timeout_tick() - rt_tick_get();

    if ( sleep_tick >= EXPECTED_IDLE_TIME_BEFORE_SLEEP)
    {
        // rt_kprintf("sleep entry:%u\n", rt_tick_get());
        _sleep_ongo( sleep_tick );
    }
}

void rt_hw_board_init(void)
{
    // sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);
    /* Activate deep sleep mode */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

    nrf_drv_clock_init();
    // nrf_drv_clock_hfclk_request(0);

    SysTick_Configuration();

    rt_thread_idle_sethook(rt_hw_system_powersave);

    rt_hw_uart_init();

#ifdef RT_USING_CONSOLE
    rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif

#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif
}