Skip to content

Commit 63cb080

Browse files
committed
first commit
1 parent 32e6ff1 commit 63cb080

25 files changed

+4900
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
install/

README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# STM32F407 Runtimes
2+
3+
This repository generates GNAT bare-metal runtimes for STM32F407 targets.
4+
5+
Supported runtime profiles:
6+
- `light`
7+
- `light-tasking`
8+
- `embedded`
9+
10+
## Using a runtime from Alire
11+
12+
Example using `light-tasking-stm32f407`:
13+
14+
1. Add the crate to your project's `alire.toml`:
15+
16+
```toml
17+
[[depends-on]]
18+
light_tasking_stm32f407 = "*"
19+
```
20+
21+
2. In your project `.gpr`, reference and use the runtime project:
22+
23+
```ada
24+
with "runtime_build.gpr";
25+
26+
project App is
27+
for Target use runtime_build'Target;
28+
for Runtime ("Ada") use runtime_build'Runtime ("Ada");
29+
30+
package Linker is
31+
for Switches ("Ada") use Runtime_Build.Linker_Switches;
32+
end Linker;
33+
end App;
34+
```
35+
36+
## Runtime Clock Configuration (important)
37+
38+
Clock setup is controlled by crate configuration variables in your
39+
application's `alire.toml`.
40+
41+
Default behavior is a 168 MHz SYSCLK from HSI through PLL.
42+
43+
For STM32F407 Discovery (8 MHz HSE crystal), a typical configuration is:
44+
45+
```toml
46+
[configuration.values]
47+
# HSE on Discovery board
48+
light_tasking_stm32f407.HSE_Clock_Frequency = 8000000
49+
light_tasking_stm32f407.HSE_Bypass = false
50+
51+
# Use PLL as SYSCLK source
52+
light_tasking_stm32f407.SYSCLK_Src = "PLLCLK"
53+
light_tasking_stm32f407.PLL_Src = "HSE"
54+
55+
# 8 MHz -> (N/M)=336/8 => 336 MHz VCO
56+
light_tasking_stm32f407.PLL_M_Div = 8
57+
light_tasking_stm32f407.PLL_N_Mul = 336
58+
59+
# SYSCLK = VCO / 2 = 168 MHz
60+
light_tasking_stm32f407.PLL_P_Div = "DIV2"
61+
62+
# 48 MHz domain for USB/SDIO/RNG
63+
light_tasking_stm32f407.PLL_Q_Div = 7
64+
65+
# Bus prescalers
66+
light_tasking_stm32f407.AHB_Pre = "DIV1"
67+
light_tasking_stm32f407.APB1_Pre = "DIV4"
68+
light_tasking_stm32f407.APB2_Pre = "DIV2"
69+
```
70+
71+
## Note about timing accuracy
72+
73+
A timing issue where `delay 1.0` behaved like ~4 seconds was caused by an
74+
incorrect PLLP register encoding in `setup_pll.adb`. This repository now uses
75+
the correct STM32F4 encoding (`00=/2, 01=/4, 10=/6, 11=/8`) consistently.
76+
77+
## Generation templates
78+
79+
The generated crate metadata and examples are based on:
80+
- `templates/alire.toml.in`
81+
- `templates/stm32f407_runtime_config.ads.in`
82+
- `stm32f407_src/setup_pll.adb`
83+
84+
If you regenerate runtimes, these sources carry the fixed behavior.

build-rts.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# This script extends bb-runtimes to define the stm32f407 target
2+
3+
import sys
4+
import os
5+
import pathlib
6+
7+
# Add bb-runtimes to the search path so that we can include and extend it
8+
sys.path.append(str(pathlib.Path(__file__).parent / "bb-runtimes"))
9+
10+
import arm.cortexm
11+
import build_rts
12+
from support import add_source_search_path
13+
14+
15+
class ArmV7MArch_Patched(arm.cortexm.ArmV7MArch):
16+
def __init__(self):
17+
super(ArmV7MArch_Patched, self).__init__()
18+
# Use our own patched version of s-bbbosu.adb which has a fix that is
19+
# not yet merged upstream (the fix ensures that Interrupt_Wrapper is
20+
# called with interrupts disabled to avoid a race condition with
21+
# nested interrupts).
22+
# See: https://forum.ada-lang.io/t/a-bug-in-stm32-bareboard-runtimes/2168
23+
self.remove_source("s-bbbosu.adb")
24+
self.add_gnarl_sources("stm32f407_src/s-bbbosu.adb")
25+
26+
27+
class Stm32F407(arm.cortexm.CortexM4F):
28+
@property
29+
def name(self):
30+
return "stm32f407"
31+
32+
@property
33+
def parent(self):
34+
return ArmV7MArch_Patched
35+
36+
@property
37+
def use_semihosting_io(self):
38+
return True
39+
40+
@property
41+
def loaders(self):
42+
return ("ROM", "RAM")
43+
44+
@property
45+
def system_ads(self):
46+
return {
47+
"light": "system-xi-arm.ads",
48+
"light-tasking": "system-xi-cortexm4-sfp.ads",
49+
"embedded": "system-xi-cortexm4-full.ads",
50+
}
51+
52+
def __init__(self):
53+
super(Stm32F407, self).__init__()
54+
55+
self.add_linker_script("stm32f407_src/ld/common-RAM.ld")
56+
self.add_linker_script("stm32f407_src/ld/common-ROM.ld")
57+
58+
# Common source files
59+
self.add_gnat_sources(
60+
"bb-runtimes/arm/stm32/start-common.S",
61+
"bb-runtimes/arm/stm32/start-ram.S",
62+
"bb-runtimes/arm/stm32/start-rom.S",
63+
"stm32f407_src/setup_pll.ads",
64+
"stm32f407_src/setup_pll.adb",
65+
"stm32f407_src/s-bbpara.ads",
66+
"stm32f407_src/s-bbbopa.ads",
67+
"stm32f407_src/s-bbmcpa.ads",
68+
"stm32f407_src/svd/handler.S",
69+
"stm32f407_src/svd/i-stm32.ads",
70+
"stm32f407_src/svd/i-stm32-flash.ads",
71+
"stm32f407_src/svd/i-stm32-pwr.ads",
72+
"stm32f407_src/svd/i-stm32-rcc.ads",
73+
)
74+
75+
self.add_gnarl_sources(
76+
"stm32f407_src/svd/a-intnam-F407.ads",
77+
)
78+
79+
80+
def build_configs(target):
81+
if target == "stm32f407":
82+
return Stm32F407()
83+
else:
84+
assert False, "unexpected target: %s" % target
85+
86+
def patch_bb_runtimes():
87+
"""Patch some parts of bb-runtimes to use our own targets and data"""
88+
add_source_search_path(os.path.dirname(__file__))
89+
90+
build_rts.build_configs = build_configs
91+
92+
if __name__ == "__main__":
93+
patch_bb_runtimes()
94+
build_rts.main()

crateify.py

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# This script takes the stm32f407 runtimes generated by build-rts.py and
2+
# patches them to turn them into an Alire crate.
3+
#
4+
# In particular it:
5+
# - adds an alire.toml
6+
# - overwrites runtime_build.gpr and ravenscar_build.gpr with our own versions
7+
# to take advantage of crate configuration variables.
8+
# - patches target_options.gpr to add a prefix to the BUILD and LIBRARY_TYPE
9+
# GPR scenario variables.
10+
# - adds stm32f407_runtime_config.ads which renames the crate config package
11+
# generated by Alire so that the common runtime sources can access the
12+
# config via one common package name.
13+
# - installs extra linker scripts with the directory hierarchy intact
14+
# (bb-runtimes flattens the directory structure when installing sources).
15+
16+
import argparse
17+
import pathlib
18+
import shutil
19+
from typing import Dict
20+
21+
22+
def patch_ravenscar_build_gpr(gpr_file: pathlib.Path, profile: str, target: str):
23+
"""Patch the ravenscar_build.gpr file to add some style switches"""
24+
25+
# Change "light-tasking" to "light_tasking"
26+
profile = profile.replace("-", "_")
27+
28+
with open(gpr_file, "r") as f:
29+
content = f.read()
30+
31+
# Add -gnaty-d to the switches used to build the runtime. This fixes style
32+
# warnings about line endings for packages which "with" the crate
33+
# configuration package generated by Alire, which uses CRLF line endings on
34+
# Windows.
35+
content = content.replace(
36+
f'for Default_Switches ("Ada") use Target_Options.GNARL_ADAFLAGS',
37+
f'for Default_Switches ("Ada") use Target_Options.GNARL_ADAFLAGS & ("-gnaty-d")',
38+
)
39+
40+
with open(gpr_file, "w") as f:
41+
f.write(content)
42+
43+
44+
def patch_target_options(gpr_file: pathlib.Path, profile: str, target: str):
45+
"""Patch the target_options.gpr file to add the crate name as a prefix
46+
to GPR variables.
47+
48+
E.g. for light-tasking-stm32f407:
49+
BUILD becomes LIGHT_TASKING_STM32F407_BUILD
50+
LIBRARY_TYPE becomes LIGHT_TASKING_STM32F407_LIBRARY_TYPE
51+
52+
This follows the Alire best practices and allows the build mode to be
53+
set for just the runtime crate if need be.
54+
"""
55+
56+
# Change "light-tasking" to "light_tasking"
57+
profile = profile.replace("-", "_")
58+
59+
with open(gpr_file, "r") as f:
60+
content = f.read()
61+
62+
content = content.replace(
63+
f'"BUILD"',
64+
f'"{profile.upper()}_{target.upper()}_BUILD"',
65+
)
66+
content = content.replace(
67+
f'"LIBRARY_TYPE"',
68+
f'"{profile.upper()}_{target.upper()}_LIBRARY_TYPE"',
69+
)
70+
71+
with open(gpr_file, "w") as f:
72+
f.write(content)
73+
74+
75+
def gen_from_template(
76+
template_file: pathlib.Path,
77+
out_file: pathlib.Path,
78+
template_values: Dict[str, str],
79+
):
80+
with open(template_file, "r") as f:
81+
content = f.read()
82+
83+
for key, value in template_values.items():
84+
content = content.replace(f"$({key})", value)
85+
86+
with open(out_file, "w", newline="\n") as f:
87+
f.write(content)
88+
89+
90+
def capitalize_underscored(s: str):
91+
return "_".join(x.capitalize() for x in s.split("_"))
92+
93+
94+
def main():
95+
parser = argparse.ArgumentParser()
96+
parser.add_argument(
97+
"--runtime-dir", type=str, help="Path to the runtime directory to patch"
98+
)
99+
parser.add_argument(
100+
"--profile",
101+
type=str,
102+
choices=["light", "light-tasking", "embedded"],
103+
help="The runtime profile",
104+
)
105+
parser.add_argument(
106+
"--version",
107+
type=str,
108+
default="15.0.0-dev",
109+
help="Version string to put in the alire.toml file",
110+
)
111+
112+
args = parser.parse_args()
113+
114+
runtime_dir = pathlib.Path(args.runtime_dir)
115+
profile = args.profile
116+
pretty_target = "STM32F407"
117+
target = "stm32f407"
118+
119+
has_libgnarl = (runtime_dir / "ravenscar_build.gpr").exists()
120+
121+
project_files = ["runtime_build.gpr"]
122+
if has_libgnarl:
123+
project_files.append("ravenscar_build.gpr")
124+
125+
patch_target_options(
126+
gpr_file=runtime_dir / "target_options.gpr", profile=profile, target=target
127+
)
128+
129+
if has_libgnarl:
130+
patch_ravenscar_build_gpr(
131+
gpr_file=runtime_dir / "ravenscar_build.gpr", profile=profile, target=target
132+
)
133+
134+
profile_underscored = profile.replace("-", "_")
135+
136+
# light and light-tasking require "Ada" and "Asm_Cpp".
137+
# embedded also requires "C".
138+
languages_list = ["Ada", "Asm_Cpp"]
139+
if profile == "embedded":
140+
languages_list.append("C")
141+
142+
template_values = {
143+
"profile": profile,
144+
"profile_underscored": profile_underscored,
145+
"target": target,
146+
"pretty_target": pretty_target,
147+
"project_files_list": str(project_files),
148+
"version": args.version,
149+
"languages_list": ", ".join(f'"{lang}"' for lang in languages_list)
150+
}
151+
152+
templates_dir = pathlib.Path(__file__).parent / "templates"
153+
154+
gen_from_template(
155+
template_file=templates_dir / "alire.toml.in",
156+
out_file=runtime_dir / "alire.toml",
157+
template_values=template_values,
158+
)
159+
160+
gen_from_template(
161+
template_file=templates_dir / "runtime_build.gpr.in",
162+
out_file=runtime_dir / "runtime_build.gpr",
163+
template_values=template_values,
164+
)
165+
166+
if has_libgnarl:
167+
gen_from_template(
168+
template_file=templates_dir / "ravenscar_build.gpr.in",
169+
out_file=runtime_dir / "ravenscar_build.gpr",
170+
template_values=template_values,
171+
)
172+
173+
gen_from_template(
174+
template_file=templates_dir / "stm32f407_runtime_config.ads.in",
175+
out_file=runtime_dir / "gnat_user" / "stm32f407_runtime_config.ads",
176+
template_values=template_values,
177+
)
178+
179+
shutil.copytree(
180+
src=pathlib.Path(__file__).parent / "stm32f407_src" / "ld",
181+
dst=runtime_dir / "ld",
182+
dirs_exist_ok=True,
183+
)
184+
185+
186+
if __name__ == "__main__":
187+
main()

0 commit comments

Comments
 (0)