ESPHome
2026.11.0-dev
Loading...
Searching...
No Matches
esphome
components
libretiny
hal.h
Go to the documentation of this file.
1
#pragma once
2
3
#ifdef USE_LIBRETINY
4
5
#include <cstdint>
6
7
// For the inline millis() fast paths (xTaskGetTickCount, portTICK_PERIOD_MS).
8
#include <FreeRTOS.h>
9
#include <task.h>
10
11
#include "
esphome/core/main_task.h
"
12
#include "
esphome/core/time_64.h
"
13
14
// IRAM_ATTR places a function in executable RAM so it is callable from an
15
// ISR even while flash is busy (XIP stall, OTA, logger flash write). All
16
// LibreTiny families that need it share the same .sram.text input section
17
// name; how that section is routed into RAM differs per family:
18
// RTL8720C: stock linker consumes *(.sram.text*) into .ram.code_text.
19
// RTL8710B: patch_linker.py.script injects KEEP(*(.sram.text*)) at the
20
// top of .ram_image2.data (which IS in ltchiptool's
21
// sections_ram). The stock linker has KEEP(*(.image2.ram.text*))
22
// in .ram_image2.text but that output section is NOT in
23
// ltchiptool's AmebaZ elf2bin sections_ram list, so code routed
24
// there is dropped from the flashed binary.
25
// LN882H: patch_linker.py.script injects KEEP(*(.sram.text*)) into
26
// .flash_copysection (> RAM0 AT> FLASH), after KEEP(*(.vectors))
27
// so the Cortex-M4 vector table stays 512-byte-aligned for VTOR.
28
//
29
// BK72xx (all variants) are left as a no-op: their SDK wraps flash
30
// operations in GLOBAL_INT_DISABLE() which masks FIQ + IRQ at the CPU for
31
// the duration of every write, so no ISR fires while flash is stalled and
32
// the race IRAM_ATTR guards against cannot occur. The trade-off is that
33
// interrupts are delayed (not dropped) by up to ~20 ms during a sector
34
// erase, but that is an SDK-level choice and cannot be changed from this
35
// layer.
36
#if defined(USE_BK72XX)
37
#define IRAM_ATTR
38
#else
39
#define IRAM_ATTR __attribute__((noinline, section(".sram.text")))
40
#endif
41
#define PROGMEM
42
43
#ifdef USE_BK72XX
44
// Declared in the Beken FreeRTOS port (portmacro.h) and built in ARM mode so
45
// it is callable from Thumb code via interworking. The MRS CPSR instruction
46
// is ARM-only and user code here may be built in Thumb, so in_isr_context()
47
// defers to this port helper on BK72xx instead of reading CPSR inline.
48
// NOLINTNEXTLINE(readability-redundant-declaration)
49
extern
"C"
uint32_t
platform_is_in_interrupt_context
(
void
);
50
#endif
51
52
// Forward decls from Arduino's <Arduino.h> for the inline wrappers below.
53
// NOLINTBEGIN(google-runtime-int,readability-identifier-naming,readability-redundant-declaration)
54
extern
"C"
void
yield
(
void
);
55
extern
"C"
void
delay
(
unsigned
long
ms);
56
extern
"C"
unsigned
long
micros
(
void
);
57
extern
"C"
unsigned
long
millis
(
void
);
58
extern
"C"
void
delayMicroseconds
(
unsigned
int
us);
59
// NOLINTEND(google-runtime-int,readability-identifier-naming,readability-redundant-declaration)
60
61
// Forward decls from libretiny's <lt_api.h> family for the inline arch_*
62
// wrappers below. Pulling the full header would drag in the rest of the
63
// LibreTiny C API.
64
// NOLINTBEGIN(readability-redundant-declaration)
65
extern
"C"
void
lt_wdt_feed
(
void
);
66
extern
"C"
uint32_t
lt_cpu_get_cycle_count
(
void
);
67
extern
"C"
uint32_t
lt_cpu_get_freq
(
void
);
68
// NOLINTEND(readability-redundant-declaration)
69
70
namespace
esphome::libretiny
{}
71
72
namespace
esphome
{
73
75
__attribute__
((always_inline))
inline
bool
in_isr_context() {
76
#if defined(USE_BK72XX)
77
// BK72xx is ARM968E-S (ARM9); see extern declaration above.
78
return
platform_is_in_interrupt_context
() != 0;
79
#else
80
// Cortex-M (AmebaZ, AmebaZ2, LN882H). IPSR is the active exception number;
81
// non-zero means we're in a handler.
82
uint32_t
ipsr;
83
__asm__
volatile
(
"mrs %0, ipsr"
:
"=r"
(ipsr));
84
return
ipsr != 0;
85
#endif
86
}
87
89
__attribute__
((always_inline))
inline
bool
is_main_loop_thread() {
90
return
xTaskGetCurrentTaskHandle() ==
esphome_main_task_handle
;
91
}
92
__attribute__
((always_inline))
inline
void
yield
() {
::yield
(); }
93
__attribute__
((always_inline))
inline
void
delay
(
uint32_t
ms) {
::delay
(ms); }
94
__attribute__
((always_inline))
inline
uint32_t
micros
() {
return
static_cast<
uint32_t
>
(
::micros
()); }
95
96
// Per-variant millis() fast path — matches MillisInternal::get().
97
#if defined(USE_RTL87XX) || defined(USE_LN882X)
98
static_assert
(configTICK_RATE_HZ == 1000,
"millis() fast path requires 1 kHz FreeRTOS tick"
);
99
__attribute__
((always_inline))
inline
uint32_t
millis
() {
100
// xTaskGetTickCountFromISR is mandatory in interrupt context per the FreeRTOS API contract.
101
return
in_isr_context() ? xTaskGetTickCountFromISR() : xTaskGetTickCount();
102
}
103
#elif defined(USE_BK72XX)
104
static_assert
(configTICK_RATE_HZ == 500,
"BK72xx millis() fast path assumes 500 Hz FreeRTOS tick"
);
105
__attribute__
((always_inline))
inline
uint32_t
millis
() {
return
xTaskGetTickCount() * portTICK_PERIOD_MS; }
106
#else
107
__attribute__
((always_inline))
inline
uint32_t
millis
() {
return
static_cast<
uint32_t
>
(
::millis
()); }
108
#endif
109
__attribute__
((always_inline))
inline
uint64_t
millis_64
() {
return
Millis64Impl::compute(
millis
()); }
110
111
// NOLINTNEXTLINE(readability-identifier-naming)
112
__attribute__
((always_inline))
inline
void
delayMicroseconds
(
uint32_t
us) {
::delayMicroseconds
(us); }
113
__attribute__
((hot, always_inline))
inline
void
arch_feed_wdt
() {
lt_wdt_feed
(); }
114
__attribute__
((always_inline))
inline
uint32_t
arch_get_cpu_cycle_count
() {
return
lt_cpu_get_cycle_count
(); }
115
__attribute__
((always_inline))
inline
uint32_t
arch_get_cpu_freq_hz
() {
return
lt_cpu_get_freq
(); }
116
117
void
arch_init
();
118
119
}
// namespace esphome
120
121
#endif
// USE_LIBRETINY
__attribute__
struct @66::@67 __attribute__
Wake the main loop task from an ISR. ISR-safe.
Definition
main_task.h:45
millis
unsigned long millis(void)
delay
void delay(unsigned long ms)
micros
unsigned long micros(void)
yield
void yield(void)
platform_is_in_interrupt_context
uint32_t platform_is_in_interrupt_context(void)
lt_cpu_get_freq
uint32_t lt_cpu_get_freq(void)
delayMicroseconds
void delayMicroseconds(unsigned int us)
lt_cpu_get_cycle_count
uint32_t lt_cpu_get_cycle_count(void)
lt_wdt_feed
void lt_wdt_feed(void)
esphome_main_task_handle
TaskHandle_t esphome_main_task_handle
Main loop task handle and wake helpers — shared between wake.h (C++) and lwip_fast_select....
Definition
main_task.c:4
main_task.h
esphome::libretiny
Definition
atexit_stubs.cpp:14
esphome
Definition
a01nyub.cpp:7
esphome::arch_get_cpu_cycle_count
uint32_t arch_get_cpu_cycle_count()
Definition
hal.cpp:71
esphome::arch_init
void arch_init()
Definition
hal.cpp:44
esphome::delayMicroseconds
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition
hal.cpp:48
esphome::arch_get_cpu_freq_hz
uint32_t arch_get_cpu_freq_hz()
Definition
hal.cpp:55
esphome::millis_64
uint64_t millis_64()
Definition
hal.cpp:29
esphome::micros
uint32_t IRAM_ATTR HOT micros()
Definition
hal.cpp:43
esphome::arch_feed_wdt
void arch_feed_wdt()
Definition
hal.cpp:58
esphome::delay
void HOT delay(uint32_t ms)
Definition
hal.cpp:85
esphome::millis
uint32_t IRAM_ATTR HOT millis()
Definition
hal.cpp:25
uint32_t
static void uint32_t
Definition
crash_handler.cpp:153
time_64.h
Generated by
1.12.0