Skip to content

Commit 6e88c94

Browse files
fimohamejhedberg
authored andcommitted
wiseconnect: Sleeptimer SDK files
Origin: Silicon Labs WiseConnect SDK License: Zlib URL: https://github.com/siliconlabs/wiseconnect Commit: 68e44ea22070bb0e594b9974047aed687538aca7 Version: v3.4.0-cf Purpose: Add Sleeptimer support for SiWx917 Signed-off-by: S Mohamed Fiaz <[email protected]>
1 parent cb17629 commit 6e88c94

File tree

1 file changed

+326
-0
lines changed

1 file changed

+326
-0
lines changed
Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
/*******************************************************************************
2+
* @file
3+
* @brief SLEEPTIMER hardware abstraction implementation for Si91x SYSRTC.
4+
*******************************************************************************
5+
* # License
6+
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
7+
*******************************************************************************
8+
*
9+
* SPDX-License-Identifier: Zlib
10+
*
11+
* The licensor of this software is Silicon Laboratories Inc.
12+
*
13+
* This software is provided 'as-is', without any express or implied
14+
* warranty. In no event will the authors be held liable for any damages
15+
* arising from the use of this software.
16+
*
17+
* Permission is granted to anyone to use this software for any purpose,
18+
* including commercial applications, and to alter it and redistribute it
19+
* freely, subject to the following restrictions:
20+
*
21+
* 1. The origin of this software must not be misrepresented; you must not
22+
* claim that you wrote the original software. If you use this software
23+
* in a product, an acknowledgment in the product documentation would be
24+
* appreciated but is not required.
25+
* 2. Altered source versions must be plainly marked as such, and must not be
26+
* misrepresented as being the original software.
27+
* 3. This notice may not be removed or altered from any source distribution.
28+
*
29+
******************************************************************************/
30+
#include "sl_sleeptimer.h"
31+
#include "sli_sleeptimer_hal.h"
32+
#include "sl_core.h"
33+
#include "rsi_sysrtc.h"
34+
#include "rsi_sysrtc_headers.h"
35+
#include "si91x_device.h"
36+
37+
#if (SL_SLEEPTIMER_PERIPHERAL != SL_SLEEPTIMER_PERIPHERAL_DEFAULT)
38+
#error "Peripheral not supported for Si91x"
39+
#endif
40+
#if (SL_SLEEPTIMER_WALLCLOCK_CONFIG == 1)
41+
#error "Wall clock feature not present"
42+
#endif
43+
// Minimum difference between current count value and what the comparator of the timer can be set to.
44+
// 1 tick is added to the minimum diff for the algorithm of compensation for the IRQ handler that
45+
// triggers when CNT == compare_value + 1. For more details refer to sleeptimer_hal_set_compare() function's header.
46+
#define SLEEPTIMER_COMPARE_MIN_DIFF (2 + 2)
47+
48+
#define SLEEPTIMER_TMR_WIDTH (_SYSRTC_CNT_MASK)
49+
50+
// Minimum difference between compare value and counter value, which requires compensation.
51+
#define MINIMUM_DIFF_FOR_COMPENSATION 4
52+
53+
#define SLEEPTIMER_SI91X_INTERRUPT_HANDLER IRQ022_Handler
54+
55+
#define SYSRTC_GROUP0 0u
56+
57+
#define SYSRTC_CHANNEL0 0u
58+
#define SYSRTC_IRQ_PRIORITY 6
59+
60+
static bool cc_disabled = true;
61+
uint32_t sleeptimer_hal_get_capture(void);
62+
void sleeptimer_hal_reset_prs_signal(void);
63+
/*******************************************************************************
64+
* Computes difference between two times taking into account timer wrap-around.
65+
*
66+
* @param a Time.
67+
* @param b Time to substract from a.
68+
*
69+
* @return Time difference.
70+
******************************************************************************/
71+
__STATIC_INLINE uint32_t get_time_diff(uint32_t a, uint32_t b)
72+
{
73+
return (a - b);
74+
}
75+
76+
/*******************************************************************************
77+
* Initializes Si91x SYSRTC sleep timer.
78+
******************************************************************************/
79+
void sleeptimer_hal_init_timer(void)
80+
{
81+
rsi_sysrtc_config_t sysrtc_config = SYSRTC_CONFIG_DEFAULT;
82+
rsi_sysrtc_group_config_t group_config = SYSRTC_GROUP_CONFIG_DEFAULT;
83+
const rsi_sysrtc_group_channel_compare_config_t group_compare_channel_config =
84+
SYSRTC_GROUP_CHANNEL_COMPARE_CONFIG_DEFAULT_REGMODE;
85+
86+
// Enable 32kHz XTAL clock to SYSRTC peripheral
87+
rsi_sysrtc_clk_set(RSI_SYSRTC_CLK_32kHz_Xtal, 0u);
88+
89+
// Initialize SYSRTC module
90+
rsi_sysrtc_init(&sysrtc_config);
91+
92+
group_config.compare_channel0_enable = false;
93+
group_config.p_compare_channel0_config = &group_compare_channel_config;
94+
// Initialize SYSRTC group 0 for sleeptimer service
95+
rsi_sysrtc_init_group(SYSRTC_GROUP0, &group_config);
96+
97+
// Disable & clear group 0 interrupts
98+
rsi_sysrtc_disable_group_interrupts(SYSRTC_GROUP0, _SYSRTC_GRP0_IEN_MASK);
99+
rsi_sysrtc_clear_group_interrupts(SYSRTC_GROUP0, _SYSRTC_GRP0_IF_MASK);
100+
// Enable SYSRTC module
101+
rsi_sysrtc_enable();
102+
// Initialize counter to 0
103+
rsi_sysrtc_set_counter(0u);
104+
105+
// Enable interrupts from SYSRTC module
106+
RSI_NpssIntrUnMask(NPSS_TO_MCU_SYSRTC_INTR);
107+
NVIC_EnableIRQ(NPSS_TO_MCU_SYRTC_INTR_IRQn);
108+
#ifdef SLI_SI91X_ENABLE_OS
109+
//Giving higher priority to SYSRTC to service wakeup
110+
NVIC_SetPriority(NPSS_TO_MCU_SYRTC_INTR_IRQn, SYSRTC_IRQ_PRIORITY);
111+
#endif
112+
// Start SYSRTC module
113+
rsi_sysrtc_start();
114+
}
115+
116+
/*******************************************************************************
117+
* Gets SYSRTC counter value.
118+
******************************************************************************/
119+
uint32_t sleeptimer_hal_get_counter(void)
120+
{
121+
return rsi_sysrtc_get_counter();
122+
}
123+
124+
/*******************************************************************************
125+
* Gets SYSRTC compare value.
126+
******************************************************************************/
127+
uint32_t sleeptimer_hal_get_compare(void)
128+
{
129+
return rsi_sysrtc_get_group_compare_channel_value(SYSRTC_GROUP0, SYSRTC_CHANNEL0);
130+
}
131+
132+
/*******************************************************************************
133+
* Sets SYSRTC group 0 compare0 value.
134+
*
135+
* @note Compare match value is set to the requested value - 1. This is done
136+
* to compensate for the fact that the SYSRTC compare match interrupt always
137+
* triggers at the end of the requested ticks and that the IRQ handler is
138+
* executed when current tick count == compare_value + 1.
139+
******************************************************************************/
140+
void sleeptimer_hal_set_compare(uint32_t value)
141+
{
142+
CORE_DECLARE_IRQ_STATE;
143+
uint32_t counter;
144+
uint32_t compare;
145+
uint32_t compare_value = value;
146+
int32_t diff;
147+
148+
CORE_ENTER_CRITICAL();
149+
150+
// Read the current compare and counter register value
151+
counter = sleeptimer_hal_get_counter();
152+
compare = sleeptimer_hal_get_compare();
153+
154+
if (((rsi_sysrtc_get_group_interrupts(SYSRTC_GROUP0) & SYSRTC_GRP0_IEN_CMP0) != 0)
155+
|| (get_time_diff(compare, counter) > SLEEPTIMER_COMPARE_MIN_DIFF) || compare == counter) {
156+
compare_value %= SLEEPTIMER_TMR_WIDTH;
157+
// Sometimes for smaller tick values compare value is not set properly because by the time
158+
// compare value is set, current counter value is exceeding the expected compare value. To compensate
159+
// this, extra ticks are added just to generate the interrupt.
160+
diff = (int32_t)(compare_value - sleeptimer_hal_get_counter());
161+
if ((diff <= MINIMUM_DIFF_FOR_COMPENSATION) && (diff > -MINIMUM_DIFF_FOR_COMPENSATION)) {
162+
compare_value += (uint32_t)((MINIMUM_DIFF_FOR_COMPENSATION - 1) - diff);
163+
}
164+
// Set the compare value for next timeout
165+
rsi_sysrtc_set_compare_value(SYSRTC_GROUP0, SYSRTC_CHANNEL0, compare_value - 1);
166+
sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_COMP);
167+
rsi_sysrtc_enable_interrupts();
168+
}
169+
CORE_EXIT_CRITICAL();
170+
// If compare interrupt is disabled previously, enable here
171+
if (cc_disabled) {
172+
SYSRTC0->GRP0_CTRL |= SYSRTC_GRP0_CTRL_CMP0EN;
173+
cc_disabled = false;
174+
}
175+
}
176+
177+
/*******************************************************************************
178+
* Enables SYSRTC interrupts.
179+
******************************************************************************/
180+
void sleeptimer_hal_enable_int(uint8_t local_flag)
181+
{
182+
uint32_t sysrtc_ien = 0u;
183+
184+
if (local_flag & SLEEPTIMER_EVENT_OF) {
185+
// Set overflow interrupt
186+
sysrtc_ien |= SYSRTC_GRP0_IEN_OVF;
187+
}
188+
189+
if (local_flag & SLEEPTIMER_EVENT_COMP) {
190+
// Set compare interrupt
191+
sysrtc_ien |= SYSRTC_GRP0_IEN_CMP0;
192+
}
193+
194+
rsi_sysrtc_enable_group_interrupts(SYSRTC_GROUP0, sysrtc_ien);
195+
}
196+
197+
/*******************************************************************************
198+
* Disables SYSRTC interrupts.
199+
******************************************************************************/
200+
void sleeptimer_hal_disable_int(uint8_t local_flag)
201+
{
202+
uint32_t sysrtc_int_dis = 0u;
203+
204+
if (local_flag & SLEEPTIMER_EVENT_OF) {
205+
// Disable overflow interrupt
206+
sysrtc_int_dis |= SYSRTC_GRP0_IEN_OVF;
207+
}
208+
209+
if (local_flag & SLEEPTIMER_EVENT_COMP) {
210+
// Disable compare interrupt
211+
sysrtc_int_dis |= SYSRTC_GRP0_IEN_CMP0;
212+
213+
cc_disabled = true;
214+
SYSRTC0->GRP0_CTRL &= ~_SYSRTC_GRP0_CTRL_CMP0EN_MASK;
215+
}
216+
217+
rsi_sysrtc_disable_group_interrupts(SYSRTC_GROUP0, sysrtc_int_dis);
218+
}
219+
220+
/*******************************************************************************
221+
* Hardware Abstraction Layer to set timer interrupts.
222+
******************************************************************************/
223+
void sleeptimer_hal_set_int(uint8_t local_flag)
224+
{
225+
if (local_flag & SLEEPTIMER_EVENT_COMP) {
226+
SYSRTC0->GRP0_IF_SET = SYSRTC_GRP0_IF_CMP0;
227+
}
228+
}
229+
230+
/*******************************************************************************
231+
* Gets status of specified interrupt.
232+
*
233+
* Note: This function must be called with interrupts disabled.
234+
******************************************************************************/
235+
bool sli_sleeptimer_hal_is_int_status_set(uint8_t local_flag)
236+
{
237+
bool int_is_set = false;
238+
// As per initial testing of SYSRTC peripheral in Si91x B0, interrupt needs to be
239+
// disabled to get the status of group interrupts.
240+
rsi_sysrtc_disable_interrupts();
241+
uint32_t irq_flag = rsi_sysrtc_get_group_interrupts(SYSRTC_GROUP0);
242+
243+
switch (local_flag) {
244+
case SLEEPTIMER_EVENT_COMP:
245+
// Update compare interrupt status
246+
int_is_set = ((irq_flag & SYSRTC_GRP0_IF_CMP0) == SYSRTC_GRP0_IF_CMP0);
247+
break;
248+
249+
case SLEEPTIMER_EVENT_OF:
250+
// update overflow interrupt status
251+
int_is_set = ((irq_flag & SYSRTC_GRP0_IF_OVF) == SYSRTC_GRP0_IF_OVF);
252+
break;
253+
254+
default:
255+
break;
256+
}
257+
// Enable back interrupts
258+
rsi_sysrtc_enable_interrupts();
259+
260+
return int_is_set;
261+
}
262+
263+
/*******************************************************************************
264+
* Si91x SYSRTC interrupt handler for sleeptimer service.
265+
******************************************************************************/
266+
void SLEEPTIMER_SI91X_INTERRUPT_HANDLER(void)
267+
{
268+
CORE_DECLARE_IRQ_STATE;
269+
uint8_t local_flag = 0;
270+
uint32_t irq_flag;
271+
272+
// As per initial testing of SYSRTC peripheral in Si91x B0, interrupt needs to be
273+
// disabled to get the status of group interrupts.
274+
rsi_sysrtc_disable_interrupts();
275+
CORE_ENTER_ATOMIC();
276+
// Get the type of interrupt
277+
irq_flag = rsi_sysrtc_get_group_interrupts(SYSRTC_GROUP0);
278+
279+
if (irq_flag & SYSRTC_GRP0_IF_OVF) {
280+
// Set overflow event
281+
local_flag |= SLEEPTIMER_EVENT_OF;
282+
}
283+
284+
if (irq_flag & SYSRTC_GRP0_IF_CMP0) {
285+
// Set compare event
286+
local_flag |= SLEEPTIMER_EVENT_COMP;
287+
}
288+
// clear interrupt
289+
rsi_sysrtc_clear_group_interrupts(SYSRTC_GROUP0, irq_flag & (SYSRTC_GRP0_IF_OVF | SYSRTC_GRP0_IF_CMP0));
290+
// Process the interrupt and executes callback functions
291+
process_timer_irq(local_flag);
292+
CORE_EXIT_ATOMIC();
293+
rsi_sysrtc_enable_interrupts();
294+
}
295+
296+
/*******************************************************************************
297+
* Gets SYSRTC timer frequency.
298+
******************************************************************************/
299+
uint32_t sleeptimer_hal_get_timer_frequency(void)
300+
{
301+
// There is currently no call for in Si91x library to obtain peripheral frequency of SYSRTC.
302+
return DEFAULT_32KHZ_XTAL_CLOCK;
303+
}
304+
305+
/*******************************************************************************
306+
* This feature is not used in Si91x.
307+
******************************************************************************/
308+
uint16_t sleeptimer_hal_get_clock_accuracy(void)
309+
{
310+
return 0;
311+
}
312+
313+
/*******************************************************************************
314+
* This feature is not used in Si91x.
315+
******************************************************************************/
316+
uint32_t sleeptimer_hal_get_capture(void)
317+
{
318+
return 0;
319+
}
320+
321+
/*******************************************************************************
322+
* This feature is not used in Si91x.
323+
******************************************************************************/
324+
void sleeptimer_hal_reset_prs_signal(void)
325+
{
326+
}

0 commit comments

Comments
 (0)