ruuvi.drivers.c ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
Loading...
Searching...
No Matches
ruuvi_nrf5_sdk15_yield.c
Go to the documentation of this file.
1
14#if RUUVI_NRF5_SDK15_YIELD_ENABLED
16#include "ruuvi_interface_log.h"
17#include "ruuvi_driver_error.h"
18#include "nrf_delay.h"
19#include "nrf_pwr_mgmt.h"
20#include "nrf_error.h"
21#if RUUVI_NRF5_SDK15_TIMER_ENABLED
23static ri_timer_id_t wakeup_timer;
24#endif
25
26static bool m_lp = false;
27static bool m_is_init = false;
28static volatile bool m_wakeup = false;
29static ri_yield_state_ind_fp_t m_ind;
30
31#ifdef FLOAT_ABI_HARD
32#define IOC_MASK (0x01U)
33#define DZC_MASK (0x02U)
34#define OFC_MASK (0x04U)
35// Function handles and clears exception flags in FPSCR register and at the stack.
36// During interrupt, handler execution FPU registers might be copied to the stack
37// (see lazy stacking option) and it is necessary to clear data at the stack
38// which will be recovered in the return from interrupt handling.
39void FPU_IRQHandler (void)
40{
41 // Prepare pointer to stack address with pushed FPSCR register
42 // (0x40 is FPSCR register offset in stacked data)
43 uint32_t * fpscr = (uint32_t *) (FPU->FPCAR + 0x40);
44 // Execute FPU instruction to activate lazy stacking
45 (void) __get_FPSCR();
46
47 // Check exception flags
48 // Critical FPU exceptions signaled:
49 // - IOC - Invalid Operation cumulative exception bit.
50 // - DZC - Division by Zero cumulative exception bit.
51 // - OFC - Overflow cumulative exception bit.
52 if (*fpscr & IOC_MASK)
53 {
54 ri_log (RI_LOG_LEVEL_WARNING, "FPU IOC Error");
55 }
56
57 if (*fpscr & DZC_MASK)
58 {
59 ri_log (RI_LOG_LEVEL_WARNING, "FPU DZC Error");
60 }
61
62 if (*fpscr & OFC_MASK)
63 {
64 ri_log (RI_LOG_LEVEL_WARNING, "FPU OFC Error");
65 }
66
67 // Clear flags in stacked FPSCR register. To clear IDC, IXC, UFC, OFC, DZC and IOC flags, use 0x0000009F mask.
68 *fpscr = *fpscr & ~ (0x0000009F);
69}
70
71static void fpu_init (void)
72{
73 NVIC_SetPriority (FPU_IRQn, 7);
74 NVIC_ClearPendingIRQ (FPU_IRQn);
75 NVIC_EnableIRQ (FPU_IRQn);
76}
77
78#else
79static void fpu_init (void)
80{}
81#endif
82
83/*
84 * Set a flag to wake up
85 */
86static void wakeup_handler (void * p_context)
87{
88 m_wakeup = true;
89}
90
92{
93 return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0;
94}
95
96
98{
99 fpu_init();
100 ret_code_t err_code = nrf_pwr_mgmt_init();
101 m_lp = false;
102 m_wakeup = false;
103 m_ind = NULL;
104 m_is_init = true;
105 return ruuvi_nrf5_sdk15_to_ruuvi_error (err_code);
106}
107
108#if RUUVI_NRF5_SDK15_TIMER_ENABLED
109rd_status_t ri_yield_low_power_enable (const bool enable)
110{
111 // Timer can be allocated after timer has initialized
112 rd_status_t timer_status = RD_SUCCESS;
113
114 if (NULL == wakeup_timer)
115 {
116 timer_status = ri_timer_create (&wakeup_timer,
117 RI_TIMER_MODE_SINGLE_SHOT, wakeup_handler);
118 }
119
120 if (timer_status == RD_SUCCESS)
121 {
122 m_lp = enable;
123 m_wakeup = true;
124 }
125 else
126 {
127 m_lp = false;
128 }
129
130 return timer_status;
131}
132#else
133// Return error if timers are not enabled.
134rd_status_t ri_yield_low_power_enable (const bool enable)
135{
137}
138#endif
139
140
142{
143 if (NULL != m_ind) { m_ind (false); }
144
145 nrf_pwr_mgmt_run();
146
147 if (NULL != m_ind) { m_ind (true); }
148
149 return RD_SUCCESS;
150}
151
152rd_status_t ri_delay_ms (uint32_t time)
153{
154 rd_status_t err_code = RD_SUCCESS;
155#if RUUVI_NRF5_SDK15_TIMER_ENABLED
156
157 // Check that low-power delay is enabled and sleep timer is not running right now.
158 if (m_lp && m_wakeup)
159 {
161 {
162 ri_delay_us (1000 * time);
163 }
164 else
165 {
166 m_wakeup = false;
167 err_code |= ri_timer_start (wakeup_timer, time, NULL);
168
169 while (RD_SUCCESS == err_code && !m_wakeup)
170 {
171 err_code |= ri_yield();
172 }
173 }
174 }
175
176#else
177
178 if (0) {}
179
180#endif
181 else
182 {
183 nrf_delay_ms (time);
184 }
185
186 return err_code;
187}
188
189rd_status_t ri_delay_us (uint32_t time)
190{
191 nrf_delay_us (time);
192 return RD_SUCCESS;
193}
194
196{
197 m_ind = indication;
198}
199
201{
202 m_ind = NULL;
203 wakeup_timer = NULL;
204 m_wakeup = false;
205 m_lp = false;
206 m_is_init = false;
207 return RD_SUCCESS;
208}
209
210#endif
uint32_t rd_status_t
bitfield for representing errors
rd_status_t ruuvi_nrf5_sdk15_to_ruuvi_error(const ret_code_t error)
convert nrf5 sdk15 error code into Ruuvi error code.
#define RD_ERROR_NOT_SUPPORTED
Not supported.
#define RD_SUCCESS
Internal Error.
void ri_log(const ri_log_severity_t severity, const char *const message)
Queues messages into log.
@ RI_LOG_LEVEL_WARNING
rd_status_t ri_timer_start(ri_timer_id_t timer_id, uint32_t ms, void *const context)
Start given timer at a mode defined in ri_timer_create.
rd_status_t ri_timer_create(ri_timer_id_t *p_timer_id, ri_timer_mode_t mode, ruuvi_timer_timeout_handler_t timeout_handler)
void * ri_timer_id_t
Pointer to timer data.
@ RI_TIMER_MODE_SINGLE_SHOT
Header to enable and disable module compilation.
Ruuvi error codes and error check function.
Interface functions to timer.
rd_status_t ri_yield_uninit(void)
Uninitializes yielding functions.
rd_status_t ri_yield_init(void)
Initializes yielding functions.
bool ri_yield_is_interrupt_context(void)
Check if current execution is in interrupt context.
rd_status_t ri_yield(void)
Function which will release execution.
void ri_yield_indication_set(const ri_yield_state_ind_fp_t indication)
rd_status_t ri_delay_us(uint32_t time)
Delay a given number of microseconds.
void(* ri_yield_state_ind_fp_t)(const bool active)
Enable implementation selected by application.
rd_status_t ri_delay_ms(uint32_t time)
Delay a given number of milliseconds.
rd_status_t ri_yield_low_power_enable(const bool enable)
Initializes yielding functions.