Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ require (
tinygo.org/x/go-llvm v0.0.0-20260721072906-185673ef46a5
)

replace tinygo.org/x/espflasher => github.com/flrossetto/espflasher v0.0.0-20260827223712-de27f3043f8f

require (
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/chavacava/garif v0.1.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/flrossetto/espflasher v0.0.0-20260827223712-de27f3043f8f h1:KzjN0vDU6jEjCmhquglQqqETitPCidw8LUJVrXbUcT8=
github.com/flrossetto/espflasher v0.0.0-20260827223712-de27f3043f8f/go.mod h1:YLkCtOCz6gdrbueTi6uZbGPSYduTYt62JdNGmiGxgc0=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
Expand Down Expand Up @@ -118,7 +120,5 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
tinygo.org/x/espflasher v0.8.1 h1:Vp+xA16af9NKVOOSJCcrJHqPSLDCpbfCd/TG3x449ks=
tinygo.org/x/espflasher v0.8.1/go.mod h1:YLkCtOCz6gdrbueTi6uZbGPSYduTYt62JdNGmiGxgc0=
tinygo.org/x/go-llvm v0.0.0-20260721072906-185673ef46a5 h1:0PKRhM1INWAi7PdIng1BHMPTDaRcOmv1UymdTgZ76Jo=
tinygo.org/x/go-llvm v0.0.0-20260721072906-185673ef46a5/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
22 changes: 21 additions & 1 deletion src/machine/machine_esp32.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,27 @@ func (uart *UART) Configure(config UARTConfig) error {
}
}

uart.Bus.CLKDIV.Set(peripheralClock / config.BaudRate)
// Select APB (80MHz) as the UART source clock. ESP-IDF always writes
// this explicitly (uart_ll_set_sclk, UART_SCLK_DEFAULT = APB,
// components/soc/esp32/include/soc/clk_tree_defs.h:238-240) rather than
// relying on the register's power-on-reset state — CONF0.TICK_REF_ALWAYS_ON
// selects APB when 1, REF_TICK (~1MHz) when 0 (components/esp_hal_uart/
// esp32/include/hal/uart_ll.h:179-189). Without this, UART0 happens to
// work because the ROM bootloader already leaves it in APB mode for its
// own console output, but UART1/UART2 (never touched by ROM) have no such
// guarantee, and the CLKDIV math below assumes an 80MHz source either way.
uart.Bus.SetCONF0_TICK_REF_ALWAYS_ON(1)

// UART_CLKDIV_REG packs a 20-bit integer divider (bits 19:0) and a 4-bit
// fractional divider (bits 23:20) — see components/soc/esp32/register/
// soc/uart_struct.h:123-129. Writing a plain integer division result
// (as before) zeroes the fractional part, which is usually a negligible
// rounding error at low baud rates but can be a significant fraction of
// the divider at high baud rates (small divider values). Compute both
// parts the way ESP-IDF's uart_ll_set_baudrate does (components/
// esp_hal_uart/esp32/include/hal/uart_ll.h:265-278): clk_div = (sclk<<4)/baud.
clkDiv := (uint32(peripheralClock) << 4) / config.BaudRate
uart.Bus.CLKDIV.Set((clkDiv >> 4) | ((clkDiv & 0xf) << 20))

if config.RX != NoPin {
config.RX.configure(PinConfig{Mode: PinInputPullup}, uart.txrxSignal)
Expand Down
16 changes: 11 additions & 5 deletions src/machine/machine_esp32_i2c.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,17 @@ func (i2c *I2C) initFrequency() {
halfCycle := sclkFreq / i2c.config.Frequency / 2
//SCL
sclLow := halfCycle
sclWaitHigh := uint32(0)
if i2c.config.Frequency > 50000 {
sclWaitHigh = halfCycle / 8 // compensate the time when freq > 50K
}
sclHigh := halfCycle - sclWaitHigh
// SCL_HIGH_PERIOD must be reduced to compensate for the SCL noise
// filter's propagation delay, per the TRM (see i2c_ll_master_set_bus_timing
// in components/esp_hal_i2c/esp32/include/hal/i2c_ll.h:110-127): with the
// filter enabled (initNoiseFilter sets SCL_FILTER_CFG=0xF, i.e. thres=7,
// en=1 — bit layout in components/soc/esp32/register/soc/i2c_struct.h:230-236),
// the correct compensation for thres in [3,7] is thres+6 = 13, a fixed
// amount independent of the bus frequency (not halfCycle/8, and not only
// applied above 50kHz — ESP-IDF applies it unconditionally whenever the
// filter is enabled).
const sclHighFilterCompensation = 13
sclHigh := halfCycle - sclHighFilterCompensation
// SDA
sdaHold := halfCycle / 4
sda_sample := halfCycle / 2
Expand Down
18 changes: 16 additions & 2 deletions src/runtime/scheduler_cooperative.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,10 +326,24 @@ func unlockAtomics(mask interrupt.State) {
interrupt.Restore(mask)
}

// printLocked serializes concurrent goroutines' print output. Without it,
// two goroutines calling println at the same time on this cooperative
// scheduler can interleave their output mid-line, since a print call can
// yield (e.g. while waiting on a UART FIFO) before it finishes writing.
var printLocked bool

const printlockMaxWait = 10000

func printlock() {
// nothing to do
for i := 0; printLocked; i++ {
if i >= printlockMaxWait {
break
}
Gosched()
}
printLocked = true
}

func printunlock() {
// nothing to do
printLocked = false
}
10 changes: 9 additions & 1 deletion targets/esp32.ld
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ MEMORY
IRAM (x) : ORIGIN = 0x40080000, LENGTH = 128K /* SRAM0 (usable portion) */

DROM (r) : ORIGIN = 0x3F400000, LENGTH = 4M /* Flash data bus (page-aligned) */
IROM (rx) : ORIGIN = 0x400D0000, LENGTH = 4M /* Flash instruction bus (page-aligned) */

/* IROM's real hardware ceiling is SOC_IROM_HIGH = 0x40400000
* (components/soc/esp32/include/soc/soc.h:166-167 in esp-idf), only
* 0x330000 (3.1875M) above SOC_IROM_LOW = 0x400D0000 — NOT 4M. A prior
* 4M declaration here silently accepted a .text large enough to map
* past the real flash-cache-mappable range into invalid address space;
* ld would not catch it until (or unless) an app grew that large. */
IROM (rx) : ORIGIN = 0x400D0000, LENGTH = 0x330000 /* Flash instruction bus (page-aligned) */
}

ENTRY(call_start_cpu0)
Expand Down Expand Up @@ -174,6 +181,7 @@ SECTIONS
*(.wifiorslpiram*)
*(.iram1*)
*(.coexiram*)
*(.coexsleepiram*)

. = ALIGN(4);
_iram_end = .;
Expand Down