Banana Pi BPi-Leaf-S3
An inexpensive development system based on ESP32S3 SiC intended for the development of IoT applications.
Pros
- Feather-like set of IO
- Good compatibility with third-party HALs
Cons
- No significant disadvantages here!
Sinovoip’s Banana Pi family has gotten another interesting member alongside of BPi-PicoW-S3. In our hands today is an MCU development board with the newest Espressif ESP32-S3 SoC – a dual-core Xtensa LX7-based chip clocked at 240MHz. The board’s called BPI-Leaf-S3 and shares the form factor of Espressif’s own ESP32-S3-DevKitC-1 system, with which it shares the pinout. This does make it a drop-in replacement for the latter in projects. There’s 512kB RAM and 2MB pseudo-SRAM, alongside 8MB of external Serial NOR Flash.
ESP32-S3 SoC, like all ESP32 chipsets, has integrated radios – namely the 2.4 GHz, 802.11 b/g/n Wi-Fi and Bluetooth 5 (supporting the Low Energy Physical Layer – with long range and fast 2 Mbps data transfer). Out of the 45 GPIO pins available on the SoC, the board breaks out 36 (among which pins with specialised SPI, I2S, I2C, PWM, RMT, ADC, UART, SD/MMC host and TWAITM functions are available).
The board also features RST and BOOT keys as well as one Neopixel RGB LED on pin 48. What sets the Leaf apart is the USB Type-C connector, a 3.7V Li-ion battery port (with a charging circuit – akin to those Adafruit’s Feather boards have) and a separate four-pin I2C (GND, 3V3, SDA, SCL) connector for attaching hardware to the main SoC serial bus.
![]() |
![]() |
Like all ESP32-based boards, the Leaf can be programmed using Espressif’s own Eclipse-based IDE. This gives low-level control over every aspect of the hardware and is ideal for developing demanding applications. For users coming from STEM backgrounds, accustomed to Adafruit CircuitPython, the board ships with the interpreter pre-installed. The board also supports code written in Processing using the Arduino IDE – which is bound to please the more experienced members in the maker community accustomed to C, and vanilla MicroPython support is also available with a custom boot loader available for download at Banana Pi’s GitHub.
For purposes of demonstrating basic capabilities of the system, we wrote a little demo project in MicroPython for driving a simple 8-segment LED display. We connected it to pins 1 through 8 of the board and wrote a driver program which is capable of sequentially parsing strings and integers and showing them on the segmented display. It’s an elegant bit of code primarily aimed at showcasing the level of code abstraction possible with such a development kit.
Overall, we opine that the BPi-Leaf-S3 is a trustworthy and powerful system which comes at a very affordable price, well supported by various IDEs. It’s based on the popular ESP32 platform – which gives it a wealth of community support, as well.
from machine import Pin, PWM import time import sys #Pin list for digits pinList = [[1,2,3,4,6,7],[4,6],[1,3,4,5,7],[1,4,5,6,7],[2,4,5,6],[1,2,5,6,7],[1,2,3,5,6,7],[1,4,6],[1,2,3,4,5,6,7],[1,2,4,5,6,7]] ############# #Driver code# ############# #Pin setup for i in range (1,9): globals()[f"PWM_LED{i}"] = PWM(Pin(i)) #Global dictionary used for dynamic global variable generation globals()[f"PWM_LED{i}"].freq(1000) globals()[f"PWM_LED{i}"].duty(0) #Clear routine def clearDisplay(): for i in range (1,9): globals()[f"PWM_LED{i}"].duty(0) #Digit display - use when dimming effects or custom timings required def displayDigit(n, dot, dutyCycle): if n in range (0,10) and dot in range (0,2): #Check if arguments in range to prevent variable naming errors clearDisplay() #Clear display in case something was displayed before for i in pinList[n]: globals()[f"PWM_LED{i}"].duty(dutyCycle) if dot == 1: #Dot as argument PWM_LED8.duty(dutyCycle) elif str(n) == '-': #Stringify n for data integrity clearDisplay() PWM_LED5.duty(dutyCycle) else: #If not, safely handle error raise Exception("displayDigit error (could be caused by arguments out of bounds or program termination).") #Number display as a wrapper for displayDigit command def displayNumber(n, dot, dutyCycle, ms, pre_ms=50): #Optional pre_ms argument for predelay settings, automatically set to 50 try: #Try if int; exception catches for logic if string numList = [int(x) for x in str(n)] #Turns an integer into a list of its digits, e.g. 429 -> [4,2,9] except ValueError: #If argument is string, do whatever it needs to make above command accept this input numList = [] for x in n: try: numList.append(int(x)) except ValueError: numList.append(x) for i in numList: #Iterate through list and pass i as argument into the displayDigit command try: #No argument check in wrapper command as subcommand performs these, try method required to pass exception along clearDisplay() time.sleep_ms(pre_ms) displayDigit(i, dot, dutyCycle) time.sleep_ms(ms) except: raise Exception("displayNumber error (could be caused by arguments out of bounds or program termination).") ########### #Main code# ########### while True: displayNumber("17-12-1973",0,1023,750)
- Youyeetoo X1 review - 04/09/2024
- NVIDIA Announces Project GR00T - 03/21/2024
- Staying in Sync: NVIDIA Combines Digital Twins With Real-Time AI for Industrial Automation - 03/21/2024