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