ESPHome 2025.12.0-dev
Loading...
Searching...
No Matches
debug_zephyr.cpp
Go to the documentation of this file.
1#include "debug_component.h"
2#ifdef USE_ZEPHYR
3#include <climits>
4#include "esphome/core/log.h"
5#include <zephyr/drivers/hwinfo.h>
6#include <hal/nrf_power.h>
7#include <cstdint>
8#include <zephyr/storage/flash_map.h>
9
10#define BOOTLOADER_VERSION_REGISTER NRF_TIMER2->CC[0]
11
12namespace esphome::debug {
13
14static const char *const TAG = "debug";
15constexpr std::uintptr_t MBR_PARAM_PAGE_ADDR = 0xFFC;
16constexpr std::uintptr_t MBR_BOOTLOADER_ADDR = 0xFF8;
17
18static void show_reset_reason(std::string &reset_reason, bool set, const char *reason) {
19 if (!set) {
20 return;
21 }
22 if (!reset_reason.empty()) {
23 reset_reason += ", ";
24 }
25 reset_reason += reason;
26}
27
28static inline uint32_t read_mem_u32(uintptr_t addr) {
29 return *reinterpret_cast<volatile uint32_t *>(addr); // NOLINT(performance-no-int-to-ptr)
30}
31
32static inline uint8_t read_mem_u8(uintptr_t addr) {
33 return *reinterpret_cast<volatile uint8_t *>(addr); // NOLINT(performance-no-int-to-ptr)
34}
35
36// defines from https://github.com/adafruit/Adafruit_nRF52_Bootloader which prints those information
37constexpr uint32_t SD_MAGIC_NUMBER = 0x51B1E5DB;
38constexpr uintptr_t MBR_SIZE = 0x1000;
39constexpr uintptr_t SOFTDEVICE_INFO_STRUCT_OFFSET = 0x2000;
40constexpr uintptr_t SD_ID_OFFSET = SOFTDEVICE_INFO_STRUCT_OFFSET + 0x10;
42
43static inline bool is_sd_present() {
44 return read_mem_u32(SOFTDEVICE_INFO_STRUCT_OFFSET + MBR_SIZE + 4) == SD_MAGIC_NUMBER;
45}
46static inline uint32_t sd_id_get() {
48 return read_mem_u32(MBR_SIZE + SD_ID_OFFSET);
49 }
50 return 0;
51}
52static inline uint32_t sd_version_get() {
54 return read_mem_u32(MBR_SIZE + SD_VERSION_OFFSET);
55 }
56 return 0;
57}
58
60 uint32_t cause;
61 auto ret = hwinfo_get_reset_cause(&cause);
62 if (ret) {
63 ESP_LOGE(TAG, "Unable to get reset cause: %d", ret);
64 return "";
65 }
66 std::string reset_reason;
67
68 show_reset_reason(reset_reason, cause & RESET_PIN, "External pin");
69 show_reset_reason(reset_reason, cause & RESET_SOFTWARE, "Software reset");
70 show_reset_reason(reset_reason, cause & RESET_BROWNOUT, "Brownout (drop in voltage)");
71 show_reset_reason(reset_reason, cause & RESET_POR, "Power-on reset (POR)");
72 show_reset_reason(reset_reason, cause & RESET_WATCHDOG, "Watchdog timer expiration");
73 show_reset_reason(reset_reason, cause & RESET_DEBUG, "Debug event");
74 show_reset_reason(reset_reason, cause & RESET_SECURITY, "Security violation");
75 show_reset_reason(reset_reason, cause & RESET_LOW_POWER_WAKE, "Waking up from low power mode");
76 show_reset_reason(reset_reason, cause & RESET_CPU_LOCKUP, "CPU lock-up detected");
77 show_reset_reason(reset_reason, cause & RESET_PARITY, "Parity error");
78 show_reset_reason(reset_reason, cause & RESET_PLL, "PLL error");
79 show_reset_reason(reset_reason, cause & RESET_CLOCK, "Clock error");
80 show_reset_reason(reset_reason, cause & RESET_HARDWARE, "Hardware reset");
81 show_reset_reason(reset_reason, cause & RESET_USER, "User reset");
82 show_reset_reason(reset_reason, cause & RESET_TEMPERATURE, "Temperature reset");
83
84 ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
85 return reset_reason;
86}
87
88uint32_t DebugComponent::get_free_heap_() { return INT_MAX; }
89
90static void fa_cb(const struct flash_area *fa, void *user_data) {
91#if CONFIG_FLASH_MAP_LABELS
92 const char *fa_label = flash_area_label(fa);
93
94 if (fa_label == nullptr) {
95 fa_label = "-";
96 }
97 ESP_LOGCONFIG(TAG, "%2d 0x%0*" PRIxPTR " %-26s %-24.24s 0x%-10x 0x%-12x", (int) fa->fa_id,
98 sizeof(uintptr_t) * 2, (uintptr_t) fa->fa_dev, fa->fa_dev->name, fa_label, (uint32_t) fa->fa_off,
99 fa->fa_size);
100#else
101 ESP_LOGCONFIG(TAG, "%2d 0x%0*" PRIxPTR " %-26s 0x%-10x 0x%-12x", (int) fa->fa_id, sizeof(uintptr_t) * 2,
102 (uintptr_t) fa->fa_dev, fa->fa_dev->name, (uint32_t) fa->fa_off, fa->fa_size);
103#endif
104}
105
107#if CONFIG_FLASH_MAP_LABELS
108 ESP_LOGCONFIG(TAG, "ID | Device | Device Name "
109 "| Label | Offset | Size");
110 ESP_LOGCONFIG(TAG, "--------------------------------------------"
111 "-----------------------------------------------");
112#else
113 ESP_LOGCONFIG(TAG, "ID | Device | Device Name "
114 "| Offset | Size");
115 ESP_LOGCONFIG(TAG, "-----------------------------------------"
116 "------------------------------");
117#endif
118 flash_area_foreach(fa_cb, nullptr);
119}
120
121void DebugComponent::get_device_info_(std::string &device_info) {
122 std::string supply = "Main supply status: ";
123 if (nrf_power_mainregstatus_get(NRF_POWER) == NRF_POWER_MAINREGSTATUS_NORMAL) {
124 supply += "Normal voltage.";
125 } else {
126 supply += "High voltage.";
127 }
128 ESP_LOGD(TAG, "%s", supply.c_str());
129 device_info += "|" + supply;
130
131 std::string reg0 = "Regulator stage 0: ";
132 if (nrf_power_mainregstatus_get(NRF_POWER) == NRF_POWER_MAINREGSTATUS_HIGH) {
133 reg0 += nrf_power_dcdcen_vddh_get(NRF_POWER) ? "DC/DC" : "LDO";
134 reg0 += ", ";
135 switch (NRF_UICR->REGOUT0 & UICR_REGOUT0_VOUT_Msk) {
136 case (UICR_REGOUT0_VOUT_DEFAULT << UICR_REGOUT0_VOUT_Pos):
137 reg0 += "1.8V (default)";
138 break;
139 case (UICR_REGOUT0_VOUT_1V8 << UICR_REGOUT0_VOUT_Pos):
140 reg0 += "1.8V";
141 break;
142 case (UICR_REGOUT0_VOUT_2V1 << UICR_REGOUT0_VOUT_Pos):
143 reg0 += "2.1V";
144 break;
145 case (UICR_REGOUT0_VOUT_2V4 << UICR_REGOUT0_VOUT_Pos):
146 reg0 += "2.4V";
147 break;
148 case (UICR_REGOUT0_VOUT_2V7 << UICR_REGOUT0_VOUT_Pos):
149 reg0 += "2.7V";
150 break;
151 case (UICR_REGOUT0_VOUT_3V0 << UICR_REGOUT0_VOUT_Pos):
152 reg0 += "3.0V";
153 break;
154 case (UICR_REGOUT0_VOUT_3V3 << UICR_REGOUT0_VOUT_Pos):
155 reg0 += "3.3V";
156 break;
157 default:
158 reg0 += "???V";
159 }
160 } else {
161 reg0 += "disabled";
162 }
163 ESP_LOGD(TAG, "%s", reg0.c_str());
164 device_info += "|" + reg0;
165
166 std::string reg1 = "Regulator stage 1: ";
167 reg1 += nrf_power_dcdcen_get(NRF_POWER) ? "DC/DC" : "LDO";
168 ESP_LOGD(TAG, "%s", reg1.c_str());
169 device_info += "|" + reg1;
170
171 std::string usb_power = "USB power state: ";
172 if (nrf_power_usbregstatus_vbusdet_get(NRF_POWER)) {
173 if (nrf_power_usbregstatus_outrdy_get(NRF_POWER)) {
175 usb_power += "ready";
176 } else {
178 usb_power += "connected (regulator is not ready)";
179 }
180 } else {
182 usb_power += "disconected";
183 }
184 ESP_LOGD(TAG, "%s", usb_power.c_str());
185 device_info += "|" + usb_power;
186
187 bool enabled;
188 nrf_power_pof_thr_t pof_thr;
189
190 pof_thr = nrf_power_pofcon_get(NRF_POWER, &enabled);
191 std::string pof = "Power-fail comparator: ";
192 if (enabled) {
193 switch (pof_thr) {
194 case POWER_POFCON_THRESHOLD_V17:
195 pof += "1.7V";
196 break;
197 case POWER_POFCON_THRESHOLD_V18:
198 pof += "1.8V";
199 break;
200 case POWER_POFCON_THRESHOLD_V19:
201 pof += "1.9V";
202 break;
203 case POWER_POFCON_THRESHOLD_V20:
204 pof += "2.0V";
205 break;
206 case POWER_POFCON_THRESHOLD_V21:
207 pof += "2.1V";
208 break;
209 case POWER_POFCON_THRESHOLD_V22:
210 pof += "2.2V";
211 break;
212 case POWER_POFCON_THRESHOLD_V23:
213 pof += "2.3V";
214 break;
215 case POWER_POFCON_THRESHOLD_V24:
216 pof += "2.4V";
217 break;
218 case POWER_POFCON_THRESHOLD_V25:
219 pof += "2.5V";
220 break;
221 case POWER_POFCON_THRESHOLD_V26:
222 pof += "2.6V";
223 break;
224 case POWER_POFCON_THRESHOLD_V27:
225 pof += "2.7V";
226 break;
227 case POWER_POFCON_THRESHOLD_V28:
228 pof += "2.8V";
229 break;
230 }
231
232 if (nrf_power_mainregstatus_get(NRF_POWER) == NRF_POWER_MAINREGSTATUS_HIGH) {
233 pof += ", VDDH: ";
234 switch (nrf_power_pofcon_vddh_get(NRF_POWER)) {
235 case NRF_POWER_POFTHRVDDH_V27:
236 pof += "2.7V";
237 break;
238 case NRF_POWER_POFTHRVDDH_V28:
239 pof += "2.8V";
240 break;
241 case NRF_POWER_POFTHRVDDH_V29:
242 pof += "2.9V";
243 break;
244 case NRF_POWER_POFTHRVDDH_V30:
245 pof += "3.0V";
246 break;
247 case NRF_POWER_POFTHRVDDH_V31:
248 pof += "3.1V";
249 break;
250 case NRF_POWER_POFTHRVDDH_V32:
251 pof += "3.2V";
252 break;
253 case NRF_POWER_POFTHRVDDH_V33:
254 pof += "3.3V";
255 break;
256 case NRF_POWER_POFTHRVDDH_V34:
257 pof += "3.4V";
258 break;
259 case NRF_POWER_POFTHRVDDH_V35:
260 pof += "3.5V";
261 break;
262 case NRF_POWER_POFTHRVDDH_V36:
263 pof += "3.6V";
264 break;
265 case NRF_POWER_POFTHRVDDH_V37:
266 pof += "3.7V";
267 break;
268 case NRF_POWER_POFTHRVDDH_V38:
269 pof += "3.8V";
270 break;
271 case NRF_POWER_POFTHRVDDH_V39:
272 pof += "3.9V";
273 break;
274 case NRF_POWER_POFTHRVDDH_V40:
275 pof += "4.0V";
276 break;
277 case NRF_POWER_POFTHRVDDH_V41:
278 pof += "4.1V";
279 break;
280 case NRF_POWER_POFTHRVDDH_V42:
281 pof += "4.2V";
282 break;
283 }
284 }
285 } else {
286 pof += "disabled";
287 }
288 ESP_LOGD(TAG, "%s", pof.c_str());
289 device_info += "|" + pof;
290
291 auto package = [](uint32_t value) {
292 switch (value) {
293 case 0x2004:
294 return "QIxx - 7x7 73-pin aQFN";
295 case 0x2000:
296 return "QFxx - 6x6 48-pin QFN";
297 case 0x2005:
298 return "CKxx - 3.544 x 3.607 WLCSP";
299 }
300 return "Unspecified";
301 };
302
303 ESP_LOGD(TAG, "Code page size: %u, code size: %u, device id: 0x%08x%08x", NRF_FICR->CODEPAGESIZE, NRF_FICR->CODESIZE,
304 NRF_FICR->DEVICEID[1], NRF_FICR->DEVICEID[0]);
305 ESP_LOGD(TAG, "Encryption root: 0x%08x%08x%08x%08x, Identity Root: 0x%08x%08x%08x%08x", NRF_FICR->ER[0],
306 NRF_FICR->ER[1], NRF_FICR->ER[2], NRF_FICR->ER[3], NRF_FICR->IR[0], NRF_FICR->IR[1], NRF_FICR->IR[2],
307 NRF_FICR->IR[3]);
308 ESP_LOGD(TAG, "Device address type: %s, address: %s", (NRF_FICR->DEVICEADDRTYPE & 0x1 ? "Random" : "Public"),
309 get_mac_address_pretty().c_str());
310 ESP_LOGD(TAG, "Part code: nRF%x, version: %c%c%c%c, package: %s", NRF_FICR->INFO.PART,
311 NRF_FICR->INFO.VARIANT >> 24 & 0xFF, NRF_FICR->INFO.VARIANT >> 16 & 0xFF, NRF_FICR->INFO.VARIANT >> 8 & 0xFF,
312 NRF_FICR->INFO.VARIANT & 0xFF, package(NRF_FICR->INFO.PACKAGE));
313 ESP_LOGD(TAG, "RAM: %ukB, Flash: %ukB, production test: %sdone", NRF_FICR->INFO.RAM, NRF_FICR->INFO.FLASH,
314 (NRF_FICR->PRODTEST[0] == 0xBB42319F ? "" : "not "));
315 bool n_reset_enabled = NRF_UICR->PSELRESET[0] == NRF_UICR->PSELRESET[1] &&
316 (NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) == UICR_PSELRESET_CONNECT_Connected
317 << UICR_PSELRESET_CONNECT_Pos;
318 ESP_LOGD(
319 TAG, "GPIO as NFC pins: %s, GPIO as nRESET pin: %s",
320 YESNO((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)),
321 YESNO(n_reset_enabled));
322 if (n_reset_enabled) {
323 uint8_t port = (NRF_UICR->PSELRESET[0] & UICR_PSELRESET_PORT_Msk) >> UICR_PSELRESET_PORT_Pos;
324 uint8_t pin = (NRF_UICR->PSELRESET[0] & UICR_PSELRESET_PIN_Msk) >> UICR_PSELRESET_PIN_Pos;
325 ESP_LOGD(TAG, "nRESET port P%u.%02u", port, pin);
326 }
327#ifdef USE_BOOTLOADER_MCUBOOT
328 ESP_LOGD(TAG, "bootloader: mcuboot");
329#else
330 ESP_LOGD(TAG, "bootloader: Adafruit, version %u.%u.%u", (BOOTLOADER_VERSION_REGISTER >> 16) & 0xFF,
331 (BOOTLOADER_VERSION_REGISTER >> 8) & 0xFF, BOOTLOADER_VERSION_REGISTER & 0xFF);
332 ESP_LOGD(TAG, "MBR bootloader addr 0x%08x, UICR bootloader addr 0x%08x", read_mem_u32(MBR_BOOTLOADER_ADDR),
333 NRF_UICR->NRFFW[0]);
334 ESP_LOGD(TAG, "MBR param page addr 0x%08x, UICR param page addr 0x%08x", read_mem_u32(MBR_PARAM_PAGE_ADDR),
335 NRF_UICR->NRFFW[1]);
336 if (is_sd_present()) {
337 uint32_t const sd_id = sd_id_get();
338 uint32_t const sd_version = sd_version_get();
339
340 uint32_t ver[3];
341 ver[0] = sd_version / 1000000;
342 ver[1] = (sd_version - ver[0] * 1000000) / 1000;
343 ver[2] = (sd_version - ver[0] * 1000000 - ver[1] * 1000);
344
345 ESP_LOGD(TAG, "SoftDevice: S%u %u.%u.%u", sd_id, ver[0], ver[1], ver[2]);
346#ifdef USE_SOFTDEVICE_ID
347#ifdef USE_SOFTDEVICE_VERSION
348 if (USE_SOFTDEVICE_ID != sd_id || USE_SOFTDEVICE_VERSION != ver[0]) {
349 ESP_LOGE(TAG, "Built for SoftDevice S%u %u.x.y. It may crash due to mismatch of bootloader version.",
350 USE_SOFTDEVICE_ID, USE_SOFTDEVICE_VERSION);
351 }
352#else
353 if (USE_SOFTDEVICE_ID != sd_id) {
354 ESP_LOGE(TAG, "Built for SoftDevice S%u. It may crash due to mismatch of bootloader version.", USE_SOFTDEVICE_ID);
355 }
356#endif
357#endif
358 }
359#endif
360 auto uicr = [](volatile uint32_t *data, uint8_t size) {
361 std::string res;
362 char buf[sizeof(uint32_t) * 2 + 1];
363 for (size_t i = 0; i < size; i++) {
364 if (i > 0) {
365 res += ' ';
366 }
367 res += format_hex_pretty<uint32_t>(data[i], '\0', false);
368 }
369 return res;
370 };
371 ESP_LOGD(TAG, "NRFFW %s", uicr(NRF_UICR->NRFFW, 13).c_str());
372 ESP_LOGD(TAG, "NRFHW %s", uicr(NRF_UICR->NRFHW, 12).c_str());
373}
374
375void DebugComponent::update_platform_() {}
376
377} // namespace esphome::debug
378#endif
void log_partition_info_()
Logs information about the device's partition table.
void get_device_info_(std::string &device_info)
constexpr std::uintptr_t MBR_PARAM_PAGE_ADDR
constexpr uintptr_t SD_ID_OFFSET
constexpr std::uintptr_t MBR_BOOTLOADER_ADDR
constexpr uintptr_t MBR_SIZE
constexpr uintptr_t SOFTDEVICE_INFO_STRUCT_OFFSET
constexpr uintptr_t SD_VERSION_OFFSET
constexpr uint32_t SD_MAGIC_NUMBER
std::string get_mac_address_pretty()
Get the device MAC address as a string, in colon-separated uppercase hex notation.
Definition helpers.cpp:640
std::string format_hex_pretty(const uint8_t *data, size_t length, char separator, bool show_length)
Format a byte array in pretty-printed, human-readable hex format.
Definition helpers.cpp:317