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 #endif
95 
96   TEMP_hw_started = false;
97   TEMP_INTEN = 0;
98   Timer_TEMP = TIME_NEVER;
99 }
100 
101 NSI_TASK(nhw_temp_init, HW_INIT, 100);
102 
103 /**
104  * TASK_START triggered handler
105  */
nhw_TEMP_TASK_START(void)106 void nhw_TEMP_TASK_START(void) {
107   if (TEMP_hw_started) {
108     return;
109   }
110   TEMP_hw_started = true;
111   Timer_TEMP = nsi_hws_get_time() + NHW_TEMP_t_TEMP;
112   nsi_hws_find_next_event();
113 }
114 
115 /**
116  * TASK_STOP triggered handler
117  */
nhw_TEMP_TASK_STOP(void)118 void nhw_TEMP_TASK_STOP(void) {
119   TEMP_hw_started = false;
120   Timer_TEMP = TIME_NEVER;
121   nsi_hws_find_next_event();
122 }
123 
nhw_TEMP_eval_interrupt(uint inst)124 static void nhw_TEMP_eval_interrupt(uint inst) {
125   static bool temp_int_line[NHW_TEMP_TOTAL_INST]; /* Is the TEMP currently driving its interrupt line high */
126   /* Mapping of peripheral instance to {int controller instance, int number} */
127   static struct nhw_irq_mapping nhw_temp_irq_map[NHW_TEMP_TOTAL_INST] = NHW_TEMP_INT_MAP;
128   bool new_int_line = false;
129 
130   NHW_CHECK_INTERRUPT_si(TEMP, DATARDY, TEMP_INTEN)
131 
132   hw_irq_ctrl_toggle_level_irq_line_if(&temp_int_line[inst],
133                                        new_int_line,
134                                        &nhw_temp_irq_map[inst]);
135 }
136 
137 NHW_SIDEEFFECTS_INTSET_si(TEMP, NRF_TEMP_regs., TEMP_INTEN)
138 NHW_SIDEEFFECTS_INTCLR_si(TEMP, NRF_TEMP_regs., TEMP_INTEN)
139 
NHW_SIDEEFFECTS_EVENTS(TEMP)140 NHW_SIDEEFFECTS_EVENTS(TEMP)
141 
142 NHW_SIDEEFFECTS_TASKS_si(TEMP, START)
143 NHW_SIDEEFFECTS_TASKS_si(TEMP, STOP)
144 
145 #if (NHW_HAS_DPPI)
146 NHW_SIDEEFFECTS_SUBSCRIBE_si(TEMP, START)
147 NHW_SIDEEFFECTS_SUBSCRIBE_si(TEMP, STOP)
148 #endif /* NHW_HAS_DPPI */
149 
150 static NHW_SIGNAL_EVENT_si(TEMP, DATARDY)
151 
152 /**
153  * Time has come when the temperature measurement is ready
154  */
155 static void nhw_temp_timer_triggered(void) {
156 
157   NRF_TEMP_regs.TEMP = temperature*(1 << NHW_TEMP_FBITS) + bs_random_uniformRi(-1,1);
158 
159   TEMP_hw_started = false;
160   Timer_TEMP = TIME_NEVER;
161   nsi_hws_find_next_event();
162 
163   nhw_TEMP_signal_EVENTS_DATARDY(0);
164 }
165 
166 NSI_HW_EVENT(Timer_TEMP, nhw_temp_timer_triggered, 50);
167