Skip to content

Commit 8d08246

Browse files
committed
Add initial support for ULP programming // Issue #95
1 parent 0dbb36d commit 8d08246

File tree

24 files changed

+1823
-0
lines changed

24 files changed

+1823
-0
lines changed

builder/frameworks/espidf.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
env.SConscript("_bare.py", exports="env")
3636
env.SConscript("_embedtxt_files.py", exports="env")
3737

38+
ulp_lib = None
39+
ulp_dir = join(env.subst("$PROJECT_DIR"), "ulp")
40+
if isdir(ulp_dir) and listdir(ulp_dir):
41+
ulp_lib = env.SConscript("ulp.py", exports="env")
42+
3843
FRAMEWORK_DIR = platform.get_package_dir("framework-espidf")
3944
assert FRAMEWORK_DIR and isdir(FRAMEWORK_DIR)
4045

@@ -56,6 +61,12 @@ def get_original_version(version):
5661
platform.get_package_version("toolchain-xtensa32"))
5762

5863

64+
def is_ulp_enabled(sdk_params):
65+
ulp_memory = int(sdk_params.get("CONFIG_ULP_COPROC_RESERVE_MEM", 0))
66+
ulp_enabled = int(sdk_params.get("CONFIG_ULP_COPROC_ENABLED", 0))
67+
return ulp_memory > 0 and ulp_enabled != 0
68+
69+
5970
def parse_mk(path):
6071
result = {}
6172
variable = None
@@ -608,6 +619,20 @@ def build_espidf_bootloader():
608619

609620
libs = []
610621

622+
if ulp_lib:
623+
if not is_ulp_enabled(sdk_params):
624+
print("Warning! ULP is not properly configured."
625+
"Add next configuration lines to your sdkconfig.h:")
626+
print (" #define CONFIG_ULP_COPROC_ENABLED 1")
627+
print (" #define CONFIG_ULP_COPROC_RESERVE_MEM 1024")
628+
629+
libs.append(ulp_lib)
630+
env.Append(
631+
CPPPATH=[join("$BUILD_DIR", "ulp_app")],
632+
LIBPATH=[join("$BUILD_DIR", "ulp_app")],
633+
LINKFLAGS=["-T", "ulp_main.ld"]
634+
)
635+
611636
ignore_dirs = (
612637
"bootloader",
613638
"esptool_py",

builder/frameworks/ulp.py

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# Copyright 2019-present PlatformIO <[email protected]>
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from os import remove
16+
from os.path import exists, join
17+
18+
from shutil import copyfile
19+
20+
from SCons.Script import Builder, Import, Return
21+
22+
Import("env")
23+
24+
ulp_env = env.Clone()
25+
26+
platform = ulp_env.PioPlatform()
27+
FRAMEWORK_DIR = platform.get_package_dir("framework-espidf")
28+
ULP_TOOLCHAIN_DIR = platform.get_package_dir("toolchain-esp32ulp")
29+
ULP_BUILD_DIR = join("$BUILD_DIR", "ulp_app")
30+
31+
# ULP toolchain binaries should be in PATH
32+
ulp_env.PrependENVPath("PATH", join(ULP_TOOLCHAIN_DIR, "bin"))
33+
34+
35+
def bin_converter(target, source, env):
36+
# A workaround that helps avoid changing working directory
37+
# in order to generate symbols that are irrespective of path
38+
temp_source = join(env.subst("$PROJECT_DIR"), source[0].name)
39+
copyfile(source[0].get_path(), temp_source)
40+
41+
command = " ".join([
42+
"xtensa-esp32-elf-objcopy", "--input-target",
43+
"binary", "--output-target",
44+
"elf32-xtensa-le", "--binary-architecture",
45+
"xtensa", "--rename-section",
46+
".data=.rodata.embedded",
47+
source[0].name, target[0].get_path()
48+
])
49+
50+
ulp_env.Execute(command)
51+
52+
if exists(temp_source):
53+
remove(temp_source)
54+
55+
return None
56+
57+
58+
ulp_env.Append(
59+
CPPPATH=["$PROJECTSRC_DIR"],
60+
61+
BUILDERS=dict(
62+
BuildElf=Builder(
63+
action=ulp_env.VerboseAction(" ".join([
64+
"esp32ulp-elf-ld",
65+
"-o", "$TARGET",
66+
"-A", "elf32-esp32ulp",
67+
"-L", ULP_BUILD_DIR,
68+
"-T", "ulp_main.common.ld",
69+
"$SOURCES"
70+
]), "Linking $TARGET"),
71+
suffix=".elf"
72+
),
73+
UlpElfToBin=Builder(
74+
action=ulp_env.VerboseAction(" ".join([
75+
"esp32ulp-elf-objcopy",
76+
"-O", "binary",
77+
"$SOURCE", "$TARGET"
78+
]), "Building $TARGET"),
79+
suffix=".bin"
80+
),
81+
ConvertBin=Builder(
82+
action=bin_converter,
83+
suffix=".bin.bin.o"
84+
),
85+
PreprocAs=Builder(
86+
action=ulp_env.VerboseAction(" ".join([
87+
"xtensa-esp32-elf-gcc",
88+
"-DESP_PLATFORM", "-MMD", "-MP", "-DGCC_NOT_5_2_0=0",
89+
"-DWITH_POSIX", "-DHAVE_CONFIG_H",
90+
"-MT", "${TARGET}.o",
91+
"-DMBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\"",
92+
"-I %s" % join(
93+
FRAMEWORK_DIR, "components", "soc", "esp32", "include"),
94+
"-E", "-P", "-xc",
95+
"-o", "$TARGET", "-D__ASSEMBLER__", "$SOURCE"
96+
]), "Preprocessing $TARGET"),
97+
single_source=True,
98+
suffix=".ulp.pS"
99+
),
100+
AsToObj=Builder(
101+
action=ulp_env.VerboseAction(" ".join([
102+
"esp32ulp-elf-as",
103+
"-o", "$TARGET", "$SOURCE"
104+
]), "Compiling $TARGET"),
105+
single_source=True,
106+
suffix=".o"
107+
)
108+
)
109+
)
110+
111+
112+
def preprocess_ld_script():
113+
arguments = ("-DESP_PLATFORM", "-MMD", "-MP", "-DGCC_NOT_5_2_0=0",
114+
"-DWITH_POSIX", "-D__ASSEMBLER__",
115+
'-DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h"',
116+
"-DHAVE_CONFIG_H", "-MT", "$TARGET", "-E", "-P", "-xc", "-o",
117+
"$TARGET", "-I $PROJECTSRC_DIR", "$SOURCE")
118+
119+
return ulp_env.Command(
120+
join(ULP_BUILD_DIR, "ulp_main.common.ld"),
121+
join(FRAMEWORK_DIR, "components", "ulp", "ld", "esp32.ulp.ld"),
122+
ulp_env.VerboseAction('xtensa-esp32-elf-gcc %s' % " ".join(arguments),
123+
"Preprocessing linker script $TARGET"))
124+
125+
126+
def collect_src_files(src_path):
127+
return ulp_env.CollectBuildFiles(ULP_BUILD_DIR, src_path)
128+
129+
130+
def generate_global_symbols(elf_file):
131+
return ulp_env.Command(
132+
join(ULP_BUILD_DIR, "ulp_main.sym"), elf_file,
133+
ulp_env.VerboseAction(
134+
"esp32ulp-elf-nm -g -f posix $SOURCE > $TARGET",
135+
"Generating global symbols $TARGET"))
136+
137+
138+
def generate_export_files(symbol_file):
139+
# generates ld script and header file
140+
gen_script = join(FRAMEWORK_DIR, "components", "ulp", "esp32ulp_mapgen.py")
141+
build_suffix = join(ULP_BUILD_DIR, "ulp_main")
142+
return ulp_env.Command(
143+
[join(ULP_BUILD_DIR, "ulp_main.ld"),
144+
join(ULP_BUILD_DIR, "ulp_main.h")], symbol_file,
145+
ulp_env.VerboseAction(
146+
'"$PYTHONEXE" "%s" -s $SOURCE -o %s' % (gen_script, build_suffix),
147+
"Exporting ULP linker and header files"))
148+
149+
150+
def create_static_lib(bin_file):
151+
return ulp_env.StaticLibrary(join(ULP_BUILD_DIR, "ulp_main"), [bin_file])
152+
153+
154+
ulp_src_files = collect_src_files(
155+
join(ulp_env.subst("$PROJECT_DIR"), "ulp"))
156+
objects = ulp_env.AsToObj(ulp_env.PreprocAs(ulp_src_files))
157+
ulp_elf = ulp_env.BuildElf(join(ULP_BUILD_DIR, "ulp_main"), objects)
158+
raw_ulp_binary = ulp_env.UlpElfToBin(ulp_elf)
159+
ulp_bin = ulp_env.ConvertBin(raw_ulp_binary)
160+
global_symbols = generate_global_symbols(ulp_elf)
161+
export_files = generate_export_files(global_symbols)
162+
163+
ulp_lib = create_static_lib(ulp_bin)
164+
165+
ulp_env.Depends(ulp_lib, export_files)
166+
ulp_env.Depends(ulp_elf, preprocess_ld_script())
167+
168+
# ULP sources must be built before the files in "src" folder
169+
ulp_env.Requires(join("$BUILD_DIR", "${PROGNAME}.elf"), ulp_lib)
170+
171+
Return("ulp_lib")

examples/espidf-ulp-adc/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.pioenvs
2+
.piolibdeps

examples/espidf-ulp-adc/.travis.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Continuous Integration (CI) is the practice, in software
2+
# engineering, of merging all developer working copies with a shared mainline
3+
# several times a day < https://docs.platformio.org/page/ci/index.html >
4+
#
5+
# Documentation:
6+
#
7+
# * Travis CI Embedded Builds with PlatformIO
8+
# < https://docs.travis-ci.com/user/integration/platformio/ >
9+
#
10+
# * PlatformIO integration with Travis CI
11+
# < https://docs.platformio.org/page/ci/travis.html >
12+
#
13+
# * User Guide for `platformio ci` command
14+
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
15+
#
16+
#
17+
# Please choose one of the following templates (proposed below) and uncomment
18+
# it (remove "# " before each line) or use own configuration according to the
19+
# Travis CI documentation (see above).
20+
#
21+
22+
23+
#
24+
# Template #1: General project. Test it using existing `platformio.ini`.
25+
#
26+
27+
# language: python
28+
# python:
29+
# - "2.7"
30+
#
31+
# sudo: false
32+
# cache:
33+
# directories:
34+
# - "~/.platformio"
35+
#
36+
# install:
37+
# - pip install -U platformio
38+
# - platformio update
39+
#
40+
# script:
41+
# - platformio run
42+
43+
44+
#
45+
# Template #2: The project is intended to be used as a library with examples.
46+
#
47+
48+
# language: python
49+
# python:
50+
# - "2.7"
51+
#
52+
# sudo: false
53+
# cache:
54+
# directories:
55+
# - "~/.platformio"
56+
#
57+
# env:
58+
# - PLATFORMIO_CI_SRC=path/to/test/file.c
59+
# - PLATFORMIO_CI_SRC=examples/file.ino
60+
# - PLATFORMIO_CI_SRC=path/to/test/directory
61+
#
62+
# install:
63+
# - pip install -U platformio
64+
# - platformio update
65+
#
66+
# script:
67+
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N

examples/espidf-ulp-adc/README.rst

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
.. Copyright 2014-present PlatformIO <[email protected]>
2+
Licensed under the Apache License, Version 2.0 (the "License");
3+
you may not use this file except in compliance with the License.
4+
You may obtain a copy of the License at
5+
http://www.apache.org/licenses/LICENSE-2.0
6+
Unless required by applicable law or agreed to in writing, software
7+
distributed under the License is distributed on an "AS IS" BASIS,
8+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
See the License for the specific language governing permissions and
10+
limitations under the License.
11+
12+
How to build PlatformIO based project
13+
=====================================
14+
15+
1. `Install PlatformIO Core <http://docs.platformio.org/page/core.html>`_
16+
2. Download `development platform with examples <https://github.com/platformio/platform-espressif32/archive/develop.zip>`_
17+
3. Extract ZIP archive
18+
4. Run these commands:
19+
20+
.. code-block:: bash
21+
22+
# Change directory to example
23+
> cd platform-espressif32/examples/espidf-ulp-adc
24+
25+
# Build project
26+
> platformio run
27+
28+
# Upload firmware
29+
> platformio run --target upload
30+
31+
# Build specific environment
32+
> platformio run -e esp32dev
33+
34+
# Upload firmware for the specific environment
35+
> platformio run -e esp32dev --target upload
36+
37+
# Clean build files
38+
> platformio run --target clean
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
This directory is intended for project header files.
3+
4+
A header file is a file containing C declarations and macro definitions
5+
to be shared between several project source files. You request the use of a
6+
header file in your project source file (C, C++, etc) located in `src` folder
7+
by including it, with the C preprocessing directive `#include'.
8+
9+
```src/main.c
10+
11+
#include "header.h"
12+
13+
int main (void)
14+
{
15+
...
16+
}
17+
```
18+
19+
Including a header file produces the same results as copying the header file
20+
into each source file that needs it. Such copying would be time-consuming
21+
and error-prone. With a header file, the related declarations appear
22+
in only one place. If they need to be changed, they can be changed in one
23+
place, and programs that include the header file will automatically use the
24+
new version when next recompiled. The header file eliminates the labor of
25+
finding and changing all the copies as well as the risk that a failure to
26+
find one copy will result in inconsistencies within a program.
27+
28+
In C, the usual convention is to give header files names that end with `.h'.
29+
It is most portable to use only letters, digits, dashes, and underscores in
30+
header file names, and at most one dot.
31+
32+
Read more about using header files in official GCC documentation:
33+
34+
* Include Syntax
35+
* Include Operation
36+
* Once-Only Headers
37+
* Computed Includes
38+
39+
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

0 commit comments

Comments
 (0)