Skip to content

Commit 08b84cf

Browse files
authored
Powerloop UART Flashing (#3661)
* working * cleanup * wip * auto flashing * linting * bug fixes * comments added * linting
1 parent 2047239 commit 08b84cf

5 files changed

Lines changed: 141 additions & 15 deletions

File tree

src/software/embedded/ansible/playbooks/deploy_powerboard.yml

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,25 @@
1111
become_method: ansible.builtin.sudo
1212
ansible.posix.synchronize:
1313
src: ../../../../../power/powerloop.tar.gz
14-
dest: ~/
14+
dest: /home/{{ ansible_user }}/
1515
recursive: true
1616
copy_links: true
1717

1818
- name: Untar powerboard files
19-
ansible.builtin.shell: "mkdir -p powerloop && tar -xzf ~/powerloop.tar.gz -C powerloop"
19+
ansible.builtin.shell: "mkdir -p powerloop && tar -xzf /home/{{ ansible_user }}/powerloop.tar.gz -C powerloop"
2020
register: result
2121
changed_when: true
2222
args:
23-
chdir: ~/
24-
25-
- name: Put the powerboard in bootloader mode
26-
ansible.builtin.pause:
27-
prompt: "Press enter to continue"
28-
echo: false
23+
chdir: /home/{{ ansible_user }}/
2924

3025
- name: Flashing... (this will take a while on the first run)
31-
ansible.builtin.command: "/opt/tbotspython/bin/platformio run --disable-auto-clean -t nobuild -t upload -d ~/powerloop/powerloop_main_workdir"
26+
become: true
27+
become_method: ansible.builtin.sudo
28+
ansible.builtin.command: >
29+
/opt/tbotspython/bin/platformio run
30+
--disable-auto-clean
31+
-t nobuild
32+
-t upload
33+
-d /home/{{ ansible_user }}/powerloop/powerloop_main_workdir
3234
register: result
3335
changed_when: true
34-
35-
- name: Reset powerboard to finish flashing
36-
ansible.builtin.pause:
37-
prompt: "Press enter to continue"
38-
echo: false

src/software/embedded/linux_configs/pi/config.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,4 @@ otg_mode=1
4848
[all]
4949
dtparam=pciex1
5050
dtoverlay=spi0-5cs
51+
dtoverlay=uart0-pi5

src/software/embedded/setup_robot_software_deps.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ set -ex
55
host_software_packages=(
66
device-tree-compiler
77
curl
8+
libssl-dev
9+
libffi-dev
10+
zlib1g-dev
11+
libbz2-dev
12+
libreadline-dev
13+
libsqlite3-dev
14+
libncursesw5-dev
15+
tk-dev
16+
libgdbm-dev
17+
libc6-dev
18+
liblzma-dev
819
)
920

1021
# Install packages
@@ -25,4 +36,21 @@ sudo make altinstall
2536

2637
if ! sudo /usr/local/bin/python3.12 -m venv /opt/tbotspython ; then
2738
echo "Error: Installing Python 3.12 failed"
39+
exit 1
2840
fi
41+
42+
sudo chown -R $USER:$USER /opt/tbotspython
43+
44+
# install PlatformIO to global environment
45+
curl -fsSL -o /tmp/tbots_download_cache/get-platformio.py https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py
46+
if ! /usr/local/bin/python3.12 /tmp/tbots_download_cache/get-platformio.py; then
47+
echo "Error: Installing PlatformIO failed"
48+
exit 1
49+
fi
50+
51+
# link platformio to /opt/tbotspython/bin so that bazel can find it
52+
ln -s $HOME/.platformio/penv/bin/platformio /opt/tbotspython/bin/platformio
53+
54+
# Programmatically enable serial communication for UART
55+
sudo raspi-config nonint do_serial_hw 0
56+
sudo raspi-config nonint do_serial_cons 1

src/software/power/BUILD

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ platformio_project(
6868
build_flags = ["-DPB_FIELD_32BIT=1"], #Makes platformio use 16 bit numbers for size
6969
framework = "arduino",
7070
lib_deps = ["Nanopb@^0.4.91"],
71-
platform = "espressif32",
71+
platform = "espressif32\nupload_port = /dev/ttyAMA0\nboard_upload.before_reset = no_reset",
7272
deps = [
7373
":charger",
7474
":chicker",
@@ -82,11 +82,17 @@ platformio_project(
8282
],
8383
)
8484

85+
# Integrates automatic bootloader mode / completion reset
8586
genrule(
8687
name = "powerloop_tar",
88+
srcs = ["auto_reset.py"],
8789
outs = ["powerloop.tar.gz"],
8890
cmd = """
8991
TARGET_DIR=$$(dirname $(location :powerloop_main))
92+
cp $(location :auto_reset.py) "$$TARGET_DIR/powerloop_main_workdir/"
93+
chmod +w "$$TARGET_DIR/powerloop_main_workdir/platformio.ini"
94+
echo "" >> "$$TARGET_DIR/powerloop_main_workdir/platformio.ini"
95+
echo "extra_scripts = pre:auto_reset.py" >> "$$TARGET_DIR/powerloop_main_workdir/platformio.ini"
9096
tar -C "$$TARGET_DIR" -czhf $@ "powerloop_main_workdir"
9197
""",
9298
local = True,

src/software/power/auto_reset.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
Import("env")
2+
import time
3+
import os
4+
import subprocess
5+
from enum import Enum
6+
7+
BOOT_GPIO = 24
8+
RESET_GPIO = 23
9+
10+
"""
11+
This script is deployed onto the remote device and configures automatic reset/boot for the target esp32 to be flashed.
12+
"""
13+
14+
15+
class PinState(Enum):
16+
LOW = 0
17+
HIGH = 1
18+
19+
20+
def sysfs_gpio(pin, value) -> None:
21+
"""Configures the pin and sets the value of the GPIO pin using the file system
22+
:param pin: Target pin
23+
:param value: Value to set to
24+
"""
25+
if not os.path.exists(f"/sys/class/gpio/gpio{pin}"):
26+
with open("/sys/class/gpio/export", "w") as f:
27+
f.write(str(pin))
28+
time.sleep(0.1)
29+
with open(f"/sys/class/gpio/gpio{pin}/direction", "w") as f:
30+
f.write("out")
31+
with open(f"/sys/class/gpio/gpio{pin}/value", "w") as f:
32+
f.write(str(value.value))
33+
34+
35+
def set_gpio(pin, value) -> None:
36+
"""Sets the value of the given GPIO pin. Uses High or Low only on fallback.
37+
:param pin: Pin to set
38+
:param value: Value to set to
39+
"""
40+
try:
41+
sysfs_gpio(pin, value)
42+
except Exception:
43+
v = "dh" if value == PinState.HIGH else "dl"
44+
try:
45+
subprocess.run(
46+
["pinctrl", "set", str(pin), "op", v],
47+
check=True,
48+
stdout=subprocess.DEVNULL,
49+
stderr=subprocess.DEVNULL,
50+
)
51+
except Exception:
52+
subprocess.run(
53+
["raspi-gpio", "set", str(pin), "op", v],
54+
check=False,
55+
stdout=subprocess.DEVNULL,
56+
stderr=subprocess.DEVNULL,
57+
)
58+
59+
60+
def before_upload(source, target, env) -> None:
61+
"""Action to be run before firmware flashing.
62+
63+
:param source: Compiled firmware
64+
:param target: Build action name
65+
:param env: Environment variables
66+
"""
67+
print(
68+
f"Setting ESP32 to bootloader mode using GPIO {BOOT_GPIO} (BOOT) and GPIO {RESET_GPIO} (EN)..."
69+
)
70+
set_gpio(BOOT_GPIO, PinState.LOW)
71+
time.sleep(0.1)
72+
set_gpio(RESET_GPIO, PinState.LOW)
73+
time.sleep(0.1)
74+
set_gpio(RESET_GPIO, PinState.HIGH)
75+
time.sleep(0.5)
76+
set_gpio(BOOT_GPIO, PinState.HIGH)
77+
78+
79+
def after_upload(source, target, env) -> None:
80+
"""Action to be run after firmware flashing.
81+
82+
:param source: Compiled firmware
83+
:param target: Build action name
84+
:param env: Environment variables
85+
"""
86+
print("Resetting ESP32...")
87+
set_gpio(RESET_GPIO, PinState.LOW)
88+
time.sleep(0.1)
89+
set_gpio(RESET_GPIO, PinState.HIGH)
90+
91+
92+
# Attach pre-upload and post-upload hooks
93+
env.AddPreAction("upload", before_upload)
94+
env.AddPostAction("upload", after_upload)

0 commit comments

Comments
 (0)