ESPHome 2026.5.0-dev
Loading...
Searching...
No Matches
hal.h
Go to the documentation of this file.
1#pragma once
2#include <string>
3#include <cstdint>
4#include "gpio.h"
5
6#if defined(USE_ESP32)
7#include <esp_attr.h>
8#ifndef PROGMEM
9#define PROGMEM
10#endif
11
12#elif defined(USE_ESP8266)
13
14#include <c_types.h>
15#ifndef PROGMEM
16#define PROGMEM ICACHE_RODATA_ATTR
17#endif
18
19#elif defined(USE_RP2040)
20
21#define IRAM_ATTR __attribute__((noinline, long_call, section(".time_critical")))
22#define PROGMEM
23
24#elif defined(USE_LIBRETINY)
25
26// IRAM_ATTR places a function in executable RAM so it is callable from an
27// ISR even while flash is busy (XIP stall, OTA, logger flash write).
28// Each family uses a section its stock linker already routes to RAM:
29// RTL8710B → .image2.ram.text, RTL8720C → .sram.text. LN882H is the
30// exception: its stock linker has no matching glob, so patch_linker.py
31// injects KEEP(*(.sram.text*)) into .flash_copysection at pre-link.
32//
33// BK72xx (all variants) are left as a no-op: their SDK wraps flash
34// operations in GLOBAL_INT_DISABLE() which masks FIQ + IRQ at the CPU for
35// the duration of every write, so no ISR fires while flash is stalled and
36// the race IRAM_ATTR guards against cannot occur. The trade-off is that
37// interrupts are delayed (not dropped) by up to ~20 ms during a sector
38// erase, but that is an SDK-level choice and cannot be changed from this
39// layer.
40#if defined(USE_BK72XX)
41#define IRAM_ATTR
42#elif defined(USE_LIBRETINY_VARIANT_RTL8710B)
43// Stock linker consumes *(.image2.ram.text*) into .ram_image2.text (> BD_RAM).
44#define IRAM_ATTR __attribute__((noinline, section(".image2.ram.text")))
45#else
46// RTL8720C: stock linker consumes *(.sram.text*) into .ram.code_text.
47// LN882H: patch_linker.py.script injects *(.sram.text*) into
48// .flash_copysection (> RAM0 AT> FLASH).
49#define IRAM_ATTR __attribute__((noinline, section(".sram.text")))
50#endif
51#define PROGMEM
52
53#else
54
55#define IRAM_ATTR
56#define PROGMEM
57
58#endif
59
60#ifdef USE_ESP32
61#include <freertos/FreeRTOS.h>
62#include <freertos/task.h>
63#endif
64
65#ifdef USE_BK72XX
66// Declared in the Beken FreeRTOS port (portmacro.h) and built in ARM mode so
67// it is callable from Thumb code via interworking. The MRS CPSR instruction
68// is ARM-only and user code here may be built in Thumb, so in_isr_context()
69// defers to this port helper on BK72xx instead of reading CPSR inline.
71#endif
72
73namespace esphome {
74
77__attribute__((always_inline)) inline bool in_isr_context() {
78#if defined(USE_ESP32)
79 return xPortInIsrContext() != 0;
80#elif defined(USE_ESP8266)
81 // ESP8266 has no reliable single-register ISR detection: PS.INTLEVEL is
82 // non-zero both in a real ISR and when user code masks interrupts. The
83 // ESP8266 wake path is context-agnostic (wake_loop_impl uses esp_schedule
84 // which is ISR-safe) so this helper is unused on this platform.
85 return false;
86#elif defined(USE_RP2040)
87 uint32_t ipsr;
88 __asm__ volatile("mrs %0, ipsr" : "=r"(ipsr));
89 return ipsr != 0;
90#elif defined(USE_BK72XX)
91 // BK72xx is ARM968E-S (ARM9); see extern declaration above.
93#elif defined(USE_LIBRETINY)
94 // Cortex-M (AmebaZ, AmebaZ2, LN882H). IPSR is the active exception number;
95 // non-zero means we're in a handler.
96 uint32_t ipsr;
97 __asm__ volatile("mrs %0, ipsr" : "=r"(ipsr));
98 return ipsr != 0;
99#else
100 // Host and any future platform without an ISR concept.
101 return false;
102#endif
103}
104
105void yield();
107uint64_t millis_64();
109void delay(uint32_t ms);
110void delayMicroseconds(uint32_t us); // NOLINT(readability-identifier-naming)
111void __attribute__((noreturn)) arch_restart();
112void arch_init();
113void arch_feed_wdt();
116
117#ifdef USE_ESP8266
118// ESP8266: pgm_read_* does real flash reads on Harvard architecture
119uint8_t progmem_read_byte(const uint8_t *addr);
120const char *progmem_read_ptr(const char *const *addr);
121uint16_t progmem_read_uint16(const uint16_t *addr);
122#else
123// All other platforms: PROGMEM is a no-op, so these are direct dereferences
124inline uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; }
125inline const char *progmem_read_ptr(const char *const *addr) { return *addr; }
126inline uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; }
127#endif
128
129} // namespace esphome
struct @65::@66 __attribute__
Wake the main loop task from an ISR. ISR-safe.
Definition main_task.h:32
uint32_t platform_is_in_interrupt_context(void)
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint32_t arch_get_cpu_cycle_count()
Definition core.cpp:56
void arch_init()
Definition core.cpp:39
const char * progmem_read_ptr(const char *const *addr)
Definition core.cpp:37
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition core.cpp:30
void HOT yield()
Definition core.cpp:25
uint32_t arch_get_cpu_freq_hz()
Definition core.cpp:57
uint64_t HOT millis_64()
Definition core.cpp:27
uint32_t IRAM_ATTR HOT micros()
Definition core.cpp:29
void HOT arch_feed_wdt()
Definition core.cpp:54
uint16_t progmem_read_uint16(const uint16_t *addr)
Definition core.cpp:40
void HOT delay(uint32_t ms)
Definition core.cpp:28
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:26
void arch_restart()
Definition core.cpp:31
uint8_t progmem_read_byte(const uint8_t *addr)
Definition core.cpp:34
static void uint32_t