Skip to content

Commit 3b31e17

Browse files
authored
Merge pull request #21 from bugadani/clocks
Use max CPU clock frequency
2 parents e4ac738 + a63ffe3 commit 3b31e17

File tree

8 files changed

+236
-23
lines changed

8 files changed

+236
-23
lines changed

Cargo.lock

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ edition = "2018"
77
[dependencies]
88
panic-never = "0.1.0"
99
ufmt = { version = "0.1.0", optional = true }
10-
10+
cfg-if = "1.0"
1111

1212
[features]
1313
log = ["ufmt"]
@@ -22,6 +22,9 @@ esp32c5 = []
2222
esp32c6 = []
2323
esp32h2 = []
2424

25+
# use max CPU frequency
26+
max-cpu-frequency = []
27+
2528
[profile.release]
2629
codegen-units = 1
2730
debug = false

build.ps1

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
param(
2+
[string]$Device,
3+
[string[]]$Features
4+
)
5+
6+
function Show-Usage {
7+
Write-Host "Usage:"
8+
Write-Host " .\build.ps1 # build all devices"
9+
Write-Host " .\build.ps1 -Device esp32 # build single device"
10+
Write-Host " .\build.ps1 -Features log,max-cpu-frequency # build with specified features"
11+
Write-Host ""
12+
Write-Host "Notes:"
13+
Write-Host " - The -Features parameter accepts multiple values or a comma-separated string."
14+
exit 1
15+
}
16+
17+
# Remove existing YAML outputs (ignore errors if none exist)
18+
Remove-Item -Path output/*.yaml -Force -ErrorAction SilentlyContinue
19+
20+
# map device -> target
21+
$deviceMap = @{
22+
"esp32" = "xtensa-esp32-none-elf"
23+
"esp32s2" = "xtensa-esp32s2-none-elf"
24+
"esp32s3" = "xtensa-esp32s3-none-elf"
25+
"esp32c2" = "riscv32imc-unknown-none-elf"
26+
"esp32c3" = "riscv32imc-unknown-none-elf"
27+
"esp32c5" = "riscv32imac-unknown-none-elf"
28+
"esp32c6" = "riscv32imac-unknown-none-elf"
29+
# "esp32c61" = "riscv32imac-unknown-none-elf"
30+
"esp32h2" = "riscv32imac-unknown-none-elf"
31+
}
32+
33+
# Validate device (if specified) and build list
34+
if ($Device) {
35+
if (-not $deviceMap.ContainsKey($Device)) {
36+
Write-Error "Unknown device: $Device. Valid devices are: $($deviceMap.Keys -join ', ')"
37+
Show-Usage
38+
}
39+
$devicesToBuild = @($Device)
40+
} else {
41+
$devicesToBuild = $deviceMap.Keys
42+
}
43+
44+
# Normalize features passed via -Features (accepts array items and comma-separated strings)
45+
$parsedFeatures = @()
46+
if ($Features) {
47+
$joined = $Features -join ','
48+
$parsedFeatures = $joined -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' }
49+
}
50+
51+
# Deduplicate while preserving order
52+
$finalFeatures = @()
53+
foreach ($f in $parsedFeatures) {
54+
if (-not ($finalFeatures -contains $f)) {
55+
$finalFeatures += $f
56+
}
57+
}
58+
59+
# Build loop
60+
foreach ($d in $devicesToBuild) {
61+
$targetPath = ("target/{0}/release/esp-flashloader" -f ( $deviceMap[$d] ))
62+
Write-Host "=== Building $d ==="
63+
64+
# Build cargo arguments
65+
$cargoArgs = @("+esp", $d)
66+
67+
if ($finalFeatures.Count -gt 0) {
68+
$cargoArgs += "--features"
69+
$cargoArgs += ($finalFeatures -join ",")
70+
Write-Host ("running command: cargo {0}" -f ($cargoArgs -join ' '))
71+
} else {
72+
Write-Host ("running command: cargo {0}" -f ($cargoArgs -join ' '))
73+
}
74+
75+
# Run cargo
76+
$cargoExit = & cargo @cargoArgs
77+
if ($LASTEXITCODE -ne 0) {
78+
Write-Error "cargo failed for device $d (exit code $LASTEXITCODE). Aborting."
79+
exit $LASTEXITCODE
80+
}
81+
82+
# Run target-gen to produce YAML
83+
$outYaml = "output/$d.yaml"
84+
Write-Host "Generating YAML: $outYaml"
85+
& target-gen elf $targetPath $outYaml --name "$d-flashloader"
86+
if ($LASTEXITCODE -ne 0) {
87+
Write-Error "target-gen failed for device $d (exit code $LASTEXITCODE). Aborting."
88+
exit $LASTEXITCODE
89+
}
90+
91+
Write-Host ""
92+
}
93+
94+
Write-Host "All done."

ld/esp32c3.x

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ MEMORY {
33
IRAM : ORIGIN = 0x40390000, LENGTH = 0x10000
44
}
55

6+
PROVIDE( ets_delay_us = 0x40000050 );
67
PROVIDE( esp_rom_spiflash_wait_idle = 0x4000010c );
78
PROVIDE( esp_rom_spiflash_write_encrypted = 0x40000110 );
89
PROVIDE( esp_rom_spiflash_write_encrypted_dest = 0x40000114 );

ld/esp32s2.x

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ MEMORY {
1010
* These are all weak symbols that could be overwritten in ESP-IDF.
1111
*/
1212

13+
PROVIDE ( ets_delay_us = 0x4000d888 );
1314
PROVIDE ( ets_efuse_get_spiconfig = 0x4000e4a0 );
1415
PROVIDE ( s_cdcacm_old_rts = 0x3ffffd34 );
1516
PROVIDE ( SelectSpiFunction = 0x40015d08 );

ld/esp32s3.x

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,7 @@ MEMORY {
33
IRAM : ORIGIN = 0x40380400, LENGTH = 0x10000
44
}
55

6-
/* ROM function interface esp32s3.rom.ld for esp32s3
7-
*
8-
*
9-
* Generated from ./interface-esp32s3.yml md5sum 39c4ce259b11323b9404c192b01b712b
10-
*
11-
* Compatible with ROM where ECO version equal or greater to 0.
12-
*
13-
* THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT.
14-
*/
15-
6+
PROVIDE( ets_delay_us = 0x40000600 );
167
PROVIDE ( esp_rom_spiflash_attach = spi_flash_attach );
178

189
/***************************************

src/flash.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ extern "C" {
4646
#[cfg(feature = "esp32s3")]
4747
#[allow(non_camel_case_types)]
4848
mod s3 {
49-
5049
type spi_flash_func_t = unsafe extern "C" fn();
5150
type spi_flash_op_t = unsafe extern "C" fn() -> i32;
5251
type spi_flash_erase_t = unsafe extern "C" fn(u32) -> i32;
@@ -82,7 +81,6 @@ use s3::*;
8281

8382
#[cfg(feature = "esp32s3")]
8483
extern "C" {
85-
8684
static mut rom_spiflash_legacy_funcs: *const spiflash_legacy_funcs_t;
8785
static mut rom_spiflash_legacy_data: *mut ();
8886

src/main.rs

Lines changed: 127 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#![no_main]
33
#![cfg_attr(target_arch = "xtensa", feature(asm_experimental_arch))]
44

5+
// TODO: implement clock frequency setting for ESP32-C5
6+
57
// Target memory configuration
68

79
// Decompressor is 43776 bytes, reserve more in case compiler changes layout
@@ -78,7 +80,6 @@ const ERROR_BASE_FLASH: i32 = -4000;
7880

7981
#[cfg(feature = "log")]
8082
mod log {
81-
8283
extern "C" {
8384
fn uart_tx_one_char(byte: u8);
8485
}
@@ -119,22 +120,138 @@ macro_rules! dprintln {
119120
($fmt:expr, $($arg:tt)*) => {};
120121
}
121122

123+
#[cfg(all(feature = "max-cpu-frequency", not(feature = "esp32c5")))]
124+
mod max_cpu_frequency {
125+
cfg_if::cfg_if! {
126+
if #[cfg(feature = "esp32")] {
127+
const SYSTEM_CPU_PER_CONF_REG: *mut u32 = 0x3FF0003C as *mut u32;
128+
const SYSTEM_CPUPERIOD_SEL_M: u32 = 3;
129+
const SYSTEM_CPUPERIOD_MAX: u32 = 2;
130+
131+
const SYSTEM_SYSCLK_CONF_REG: *mut u32 = 0x3FF48070 as *mut u32;
132+
const SYSTEM_SOC_CLK_SEL_M: u32 = 3 << 27;
133+
const SYSTEM_SOC_CLK_MAX: u32 = 1 << 27;
134+
} else if #[cfg(feature = "esp32s2")] {
135+
const SYSTEM_CPU_PER_CONF_REG: *mut u32 = 0x3F4C0018 as *mut u32;
136+
const SYSTEM_CPUPERIOD_SEL_M: u32 = 3;
137+
const SYSTEM_CPUPERIOD_MAX: u32 = 2;
138+
139+
const SYSTEM_SYSCLK_CONF_REG: *mut u32 = 0x3F4C008C as *mut u32;
140+
const SYSTEM_SOC_CLK_SEL_M: u32 = 3 << 10;
141+
const SYSTEM_SOC_CLK_MAX: u32 = 1 << 10;
142+
} else if #[cfg(feature = "esp32s3")] {
143+
const SYSTEM_CPU_PER_CONF_REG: *mut u32 = 0x600C0010 as *mut u32;
144+
const SYSTEM_CPUPERIOD_SEL_M: u32 = 3;
145+
const SYSTEM_CPUPERIOD_MAX: u32 = 2;
146+
147+
const SYSTEM_SYSCLK_CONF_REG: *mut u32 = 0x600C0060 as *mut u32;
148+
const SYSTEM_SOC_CLK_SEL_M: u32 = 3 << 10;
149+
const SYSTEM_SOC_CLK_MAX: u32 = 1 << 10;
150+
} else if #[cfg(any(feature = "esp32c2", feature = "esp32c3"))] {
151+
const SYSTEM_CPU_PER_CONF_REG: *mut u32 = 0x600C0008 as *mut u32;
152+
const SYSTEM_CPUPERIOD_SEL_M: u32 = 3;
153+
const SYSTEM_CPUPERIOD_MAX: u32 = 1;
154+
155+
const SYSTEM_SYSCLK_CONF_REG: *mut u32 = 0x600C0058 as *mut u32;
156+
const SYSTEM_SOC_CLK_SEL_M: u32 = 3 << 10;
157+
const SYSTEM_SOC_CLK_MAX: u32 = 1 << 10;
158+
} else if #[cfg(feature = "esp32h2")] {
159+
const PCR_SYSCLK_CONF_REG: *mut u32 = 0x6009610c as *mut u32;
160+
161+
const PCR_SOC_CLK_SEL_M: u32 = 3 << 16;
162+
const PCR_SOC_CLK_MAX: u32 = 1 << 16;
163+
} else if #[cfg(feature = "esp32c6")] {
164+
const PCR_SYSCLK_CONF_REG: *mut u32 = 0x60096110 as *mut u32;
165+
166+
const PCR_SOC_CLK_SEL_M: u32 = 3 << 16;
167+
const PCR_SOC_CLK_MAX: u32 = 1 << 16;
168+
}
169+
}
170+
171+
pub struct CpuSaveState {
172+
#[cfg(not(any(feature = "esp32c6", feature = "esp32h2")))]
173+
saved_cpu_per_conf_reg: u32,
174+
saved_sysclk_conf_reg: u32,
175+
}
176+
177+
pub fn set_max_cpu_freq(state: &mut CpuSaveState) {
178+
cfg_if::cfg_if! {
179+
if #[cfg(any(feature = "esp32c6", feature = "esp32h2"))] {
180+
state.saved_sysclk_conf_reg = unsafe { PCR_SYSCLK_CONF_REG.read_volatile() };
181+
} else {
182+
state.saved_cpu_per_conf_reg = unsafe { SYSTEM_CPU_PER_CONF_REG.read_volatile() };
183+
state.saved_sysclk_conf_reg = unsafe { SYSTEM_SYSCLK_CONF_REG.read_volatile() };
184+
}
185+
}
186+
187+
cfg_if::cfg_if! {
188+
if #[cfg(any(feature = "esp32c6", feature = "esp32h2"))] {
189+
unsafe { PCR_SYSCLK_CONF_REG.write_volatile((state.saved_sysclk_conf_reg & !PCR_SOC_CLK_SEL_M) | PCR_SOC_CLK_MAX) };
190+
} else if #[cfg(feature = "esp32s3")] {
191+
extern "C" {
192+
fn ets_delay_us(us: u32);
193+
}
194+
195+
unsafe { SYSTEM_SYSCLK_CONF_REG.write_volatile((state.saved_sysclk_conf_reg & !SYSTEM_SOC_CLK_SEL_M) | SYSTEM_SOC_CLK_MAX) };
196+
// Leave some time for the change to settle, needed for ESP32-S3
197+
unsafe { ets_delay_us(100) };
198+
unsafe { SYSTEM_CPU_PER_CONF_REG.write_volatile((state.saved_cpu_per_conf_reg & !SYSTEM_CPUPERIOD_SEL_M) | SYSTEM_CPUPERIOD_MAX) };
199+
} else {
200+
unsafe { SYSTEM_CPU_PER_CONF_REG.write_volatile((state.saved_cpu_per_conf_reg & !SYSTEM_CPUPERIOD_SEL_M) | SYSTEM_CPUPERIOD_MAX) };
201+
unsafe { SYSTEM_SYSCLK_CONF_REG.write_volatile((state.saved_sysclk_conf_reg & !SYSTEM_SOC_CLK_SEL_M) | SYSTEM_SOC_CLK_MAX) };
202+
}
203+
}
204+
}
205+
206+
pub fn restore_max_cpu_freq(state: &mut CpuSaveState) {
207+
cfg_if::cfg_if! {
208+
if #[cfg(any(feature = "esp32c6", feature = "esp32h2"))] {
209+
unsafe { PCR_SYSCLK_CONF_REG.write_volatile(state.saved_sysclk_conf_reg) };
210+
} else {
211+
unsafe { SYSTEM_SYSCLK_CONF_REG.write_volatile(state.saved_sysclk_conf_reg) };
212+
unsafe { SYSTEM_CPU_PER_CONF_REG.write_volatile(state.saved_cpu_per_conf_reg) };
213+
}
214+
}
215+
}
216+
}
217+
218+
#[cfg(any(not(feature = "max-cpu-frequency"), feature = "esp32c5"))]
219+
mod max_cpu_frequency {
220+
pub struct CpuSaveState {}
221+
222+
pub fn set_max_cpu_freq(_: &mut CpuSaveState) {}
223+
pub fn restore_max_cpu_freq(_: &mut CpuSaveState) {}
224+
}
225+
226+
use max_cpu_frequency::*;
227+
228+
struct FlasherState {
229+
inited: u32,
230+
saved_cpu_state: CpuSaveState,
231+
decompressor: Decompressor,
232+
}
233+
122234
const INITED_MAGIC: u32 = 0xAAC0FFEE;
123-
const INITED: *mut u32 = STATE_ADDR as *mut u32;
124-
const DECOMPRESSOR: *mut Decompressor = (STATE_ADDR + 4) as *mut Decompressor;
235+
const STATE_OBJ: *mut FlasherState = STATE_ADDR as *mut FlasherState;
236+
237+
fn state() -> &'static mut FlasherState {
238+
unsafe { &mut *STATE_OBJ }
239+
}
125240

126241
fn is_inited() -> bool {
127-
unsafe { *INITED == INITED_MAGIC }
242+
state().inited == INITED_MAGIC
128243
}
129244

130245
/// Setup the device for the flashing process.
131246
#[no_mangle]
132247
pub unsafe extern "C" fn Init_impl(_adr: u32, _clk: u32, _fnc: u32) -> i32 {
133248
dprintln!("INIT");
134249

250+
set_max_cpu_freq(&mut state().saved_cpu_state);
251+
135252
if flash::attach() == 0 {
136-
*DECOMPRESSOR = Decompressor::new();
137-
*INITED = INITED_MAGIC;
253+
state().decompressor = Decompressor::new();
254+
state().inited = INITED_MAGIC;
138255
0
139256
} else {
140257
1
@@ -175,7 +292,7 @@ pub unsafe extern "C" fn ProgramPage_impl(adr: u32, sz: u32, buf: *const u8) ->
175292

176293
let input = core::slice::from_raw_parts(buf, sz as usize);
177294

178-
(*DECOMPRESSOR).program(adr, input)
295+
state().decompressor.program(adr, input)
179296
}
180297

181298
#[no_mangle]
@@ -193,7 +310,7 @@ pub unsafe extern "C" fn Verify_impl(adr: u32, sz: u32, buf: *const u8) -> i32 {
193310

194311
let input = core::slice::from_raw_parts(buf, sz as usize);
195312

196-
(*DECOMPRESSOR).verify(adr, input)
313+
state().decompressor.verify(adr, input)
197314
}
198315

199316
#[no_mangle]
@@ -219,7 +336,8 @@ pub unsafe extern "C" fn UnInit_impl(fnc: u32) -> i32 {
219336
return ERROR_BASE_INTERNAL - 1;
220337
};
221338

222-
*INITED = 0;
339+
restore_max_cpu_freq(&mut state().saved_cpu_state);
340+
state().inited = 0;
223341

224342
if fnc == 2 {
225343
// The flash ROM functions don't wait for the end of the last operation.

0 commit comments

Comments
 (0)