Appiko
aux_clk.c
1 /*
2  * aux_clk.c : Module to handle auxiliary clock used by different modules
3  * Copyright (C) 2019 Appiko
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
19 #include "aux_clk.h"
20 #include "log.h"
21 #include "nrf.h"
22 #include "string.h"
23 #include "gpio_level_handler.h"
24 #include "hal_ppi.h"
25 #include "hal_clocks.h"
26 #include "common_util.h"
27 
28 #define RTC_USED CONCAT_2(NRF_RTC, AUX_CLK_LFCLK_RTC_USED)
29 
30 
31 //#if RTC_USED != NRF_RTC0
32 //#error "RTC Used not set"
33 //#endif
34 
35 #define RTC_IRQ_Handler_a(n) RTC_IRQ_Handler_b(n)
36 #define RTC_IRQ_Handler_b(n) RTC##n##_IRQHandler
37 
38 #define RTC_IRQN_a(n) RTC_IRQN_b(n)
39 #define RTC_IRQN_b(n) RTC##n##_IRQn
40 
41 #define RTC_IRQN RTC_IRQN_a(AUX_CLK_LFCLK_RTC_USED)
42 #define RTC_IRQ_Handler RTC_IRQ_Handler_a(AUX_CLK_LFCLK_RTC_USED)
43 
44 #define RTC_TICKS_MS(x) (uint32_t)(ROUNDED_DIV((32768 * x),1000))
45 
46 
47 #define TIMER_USED CONCAT_2(NRF_TIMER, AUX_CLK_HFCLK_TIMER_USED)
48 
49 
50 #define TIMER_IRQ_Handler TIMER_IRQ_Handler_a(AUX_CLK_HFCLK_TIMER_USED)
51 #define TIMER_IRQ_Handler_a(n) TIMER_IRQ_Handler_b(n)
52 #define TIMER_IRQ_Handler_b(n) TIMER##n##_IRQHandler
53 
54 #define TIMER_IRQN TIMER_IRQN_a(AUX_CLK_HFCLK_TIMER_USED)
55 #define TIMER_IRQN_a(n) TIMER_IRQN_b(n)
56 #define TIMER_IRQN_b(n) TIMER##n##_IRQn
57 
58 #define TIMER_TICKS_MS(x) (x * 1000)
59 
60 
62 void (*callbac_buffer) (uint8_t events);
63 
65 static aux_clk_source_t g_source = AUX_CLK_SRC_LFCLK;
66 
67 static app_irq_priority_t g_irq_priority;
68 
69 static aux_clk_ppi_t g_arr_ppi_cnf[AUX_CLK_PPI_CHANNELS_USED];
70 
71 #if ISR_MANAGER == 1
72 void aux_clk_rtc_handler (void)
73 #else
74 void RTC_IRQ_Handler(void)
75 #endif
76 {
77  uint8_t events = 0;
78  if(RTC_USED->EVENTS_COMPARE[0] == 1)
79  {
80  events |= AUX_CLK_EVT_CC0;
81 #if isr_manager == 0
82  RTC_USED->EVENTS_COMPARE[0] = 0;
83 #endif
84  }
85  if(RTC_USED->EVENTS_COMPARE[1] == 1)
86  {
87  events |= AUX_CLK_EVT_CC1;
88 #if isr_manager == 0
89  RTC_USED->EVENTS_COMPARE[1] = 0;
90 #endif
91  }
92  if(RTC_USED->EVENTS_COMPARE[2] == 1)
93  {
94  events |= AUX_CLK_EVT_CC2;
95 #if isr_manager == 0
96  RTC_USED->EVENTS_COMPARE[2] = 0;
97 #endif
98  }
99  if(RTC_USED->EVENTS_COMPARE[3] == 1)
100  {
101  events |= AUX_CLK_EVT_CC3;
102 #if isr_manager == 0
103  RTC_USED->EVENTS_COMPARE[3] = 0;
104 #endif
105  }
106  callbac_buffer (events);
107 }
108 
109 #if ISR_MANAGER == 1
110 void aux_clk_timer_handler (void)
111 #else
112 void TIMER_IRQ_Handler (void)
113 #endif
114 {
115  uint8_t events = 0;
116  if(TIMER_USED->EVENTS_COMPARE[0] == 1)
117  {
118  events |= AUX_CLK_EVT_CC0;
119 #if ISR_MANAGER == 0
120  TIMER_USED->EVENTS_COMPARE[0] = 0;
121 #endif
122  }
123  if(TIMER_USED->EVENTS_COMPARE[1] == 1)
124  {
125  events |= AUX_CLK_EVT_CC1;
126 #if ISR_MANAGER == 0
127  TIMER_USED->EVENTS_COMPARE[1] = 0;
128 #endif
129  }
130  if(TIMER_USED->EVENTS_COMPARE[2] == 1)
131  {
132  events |= AUX_CLK_EVT_CC2;
133 #if ISR_MANAGER == 0
134  TIMER_USED->EVENTS_COMPARE[2] = 0;
135 #endif
136  }
137  if(TIMER_USED->EVENTS_COMPARE[3] == 1)
138  {
139  events |= AUX_CLK_EVT_CC3;
140 #if ISR_MANAGER == 0
141  TIMER_USED->EVENTS_COMPARE[3] = 0;
142 #endif
143  }
144  callbac_buffer (events);
145 }
146 
147 void set_timer ()
148 {
149 #if AUX_CLK_HFCLK_SOLO_MODULE == 1
151 #endif
152  if(g_irq_priority != APP_IRQ_PRIORITY_THREAD)
153  {
154  NVIC_SetPriority (TIMER_IRQN, g_irq_priority);
155  NVIC_EnableIRQ (TIMER_IRQN);
156  }
157  TIMER_USED->TASKS_START = 1;
158  (void) TIMER_USED->TASKS_START;
159 }
160 
161 void set_rtc ()
162 {
163 #if AUX_CLK_HFCLK_SOLO_MODULE == 1
165 #endif
166  if(g_irq_priority != APP_IRQ_PRIORITY_THREAD)
167  {
168  NVIC_SetPriority (RTC_IRQN, g_irq_priority);
169  NVIC_EnableIRQ (RTC_IRQN);
170  }
171  RTC_USED->TASKS_START = 1;
172  (void) RTC_USED->TASKS_START;
173 }
174 
175 uint32_t select_event (uint32_t evt)
176 {
177 
178  uint32_t event;
179  switch (evt)
180  {
181  case AUX_CLK_EVT_NON :
182  event = 0;
183  break;
184 
185  case AUX_CLK_EVT_CC0 :
186  event = (uint32_t)((g_source == AUX_CLK_SRC_LFCLK) ?
187  &RTC_USED->EVENTS_COMPARE[0] :
188  &TIMER_USED->EVENTS_COMPARE[0]);
189  break;
190 
191  case AUX_CLK_EVT_CC1 :
192  event = (uint32_t)((g_source == AUX_CLK_SRC_LFCLK) ?
193  &RTC_USED->EVENTS_COMPARE[1] :
194  &TIMER_USED->EVENTS_COMPARE[1]);
195  break;
196 
197  case AUX_CLK_EVT_CC2 :
198  event = (uint32_t)((g_source == AUX_CLK_SRC_LFCLK) ?
199  &RTC_USED->EVENTS_COMPARE[2] :
200  &TIMER_USED->EVENTS_COMPARE[2]);
201  break;
202 
203  case AUX_CLK_EVT_CC3 :
204  event = (uint32_t)((g_source == AUX_CLK_SRC_LFCLK) ?
205  &RTC_USED->EVENTS_COMPARE[3] :
206  &TIMER_USED->EVENTS_COMPARE[3]);
207  break;
208 
209  default :
210  event = evt;
211  break;
212  }
213  return event;
214 }
215 
216 uint32_t select_task (uint32_t tsk)
217 {
218  uint32_t task;
219  switch (tsk)
220  {
221  case AUX_CLK_TASKS_START :
222  task = (uint32_t) ((g_source == AUX_CLK_SRC_LFCLK) ?
223  &RTC_USED->TASKS_START :
224  &TIMER_USED->TASKS_START);
225  break;
226 
227  case AUX_CLK_TASKS_STOP :
228  task = (uint32_t) ((g_source == AUX_CLK_SRC_LFCLK) ?
229  &RTC_USED->TASKS_STOP :
230  &TIMER_USED->TASKS_STOP);
231  break;
232 
233  case AUX_CLK_TASKS_CLEAR :
234  task = ((g_source == AUX_CLK_SRC_LFCLK) ?
235  (uint32_t) &RTC_USED->TASKS_CLEAR :
236  (uint32_t) &TIMER_USED->TASKS_CLEAR);
237  break;
238 
239  default :
240  task = tsk;
241  break;
242  }
243  return task;
244 }
245 
246 void set_ppi ()
247 {
248  hal_ppi_setup_t ppi_setup;
249  uint8_t ppi_status;
250  for(uint32_t cnt = 0; cnt < AUX_CLK_PPI_CHANNELS_USED; cnt++)
251  {
252  ppi_setup.ppi_id = AUX_CLK_PPI_CHANNEL_BASE + cnt;
253  ppi_setup.event = select_event (g_arr_ppi_cnf[cnt].event);
254  ppi_setup.task = select_task (g_arr_ppi_cnf[cnt].task1);
255  ppi_setup.fork = select_task (g_arr_ppi_cnf[cnt].task2);
256  ppi_status = hal_ppi_set (&ppi_setup);
257  if(ppi_status == PPI_SETUP_SUCCESSFUL)
258  {
259  hal_ppi_en_ch (ppi_setup.ppi_id);
260  }
261  }
262 }
263 
265 {
266  g_source = source;
267  NVIC_DisableIRQ (RTC_IRQN);
268  NVIC_DisableIRQ (TIMER_IRQN);
269  RTC_USED->TASKS_CLEAR = 1;
270  TIMER_USED->TASKS_CLEAR =1;
271  for(uint32_t cnt = 0; cnt < AUX_CLK_MAX_CHANNELS; cnt++)
272  {
273  RTC_USED->EVENTS_COMPARE[cnt] = 0;
274  TIMER_USED->EVENTS_COMPARE[cnt] = 0;
275  }
276  set_ppi ();
277  (g_source == AUX_CLK_SRC_LFCLK) ? set_rtc () : set_timer ();
278 
279 }
280 
281 void aux_clk_set (aux_clk_setup_t * aux_clk)
282 {
283  g_source = aux_clk->source;
284  memcpy (g_arr_ppi_cnf, aux_clk->arr_ppi_cnf,
285  (sizeof(aux_clk_ppi_t) * AUX_CLK_PPI_CHANNELS_USED));
286  callbac_buffer = aux_clk->callback_handler;
287 
288  RTC_USED->PRESCALER = 0;
289 
290  TIMER_USED->PRESCALER = 4;
291  TIMER_USED->BITMODE = TIMER_BITMODE_BITMODE_32Bit;
292  TIMER_USED->MODE = TIMER_MODE_MODE_Timer;
293 
294  for(uint32_t cnt = 0; cnt < AUX_CLK_MAX_CHANNELS; cnt++)
295  {
296  RTC_USED->CC[cnt] = RTC_TICKS_MS(aux_clk->arr_cc_ms[cnt]);
297  TIMER_USED->CC[cnt] = TIMER_TICKS_MS(aux_clk->arr_cc_ms[cnt]);
298  if((aux_clk->events_en & (uint8_t)(1<<cnt)))
299  {
300  RTC_USED->EVTENSET |= 1 << (16 + cnt);
301  RTC_USED->INTENSET |= 1 << (16 + cnt);
302  TIMER_USED->INTENSET |= 1 << (16 + cnt);
303  }
304 
305  }
306 }
307 
309 {
310  set_ppi ();
311  (g_source == AUX_CLK_SRC_LFCLK) ? set_rtc () : set_timer ();
312 }
313 
315 {
316  NVIC_DisableIRQ (RTC_IRQN);
317  RTC_USED->TASKS_CLEAR = 1;
318  RTC_USED->TASKS_STOP = 1;
319  NVIC_DisableIRQ (TIMER_IRQN);
320  TIMER_USED->TASKS_CLEAR = 1;
321  TIMER_USED->TASKS_STOP = 1;
322  TIMER_USED->TASKS_SHUTDOWN = 1;
323  (void) TIMER_USED->TASKS_SHUTDOWN;
324 }
325 
327 {
328  TIMER_USED->TASKS_CLEAR = 1;
329  RTC_USED->TASKS_CLEAR = 1;
330 }
331 
332 void aux_clk_en_evt (uint8_t events)
333 {
334  RTC_USED->EVTENSET |= (events << 16);
335  RTC_USED->INTENSET |= (events << 16);
336  TIMER_USED->INTENSET |= (events << 16);
337 }
338 
339 void aux_clk_dis_evt (uint8_t events)
340 {
341  RTC_USED->EVTENCLR |= (events << 16);
342  RTC_USED->INTENCLR |= (events << 16);
343  TIMER_USED->INTENCLR |= (events << 16);
344 }
345 
346 void aux_clk_update_ppi (uint32_t ppi_channel, aux_clk_ppi_t * new_ppi)
347 {
348  memcpy (&g_arr_ppi_cnf[ppi_channel - AUX_CLK_PPI_CHANNEL_BASE],
349  new_ppi, sizeof(aux_clk_ppi_t));
350  hal_ppi_setup_t ppi_update =
351  {
352  .ppi_id = ppi_channel,
353  .event = select_event (new_ppi->event),
354  .task = select_task (new_ppi->task1),
355  .fork = select_task (new_ppi->task2),
356  };
357  hal_ppi_set (&ppi_update);
358 }
359 
360 void aux_clk_update_cc (uint32_t cc_id,uint32_t new_val_ms)
361 {
362  TIMER_USED->CC[cc_id] = TIMER_TICKS_MS(new_val_ms);
363  RTC_USED->CC[cc_id] = RTC_TICKS_MS(new_val_ms);
364 }
365 
367 {
368  g_irq_priority = new_priority;
369 }
370 
371 uint32_t aux_clk_get_ms (void)
372 {
373  uint32_t ms;
374 
375  if(g_source ==AUX_CLK_SRC_LFCLK)
376  {
377  ms = (RTC_USED->COUNTER * 1000)/32768;
378  }
379  else
380  {
381  uint32_t cc0 = TIMER_USED->CC[0];
382  TIMER_USED->TASKS_CAPTURE[0] = 1;
383  uint32_t counter = TIMER_USED->CC[0];
384  TIMER_USED->CC[0] = cc0;
385  ms = counter / 1000;
386  }
387 
388  return ms;
389 }
void aux_clk_en_evt(uint8_t events)
Function to enable one or more events from aux_clk_evt_t.
Definition: aux_clk.c:332
void aux_clk_set(aux_clk_setup_t *aux_clk)
Function to setup the Auxiliary clock module.
Definition: aux_clk.c:281
uint32_t event
Definition: hal_ppi.h:57
aux_clk_source_t source
Definition: aux_clk.h:143
uint32_t fork
Definition: hal_ppi.h:61
uint32_t aux_clk_get_ms(void)
Function to get ms since Auxiliary clock has started or cleared.
Definition: aux_clk.c:371
uint32_t task
Definition: hal_ppi.h:59
void hfclk_xtal_deinit(void)
Function to de-initialize the HF clock from using the crystal. RC oscillator will be used to generate...
Definition: hal_clocks.c:132
void aux_clk_start()
Definition: aux_clk.c:308
void(* callback_handler)(uint8_t events)
Definition: aux_clk.h:149
uint32_t task1
Definition: aux_clk.h:133
void aux_clk_select_src(aux_clk_source_t source)
Function to select the clock source for auxiliary clock module.
Definition: aux_clk.c:264
app_irq_priority_t
Priority levels that the application can use based on whether the SoftDevice (SD) is used.
Definition: nrf_util.h:63
void aux_clk_dis_evt(uint8_t events)
Function to disable one or more events from aux_clk_evt_t.
Definition: aux_clk.c:339
uint32_t event
Definition: aux_clk.h:130
void aux_clk_stop()
Function to stop clock.
Definition: aux_clk.c:314
ppi_setup_status_t hal_ppi_set(hal_ppi_setup_t *setup)
Function to setup a PPI.
Definition: hal_ppi.c:30
void aux_clk_update_irq_priority(app_irq_priority_t new_priority)
Function to change IRQ Priority if needed.
Definition: aux_clk.c:366
aux_clk_source_t
Definition: aux_clk.h:91
void aux_clk_clear()
Function to clear clock counter value.
Definition: aux_clk.c:326
aux_clk_ppi_t arr_ppi_cnf[AUX_CLK_PPI_CHANNELS_USED]
Definition: aux_clk.h:157
void hal_ppi_en_ch(uint32_t ppi_id)
Function to Enable given PPI channel.
Definition: hal_ppi.c:68
uint8_t events_en
Definition: aux_clk.h:155
void aux_clk_update_cc(uint32_t cc_id, uint32_t new_val_ms)
Function to update the given CC value for clock channel.
Definition: aux_clk.c:360
uint32_t arr_cc_ms[AUX_CLK_MAX_CHANNELS]
Definition: aux_clk.h:151
void hfclk_xtal_init_blocking(void)
Function to start the crystal oscillator to be used for HF clock. This function blocks until the crys...
Definition: hal_clocks.c:71
void aux_clk_update_ppi(uint32_t ppi_channel, aux_clk_ppi_t *new_ppi)
Function to Update PPI settings for given ppi channel.
Definition: aux_clk.c:346
uint32_t ppi_id
Definition: hal_ppi.h:55
uint32_t task2
Definition: aux_clk.h:136