This article is originally from the WeChat Official Account [PY Study Notes], and was further processed by user Wang Chuanfu. Together, they completed this article.
We are deeply grateful to both creators for their hard work and boundless creativity. Their joint efforts have made this article shine even brighter. We hereby express our sincere thanks to both creators for their precious contributions to the ecosystem and for promoting a culture of sharing through open-source sharing.
Original links:
Click to jump 1Click to jump 2
Preface
TIP
Have you ever dreamed of building your own smart surveillance system? Or imagined making a remote control that can transmit real-time images? Or wished for a practical portable camera to record the wonderful moments in life? Achieving all this is now within reach.
The camera expansion board designed for the LCSC ESP32S3 development board integrates an OV2640 camera, has the ability to read and write SD cards, and can display images on a screen in real time. Leveraging the convenience of MicroPython, even programming beginners can easily master it, allowing you to quickly get started with applications and stay at the forefront of implementing creative projects.
Feature-rich, unleash your creativity
- Hardware integration: A compact expansion board integrates the OV2640 camera, SD card slot, and display interface. It is not only easy to connect, but also has strong interoperability.
- Software support: We provide detailed MicroPython tutorials to help you quickly master image processing and data access.
- Case-driven learning: Through practical runnable project cases, you can experience the construction process of a wireless web monitor, an image transmission remote control, and a portable camera.
Project cases that break the boundaries of imagination
- Wireless web monitoring: Build a security monitoring system or baby monitor, so you can view your home situation in real time even when you are out.
- Image transmission remote control: Take traditional remote controls to a new level, transmitting image data in real time, making your remote control experience more intuitive and precise.
- Portable camera: Forget about heavy photography equipment, and use this lightweight camera to capture and share every trip and adventure.
Friendly step-by-step guidance, easy to master programming
Our tutorial will walk you through every key step, from hardware wiring to software programming. Whether you are a MicroPython beginner or an experienced developer, our step-by-step guidance can ensure that you successfully complete the project, while leaving room for extension and in-depth learning.
Code examples and visual results, inspiring your hands-on practice
To give you a more intuitive understanding of the role and results of each step, we provide detailed code examples and screenshots/videos of finished projects. You can see the meaning and output behind each line of code in real time, making learning a rewarding experience.
1. Hardware Design
1.1 Component Selection
1.1.1 Camera
The camera used is the OV2640, a popular low-cost CMOS camera sensor produced by OmniVision Technologies. It is a 2-megapixel sensor; there is also a 5640 version with 5 megapixels. It is commonly used in embedded systems and small camera projects, such as drones, mobile phones, webcams, and other portable devices. Due to its small size and high integration, the OV2640 is particularly suitable for space-constrained designs.
The OV2640 can provide resolutions up to 1600x1200 pixels. It supports JPEG compression output, and can also provide YUV422, YUV420, and RGB565 format outputs. These features make it very adaptable to a variety of graphics interfaces and microcontrollers. It also features automatic exposure control, automatic gain control, automatic white balance, and more. It can be configured through the SCCB (Serial Camera Control Bus) interface, which is a communication protocol similar to I2C.
The basic features of the OV2640 are:
- Image sensor: 1/4" CMOS 2MP
- Resolution: up to 1600x1200
- Photo format: JPEG, YUV (422/420), RGB565, etc.
- Viewing angle: can be obtained through different lenses (usually standard, wide-angle, etc.)
- Interface: SCCB (control), DVP (Digital Video Port)
- Special features: automatic exposure control, automatic gain control, automatic white balance, etc.
The OV2640 camera module is usually equipped with the following interfaces:
- SCCB interface, used to control camera settings.
- DVP interface, used to transmit image data.
- Clock input (XCLK).
- Power input (3.3V supply and ground).
- Reset signal (RESET).
- Power down (PWDN, Power Down).
The OV2640 camera driver circuit generally includes the following parts:
Regulated power supply To ensure the stable operation of the OV2640, multiple stable power supplies are generally required. An LDO (Low Dropout Regulator) linear regulator may be used to step down from a higher voltage power supply (e.g., 5V or higher) to the 3.3V, 2.8V, or 1.2V required by the camera.
Clock source The camera module requires a high-frequency clock signal to drive its operation. This is usually provided through an external crystal oscillator (such as 12MHz or higher) or by the main controller. This clock signal is usually supplied to the XCLK pin of the camera module through a clock generation circuit.
Interface level matching If the I/O voltage of the main controller (such as the ESP32S3) is different from that of the camera module, a level conversion circuit is required to ensure signal level compatibility between the two, so that the SCCB and DVP interfaces can be safely connected without damaging the devices due to voltage issues.
When writing the driver, you need to initialize the camera module and configure the sensor's registers. This involves setting the resolution, image format, frame rate, and other camera features. Then, your program needs to receive frame data through the DVP interface, and process, display, or store this data.
1.1.2 SD Card
An SD card (Secure Digital Card) is a very popular storage medium, widely used in portable devices such as digital cameras, mobile phones, tablets, personal computers, and embedded systems. SD cards are based on flash memory technology, featuring high storage density, solid-state durability, and good data stability.
SD cards typically support three communication modes: 1-bit serial mode (SD mode), 4-bit serial mode (4-bit SD mode), and SPI mode. In embedded applications, especially in the microcontroller field, SPI mode is particularly popular because its interface is simple, has fewer wiring requirements, and has lower hardware requirements than SD mode.
An SD card controlled by the SPI protocol requires the following signal lines:
- CS (Chip Select) - Chip select. Through this signal, the master can select or ignore the SD card to enable or disable it.
- MOSI (Master Out Slave In) - Master output, SD card input. Used to send commands and data to the SD card.
- MISO (Master In Slave Out) - Master input, SD card output. The SD card sends data back to the master through this line.
- SCK (Serial Clock) - Serial clock. Used to synchronize data transmission.
- VCC - Supply voltage. SD cards generally use 3.3V power supply, but some modules have a 5V to 3.3V voltage converter.
- GND - Ground.
SD card driver circuit design generally involves the following parts:
- Power regulation: SD cards usually require a stable 3.3V power supply. If the system power is higher than this voltage, such as 5V, then an LDO or DC-DC converter is needed to step it down.
- Level conversion: If the microcontroller's I/O port is 5V and the SD card operates at 3.3V level, then the SPI communication lines (CS, MOSI, MISO, SCK) need a level conversion circuit to avoid damaging the SD card.
- Signal isolation: In some operating environments, to prevent signal interference and power noise, the signal lines may need to be isolated.
On the software side of driving the SD card, the program needs to communicate with the SD card through the SPI interface to send commands and read data. The driver must be able to initialize the card, identify its storage capacity, and read/write the file system.
In high-level programming environments such as MicroPython, there are usually ready-made libraries that can be used directly to handle SD cards, such as the machine.SDcard module, allowing developers to integrate SD card read/write functionality relatively easily. These libraries provide methods for opening, reading, writing, and closing files, and usually also support file system operations, such as creating and listing directories. With just a few lines of code, developers can store and retrieve files on the SD card.
When in use, ensure that the corresponding SPI communication pins are correctly configured, and that the correct commands are sent according to the SD card communication specification to ensure smooth data read/write operations.
1.1.3 Screen Display
In embedded systems, several common screens are mainly LCD (Liquid Crystal Display) and OLED (Organic Light-Emitting Diode) displays. Different types of displays differ in technical parameters, display effects, power consumption, and cost.
We chose a 2.4-inch 240x320 pixel LCD screen driven by the ST7789.
Purchase link: https://item.taobao.com/item.htm?_u=l2t4uge5dd15&id=758981467180&spm=a1z09.2.0.0.4fe32e8dFRJa8Y
Now, let's introduce the ST7789 TFT LCD in detail. The ST7789 is a common TFT LCD driver chip produced by Sitronix Technology Corporation. It is widely used in a variety of small displays, especially 2.4-inch RGB screens with a resolution of 320x240 pixels.
Features of the ST7789 display include:
- Resolution: The ST7789 controller is typically used for screens with 240x320 (QVGA) resolution.
- Color depth: Supports 16-bit (65K colors) and 18-bit (262K colors) modes.
- Size: The ST7789 controller is commonly equipped with screens of various sizes such as 1.44-inch, 1.8-inch, and 2.4-inch.
- Interface: Supports SPI interface, making it easy to connect with various microcontrollers. Some variants may also support parallel interfaces.
When communicating using the SPI protocol, the ST7789 screen requires the following signal lines:
- SCL (Serial Clock) - SPI clock line, controls the timing of data transmission.
- SDA (Serial Data) - SPI data line, used to send data to the display. Sometimes, the data line is split into two: SDI (input) and SDO (output).
- RS (Register Select) or DC (Data/Command) - Data/command control line, used to distinguish whether the SPI data sent is data or a command.
- CS (Chip Select) - Chip select control line, used to activate the SPI communication of the display.
- RST (Reset) - Control line used to hardware-reset the display.
- BLK (Backlight) - Backlight control line, used to turn on or adjust the screen backlight.
ST7789 driver circuit design usually includes:
- Power supply: The screen requires a 3.3V power supply. A regulated circuit should be used to ensure a stable voltage supply, avoiding voltage fluctuations that affect the display effect.
- Backlight control: Depending on specific needs, the backlight usually has a PWM dimming circuit for adjusting the screen's backlight brightness. Sometimes, simple on/off control can also turn the backlight on or off.
- Reset circuit: The RST pin may need a pull-up or pull-down resistor to ensure correct reset of the display at startup.
- Communication interface circuit: Ensure stable connection of the SPI interface pins.
Software drivers usually include initializing the display, configuring screen parameters (such as resolution, color mode), and functions for drawing pixels, text, and graphics. On many modern microcontroller platforms, such as those using the Arduino framework or MicroPython, you can find ST7789 libraries. These libraries have already implemented the basic control functions related to the screen. Developers only need to simply configure the screen parameters and SPI communication settings, and then they can control the screen display content by calling the corresponding library functions.
1.2 Schematic Design
1.2.1 Camera Peripheral Hardware Circuit

1.2.2 SD Card Slot Interface Circuit
1.2.3 LCD Display Circuit
1.3 PCB Design
【ProProject_Camera_Expansion_Board_2024-04-12.epro】 Download
📌 Download Center (click to jump)
📌 In Download Center -> Beginner Manual Documentation Baidu Netdisk link -> Chapter 08. [LCSC ESP32S3R8N8] Project Cases -> Camera Expansion Board for the ESP32S3 Development Board.
Import the above .epro file into JLCEDA Pro to see the schematic and PCB.
2. Firmware Compilation
2.1 Environment Setup
2.1.1 Basic Environment Setup
Use VMware + Ubuntu 22.04.3 for environment setup. For installation of these two, refer to:
https://zhuanlan.zhihu.com/p/569274366
2.1.2 Firmware Environment Installation
Install dependency packages
Open the command line and enter the following command to install the dependency packages.
sudo apt-get install git wget libncurses-dev flex bison gperf python3 python3-pip python3-setuptools python3-serial python3-click python3-cryptography python3-future python3-pyparsing python3-pyelftools cmake ninja-build ccache libffi-dev libssl-dev python-is-python3pip source configuration
During the Esp-IDF installation process, pip is used in a python virtual environment to install the required packages. By default, pip uses the official source abroad, making the installation very slow. Use the following command to configure the pip source to Aliyun.
pip config set global.index-url http://mirrors.aliyun.com/pypi/simple
pip config set global.trusted-host mirrors.aliyun.com2
Download esp-idf and MicroPython
mkdir -p ~/esp
cd ~/esp
git clone https://gitee.com/EspressifSystems/esp-gitee-tools.git
git clone https://gitee.com/EspressifSystems/esp-idf.git
git clone https://github.com/micropython/micropython.git2
3
4
5
If git cloning micropython fails, use the following instead:
git clone https://gitee.com/yangyoulikedog/micropython.gitIf micropython really cannot be downloaded, copy the following file to ~/esp in the virtual machine, extract it, and rename it to micropython.
【micropython-master.zip】 Download
📌 Download Center (click to jump)
📌 In Download Center -> Beginner Manual Documentation Baidu Netdisk link -> Chapter 08. [LCSC ESP32S3R8N8] Project Cases -> Camera Expansion Board for the ESP32S3 Development Board.
Confirm the esp-idf version supported by MicroPython
Go to micropython/ports/esp32/README.md to confirm the supported version number:
Switch the ESP-IDF version
cd esp-idf
git checkout v5.0.42
Tip: HEAD is now at 5181de8ac5 versions: Update version to 5.0.4. This means success.
Configure esp-idf
First update the submodules: There must be no errors when executing the following command!! If there are errors, re-execute.
git submodule update --init --recursiveIf the above command fails, the prompt is:
Then proceed to the next step first.
To solve the problem of slow cloning of esp-related repositories from github for domestic developers, the official has mirrored esp-idf and some important repositories and their associated submodules to jihu. According to official recommendations, use the following commands to replace the repository URLs with jihu URLs, and update the submodules to complete the installation.
cd ~/esp/esp-gitee-tools
./jihu-mirror.sh set
./submodule-update.sh ~/esp/esp-idf/
./install.sh ~/esp/esp-idf/2
3
4
It may prompt that the Python virtual environment was not installed successfully. Follow the suggestion to execute the following command and reinstall.
sudo apt install python3.10-venv
./install.sh ~/esp/esp-idf/2
After installing a bunch of things, it prompts:
All done! You can now run:
. /home/yle/esp/esp-idf/export.sh2
This means the installation was successful. Add the environment variables in the command line:
cd ~/esp/esp-idf
source export.sh2
Tip: idf.py build means success.
Note: The install.sh step only needs to be executed once. Every new session requires using export.sh.
2.2 Firmware Compilation
Build the firmware
Enter the following command in the command line:
cd ~/esp/micropython
make -C mpy-cross
cd ports/esp32
make submodules
make2
3
4
5
If all goes well, a firmware.bin firmware will be generated in ~/esp/micropython/ ports/esp32/build-ESP32_GENERIC/. However, errors usually occur during the make submodules and make commands. Here, you need to ensure that the versions of micropython and esp-idf are consistent. Otherwise, the command git submodule update --init --recursive was not done properly. If it cannot be fixed, change the version.
git checkout v5.0.4, change to the other version, for example, the previously seen one can be v5.1.2.
Add camera firmware
2.2.1 Download the IDF environment camera driver
cd ~/esp/esp-idf/components
git clone https://github.com/espressif/esp32-camera2
2.2.2 Install the MicroPython camera driver
cd ~/esp/esp-idf/components
git clone https://github.com/espressif/esp32-camera2
If git clone https://github.com/lemariva/micropython-camera-driver fails, download the following file:
【micropython-camera-driver-master.zip】 Download
📌 Download Center (click to jump)
📌 In Download Center -> Beginner Manual Documentation Baidu Netdisk link -> Chapter 08. [LCSC ESP32S3R8N8] Project Cases -> Camera Expansion Board for the ESP32S3 Development Board.
Extract it to ~/esp/micropython/ports/esp32:
Create a new cam folder under ~/esp/micropython/examples/usercmodule/, and copy the 4 files micropython.cmake, micropython.mk, modcamera.c, modecamera.h from micropython-camera-driver/src to the cam folder.
2.2.3 ST7789 Driver Installation
The ST7789 driver is in C language and can only be used by compiling it into the firmware.
First git clone the library:
git clone https://github.com/russhughes/st7789_mpy.gitIf the download fails, please download the following file.
【st7789_mpy-master.zip】 Download
📌 Download Center (click to jump)
📌 In Download Center -> Beginner Manual Documentation Baidu Netdisk link -> Chapter 08. [LCSC ESP32S3R8N8] Project Cases -> Camera Expansion Board for the ESP32S3 Development Board.
Place the entire st7789 folder from the st7789_mpy files into the usercmodules directory:
~/esp/micropython/examples/usercmodules/This time, you need to compile both the camera driver and the ST7789 driver into the firmware simultaneously. You need to edit the micropython.cmake file in the usercmodules folder to make both drivers take effect simultaneously:
Enable the default 8M PSRAM. In the file at the path shown below:
In set SDKCONFIG_DEFAULTS, add boards/sdkconfig.spiram_oct. The result is as follows:
2.2.4 Compile the ESP32-S3 Firmware
By default, esp-idf compiles ESP32 firmware. To compile ESP32-S3 firmware, you need to modify the Makefile. Open the Makefile file under ~/esp/micropython/ports/esp32, and change BOARD ?= ESP32_GENERIC on line 12 to BOARD ?= ESP32_GENERIC_S3.
Add the camera module to micropython
Modify modcamera.c in the camera module, and delete #if MODULE_CAMERA_ENABLED on line 24.
Note: modify the file under the ~/esp/micropython/examples/usercmodule/cam path!
Delete the #endif on the last line, and change the second-to-last line MP_REGISTER_MODULE(MP_QSTR_camera, mp_module_camera_system, MODULE_CAMERA_ENABLED); to:
MP_REGISTER_MODULE(MP_QSTR_camera, mp_module_camera_system);Finally, compile the firmware:
Successful compilation result:
At this point, a firmware.bin firmware will be generated in ~/esp/micropython/ ports/esp32/build-ESP32_GENERIC_S3/. This firmware is the micropython firmware we compiled. The burning address is 0x0.
2.3 Firmware Burning Verification
2.3.1 Firmware Burning
For firmware burning, please refer to Section 1.2 Burning Firmware of the Environment Setup chapter in the MicroPython Beginner Manual: MicroPython Beginner Manual
Replace the firmware with our own compiled firmware. The burning address is 0x0.
If your firmware compilation fails, you can use the following firmware.
【LCKFB_MicroPython_cam_st7789_8Mpsram_20240221.bin】 Download
📌 Download Center (click to jump)
📌 In Download Center -> Beginner Manual Documentation Baidu Netdisk link -> Chapter 08. [LCSC ESP32S3R8N8] Project Cases -> Camera Expansion Board for the ESP32S3 Development Board.
2.3.2 Firmware Verification
Verify that it supports both the camera and st7789 drivers, and supports SPIRAM and 16M FLASH: Connect the development board to Thonny, and enter the following code in the command console window at the bottom:
import camera
import st7789
import micropython
import esp
micropython.mem_info()
esp.flash_size()/1024/10242
3
4
5
6
If successful, it will display normally as follows:
3. Screen Display
3.1 API Introduction
Screen initialization settings
st7789.ST7789(spi, width, height, dc, reset, cs, backlight, rotations, rotation, custom_init, color_order, inversion, options, buffer_size)
Required positional parameters:
- spi: SPI device
- width: display width
- height: display height
Required keyword parameters:
- dc: Sets the pin connected to the display's data/command select input. This parameter is always required.
Optional keyword parameters:
- reset: Sets the pin connected to the display's hardware reset input. If the display's reset pin is high, the
resetparameter is not required. - cs: Sets the pin connected to the display's chip select input. If the display's CS pin is low, the display must be the only device connected to the SPI port. The display will always be the selected device, and this parameter is not required.
- backlight: Sets the pin connected to the display's backlight enable input. The display's backlight input can usually be left floating or disconnected, because the backlight on some displays is always on and cannot be turned off.
- rotations: Sets the orientation table. The orientation table is a list of tuples used to set the MADCTL register, display width, display height, start_x, and start_y values.
The st7789 and st7735 packages include default rotations for the following display sizes:
You can define as many rotations as you need.
- rotation: Sets the display rotation according to the orientation table. The default orientation table defines 240x320, 240x240, 134x240, 128x160, and 128x128 displays with the LCD ribbon cable at the bottom of the display. The default rotation is portrait (0 degrees).
- custom_init: A list of display configuration commands sent to the display during display init(). The list contains tuples with bytes objects, optionally followed by a delay specified in ms. The first byte of the first bytes object contains the command to send (optional), followed by data bytes. See the file or examples.
- color_order: Sets the color order for the driver (st7789.RGB or st7789.BGR).
- inversion: If set to True, sets the display color inversion mode; if False, no color inversion mode.
- options: Sets the driver option flags.
- buffer_size: If buffer_size is not specified, the buffer is dynamically allocated and freed as needed. If buffer_size is set, it must be large enough to contain the largest bitmap, font character, and decoded JPG image used (row column 2 bytes, 16-bit color in RGB565 notation). Dynamic allocation is slower and may cause heap fragmentation, so garbage collection (GC) should be enabled.
Screen initialization run
- init()
Must be called to initialize the display.
Color inversion display
inversion_mode(bool)
If bool is True, sets the display color inversion mode; if bool is False, no color inversion mode.
Query screen width and height
width()
Returns the current logical width of the display. (i.e., a 135x240 display rotated 90 degrees is 240 pixels wide)
height()
Returns the current logical height of the display. (i.e., a 135x240 display rotated 90 degrees is 135 pixels high)
Set screen rotation
rotation(r)
Sets the counterclockwise rotation of the logical display. 0 - Portrait (0 degrees), 1 - Landscape (90 degrees), 2 - Reverse Portrait (180 degrees), 3 - Reverse Landscape (270 degrees).
Backlight control
on()
If a backlight pin was defined during initialization, turns on the backlight.
off()
If a backlight pin was defined during initialization, turns off the backlight.
Sleep mode
sleep_mode(value)
If value is True, puts the display into sleep mode; if value is False, wakes it up. During sleep, the display content may not be preserved.
Full-screen color fill
- fill(color)
Fills the display with the specified color. Color reference:
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define PURPLE 0x780F // Purple
#define BROWN 0XBC40 // Brown
#define BRRED 0XFC07 // Brownish red
#define GRAY 0X8430 // Gray
#define DARKBLUE 0X01CF // Dark blue
#define LIGHTBLUE 0X7D7C // Light blue
#define GRAYBLUE 0X5458 // Gray blue
#define LIGHTGREEN 0X841F // Light green
#define LGRAY 0XC618 // Light gray (PANEL), window background color
#define LGRAYBLUE 0XA651 // Light gray blue (intermediate layer color)
#define LBBLUE 0X2B12 // Light brown blue (inverse color of selected item)2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Draw a point
- pixel(x, y, color)
Sets the specified pixel display position to the given color.
Draw a line
line(x0, y0, x1, y1, color) Draws a line of the specified color from the starting coordinate (x0,y0) to the ending coordinate (x1,y1).
hline(x, y, length, color)
Draws a horizontal line of the specified length with the starting coordinate (x,y) and the specified color. In addition, this is a fast version with fewer SPI calls.
- vline(x, y, length, color)
Draws a vertical line of the specified length with the starting coordinate (x,y) and the specified color.
Draw a rectangle
- rect(x, y, width, height, color)
Draws a hollow rectangle with the corresponding dimensions (width, height) starting from the coordinate (x,y).
- fill_rect(x, y, width, height, color)
Draws a filled rectangle with the corresponding dimensions (width, height) starting from the coordinate (x,y).
Draw a circle
- circle(x, y, r, color)
Draws a hollow circle with the center at coordinate (x,y), a radius of r, and the specified color.
- fill_circle(x, y, r, color)
Draws a filled circle with the center at coordinate (x,y), a radius of r, and the specified color.
Display a string
- text(font, s, x, y[, fg, bg])
Writes (integer, string, or bytes) using the specified bitmap, with the coordinate as the upper-left corner of the text.
- write(bitmap_font, s, x, y[, fg, bg, background_tuple, fill_flag])
Writes text to the display using the specified scaled bitmap or monospaced bitmap, with the coordinate as the upper-left corner of the text.
- write_len(bitap_font, s)
Returns the width (in pixels) of the string if printed with the specified font.
- draw(vector_font, s, x, y[, fg, scale])
Draws text to the display using the specified Hershey vector font, with the xy coordinate as the lower-left corner of the text.
- draw_len(vector_font, s[, scale])
Returns the width (in pixels) of the string if drawn with the specified font.
Display an image
- jpg(jpg, x, y [, method]) Draws a JPEG image on the display with the given coordinate as the upper-left corner of the image. Can be a string containing a filename or a buffer containing JPEG image data.
The memory required to decode and display a JPG can be considerable, since a full-screen 320x240 JPG requires at least 3100 bytes of working area + 320 * 240 * 2 RAM bytes for buffering the image.
- jpg_decode(jpg_filename [, x, y, width, height])
Decodes a jpg file and returns it or a portion of it as a tuple consisting of (buffer, width, height). The buffer is a color565 blit_buffer compatible byte array. The buffer requires width * height * 2 bytes of memory.
- png(png_filename, x, y [, mask])
Draws a PNG file on the display with the upper-left corner of the image at the given coordinate. If the PNG cannot fit entirely on the display, it will be clipped. The PNG is drawn one line at a time. Since the driver does not contain a frame buffer, transparency is not supported.
3.2 Screen Display Verification
Note that displaying characters requires uploading the following code to the development board's memory.
【vga1_16x16.py】 Download
📌 Download Center (click to jump)
📌 In Download Center -> Beginner Manual Documentation Baidu Netdisk link -> Chapter 08. [LCSC ESP32S3R8N8] Project Cases -> Camera Expansion Board for the ESP32S3 Development Board.
Run the following example code:
import machine
from machine import SPI,Pin,UART,PWM,SoftSPI
import time,camera,sdcard,st7789,os
import vga1_16x16 as font
machine.freq(240000000) # Set the CPU operating frequency to 240 MHz
# SPI initialization
spi=SPI(2,baudrate=40000000, sck=Pin(41), mosi=Pin(46), miso=Pin(48))
# Create a screen object, set the screen pins and parameters, and turn off color inversion
tft=st7789.ST7789(spi, 240, 320, reset=Pin(15, Pin.OUT), dc=Pin(42, Pin.OUT), cs=Pin(45, Pin.OUT),inversion=False)
# Screen initialization
tft.init()
# Color test
tft.fill(0xF800) # Full-screen refresh red
time.sleep(0.5) # Delay 500ms
tft.fill(0x07E0) # Full-screen refresh green
time.sleep(0.5) # Delay 500ms
tft.fill(0x001F) # Full-screen refresh blue
time.sleep(0.5) # Delay 500ms
# Draw point test
for i in range(100):
tft.pixel(i, i, 0xFFFF) # Draw white point
time.sleep(1)
# Draw line test
tft.line(20, 20, 200, 20, 0x0000) # Draw black line
time.sleep(1)
# Draw rectangle test
tft.rect(20, 30, 200, 20, 0xF800) # Draw red hollow rectangle
tft.fill_rect(25, 35, 190, 10, 0xF800) # Draw red filled rectangle
time.sleep(1)
# Draw circle test
tft.circle( int(240/2), int(320/2), 20, 0xFFE0) # Draw yellow hollow circle
tft.fill_circle( int(240/2), int(320/2), 10, 0xFFE0) # Draw yellow filled circle
time.sleep(1)
# String display test
tft.text(font, b'hello', 100, 100)
time.sleep(1)
# Screen rotation display test
tft.rotation(0)
tft.fill(0xFFFF)
tft.text(font, b'hello', 100, 100)
time.sleep(1)
tft.rotation(1)
tft.fill(0xFFFF)
tft.text(font, b'hello', 100, 100)
time.sleep(1)
tft.rotation(2)
tft.fill(0xFFFF)
tft.text(font, b'hello', 100, 100)
time.sleep(1)
tft.rotation(3)
tft.fill(0xFFFF)
tft.text(font, b'hello', 100, 100)
time.sleep(1)
# Image display test (requires camera connected)
camera.deinit()
try:
camera.init(0, d0=21, d1=17, d2=18, d3=16, d4=40, d5=38, d6=1, d7=3,
format=camera.JPEG, framesize=camera.FRAME_QVGA,
fb_location=camera.PSRAM,
xclk_freq=camera.XCLK_20MHz,
href=4, vsync=5, reset=-1, pwdn=-1,
sioc=6, siod=7, xclk=2, pclk=39)
except Exception as e:
camera.deinit()
camera.init(0, d0=21, d1=17, d2=18, d3=16, d4=40, d5=38, d6=1, d7=3,
format=camera.JPEG, framesize=camera.FRAME_QVGA,#320x240
#framesize=camera.FRAME_240X240,#240x240
fb_location=camera.PSRAM,
xclk_freq=camera.XCLK_20MHz,
href=4, vsync=5, reset=-1, pwdn=-1,
sioc=6, siod=7, xclk=2, pclk=39)
while True:
tft.jpg(camera.capture(), 0, 0)2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
Verification result:
4. SD Card Read/Write
In the MicroPython source code, there is source code for SD card operations.
Download the latest MicroPython sdcard driver code from the website https://github.com/micropython/micropython/tree/v1.19/drivers/sdcard.
If you cannot access the website, you can directly download the following file.
【sdcard.py】 Download
📌 Download Center (click to jump)
📌 In Download Center -> Beginner Manual Documentation Baidu Netdisk link -> Chapter 08. [LCSC ESP32S3R8N8] Project Cases -> Camera Expansion Board for the ESP32S3 Development Board.
Save the sdcard.py file to the ESP32S3 development board; (In Thonny, connect the development board, open the corresponding path of the sdcard.py file, right-click and select Upload to / to upload the file to the development board.)
4.1 API Introduction
SD card initialization
- classmachine.SDCard(slot=1, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, cs=None, freq=20000000)
This class provides access to SD or MMC memory cards via dedicated SD/MMC interface hardware or through an SPI channel. This class implements the block protocol defined by uos.AbstractBlockDev.
The constructor takes the following parameters:
- slot: Selects the available interface to use. Not setting this selects the default interface. We usually change it to the SPI interface.
- width: Selects the bus width of the SD/MMC interface.
- cd: Can be used to specify the card detect pin.
- wp: Can be used to specify the write protect pin.
- sck: Can be used to specify the SPI clock pin.
- miso: Can be used to specify the SPI miso pin.
- mosi: Can be used to specify the SPI mosi pin.
- cs: Can be used to specify the SPI chip select pin.
- freq: Selects the SD/MMC interface frequency in Hz (only supported on ESP32).
In the sdcard.py file, the official has already configured it for us. We only need to configure the pins.
For example, use software SPI to configure the SD card communication pins:
sd = sdcard.SDCard(SoftSPI(2, sck=Pin(13), mosi=Pin(12), miso=Pin(14)), Pin(11))SD card mount
- os.mount(fsobj, mount_point, *, readonly)
Mounts the file system object fsobj at the location in the path given by the mount_point string. fsobj is the object we get after calling sdcard.SDCard(). mount_point may be / to mount fsobj at the root directory, or a subdirectory /<name> under the root directory.
If the readonly parameter is True, the file system is mounted read-only.
During mounting, the mount() method is called on the file system object.
OSError(EPERM) is raised if mount_point is already mounted.
SD card unmount
- uos.umount(mount_point)
Unmounts a file system. mount_point can be a string naming the mount location, or a previously mounted file system object. During unmounting, the umount() method is called on the file system object.
If mount_point is not found, OSError(EINVAL) is raised.
In MicroPython, basic file operations are mainly implemented through the built-in open function, which can open a file at a specified path and return a file object. Then, you can use the file object's methods for reading, writing, and other operations.
Here are the common file operation steps:
Open file
file = open('example.txt', 'r')2
'r' stands for read mode.
Read file content
content = file.read() # Read the entire file
line = file.readline() # Read one line
lines = file.readlines() # Read all lines and return a list2
3
Write file content
file = open('example.txt', 'w') # 'w' stands for write mode, will overwrite existing content
file.write('Hello, World!') # Write string to file2
Append content to file
file = open('example.txt', 'w') # 'w' stands for write mode, will overwrite existing content
file.write('Hello, World!') # Write string to file2
Append content to file
file = open('example.txt', 'a') # 'a' stands for append mode
file.write('Hello, again!') # Append content at the end of the file2
Close file
file.close() # Close the file and release resourcesYou can also use the with statement to open a file. This ensures that the file is properly closed after use, even if an exception occurs during reading or writing:
with open('example.txt', 'r') as file:
content = file.read() # The file will be automatically closed after this with block ends2
The above are basic file operations. In practical use later, you will also encounter advanced operations such as file mode selection (e.g., text mode and binary mode), file pointer movement, and exception handling.
Note
After each file operation is completed, you must perform a close file operation. Otherwise, previous operations will be invalid, and it may cause file exceptions that prevent the file from being opened.
For more file operations, please refer to the official MicroPython documentation:
http://www.micropython.com.cn/en/latet/library/uos.html#filesystem-mounting
4.2 SD Card Read/Write Verification
Insert the SD card and run the following code:
import sdcard
from machine import SoftSPI, Pin
import os,time
# SD card initialization configuration
sd = sdcard.SDCard(SoftSPI(2, sck=Pin(13), mosi=Pin(12), miso=Pin(14)), Pin(11))
# Mount the SD card
os.mount(sd, '/sd')
# Open example.txt file and write. If it does not exist, create the file
file = open('/sd/example.txt', 'w') # 'w' stands for write mode, will overwrite existing content
file.write('Hello, World!') # Write string to file
file.close() # Close the file and release resources
# Open example.txt file and append write. If it does not exist, create the file
file = open('/sd/example.txt', 'a') # 'a' stands for append mode
file.write('Hello, again!') # Append content at the end of the file
file.close() # Close the file and release resources
# Open example.txt file and append write. If it does not exist, create the file
file = open('/sd/example.txt', 'r') # 'r' stands for read mode
content = file.read() # Read the entire file
print("content: " + content)
print('\n')
file.close() # Close the file and release resources
file = open('/sd/example.txt', 'r') # 'r' stands for read mode
line = file.readline() # Read one line
print("line: " + line)
print('\n')
file.close() # Close the file and release resources
file = open('/sd/example.txt', 'r') # 'r' stands for read mode
lines = file.readlines() # Read all lines and return a list
# Iterate through the list and print each line
print('lines:')
for line in lines:
print(line, end='') # Add the end='' parameter to prevent print from automatically adding extra newlines
print('\n')
file.close() # Close the file and release resources
# First open a file in read mode
with open('/sd/example.txt', 'r') as file:
# Loop to read each line
while True:
line = file.readline()
# If the end of the file is reached, stop the loop (when line is '')
if not line:
break
# Process the read line
print(line.strip()) # Print each line content, use strip() to remove trailing newline2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Verification result
Thonny console result
Result of the file in the SD card:
5. Image Acquisition
5.1 API Introduction
5.2 Image Acquisition Verification
6. Project Cases
6.1 Wireless Web Monitoring
Introduction
MicroPython currently has two web frameworks: microWebSrv and microdot. Since microWebSrv does not support ESP, we chose to learn how to use microdot.
microdot source code official open-source link:
https://github.com/miguelgrinberg/microdot
Microdot is a minimalist Python web framework inspired by Flask. It is designed as a lightweight web server, suitable for resource-constrained embedded devices, such as ESP32 and ESP8266. It requires very little RAM and storage space, and has low CPU consumption.
You can handle different URL requests by defining multiple routes. Each route consists of a URL path and a corresponding handler function. When a matching request is received, the server calls the corresponding handler function. Microdot also supports static file serving, allowing you to easily serve static files (such as HTML, CSS, JavaScript, images, etc.) to clients. You only need to specify a directory, and the server will automatically handle requests for static files. It integrates a simple template engine, allowing you to easily generate dynamic HTML responses. You can define placeholders in HTML files, and then use the template engine to replace the placeholders with actual values.
Microdot supports HTTP GET and POST requests. You can handle different types of requests by defining corresponding routes and handler functions.
Here is a brief introduction on how to use Microdot:
First, we need to download the corresponding file from Microdot's GitHub repository
microdot.pyopen in new window.
If the download fails, use the .py file provided below directly.
【microdot.py】 Download
📌 Download Center (click to jump)
📌 In Download Center -> Beginner Manual Documentation Baidu Netdisk link -> Chapter 08. [LCSC ESP32S3R8N8] Project Cases -> Camera Expansion Board for the ESP32S3 Development Board.
Just upload it to the development board.
Source Code
from microdot import Microdot
import time
import camera
import network
import machine
machine.freq(240000000) # Set the CPU operating frequency to 240 MHz
def connect():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('esp32s3 is connecting to the network...')
wlan.connect('ESP32S3_TEST', '12345678')
while not wlan.isconnected():
pass
print('Network info: ', wlan.ifconfig())
ifconfig = wlan.ifconfig()
print('Please open in browser:{}:5000'.format(ifconfig[0]))
connect()
app = Microdot()
# Initialize the camera
for i in range(5):
cam = camera.init(0, d0=21, d1=17, d2=18, d3=16, d4=40, d5=38, d6=1, d7=3,
format=camera.JPEG, framesize=camera.FRAME_HVGA,#FRAME_HVGA,
fb_location=camera.PSRAM,
xclk_freq=camera.XCLK_20MHz,
href=4, vsync=5, reset=-1, pwdn=-1,
sioc=6, siod=7, xclk=2, pclk=39)
print("Camera initialized successfully?: ", cam)
if cam:
print("Yes")
break
else:
time.sleep(2)
else:
print('Timeout')
reset()
@app.route('/')
def index(request):
return '''<!doctype html>
<html>
<head>
<title>ESP32S3 Web Image Transmission</title>
<meta charset="UTF-8">
</head>
<body>
<h1>ESP32S3 Web Image Transmission</h1>
<img alt="Image" src="/video_feed" width="30%">
</body>
</html>''', 200, {'Content-Type': 'text/html; charset=utf-8'}
@app.route('/video_feed')
def video_feed(request):
def stream():
yield b'--frame\r\n'
while True:
frame = camera.capture()
yield b'Content-Type: image/jpeg\r\n\r\n' + frame + \
b'\r\n--frame\r\n'
return stream(), 200, {'Content-Type':
'multipart/x-mixed-replace; boundary=frame'}
if __name__ == '__main__':
app.run(debug=True)
#camera.deinit()2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
Experiment
Editor-side display
Web-side display
6.2 Portable Camera
Combination of SD card, screen, and camera