1 /*
2  * Copyright (c) 2019 - 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_TEMP_ENABLED)
35 
36 #include <nrfx_temp.h>
37 
38 #if !defined(USE_WORKAROUND_FOR_TEMP_OFFSET_ANOMALY) && defined(NRF51)
39 // Enable workaround for nRF51 series anomaly 28
40 // (TEMP: Temperature offset value has to be manually loaded to the TEMP module).
41 #define USE_WORKAROUND_FOR_TEMP_OFFSET_ANOMALY 1
42 #endif
43 
44 /** @brief Time of one check attempt.*/
45 #define NRFX_TEMP_TIME_US 4
46 
47 /** @brief Maximum attempts to check whether conversion passed.*/
48 #define NRFX_TEMP_ATTEMPTS 10
49 
50 /** @brief Internal state of TEMP driver. */
51 static nrfx_drv_state_t m_temp_state;
52 
53 /** @brief Pointer to handler to be called from interrupt routine. */
54 static nrfx_temp_data_handler_t m_data_handler;
55 
nrfx_temp_init(nrfx_temp_config_t const * p_config,nrfx_temp_data_handler_t handler)56 nrfx_err_t nrfx_temp_init(nrfx_temp_config_t const * p_config, nrfx_temp_data_handler_t handler)
57 {
58     NRFX_ASSERT(p_config);
59 
60     if (m_temp_state != NRFX_DRV_STATE_UNINITIALIZED)
61     {
62         return NRFX_ERROR_ALREADY_INITIALIZED;
63     }
64 
65 #if NRFX_CHECK(USE_WORKAROUND_FOR_TEMP_OFFSET_ANOMALY)
66     *(uint32_t volatile *)0x4000C504 = 0;
67 #endif
68 
69     m_data_handler = handler;
70 
71     if (m_data_handler)
72     {
73         nrf_temp_int_enable(NRF_TEMP, NRF_TEMP_INT_DATARDY_MASK);
74         NRFX_IRQ_PRIORITY_SET(TEMP_IRQn, p_config->interrupt_priority);
75         NRFX_IRQ_ENABLE(TEMP_IRQn);
76     }
77 
78     m_temp_state = NRFX_DRV_STATE_INITIALIZED;
79     return NRFX_SUCCESS;
80 }
81 
nrfx_temp_uninit(void)82 void nrfx_temp_uninit(void)
83 {
84     NRFX_ASSERT(m_temp_state == NRFX_DRV_STATE_INITIALIZED);
85     nrf_temp_task_trigger(NRF_TEMP, NRF_TEMP_TASK_STOP);
86 
87     if (m_data_handler)
88     {
89         nrf_temp_int_disable(NRF_TEMP, NRF_TEMP_INT_DATARDY_MASK);
90         NRFX_IRQ_DISABLE(TEMP_IRQn);
91     }
92 
93     m_temp_state = NRFX_DRV_STATE_UNINITIALIZED;
94 }
95 
nrfx_temp_calculate(int32_t raw_measurement)96 int32_t nrfx_temp_calculate(int32_t raw_measurement)
97 {
98     /* Raw temperature is a 2's complement signed value. Moreover, it is represented
99      * by 0.25[C] intervals, so division by 4 is needed. To preserve
100      * fractional part, raw value is multiplied by 100 before division.*/
101 
102     return (raw_measurement * 100) / 4;
103 }
104 
nrfx_temp_measure(void)105 nrfx_err_t nrfx_temp_measure(void)
106 {
107     NRFX_ASSERT(m_temp_state == NRFX_DRV_STATE_INITIALIZED);
108 
109     nrfx_err_t result = NRFX_SUCCESS;
110     nrf_temp_event_clear(NRF_TEMP, NRF_TEMP_EVENT_DATARDY);
111     nrf_temp_task_trigger(NRF_TEMP, NRF_TEMP_TASK_START);
112 
113     if (!m_data_handler)
114     {
115         bool ev_result;
116         NRFX_WAIT_FOR(nrf_temp_event_check(NRF_TEMP, NRF_TEMP_EVENT_DATARDY),
117                       NRFX_TEMP_ATTEMPTS,
118                       NRFX_TEMP_TIME_US,
119                       ev_result);
120         if (!ev_result)
121         {
122             result = NRFX_ERROR_INTERNAL;
123         }
124         else
125         {
126             nrf_temp_event_clear(NRF_TEMP, NRF_TEMP_EVENT_DATARDY);
127         }
128         nrf_temp_task_trigger(NRF_TEMP, NRF_TEMP_TASK_STOP);
129     }
130 
131     return result;
132 }
133 
nrfx_temp_irq_handler(void)134 void nrfx_temp_irq_handler(void)
135 {
136     NRFX_ASSERT(m_data_handler);
137 
138     nrf_temp_task_trigger(NRF_TEMP, NRF_TEMP_TASK_STOP);
139     nrf_temp_event_clear(NRF_TEMP, NRF_TEMP_EVENT_DATARDY);
140 
141     uint32_t raw_temp = nrfx_temp_result_get();
142 
143     m_data_handler(raw_temp);
144 }
145 
146 #endif // NRFX_CHECK(NRFX_TEMP_ENABLED)
147