1 /*
2 * Copyright (c) 2015 - 2020, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <nrfx.h>
33
34 #if NRFX_CHECK(NRFX_WDT_ENABLED)
35
36 #if !(NRFX_CHECK(NRFX_WDT0_ENABLED) || NRFX_CHECK(NRFX_WDT1_ENABLED))
37 #error "No enabled WDT instances. Check <nrfx_config.h>."
38 #endif
39
40 #include <nrfx_wdt.h>
41
42 #define NRFX_LOG_MODULE WDT
43 #include <nrfx_log.h>
44
45 // Control block - driver instance local data.
46 typedef struct
47 {
48 nrfx_drv_state_t state;
49 uint8_t alloc_index;
50 #if !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
51 nrfx_wdt_event_handler_t wdt_event_handler;
52 #endif
53 } wdt_control_block_t;
54
55 static wdt_control_block_t m_cb[NRFX_WDT_ENABLED_COUNT];
56
nrfx_wdt_init(nrfx_wdt_t const * p_instance,nrfx_wdt_config_t const * p_config,nrfx_wdt_event_handler_t wdt_event_handler)57 nrfx_err_t nrfx_wdt_init(nrfx_wdt_t const * p_instance,
58 nrfx_wdt_config_t const * p_config,
59 nrfx_wdt_event_handler_t wdt_event_handler)
60 {
61 NRFX_ASSERT(p_config);
62 nrfx_err_t err_code;
63
64 wdt_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
65
66 #if NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
67 (void)wdt_event_handler;
68 #else
69 p_cb->wdt_event_handler = wdt_event_handler;
70 #endif
71
72 if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
73 {
74 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
75 }
76 else
77 {
78 err_code = NRFX_ERROR_INVALID_STATE;
79 NRFX_LOG_WARNING("Function: %s, error code: %s.",
80 __func__,
81 NRFX_LOG_ERROR_STRING_GET(err_code));
82 return err_code;
83 }
84
85 nrf_wdt_behaviour_set(p_instance->p_reg, p_config->behaviour);
86
87 uint64_t ticks = (p_config->reload_value * 32768ULL) / 1000;
88 NRFX_ASSERT(ticks <= UINT32_MAX);
89
90 nrf_wdt_reload_value_set(p_instance->p_reg, (uint32_t) ticks);
91
92 #if !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
93 if (wdt_event_handler)
94 {
95 nrf_wdt_int_enable(p_instance->p_reg, NRF_WDT_INT_TIMEOUT_MASK);
96 NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg), p_config->interrupt_priority);
97 NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
98 }
99 #endif
100
101 err_code = NRFX_SUCCESS;
102 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
103 return err_code;
104 }
105
106
nrfx_wdt_enable(nrfx_wdt_t const * p_instance)107 void nrfx_wdt_enable(nrfx_wdt_t const * p_instance)
108 {
109 wdt_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
110 NRFX_ASSERT(p_cb->alloc_index != 0);
111 NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
112 nrf_wdt_task_trigger(p_instance->p_reg, NRF_WDT_TASK_START);
113 p_cb->state = NRFX_DRV_STATE_POWERED_ON;
114 NRFX_LOG_INFO("Enabled.");
115 }
116
117
nrfx_wdt_feed(nrfx_wdt_t const * p_instance)118 void nrfx_wdt_feed(nrfx_wdt_t const * p_instance)
119 {
120 wdt_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
121 NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_POWERED_ON);
122 for (uint8_t i = 0; i < p_cb->alloc_index; i++)
123 {
124 nrf_wdt_reload_request_set(p_instance->p_reg, (nrf_wdt_rr_register_t)(NRF_WDT_RR0 + i));
125 }
126 }
127
nrfx_wdt_channel_alloc(nrfx_wdt_t const * p_instance,nrfx_wdt_channel_id * p_channel_id)128 nrfx_err_t nrfx_wdt_channel_alloc(nrfx_wdt_t const * p_instance, nrfx_wdt_channel_id * p_channel_id)
129 {
130 nrfx_err_t result;
131 wdt_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
132
133 NRFX_ASSERT(p_channel_id);
134 NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
135
136 NRFX_CRITICAL_SECTION_ENTER();
137 if (p_cb->alloc_index < NRF_WDT_CHANNEL_NUMBER)
138 {
139 *p_channel_id = (nrfx_wdt_channel_id)(NRF_WDT_RR0 + p_cb->alloc_index);
140 p_cb->alloc_index++;
141 nrf_wdt_reload_request_enable(p_instance->p_reg, *p_channel_id);
142 result = NRFX_SUCCESS;
143 }
144 else
145 {
146 result = NRFX_ERROR_NO_MEM;
147 }
148 NRFX_CRITICAL_SECTION_EXIT();
149 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(result));
150 return result;
151 }
152
nrfx_wdt_channel_feed(nrfx_wdt_t const * p_instance,nrfx_wdt_channel_id channel_id)153 void nrfx_wdt_channel_feed(nrfx_wdt_t const * p_instance, nrfx_wdt_channel_id channel_id)
154 {
155 NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_POWERED_ON);
156 nrf_wdt_reload_request_set(p_instance->p_reg, channel_id);
157 }
158
159 #if NRFX_CHECK(NRFX_WDT0_ENABLED) && !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
nrfx_wdt_0_irq_handler(void)160 void nrfx_wdt_0_irq_handler(void)
161 {
162 if (nrf_wdt_event_check(NRF_WDT0, NRF_WDT_EVENT_TIMEOUT))
163 {
164 m_cb[NRFX_WDT0_INST_IDX].wdt_event_handler();
165 nrf_wdt_event_clear(NRF_WDT0, NRF_WDT_EVENT_TIMEOUT);
166 }
167 }
168 #endif
169
170 #if NRFX_CHECK(NRFX_WDT1_ENABLED) && !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
nrfx_wdt_1_irq_handler(void)171 void nrfx_wdt_1_irq_handler(void)
172 {
173 if (nrf_wdt_event_check(NRF_WDT1, NRF_WDT_EVENT_TIMEOUT))
174 {
175 m_cb[NRFX_WDT1_INST_IDX].wdt_event_handler();
176 nrf_wdt_event_clear(NRF_WDT1, NRF_WDT_EVENT_TIMEOUT);
177 }
178 }
179 #endif
180
181 #endif // NRFX_CHECK(NRFX_WDT_ENABLED)
182