1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * TEMP - Temperature sensor
9  * https://infocenter.nordicsemi.com/topic/ps_nrf52833/temp.html?cp=4_1_0_5_25
10  *
11  * A very simple and rough model
12  *
13  * Notes:
14  *   * At this point the device is always at 25 C
15  *   * The measurement result will just be 25 +- 0.25 C
16  *   * There is no per device variability
17  *   * There is no modeling of possible calibration errors or inaccuracies due to no non-linearities compensation
18  */
19 
20 #include <string.h>
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include "bs_rand_main.h"
24 #include "nsi_tasks.h"
25 #include "nsi_hws_models_if.h"
26 #include "nsi_hw_scheduler.h"
27 #include "NHW_common_types.h"
28 #include "NHW_config.h"
29 #include "NHW_templates.h"
30 #include "NHW_TEMP.h"
31 #include "NHW_peri_types.h"
32 #include "NHW_xPPI.h"
33 #include "irq_ctrl.h"
34 
35 #if NHW_TEMP_TOTAL_INST > 1
36 #error "This model only supports 1 instance so far"
37 #endif
38 
39 NRF_TEMP_Type NRF_TEMP_regs;
40 
41 #if (NHW_HAS_DPPI)
42 /* Mapping of peripheral instance to DPPI instance */
43 static uint nhw_TEMP_dppi_map[NHW_TEMP_TOTAL_INST] = NHW_TEMP_DPPI_MAP;
44 #endif
45 
46 static bs_time_t Timer_TEMP = TIME_NEVER; //Time when the next temperature measurement will be ready
47 
48 static bool TEMP_hw_started;
49 static uint32_t TEMP_INTEN; //interrupt enable
50 
51 static double temperature = 25.0; /* Actual temperature the device is at */
52 
53 /**
54  * Initialize the TEMP model
55  */
nhw_temp_init(void)56 static void nhw_temp_init(void) {
57   memset(&NRF_TEMP_regs, 0, sizeof(NRF_TEMP_regs));
58 #if defined(NRF52833)
59   NRF_TEMP_regs.A0 = 0x00000326;
60   NRF_TEMP_regs.A1 = 0x00000348;
61   NRF_TEMP_regs.A2 = 0x000003AA;
62   NRF_TEMP_regs.A3 = 0x0000040E;
63   NRF_TEMP_regs.A4 = 0x000004BD;
64   NRF_TEMP_regs.A5 = 0x000005A3;
65   NRF_TEMP_regs.B0 = 0x00003FEF;
66   NRF_TEMP_regs.B1 = 0x00003FBE;
67   NRF_TEMP_regs.B2 = 0x00003FBE;
68   NRF_TEMP_regs.B3 = 0x00000012;
69   NRF_TEMP_regs.B4 = 0x00000124;
70   NRF_TEMP_regs.B5 = 0x0000027C;
71   NRF_TEMP_regs.T0 = 0x000000E2;
72   NRF_TEMP_regs.T1 = 0x00000000;
73   NRF_TEMP_regs.T2 = 0x00000019;
74   NRF_TEMP_regs.T3 = 0x0000003C;
75   NRF_TEMP_regs.T4 = 0x00000050;
76 #elif defined(NRF5340)
77   NRF_TEMP_regs.A0 = 0x000002D9;
78   NRF_TEMP_regs.A1 = 0x00000322;
79   NRF_TEMP_regs.A2 = 0x00000355;
80   NRF_TEMP_regs.A3 = 0x000003DF;
81   NRF_TEMP_regs.A4 = 0x0000044E;
82   NRF_TEMP_regs.A5 = 0x000004B7;
83   NRF_TEMP_regs.B0 = 0x00000FC7;
84   NRF_TEMP_regs.B1 = 0x00000F71;
85   NRF_TEMP_regs.B2 = 0x00000F6C;
86   NRF_TEMP_regs.B3 = 0x00000FCB;
87   NRF_TEMP_regs.B4 = 0x0000004B;
88   NRF_TEMP_regs.B5 = 0x000000F6;
89   NRF_TEMP_regs.T0 = 0x000000E1;
90   NRF_TEMP_regs.T1 = 0x000000F9;
91   NRF_TEMP_regs.T2 = 0x00000010;
92   NRF_TEMP_regs.T3 = 0x00000026;
93   NRF_TEMP_regs.T4 = 0x0000003F;
94 #elif defined(NRF54L15)
95   NRF_TEMP_regs.A0 = 0x000002D6;
96   NRF_TEMP_regs.A1 = 0x0000032D;
97   NRF_TEMP_regs.A2 = 0x00000384;
98   NRF_TEMP_regs.A3 = 0x000003E9;
99   NRF_TEMP_regs.A4 = 0x0000046F;
100   NRF_TEMP_regs.A5 = 0x00000522;
101   NRF_TEMP_regs.A6 = 0x000005B7;
102   NRF_TEMP_regs.B0 = 0x00000FD6;
103   NRF_TEMP_regs.B1 = 0x00000F76;
104   NRF_TEMP_regs.B2 = 0x00000F8A;
105   NRF_TEMP_regs.B3 = 0x00000FF8;
106   NRF_TEMP_regs.B4 = 0x000000CC;
107   NRF_TEMP_regs.B5 = 0x00000207;
108   NRF_TEMP_regs.B6 = 0x00000558;
109   NRF_TEMP_regs.T0 = 0x000000E2;
110   NRF_TEMP_regs.T1 = 0x00000002;
111   NRF_TEMP_regs.T2 = 0x0000001F;
112   NRF_TEMP_regs.T3 = 0x00000038;
113   NRF_TEMP_regs.T4 = 0x0000004F;
114   NRF_TEMP_regs.T5 = 0x00000066;
115 #endif
116 
117   TEMP_hw_started = false;
118   TEMP_INTEN = 0;
119   Timer_TEMP = TIME_NEVER;
120 }
121 
122 NSI_TASK(nhw_temp_init, HW_INIT, 100);
123 
124 /**
125  * TASK_START triggered handler
126  */
nhw_TEMP_TASK_START(void)127 void nhw_TEMP_TASK_START(void) {
128   if (TEMP_hw_started) {
129     return;
130   }
131   TEMP_hw_started = true;
132   Timer_TEMP = nsi_hws_get_time() + NHW_TEMP_t_TEMP;
133   nsi_hws_find_next_event();
134 }
135 
136 /**
137  * TASK_STOP triggered handler
138  */
nhw_TEMP_TASK_STOP(void)139 void nhw_TEMP_TASK_STOP(void) {
140   TEMP_hw_started = false;
141   Timer_TEMP = TIME_NEVER;
142   nsi_hws_find_next_event();
143 }
144 
nhw_TEMP_eval_interrupt(uint inst)145 static void nhw_TEMP_eval_interrupt(uint inst) {
146   static bool temp_int_line[NHW_TEMP_TOTAL_INST]; /* Is the TEMP currently driving its interrupt line high */
147   /* Mapping of peripheral instance to {int controller instance, int number} */
148   static struct nhw_irq_mapping nhw_temp_irq_map[NHW_TEMP_TOTAL_INST] = NHW_TEMP_INT_MAP;
149   bool new_int_line = false;
150 
151   NHW_CHECK_INTERRUPT_si(TEMP, DATARDY, TEMP_INTEN)
152 
153   hw_irq_ctrl_toggle_level_irq_line_if(&temp_int_line[inst],
154                                        new_int_line,
155                                        &nhw_temp_irq_map[inst]);
156 }
157 
158 NHW_SIDEEFFECTS_INTSET_si(TEMP, NRF_TEMP_regs., TEMP_INTEN)
159 NHW_SIDEEFFECTS_INTCLR_si(TEMP, NRF_TEMP_regs., TEMP_INTEN)
160 
NHW_SIDEEFFECTS_EVENTS(TEMP)161 NHW_SIDEEFFECTS_EVENTS(TEMP)
162 
163 NHW_SIDEEFFECTS_TASKS_si(TEMP, START)
164 NHW_SIDEEFFECTS_TASKS_si(TEMP, STOP)
165 
166 #if (NHW_HAS_DPPI)
167 NHW_SIDEEFFECTS_SUBSCRIBE_si(TEMP, START)
168 NHW_SIDEEFFECTS_SUBSCRIBE_si(TEMP, STOP)
169 #endif /* NHW_HAS_DPPI */
170 
171 static NHW_SIGNAL_EVENT_si(TEMP, DATARDY)
172 
173 /**
174  * Time has come when the temperature measurement is ready
175  */
176 static void nhw_temp_timer_triggered(void) {
177 
178   NRF_TEMP_regs.TEMP = temperature*(1 << NHW_TEMP_FBITS) + bs_random_uniformRi(-1,1);
179 
180   TEMP_hw_started = false;
181   Timer_TEMP = TIME_NEVER;
182   nsi_hws_find_next_event();
183 
184   nhw_TEMP_signal_EVENTS_DATARDY(0);
185 }
186 
187 NSI_HW_EVENT(Timer_TEMP, nhw_temp_timer_triggered, 50);
188