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
18 changes: 18 additions & 0 deletions ports/esp32/boards/CM_-CombinedS3CH340/board.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"vendor": "CircuitMess",
"product": "ESP32S3 CH340 Devices",
"thumbnail": "",
"url": "https://circuitmess.com/",
"images": [],

"docs": "",
"mcu": "esp32s3",
"features": [
"USB-C",
"BLE",
"WiFi"
],
"deploy": [
"../deploy_s3.md"
]
}
3 changes: 3 additions & 0 deletions ports/esp32/boards/CM_-CombinedS3CH340/board.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The following files are daily firmware for ESP32-based boards without external SPIRAM.

This firmware is compiled using ESP-IDF v4.x. Some older releases are also provided that are compiled with ESP-IDF v3.x.
4 changes: 4 additions & 0 deletions ports/esp32/boards/CM_-CombinedS3CH340/manifest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include("$(PORT_DIR)/boards/manifest.py")

package("ButterBotCtrl", base_path="$(PORT_DIR)/libraries")
package("ButterBot", base_path="$(PORT_DIR)/libraries")
9 changes: 9 additions & 0 deletions ports/esp32/boards/CM_-CombinedS3CH340/mpconfigboard.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
set(IDF_TARGET esp32s3)

set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
boards/sdkconfig.ble
boards/CM_-CombinedS3CH340/sdkconfig.board
)

set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
9 changes: 9 additions & 0 deletions ports/esp32/boards/CM_-CombinedS3CH340/mpconfigboard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#define MICROPY_HW_BOARD_NAME "CircuitMess ESP32S3 CH340 Devices"
#define MICROPY_HW_MCU_NAME "ESP32S3"

#define MICROPY_PY_MACHINE_DAC (0)

// Enable UART REPL for modules that have an external USB-UART and don't use native USB. - set to 1 to enable
// These devices route USB-C through an onboard CH340 to UART0; the S3's native USB pins
// (GPIO19/20) are repurposed as regular GPIOs.
#define MICROPY_HW_ENABLE_UART_REPL (1)
7 changes: 7 additions & 0 deletions ports/esp32/boards/CM_-CombinedS3CH340/sdkconfig.board
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_AFTER_NORESET=y

CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=
16 changes: 16 additions & 0 deletions ports/esp32/boards/CM_ButterBot/board.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"vendor": "CircuitMess",
"product": "Butter Bot",
"thumbnail": "",
"url": "https://circuitmess.com/",
"images": [],

"docs": "",
"mcu": "esp32s3",
"features": [
"USB-C"
],
"deploy": [
"../deploy_s3.md"
]
}
3 changes: 3 additions & 0 deletions ports/esp32/boards/CM_ButterBot/board.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The following files are daily firmware for ESP32-based boards without external SPIRAM.

This firmware is compiled using ESP-IDF v4.x. Some older releases are also provided that are compiled with ESP-IDF v3.x.
3 changes: 3 additions & 0 deletions ports/esp32/boards/CM_ButterBot/manifest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include("$(PORT_DIR)/boards/manifest.py")

package("ButterBot", base_path="$(PORT_DIR)/libraries")
9 changes: 9 additions & 0 deletions ports/esp32/boards/CM_ButterBot/mpconfigboard.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
set(IDF_TARGET esp32s3)

set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
boards/sdkconfig.ble
boards/CM_ButterBot/sdkconfig.board
)

set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
12 changes: 12 additions & 0 deletions ports/esp32/boards/CM_ButterBot/mpconfigboard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#define MICROPY_HW_BOARD_NAME "CircuitMess Butter Bot"
#define MICROPY_HW_MCU_NAME "ESP32S3"

#define MICROPY_PY_MACHINE_DAC (0)

#define MICROPY_HW_I2C0_SCL (48)
#define MICROPY_HW_I2C0_SDA (47)

// Enable UART REPL for modules that have an external USB-UART and don't use native USB. - set to 1 to enable
// Butter Bot has no native USB (GPIO19/20 are used as the accelerometer and motor base board
// interrupts); its USB-C routes through an onboard CH340 to UART0.
#define MICROPY_HW_ENABLE_UART_REPL (1)
9 changes: 9 additions & 0 deletions ports/esp32/boards/CM_ButterBot/sdkconfig.board
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_AFTER_NORESET=y

CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions/noota_4MB.csv"
16 changes: 16 additions & 0 deletions ports/esp32/boards/CM_ButterBotCtrl/board.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"vendor": "CircuitMess",
"product": "Butter Bot Controller",
"thumbnail": "",
"url": "https://circuitmess.com/",
"images": [],

"docs": "",
"mcu": "esp32s3",
"features": [
"USB-C"
],
"deploy": [
"../deploy_s3.md"
]
}
3 changes: 3 additions & 0 deletions ports/esp32/boards/CM_ButterBotCtrl/board.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The following files are daily firmware for ESP32-based boards without external SPIRAM.

This firmware is compiled using ESP-IDF v4.x. Some older releases are also provided that are compiled with ESP-IDF v3.x.
3 changes: 3 additions & 0 deletions ports/esp32/boards/CM_ButterBotCtrl/manifest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include("$(PORT_DIR)/boards/manifest.py")

package("ButterBotCtrl", base_path="$(PORT_DIR)/libraries")
9 changes: 9 additions & 0 deletions ports/esp32/boards/CM_ButterBotCtrl/mpconfigboard.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
set(IDF_TARGET esp32s3)

set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
boards/sdkconfig.ble
boards/CM_ButterBotCtrl/sdkconfig.board
)

set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
9 changes: 9 additions & 0 deletions ports/esp32/boards/CM_ButterBotCtrl/mpconfigboard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#define MICROPY_HW_BOARD_NAME "CircuitMess Butter Bot Controller"
#define MICROPY_HW_MCU_NAME "ESP32S3"

#define MICROPY_PY_MACHINE_DAC (0)

// Enable UART REPL for modules that have an external USB-UART and don't use native USB. - set to 1 to enable
// Butter Bot Controller has no native USB (GPIO19/D- is used as the battery calibration
// reference); its USB-C routes through an onboard CH340 to UART0.
#define MICROPY_HW_ENABLE_UART_REPL (1)
9 changes: 9 additions & 0 deletions ports/esp32/boards/CM_ButterBotCtrl/sdkconfig.board
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_AFTER_NORESET=y

CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions/noota_4MB.csv"
116 changes: 116 additions & 0 deletions ports/esp32/libraries/ButterBot/Motors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import time
import ustruct
from machine import I2C, Timer
from micropython import const


class Motor:
Left = const(0)
Right = const(1)


class Motors:
REG_IDENTIFY = 0x00
REG_RESET = 0x01
REG_MOTOR_L = 0x02

# The base board stops both motors if it doesn't receive a motor command within 500ms
# (dead-man switch), so the current speeds are re-sent every 250ms while any motor is running.
RESEND_PERIOD = 250

# Setup time needed between a reset and the following command [ms]
RESET_DELAY = 200

def __init__(self, bus: I2C, addr: int = 0x69, timer_id: int = 0):
self.bus = bus
self.addr = addr
self.timer = Timer(timer_id)
self.__values = [0] * 2

def begin(self) -> bool:
try:
ident = self.bus.readfrom_mem(self.addr, self.REG_IDENTIFY, 1)[0]
except OSError:
print("Motor base board not responding on address", self.addr)
return False

if ident != self.addr:
print("Motor base board ID mismatch: expected", self.addr, ", got", ident)
return False

self.timer.deinit()
self.__values = [0, 0]

# Reset is a bare command byte with no register data
self.bus.writeto(self.addr, bytes([self.REG_RESET]))
time.sleep_ms(self.RESET_DELAY)

return True

def set(self, motor: int, value: int):
if motor < 0 or motor >= 2:
return

value = min(max(value, -100), 100)
if value == self.__values[motor]:
return

self.__values[motor] = value
self.__send()

def get(self, motor: int):
if motor < 0 or motor >= 2:
return 0

return self.__values[motor]

def set_left(self, value: int):
self.set(Motor.Left, value)

def set_right(self, value: int):
self.set(Motor.Right, value)

def get_left(self):
return self.get(Motor.Left)

def get_right(self):
return self.get(Motor.Right)

def set_all(self, val: int | [int] | (int, int)):
if type(val) == int:
self.set_all((val, val))
return

if type(val) == tuple or type(val) == list:
if len(val) != 2:
return

values = [min(max(v, -100), 100) for v in val]
if values == self.__values:
return

self.__values = values
self.__send()

def get_all(self):
return tuple(self.get(i) for i in range(2))

def stop_all(self):
self.set_all((0, 0))

def __send(self):
self.__write()

if self.__values[Motor.Left] == 0 and self.__values[Motor.Right] == 0:
self.timer.deinit()
else:
self.timer.init(mode=Timer.PERIODIC, period=self.RESEND_PERIOD, callback=self.__resend)

def __resend(self, timer):
self.__write()

def __write(self):
# Motor direction is inverted between the user-facing API and the base board.
# Both motor registers are written in a single sequential transfer.
data = ustruct.pack("<bb", -self.__values[Motor.Left], -self.__values[Motor.Right])
self.bus.writeto_mem(self.addr, self.REG_MOTOR_L, data)
58 changes: 58 additions & 0 deletions ports/esp32/libraries/ButterBot/Pins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from micropython import const


class Pins:
BTN_POWER: int = const(0)
I2C_SDA: int = const(1)
I2C_SCL: int = const(2)
PIN_PWDN: int = const(3)

# TCA9555 expander pins (not ESP32 GPIOs - don't pass these to get())
EXP_LED: int = const(0)
EXP_SD_MODE: int = const(4)

Rev1Map = {
BTN_POWER: const(42),
I2C_SDA: const(47),
I2C_SCL: const(48),
PIN_PWDN: const(4),
}

def __init__(self, revision):
self.currentMap = None
if revision == 0:
self.currentMap = self.Rev1Map
else:
print("Unknown revision", revision)

def get(self, pin: int) -> int:
if not pin in self.currentMap:
print("Pin", pin, "not in map")
return -1
return self.currentMap[pin]


class Buttons:
Power: int = const(0)

def __init__(self, pins: Pins):
# Maps Buttons [0] to their respective GPIO pins
self.Pins: [int] = const([
pins.get(Pins.BTN_POWER)
])

def get_pins_array(self) -> [int]:
return self.Pins


class LEDs:
Status: int = const(0)

def __init__(self, pins: Pins):
# Maps LEDs to their respective TCA9555 expander pins
self.pins: [int] = const([
Pins.EXP_LED
])

def get_pins_array(self) -> [int]:
return self.pins
22 changes: 22 additions & 0 deletions ports/esp32/libraries/ButterBot/_LED.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from CircuitOS import PCA95XX


class LED:
def __init__(self, expander: PCA95XX, pins: [int]):
self.expander = expander
self.pins = pins

def set(self, led: int, value: int):
"""
@param led: LED from LEDs
@param value: value from 0 to 100. The LED is on the TCA9555 expander and can't be
dimmed - any value above 0 turns it on
"""
if led < 0 or led >= len(self.pins):
return

self.expander.pin_write(self.pins[led], value > 0)

def set_all(self, value: int):
for pin in self.pins:
self.expander.pin_write(pin, value > 0)
Loading