ruuvi.drivers.c  ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
ruuvi_nrf5_sdk15_yield.c
Go to the documentation of this file.
1 
13 #include "ruuvi_interface_yield.h"
14 #if RUUVI_NRF5_SDK15_YIELD_ENABLED
15 #include "ruuvi_nrf5_sdk15_error.h"
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
22 #include "ruuvi_interface_timer.h"
23 static ri_timer_id_t wakeup_timer;
24 #endif
25 
26 static bool m_lp = false;
27 static bool m_is_init = false;
28 static volatile bool m_wakeup = false;
29 static 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.
39 void 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 
71 static 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
79 static void fpu_init (void)
80 {}
81 #endif
82 
83 /*
84  * Set a flag to wake up
85  */
86 static 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
109 rd_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.
134 rd_status_t ri_yield_low_power_enable (const bool enable)
135 {
136  return RD_ERROR_NOT_SUPPORTED;
137 }
138 #endif
139 
140 
141 rd_status_t ri_yield (void)
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 
152 rd_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 
189 rd_status_t ri_delay_us (uint32_t time)
190 {
191  nrf_delay_us (time);
192  return RD_SUCCESS;
193 }
194 
195 void ri_yield_indication_set (const ri_yield_state_ind_fp_t indication)
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.