【MicroPython】开发环境搭建【Thonny】软件安装及【flash_download_tool】固件下载烧录(C 模块)

【MicroPython】开发环境搭建【Thonny】软件安装及【flash_download_tool】固件下载烧录(C 模块)

一、MicroPython简介

MicroPython确实是一种非常适合在资源受限的微控制器上运行的Python解释器版本。它被设计成可以轻松地集成到各种嵌入式系统中,并且能够提供接近于原生代码的性能,这在物联网(IoT)项目和其他需要在小型设备上运行复杂脚本的场景中尤其有用。

以下是MicroPythons的一些关键特性和优势:

  1. Python 3 兼容性
    MicroPython支持Python 3的语法和特性,这意味着你可以使用Python 3中的大多数语言结构和标准库函数。例如,你可以使用列表推导式、生成器表达式、字典和集合等高级数据结构。

  2. 内置模块和库
    MicroPython包含了一些专门为微控制器设计的模块,如utime用于时间相关的操作,machine模块提供了对微控制器硬件(如GPIO引脚、ADC、DAC、SPI、I2C等)的直接访问。

  3. 轻量级和高效
    MicroPython被优化以在有限的RAM和闪存中运行,通常只需要几百K的闪存空间和几十K的RAM就能运行。它的内存管理机制也进行了优化,以减少碎片和提高性能。

  4. 可扩展性
    开发者可以通过编写C语言扩展模块来增强MicroPython的功能,这些模块可以添加对特定硬件的支持或实现高性能计算密集型任务。

  5. 跨平台支持
    MicroPython可以在多种微控制器架构上运行,包括ARM Cortex-M系列、ESP8266、ESP32、STM32等,甚至可以在某些具有Linux内核的设备上作为用户空间程序运行。

  6. 社区和生态系统
    MicroPython有一个活跃的社区,提供了大量的教程、示例代码和第三方库,这使得新用户更容易上手,同时也促进了硬件和软件的创新。

由于其易用性和高效性,MicroPython已经成为教育、原型制作和产品开发领域的一个重要工具,特别是在那些需要快速迭代和简化开发流程的场合。

MicroPython操作微控制器

在MicroPython环境中,开发者可以利用这种精简的Python解释器直接在微控制器上编写和运行代码。下面是各个组件如何协同工作的更详细说明:

  1. 微控制器硬件
    微控制器是整个系统的物理基础,它包含CPU、RAM、闪存和一系列的外设接口,如GPIO(通用输入/输出)、ADC(模数转换器)、DAC(数模转换器)、SPI(串行外设接口)、I2C(集成电路总线)、PWM(脉冲宽度调制)等。常见的微控制器芯片有ESP32、ESP8266、STM32、Arduino等。

  2. MicroPython固件
    这是由MicroPython项目提供的固件,它包含了MicroPython解释器以及一系列针对微控制器优化的标准库和额外模块。固件通常是基于特定的微控制器开发框架(如ESP-IDF、STM32 HAL库等)构建的,这样可以确保MicroPython能够充分利用硬件的特性。开发者通过烧录固件到微控制器上,使微控制器能够理解和执行MicroPython代码。

  3. 用户程序
    这是开发者使用MicroPython语言编写的代码,它可以包括对微控制器硬件的直接操作,如读取传感器数据、控制LED灯、与无线网络通信等。用户程序可以是简单的脚本文件,也可以是包含多个模块的复杂项目。

开发者通过串口连接或者WiFi等方式将用户程序上传到已经安装了MicroPython固件的微控制器上。然后,微控制器上的MicroPython解释器会逐行解析并执行这些代码,从而实现对硬件的控制和所需功能的实现。

MicroPython为开发者提供了一种简洁而强大的方式来与微控制器交互,同时保持了Python语言的易用性和灵活性。

Thonny IDE 简介

Thonny是一种免费且开源的集成开发环境(IDE),特别设计用于Python编程的教学和学习。它旨在帮助初学者更容易地入门编程,同时也适合有一定经验的程序员使用。Thonny支持多种版本的Python,包括标准Python和MicroPython,这使得它成为学习和开发微控制器项目的好工具。

以下是Thonny的一些主要特点:

  1. 代码高亮与调试:Thonny提供了语法高亮和基本的调试功能,如设置断点、单步执行和查看变量值,这有助于理解代码的执行流程和调试错误。

  2. 实时反馈:当代码运行时,Thonny会实时显示控制台输出,便于观察程序的运行状态。

  3. 简单友好的界面:Thonny有一个直观的用户界面,包括文件管理、代码编辑、运行控制和输出窗口,所有这些都集中在一个易于导航的环境中。

  4. MicroPython支持:Thonny可以与各种微控制器配合使用,比如ESP8266、ESP32、Raspberry Pi Pico和其他基于MicroPython的设备。它允许直接上传和运行MicroPython代码,无需离开IDE。

  5. 教育功能:Thonny包括一些教学功能,如“Turtle”图形库的可视化,以及一个“Learn to program”教程,这些都是为了帮助新手更好地理解编程概念。

  6. 多平台兼容性:Thonny可以在Windows、macOS和Linux操作系统上运行,这增加了它的可用性和可访问性。

要使用Thonny进行MicroPython开发,你需要做的是:

  • 安装Thonny IDE。
  • 配置Thonny以识别你的微控制器和相应的串口。
  • 编写或上传MicroPython代码到微控制器上。
  • 使用Thonny的功能来测试和调试你的代码。

Thonny对于学习编程和进行实际项目开发都是一个很好的选择。

二、Thonny软件安装与使用

Thonny官网

安装基本没有什么需要配置选项PC软件正常安装流程
可修改下载路径 和 “create desktop icon”选项 创建桌面图标界面

这里就选择简体中文和标准(Standard)设置。

三、Thonny 工具的框架解析

1. 菜单板块

在这个板块下包含了文件、编辑、视图、运行、工具和帮助选项。
① 文件选项:
Thonny 工具的文件功能主要是指在程序运行过程中,对文件输入/输出的处理。具体功能包括:新建文件、打开新建、关闭文件等操作,文本界面如下图所示。

② 编辑选项:
Thonny 工具提供了丰富的编辑功能,包括复制/剪切/粘贴、撤销/重做、查找/替换、自动补全、缩进与反缩进选择行、注释代码、折等操作,可以帮助用户更方便地编辑代码文本。编辑界面如下图所示。

③ 视图选项:
Thonny 工具的视图功能主要是指在程序运行过程中,通过勾选不同的选项来显示和关闭不同的视图窗口。有些视图窗口会显示程序运行过程中变量的值,这对于调试程序非常有帮助。

④ 运行选项:
Thonny 工具提供了运行 Python 脚本、单步执行、中断执行、停止/重启后端进程、运行脚本等功能,帮助用户控制和调试 Python 脚本的执行过程。运行界面如下图所示。

⑤ 工具选项:
在“工具”选项中,用户可以管理插件和软件。例如,可以安装和卸载插件,配置解释器和编辑器属性等。工具界面如下图所示。

对于管理插件,用户可以浏览可用的插件列表,选择需要安装的插件,并查看已安装的插件列表。如果需要卸载某个插件,只需选择该插件并点击“卸载”按钮即可。

打开“工具”选项,接着点击管理插件进入插件管理界面,如下图所示。

然后,我们在文本框输入要安装的插件,这里我们安装“thonny-black-format”插件,接着,点击“在 PyPI 上搜索”,搜索成功后的界面如下所示:

上图中,我们选择“thonny-black-format”插件,然后进入安装界面,如下图所示。

到了这里,我们点击“安装”选项,即可安装这个插件,安装成功后需重启 Thonny 软件,在“工具”选项下会多出“thonny-black-format”插件。

2. 调试与下载板块

这个板块的功能只不过在菜单板块下截取一些非常实用的功能,如下载调试、新建文件和另存文件等操作。

3. 文本编辑板块

这一个板块是 Python 代码的编辑器,用来编写代码用的。

4. 5. 本地浏览板块和设备存储板块

本地浏览板块可以用来浏览电脑磁盘的内容,而设备存储板块则可以显示 ESP32 开发板的内部文件系统。这些功能使得我们可以在开发过程中,方便地查看和编辑文件。若用户在本地编写好的 py 脚本,可直接保存到 MicroPython 设备(ESP32-S3 内部文件系统)当中。

6. 7. 交互板块和解释器选择板块

交互板块是指 Python 解释器与用户进行交互的界面,它可以用于输出程序结果、错误信息以及其他相关信息,如下图 5.2.2.20 所示。而解释器选择板块则是指选择哪个 Python 解释器来编译和运行 Python 脚本,如下图所示。

在 ESP32 开发板上,通常会选择 MicroPython 解释器来编译和运行 Python 脚本。这是因为MicroPython 是专门为微控制器和嵌入式系统设计的 Python 3 解释器,它具有轻量级、高效和易于使用等特点,非常适合在 ESP32 这样的低功耗设备上运行。

在本地计算机上运行 Python 程序时,则通常会选择本地 Python 3 解释器。这是因为 Python是一种跨平台的语言,可以在不同的操作系统和设备上运行,而本地 Python 解释器则是针对特定平台和操作系统的。

四、下载固件及测试

USB转串口Windows一键式安装驱动程序

ESP-32S3 开发 Thonny 的基本配置

使用 Thonny 工具进行 ESP32-S3 应用开发,需要完成以下配置:
打开 Thonny 工具,点击“运行”->“配置解释器”选项。
在配置解释器界面下配置解释器和串口端口,如下图所示。

配置完成后,就可以在 Thonny 工具中开发 ESP32-S3 芯片了。然而,在进行开发之前,需要用户将 MicroPython固件下载到 ESP32-S3芯片中,以便在 Thonny工具中进行开发。固件的下载和烧录将在下一小节中讲解。

固件的下载与烧录

MicroPython 官方

MicroPython 官方提供了多种固件,可直接下载后烧录至开发板运行。
官方的固件大致分为 pyboard、ESP 系列、STM32 系列等几类,下面分别说明:

  1. pyboard 固件
    从 v1.9.1 版本开始,pyboard 的固件分为下面几个不同版本:
    ① 标准版(standard)
    ② 双精度浮点版(double FP)
    ③ 线程版(threading)
    ④ 双进度浮点+线程版(double FP + threading)
    ⑤ 网络版(network)
    这些版本具有相同的底层功能和包含的模块,但具有不同的专项优化。双精度浮点版本提升了浮点运算的精度,一般版本使用 32 位单精度浮点,而双精度浮点版本则使用 64 位。线程版本支持多线程功能,适合处理并行任务。双精度浮点+线程版本同时具备高精度浮点运算和多线程功能。网络版本通过 SPI接口连接外部网络模块(CC3000等),为 pyboaed增加网络功能。
  2. ESP 系列固件
    ESP 系列包括 ES8266、ESP32、ESP32S3 等多款芯片,每款芯片都有其特定的固件。虽然MicroPython 为这些芯片提供了相应的固件,但有时候这些固件可能不能满足开发需求。因为MicroPython 的固件是针对特定型号的,所以一个芯片的固件资源无法与其他类型的芯片匹配。
  3. STM32 系列固件
    除了前面几种固件外,MicroPython 官方还提供了下面几种芯片的固件,它们分别为:stm32f0、 stm32f4、stm32f7、stm32g0、stm32g4、stm32h5、stm32h7、stm32l0、stm32l1、stm32l4、stm32wb 和 stm32wl。
  4. MicroPython 中文社区固件
    虽然MicroPython官方提供了多种固件,但仍然有许多开发板没有官方支持的固件。对于许多使用者来说,编译源码是一项复杂和具有挑战性的任务。为了解决这个问题,MicroPython 中文社区特别提供了多种常见开发板的预编译固件,以便大家能够轻松地使用和测试这些开发板。
    MicroPython 中文社区地址是:https://git.oschina.net/shaoziyang/

在官方主界面下,点击“DOWNLOAD”下载选项,然后找到“ESP32”端口,点击“esp32”选项进入 ESP32 MicroPython 固件下载网页,接着往下找到“ESP32-S3 Espressif”选择,如下图所示。

开发板的模组为 ESP32-S3-WROOM-1-N16R8 型号,从《esp32-s3-wroom-1_wroom-1u_datasheet_cn.pdf》模组数据手册

ESP32-S3 MicroPython 固件下载界面,在此界面下找到 Firmware(Support for Octal-SPIRAM)标签

下载固件成功之后,我们得到了 ESP32_GENERIC_S3-SPIRAM_OCT-20240602-v1.23.0.bin 固件文件,下面我们把这个固件烧录到 ESP32-S3 开发板中,这里会涉及到两种烧录方式。第一种是使用 Thonny 工具烧录,另一种是使用乐鑫官方提供的烧录固件软件 flash_download_tool

1. 使用 Thonny 工具烧录:

在 Thonny 工具中,选择“运行”菜单中的“配置解释器”选项,然后点击“安装或者更新microPython(esptool)”如下图 5.3.6 所示,进入固件烧录界面。

在上图中,我们点击红色箭头按键,在它弹出的下拉列表上选择“Select local microPythonimage…”选项,接着选择刚刚下载的 ESP32_GENERIC_S3-SPIRAM_OCT-20240602-v1.23.0.bin 固件文件,此时,esptool 烧录界面变成可编辑界面,如下图所示。

点击“安装”按钮就执行烧录操作了,此时点击“烧录”进度条即可看到烧录进度信息,如下图所示。

等待烧录进度提示“Hard resetting via RTS Pin … Done”表示烧录完成,接着关闭 esptool 工具,重新选择解释器(MicroPython (ESP32) · USB Serial @ COM46),并按下开发板上的复位按键,即可启动 MicroPython 固件了。最后,在 Shell 交互窗口上看到固件的信息,如下图所示。

从上图可以看到,Shell 交互式窗口提示“MicroPython v1.23.0 on 2024-06-02; Generic ESP32S3 module with Octal-SPIRAM with ESP32S3”信息,表示已成功烧录 v1.23.0 版本 MicroPython。

Pins and GPIO

from machine import Pin  # 导入 Pin 类,用于控制 GPIO 引脚。
from neopixel import NeoPixel  # 导入 NeoPixel 类,用于控制 NeoPixel LED。
import time  # 导入 time 模块,用于延时。

pin = Pin(48, Pin.OUT)  # 创建一个 Pin 对象,设置 GPIO 48 为输出模式。
np = NeoPixel(pin, 1)  # 创建一个 NeoPixel 对象,指定使用上面的 Pin 对象和 LED 数量为 1。
np[0] = (10, 10, 10)  # 设置 LED 的颜色为白色(红光强度、绿光和蓝光强度为 10)。
np.write()  # 将设置的颜色数据写入到 LED。
time.sleep(1)  # 延时 1 秒。
r, g, b = np[0]  # 读取 LED 当前的颜色值。

while True:
    np[0] = (10, 0, 0)  # 设置 LED 颜色为红色。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。
    
    np[0] = (0, 0, 0)  # 设置 LED 颜色为黑色(熄灭)。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。

    np[0] = (20, 10, 0)  # 设置 LED 颜色为橙色。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。
    
    np[0] = (0, 0, 0)  # 设置 LED 颜色为黑色(熄灭)。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。
    
    np[0] = (10, 10, 0)  # 设置 LED 颜色为黄色。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。
    
    np[0] = (0, 0, 0)  # 设置 LED 颜色为黑色(熄灭)。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。
    
    np[0] = (0, 10, 0)  # 设置 LED 颜色为绿色。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。
    
    np[0] = (0, 0, 0)  # 设置 LED 颜色为黑色(熄灭)。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。
    
    np[0] = (0, 10, 10)  # 设置 LED 颜色为青色。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。
    
    np[0] = (0, 0, 0)  # 设置 LED 颜色为黑色(熄灭)。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。

    np[0] = (0, 0, 10)  # 设置 LED 颜色为蓝色。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。
    
    np[0] = (0, 0, 0)  # 设置 LED 颜色为黑色(熄灭)。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。
    
    np[0] = (10, 0, 10)  # 设置 LED 颜色为紫色。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。
    
    np[0] = (0, 0, 0)  # 设置 LED 颜色为黑色(熄灭)。
    np.write()  # 更新 LED 的颜色。
    time.sleep(1)  # 延时 1 秒。
    
    
def handle_interrupt(pin):  # 定义一个中断处理函数。
    
    np[0] = (10, 0, 0)  # 设置 LED 颜色为红色。
    np.write()  # 更新 LED 的颜色。
    time.sleep_ms(150)  # 延时 150 毫秒。
    
    np[0] = (0, 0, 0)  # 设置 LED 颜色为黑色(熄灭)。
    np.write()  # 更新 LED 的颜色。
    time.sleep_ms(150)  # 延时 150 毫秒。

    print("test-usr key")  # 输出一条消息。

p0 = Pin(0)  # 创建一个 Pin 对象,设置 GPIO 0 为默认输入模式。
p0.init(p0.IN, p0.PULL_UP)  # 显式设置 GPIO 0 为输入模式,并启用上拉电阻。
p0.irq(trigger=p0.IRQ_FALLING, handler=handle_interrupt)  # 设置 GPIO 0 的中断触发条件为下降沿,并关联到 handle_interrupt 函数。

2. flash_download_tool 烧录:

乐鑫 Flash 下载工具

首先打开乐鑫下载工具网页,接着下载 Flash 下载工具,如下图所示。

在上图中,点击下载 Flash 下载工具的链接,当前版本为 3.9.5,下载完成之后双击打开程序文件 flash_download_tool_3.9.5.exe,然后在“DOWNLOAD TOOL MODE” 界面下选择芯片信息(Flash 下载工具相关介绍,请参考 flash_download_tool_3.9.5\doc 路径下的《Flash_Download_Tool_cn.pdf 使用手册》),如下图所示。

上图中,ChipType 选择 ESP32S3,WorkMode 选择 Develop LoadMode 选择 UART,点击OK,进入下载页面,如下图所示。

上图①表示选择下载的固件;上图②表示该固件将被下载到 ESP32-S3 的 Flash 哪个地址,这里我们选择 0x0000;上图③和④表示 SPI Flash 速率及模式,这里我们选择 80MHz 和 QIO 模式;上图⑤表示串口端口和波特率,这里我们选择 COM4(不同电脑插入,端口号也不同)和 115200;上图⑥表示 Flash 固件下载开始、停止和擦除按键。
首先点击“ERASE”擦除按键,等待 ESP32-S3 擦除完成,然后点击“STOP”按键停止操作,接着点击“START”开始烧录操作,等待烧录完成后,就关闭 flash_download_tool 软件。
需要注意的是,在烧录固件之前,需要确认 ESP32-S3 开发板已经正确连接到电脑,并且端口号正确选择。同时,在烧录过程中要避免断电或断开连接等操作,以免对开发板造成损坏。

五、MicroPython 固件编译

1、搭建编译环境

自编译 MicroPython ESP32-S3 固件需要搭建两个开发环境,一个是 Linux 环境,另一个是ESP-IDF 环境。这两个环境是必需的,因为 MicroPython ESP32 固件依赖于它们进行编译。

1. Linux 环境搭建

全网最全 【Vmware】 下虚拟机 Linux Ubuntu 安装和配置

Linux 环境的搭建有三种方式。
第一种是使用 VMware 虚拟机并安装 Ubuntu 系统来搭建,
第二种是安装多个操作系统(Windows 和 Ubuntu 系统),每次重启电脑时根据需要进行选择进入,
第三种是在 Windows 系统下安装 WSL Ubuntu子系统。
前两种方式属于比较完整的安装方式,都可以有图形用户界面,适合对图形界面有需求的同学。而最后一种 Linux 子系统的方式,安装和运行最快,但是只有命令行,适合 Linux 老手或者对图形界面需求不大的用户。

ubuntu官网

进入 Windows store 微软商城,输入关键词 ubuntu,即可找到多个版本的 ubuntu 子系统,如下图所示。

这里选的是 Ubuntu22.04.3 LTS 版本。点进去下载安装。接着我们打开 linux 子系统功能,如下步骤所示:

2. WSL 子系统搬迁

Windows Store 微软商城安装的 APP 都默认被安装在 C 盘。我们最好将子系统搬离 C 盘,也就是说,不使用 C 盘来存放文件。将子系统搬到 D 盘存储。WSL 子系统搬迁流程,如下所示:

  1. 查询 WSL 系统状态。使用管理员身份打开 CMD 命令行,并在命令行输入“wsl -l -v”查看 wsl 虚拟机的名称和状态,如下图所示。
  1. 停止 WSL 子系统。输入 wsl --shutdown 使 Ubuntu-22.04 停止运行,再次使用 wsl -l -v 确保其处于 stopped 状态,如下图所示。
  1. 导出/恢复备份。在 D 盘创建一个文件夹用来存放新的 WSL,比如创建了一个 D:\Ubuntu_WSL 文件夹。
    ①:导出它的备份(比如命名为 Ubuntu.tar)。在 CMD 命令行下输入“wsl --export Ubuntu-22.04 D:\Ubuntu_WSL\Ubuntu.tar”。
    ②:确定在 D:\Ubuntu_WSL 下是否可看见备份 Ubuntu.tar 文件,如下图所示那样,之后注销原有的 WSL。在 CMD 命令行输入“wsl --unregister Ubuntu-22.04”注销原本的 WSL。

③:将备份文件恢复到 D:\Ubuntu_WSL 中去。在 CMD 命令行下输入“wsl --import Ubuntu-22.04 D:\Ubuntu_WSL D:\Ubuntu_WSL\Ubuntu.tar”恢复备份文件,如下图所示。

关于将 C 盘的数据移植到 D 盘,这可能是出于以下几个原因:

  1. 磁盘空间不足:C 盘可能没有足够的空间来容纳更多的数据,或者你想要释放 C 盘的空间以便更好地管理操作系统所在磁盘的存储。

  2. 性能考虑:如果你的 D 盘是一个 SSD(固态硬盘),而 C 盘是一个传统的 HDD(机械硬盘),那么将数据迁移到 D 盘可能会带来更好的读写性能。

  3. 组织结构:你可能希望将 WSL 分发版和相关数据放在 D 盘以更好地组织你的文件和项目,使它们与其他开发相关的文件分开。

  4. 备份和恢复:如果你计划定期备份 D 盘的内容,那么将 WSL 分发版放在 D 盘可以方便进行备份和恢复操作。

  5. 多用户环境:在某些情况下,你可能需要在一台机器上为不同的用户提供独立的工作环境。将 WSL 分发版放在 D 盘可以更容易地为每个用户分配单独的文件系统。

如何将 C 盘的数据移植到 D 盘

如果你想将 C 盘的数据移植到 D 盘上的 WSL 分发版中,你可以采取以下步骤:

  1. 导出当前的 WSL 分发版:首先,你需要将现有的 Ubuntu-22.04 分发版导出为一个 .tar 文件。

    wsl --export Ubuntu-22.04 D:\Ubuntu_WSL\Ubuntu.tar
    
  2. 在 D 盘创建新的 WSL 分发版:接下来,使用之前导出的 .tar 文件创建一个新的 WSL 分发版。

    wsl --import Ubuntu-22.04 D:\Ubuntu_WSL D:\Ubuntu_WSL\Ubuntu.tar
    
  3. 验证新分发版:确保新的分发版正确导入了数据,并且所有必要的配置都已迁移。

    wsl -d Ubuntu-22.04
    
  4. 取消注册旧分发版:如果不再需要原来的分发版,可以取消注册并删除旧的根文件系统。

    wsl --unregister Ubuntu-22.04
    
  5. 设置新分发版为默认分发版:如果需要的话,你可以将新分发版设置为默认分发版。

    wsl --set-default Ubuntu-22.04
    

完成这些步骤后,你就可以在 D 盘上使用新的 Ubuntu-22.04 分发版了,其中包含了从 C 盘迁移过来的数据。

3. 安装工具链

1,更新工具:
sudo apt-get update
2,安装 GCC:
sudo apt-get install gcc
3,安装 Cmake:
sudo apt-get install cmake
4,安装 python3.10:
sudo apt-get install python3.10
5,安装 python pip:
sudo apt-get install python3-pip
6,安装子系统:
sudo apt-get install source/ linux-source-5.7
7,安装 virtualenv:
sudo apt-get install virtualenv
sudo apt-get install python3.10-venv
8,安装 git:
sudo apt-get install git

4. ESP-IDF 环境搭建

国内的 gitee 仓库克隆搭建 ESP-IDF 环境

乐鑫芯片在 ESP-IDF 各版本中的支持状态

MicroPython IDF 版本要求: MicroPython 目前支持的 IDF 版本

4.1 克隆 IDF 库

首先打开 ubuntu 22.04.2 LTS 子系统,然后在命令行下输出“git clone -b v5.0.4 --recursive https://github.com/espressif/esp-idf.git”克隆 Github 仓库中的 ESP-IDF 源码库,如下图所示。

https://github.com/espressif/esp-idf/tree/release/v5.2

git clone -b v5.0.4 --recursive https://github.com/espressif/esp-idf.git

子系统(D:\Ubuntu_WSL\root)根目录下找到一个名为“esp-idf”的文件夹。这个文件夹包含了 ESP-IDF 开发环境的相关文件和工具

4.2 切换 IDF 5.0.4 版本
cd esp-idf
git checkout v5.0.4
4.3 更新 IDF 版本子模块
git submodule update --init --recursive
4.4 运行安装脚本安装所需依赖项和设置环境变量
./install.sh
source export.sh

分别是安装 ESP-IDF 开发所需的依赖项和设置环境变量,设置成功之后系统提示“../export.sh”信息表示安装及设置环境变量成功

上图提示“idf.py build”信息表示设置环境变量成功。
请注意,每次进入 Ubuntu 22.04.2 LTS 子系统时,用户必须在 ~/esp-idf#目录下输入“source export.sh”来操作环境变量,否则在生成固件时可能会报错。
为了解决上述的问题,在~/.bashrc 直接执行 export.sh 文件,来设置 ESP-IDF 环境变量。
~/.bashrc 是一个在 Unix 和 Linux 系统中非常重要的 Shell 初始化文件。这个文件在 bash shell (Bourne Again SHell)启动时被读取(系统启动时),用户可以在这里定义别名、函数、环境变量、路径等,所有这些在以后启动的 bash shell 中都可用。
这个文件通常位于系统的 home 目录下(~/.bashrc),用户可以使用文本编辑器(如 vimnanoemacs)来编辑它。在此文件最后一行命令下添加以下命令,如下所示:

source ./esp-idf/export.sh

4. 搭建 MicroPython 开发环境

https://github.com/micropython/micropython

# 克隆 MicroPython 库
git clone https://github.com/micropython/micropython.git

cd micropython
# 更新 MicroPython 子模块
git submodule update --init --recursive
# 构建 MicroPython 交叉编译器
make -C mpy-cross

构建 MicroPython 交叉编译器完成之后,就可以构建 MicroPython ESP32 固件了。“cd ports/esp32”进入 MicroPython ESP32 编译工程,在此目录下输入“make”构建 ESP32 MicroPython 固件,如下图所示。

cd ports/esp32
make

系统在 esp32\build-ESP32_GENERIC文件夹下生成了三个 bin文件,它们分别为 bootloader.binpartition-table.binmicropython.bin。然后,我们使用 flash_download_tool_3.9.5.exe 工具将这三个 bin 文件烧录到 ESP32 芯片中

这些文件通常是在嵌入式系统中使用的固件文件,每个文件有特定的功能和用途。以下是它们的作用和用途的简要说明:

  1. bootloader.bin

    • 功能:引导加载程序(Bootloader)的二进制文件。
    • 用途:负责在设备上电时初始化硬件设置,加载并启动操作系统或主应用程序。在ESP32系列设备中,bootloader通常位于Flash存储的固定位置,启动时首先执行。
  2. partition-table.bin

    • 功能:分区表的二进制文件。
    • 用途:定义了Flash存储的布局,包括每个分区的起始地址、大小和用途。例如,可以定义一个分区用于存储应用程序固件(App),另一个分区用于存储文件系统(SPIFFS、FAT等)。ESP32设备使用这个文件来确定每个分区的位置和大小。
  3. micropython.bin

    • 功能:MicroPython固件的二进制文件。
    • 用途:包含MicroPython解释器和相关的库,用于运行Python代码的固件。这个文件被烧录到设备的特定分区中,使设备能够解释和执行MicroPython代码。
  4. firmware.bin

    • 功能:设备的主固件二进制文件。
    • 用途:包含设备的主要功能代码和应用程序逻辑。对于基于ESP32的设备,这通常是最终用户要烧录的应用程序固件。这个文件可以包括操作系统、设备驱动程序、用户应用程序等。
烧录顺序和注意事项

烧录这些文件到设备时,通常遵循以下顺序:

  1. bootloader.bin:通常首先烧录到Flash的起始位置。
  2. partition-table.bin:接下来烧录分区表,定义Flash存储的布局。
  3. micropython.binfirmware.bin:最后烧录主固件,取决于使用的框架或操作系统。
esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect \
    0x1000 bootloader.bin \
    0x8000 partition-table.bin \
    0x10000 micropython.bin

烧录这些文件时,必须确保它们的地址和大小与分区表中的定义一致。此外,确保使用适当的工具(如 esptool.pyflash_download_tool)和正确的命令来烧录这些文件,以避免损坏设备或导致无法启动的问题。

根据提示信息,我们需要将生成的 bin 文件烧录到对应的地址中。另外,我们也可以使用 esp32\build-ESP32_GENERIC 文件夹下的 firmware.bin 文件,这个文件是bootloader.binpartition-table.binmicropython.bin 三个文件的总 bin 文件:

注意:此固件虽然能满足 ESP32 在 MicroPython 下的运作,但它是有缺陷的。它并没有适配芯片的资源,如,是否挂载 PSRAM、Flash/PSRAM 的大小、时钟是否调节到 240MHz 等等。
如果我们不去配置的话,系统可能选择默认的配置,如时钟只能达到 160MHz、Flash 大小为2MB 等。这种默认的配置无法体现该芯片的价值,所以作者在后续的教程中,会详细讲解如何

5. MicroPython 源文件结构分析

子系统的 Ubuntu 下克隆了 MicroPython 源码包,并且在这个源码包下编译出了 ESP32 MicroPython 固件。
MicroPython 的基础源程序基本由 C 语言编写的,在编译过程中,使用了少量的 Python 脚本,用于在预编译过程中处理字符串。如下表中展示了 MicroPython 项目的源码文件结构。

docs 目录: 可生成 MicroPython 文档,可以在 GitHub 仓库中找到 MicroPython/docs 目录,并安装相关的工具来生成 HTML,如下图所示。

先使用 pip 命令安装 sphinxsphinx_rtd_theme 工具,然后在子系统上使用 cd 命令跳到 micropython/docs 目录下,最后在此目录下输入“make html”命令构建 html 文档。

py 目录:在 MicroPython 的开发过程中,为了确保与 Python 标准库的一致性,我们不会修改 py 目录中的任何源代码。这是因为 py 目录存放着 Python 内核的全部源代码,是实现 Python功能的重要基础。

lib 目录和 extmod 目录:它们都包含了 MicroPython 扩展功能的组件,但它们的分工有所不同。lib 目录中的内容是与 MicroPython 无关的,它们针对特定的微控制器平台,并可以独立地在这些平台上运行,以支持 MicroPython 功能的实现。它们位于 MicroPython 的下层,例如,包括各个微控制器平台的固件库、基本的文件系统协议栈和 USB 协议栈等。而 extmod 目录中实现的是扩展模块,这些模块都是基于 MicroPython 实现的,并在 MicroPython 内部实现扩展功能,例如,machine_spi 模块就是在 MicroPython 的 machine 类中实现的 SPI 类模块。
对于微控制器开发者最有用也是最直接操作的目录是 ports,里面存在了 MicroPython 支持的所有微控制器的移植代码,如下图所示。

在具体微控制器平台的目录下,存放了各自对MicroPython的底层移植源文件以及移植工程的 Makefile 文件。

2、编译 ESP32-S3 固件

Makefile 是用于自动编译和构建软件项目的工具。它使用简单的规则来告诉编译器如何构建软件。Makefile 包含一组命令,这些命令用于编译、链接和构建源代码文件。

在 ESP32-S3 的固件编译过程中,可以在 ports/esp32 目录中找到一个 Makefile 文件。这个Makefile 文件包含了编译 ESP32-S3 固件的规则和指令。通过编辑 Makefile 文件,可以设置要编译的型号,例如 GENERIC_S3,然后保存文件后在终端使用 make命令开始编译适用于对应板型的固件。

2.1 Makefile 文件

micropython\ports\esp32\Makefile

# Makefile for MicroPython on ESP32.
#
# This is a simple, convenience wrapper around idf.py (which uses cmake).

# Select the board to build for:
# (1)选择要构建的板卡:
ifdef BOARD_DIR
# Custom board path - remove trailing slash and get the final component of
# the path as the board name.
BOARD ?= $(notdir $(BOARD_DIR:/=))
else
# (2)如果命令行中没有指定 BOARD_DIR,默认使用 ESP32_GENERIC
BOARD ?= ESP32_GENERIC
# (3)得到对应芯片的编译路径
BOARD_DIR ?= boards/$(BOARD)
endif

ifeq ($(wildcard $(BOARD_DIR)/.),)
ifeq ($(findstring boards/GENERIC,$(BOARD_DIR)),boards/GENERIC)
$(warning The GENERIC* boards have been renamed to ESP32_GENERIC*)
endif
$(error Invalid BOARD specified: $(BOARD_DIR))
endif

# If the build directory is not given, make it reflect the board name (and
# optionally the board variant).
# (4)如果没有给出指定 BUILD 构建目录,使用默认文件名
ifneq ($(BOARD_VARIANT),)
BUILD ?= build-$(BOARD)-$(BOARD_VARIANT)
else
BUILD ?= build-$(BOARD)
endif

# Device serial settings.
# 设备串口波特率设置,默认值为 /dev/ttyUSB0 和 460800 波特率
PORT ?= /dev/ttyUSB0
BAUD ?= 460800

# 指定使用的 Python 解释器,默认是 python3
PYTHON ?= python3

.PHONY: all clean deploy erase submodules FORCE

CMAKE_ARGS =

# (5)使用 C 模块,把自己的 C 驱动编译成 MicroPython 调用的 API
ifdef USER_C_MODULES
	CMAKE_ARGS += -DUSER_C_MODULES=${USER_C_MODULES}
endif

IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -D MICROPY_BOARD_DIR="$(abspath $(BOARD_DIR))" $(CMAKE_ARGS)

ifdef FROZEN_MANIFEST
       IDFPY_FLAGS += -D MICROPY_FROZEN_MANIFEST=$(FROZEN_MANIFEST)
endif

# (6)设置 PSRAM SPI 模式、D2WD 等
ifdef BOARD_VARIANT
	IDFPY_FLAGS += -D MICROPY_BOARD_VARIANT=$(BOARD_VARIANT)
endif

ifdef MICROPY_PREVIEW_VERSION_2
	IDFPY_FLAGS += -D MICROPY_PREVIEW_VERSION_2=1
endif

HELP_BUILD_ERROR ?= "See \033[1;31mhttps://github.com/micropython/micropython/wiki/Build-Troubleshooting\033[0m"

define RUN_IDF_PY
	idf.py $(IDFPY_FLAGS) -B $(BUILD) -p $(PORT) -b $(BAUD) $(1)
endef

all:
	idf.py $(IDFPY_FLAGS) -B $(BUILD) build || (echo -e $(HELP_BUILD_ERROR); false)
	@$(PYTHON) makeimg.py \
		$(BUILD)/sdkconfig \
		$(BUILD)/bootloader/bootloader.bin \
		$(BUILD)/partition_table/partition-table.bin \
		$(BUILD)/micropython.bin \
		$(BUILD)/firmware.bin \
		$(BUILD)/micropython.uf2

$(BUILD)/bootloader/bootloader.bin $(BUILD)/partition_table/partition-table.bin $(BUILD)/micropython.bin: FORCE

# 清理构建文件
clean:
	$(call RUN_IDF_PY,fullclean)

# 自动烧录
deploy:
	$(call RUN_IDF_PY,flash)

# 擦除设备的Flash存储指令
erase:
	$(call RUN_IDF_PY,erase-flash)

# 监控设备的串口输出
monitor:
	$(call RUN_IDF_PY,monitor)

# 显示固件的大小
size:
	$(call RUN_IDF_PY,size)

# 显示固件中各组件的大小
size-components:
	$(call RUN_IDF_PY,size-components)

size-files:
	$(call RUN_IDF_PY,size-files)

# Running the build with ECHO_SUBMODULES set will trigger py/mkrules.cmake to
# print out the value of the GIT_SUBMODULES variable, prefixed with
# "GIT_SUBMODULES", and then abort. This extracts out that line from the idf.py
# output and passes the list of submodules to py/mkrules.mk which does the
# `git submodule init` on each.
# 初始化和更新 git 子模块
submodules:
	@GIT_SUBMODULES=$$(idf.py $(IDFPY_FLAGS) -B $(BUILD)/submodules -D ECHO_SUBMODULES=1 build 2>&1 | \
	                  grep '^GIT_SUBMODULES=' | cut -d= -f2); \
	$(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="$${GIT_SUBMODULES}" submodules

上述源码中
(1)表示要编译型号(如 make BOARD=GENERIC_S3 就是编译 S3 的MicroPython 固件),如果在命令行中没有给出这个变量,则默认为 ESP32_GENERIC;
(2),即编译 ESP32这款芯片;
(3)表示编译路径,也就是在这个路径下编译哪些文件,如果(1)中没有设置 BOARD 变量,则系统会编译 boards/ESP32_GENERIC 路径下的文件(如下图所示);
(4)表示构建文件夹名称,这个文件夹包含系统编译产生的文件都会保存在这个文件夹中;
(5)表示是否使用 C 模块,也就是说,使用 C 驱动编译成 MicroPython可调用的 API,这个方法我们到第六章时候讲解;
(6)表示编译条件,如挂在 PSRAM 的 SPI 模式为 SPIRAM_OCT。

2.2 mpconfigboard.cmake 文件、sdkconfig文件

MicroPython在ESP32平台上构建过程中的关键配置文件的作用

在MicroPython的ESP32项目中,boards/ESP32_GENERIC路径下的mpconfigboard.cmake文件、boards/sdkconfig.base文件以及boards/sdkconfig.ble文件都扮演着不同的角色,但它们共同协作以定制和优化MicroPython在ESP32上的构建和运行环境。下面分别解释这三个文件的作用:

  1. mpconfigboard.cmake:

    • 作用:这个CMake脚本文件负责合并多个sdkconfig片段文件,以创建一个完整的sdkconfig文件用于构建过程。它决定了哪些配置片段应该被包含在内,从而间接控制了哪些ESP-IDF组件和特性会被编译。
    • 示例内容
      set(SDKCONFIG_DEFAULTS
         	boards/sdkconfig.base
         	${SDKCONFIG_IDF_VERSION_SPECIFIC}
         	boards/sdkconfig.ble
         )
      
  2. sdkconfig.base:

    • 作用:这是一个基础的sdkconfig文件,包含了ESP-IDF项目构建的默认配置选项。它定义了所有基本的组件和特性,比如Wi-Fi、以太网、串行通信等。
  3. sdkconfig.ble:

    • 作用:这个文件专门用来配置蓝牙低功耗(BLE)相关的选项。如果您的项目需要BLE功能,那么这个文件会添加必要的配置以启用BLE。

这三个文件协同工作,允许开发者选择性地开启或关闭ESP-IDF的不同组件和特性。通过在mpconfigboard.cmake中合并sdkconfig.basesdkconfig.ble,您可以确保ESP32的MicroPython固件同时具有基础的系统功能和BLE能力,如果需要的话。

在开发过程中,根据项目需求,您可能需要编辑这些文件以启用或禁用特定的特性,从而优化资源使用和性能。

2.3 修改 sdkconfig.board 文件

ports/esp32/borads/ESP32_GENERIC_S3 路径下 sdkconfig.board 文件

CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_AFTER_NORESET=y

CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MiB.csv"

此文件默认设置 Flash 大小为 8MB,显然不符合 ESP32-S3-WROOM-1-N16R8 模组内置16MB Flash 大小,因此,把CONFIG_ESPTOOLPY_FLASHSIZE_16MB 配置为 y,并且修改分区表名称为“partitions-16MiB.csv”,修改后如下:

CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_AFTER_NORESET=y

CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-16MiB.csv"

2.4 修改 partitions-16MiB.csv 分区表

micropython\ports\esp32\partitions-16MiB.csv
乐鑫AI 库存储在 Flash 内需要大量的内存。因此,我们将分区表中的 factory 子分区(存储代码的区域)设置为 6M。

# Notes: the offset of the partition table itself is set in
# $IDF_PATH/components/partition_table/Kconfig.projbuild.
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x6000,
phy_init, data, phy,     0xf000,  0x1000,
factory,  app,  factory, 0x10000, 0x600000,  # 6M 内存
vfs,      data, fat,     0x700000, 0x900000, # 9M 内存

MicroPython 源代码适配 ESP32-S3-WROOM-1-N16R8 模组完成,接下来,在 ports/esp32/路径下输入“make BOARD=ESP32_GENERIC_S3 BOARD_VARIANT=SPIRAM_OCT”命令构建 ESP32-S3-WROOM-1-N16R8 模组 MicroPython 固件,如下图所示。

make BOARD=ESP32_GENERIC_S3 BOARD_VARIANT=SPIRAM_OCT

根据上图所示,系统会在 build-ESP32_GENERIC_S3-SPIRAM_OCT 文件夹下生成四个 bin文件,它们分别是 bootloader.bin、partition-table.bin、micropython.bin 和 firmware.bin(总 bin)。
接着,我们使用 flash_download_tool.exe 工具将这三个 bin 文件烧录到 ESP32-S3-WROOM-1-N16R8 模组中。需要注意的是,
bootloader.binpartition-table.binmicropython.bin 设置的下载地址分别为 0x0000、0x8000 和 0x10000
如果烧录的是 firmware.bin(总 bin),则将烧录地址设置为 0x0000。当然,我们也可以借助 Thonny 软件来烧录这个固件,如下图所示。

build-ESP32_GENERIC_S3-SPIRAM_OCT\bootloader\bootloader.bin
build-ESP32_GENERIC_S3-SPIRAM_OCT\partition_table\partition-table.bin
build-ESP32_GENERIC_S3-SPIRAM_OCT\micropython.bin
build-ESP32_GENERIC_S3-SPIRAM_OCT\firmware.bin
import machine				# 导入 machine 模块,用于控制底层硬件,如 GPIO、ADC、DAC 等。
import esp					# 导入 esp 模块,用于访问与 ESP32-S3 相关的特定功能。
import gc					# 导入 gc(垃圾回收)模块,用于管理内存,特别是检查和释放不再使用的内存。
import micropython			# 导入 micropython 模块,用于访问 MicroPython 的底层功能和配置。

if __name__ == '__main__':
    
    # 获取并打印系统时钟频率
    freq = machine.freq()# 调用 machine.freq() 函数获取当前的 CPU 时钟频率。

    # 获取并打印内部 Flash 的大小
    flash_size = esp.flash_size()# 调用 esp.flash_size() 函数获取内部 Flash 的大小。

    # 获取并打印 当前可用的 PSRAM 内存大小
    psram_free = gc.mem_free()# 调用 gc.mem_free() 函数获取当前空闲的内存大小。
    
    # 获取当前已分配的内存大小。
    psram_allocated = gc.mem_alloc()
    
    # 计算总的内存大小。
    psram_total = psram_free + psram_allocated
    
    print(f'当前系统时钟 {freq / (1000 * 1000)} MHz')				# 打印频率,单位转换为 MHz。(240MHz = 240 * 10^6 Hz)
    print(f'内部 Flash 大小 {flash_size / (1024 * 1024)} MB')		# 打印 Flash 大小,单位转换为 MB。(8MB = 8 * 2^20 byte)
    print(f'当前可用 PSRAM 大小 {psram_free / (1024 * 1024)} MB')	# 打印当前可用的内存大小,单位转换为 MB。
    print(f'已使用 PSRAM 大小: {psram_allocated / (1024 * 1024)} MB')# 打印已使用的内存大小,单位转换为 MB。 
    print(f'总的 PSRAM 大小: {psram_total / (1024 * 1024)} MB')		# 打印总的内存大小,单位转换为 MB。

这个固件的系统时钟被设置为 240MHz,内部 Flash 大小为 16MB,PSRAM经过申请和释放操作,最后打印剩余空间为 约等于 8MB。

六、MicroPython 组件扩展(C模块)

C模块是MicroPython生态系统中的一个重要组成部分,它们是用C语言编写的扩展模块,能够被MicroPython解释器直接加载和执行。C模块之所以重要,主要有以下几个原因:

  1. 性能优化:

    • C模块通常提供比纯Python代码更高的执行效率。这是因为C语言是一种编译型语言,其执行速度通常远快于解释型语言如Python。对于计算密集型任务或实时操作,使用C模块可以显著提高应用程序的性能。
  2. 环境限制:

    • 微控制器和嵌入式设备往往资源有限,如内存和处理能力。C模块可以通过更有效地利用这些资源来支持特定的硬件功能,比如直接访问GPIO、I2C、SPI等接口,或实现复杂的硬件驱动程序,这些都是纯Python代码难以实现的。
  3. 功能扩展:

    • MicroPython本身已经包含了丰富的内置模块,但是C模块可以进一步扩展其功能集,允许用户自定义新的模块来满足特定应用的需求。例如,你可以编写C模块来支持特定的传感器、执行高级数学运算、图像处理等。

要创建和使用C模块,你需要对C语言和MicroPython的内部结构有一定了解。通常,这涉及到在MicroPython源代码树中添加新的C文件,编写C函数来封装所需的逻辑,并使用MicroPython的API将这些函数暴露给Python层。然后,你需要重新编译MicroPython固件,将你的C模块包含进去。一旦完成,你的C模块就可以像任何其他Python模块一样从MicroPython中导入和使用了。

1、组件扩展原理

在MicroPython中调用C语言实现的函数,主要通过MicroPython的“C模块”机制来完成。这种机制允许你在C语言中编写函数,然后在MicroPython的Python环境中调用这些函数。下面是一个基本的步骤指南:

  1. 编写C代码:
    首先,你需要用C语言编写你的函数。这个函数需要遵循一些规则,以便能够被MicroPython正确地识别和调用。

  2. 注册函数到MicroPython:
    在C代码中,你需要使用MicroPython的API(如mp_obj_tmp_uint_t等)来包装你的C函数,使其能够理解Python对象,并返回Python可理解的结果。然后,你需要使用MP_DEFINE_CONST_FUN_OBJ_1MP_DEFINE_CONST_FUN_OBJ_2等宏来定义你的函数,并将其添加到一个模块的const mp_rom_map_elem_t mp_module_name_globals_table[]数组中。

  3. 重新编译MicroPython固件:
    将你的C代码加入到MicroPython的源代码目录中,通常是加入到ports/<port_name>/modules目录下,然后重新编译整个MicroPython固件。这样,你的C模块就会被包含在最终的固件中。

  4. 在MicroPython中导入和使用:
    最后,在MicroPython中,你可以像导入和使用任何其他模块一样来导入和使用你的C模块,调用其中定义的函数。

以下是一个简单的示例,展示如何在C中定义一个函数并在MicroPython中调用它:

假设你想定义一个名为my_add的函数,它接收两个整数并返回它们的和。

C代码示例(my_mod.c):

#include "py/obj.h"
#include "py/runtime.h"

STATIC mp_obj_t my_add(mp_obj_t x_in, mp_obj_t y_in) {
    int x = mp_obj_get_int(x_in);
    int y = mp_obj_get_int(y_in);
    return mp_obj_new_int(x + y);
}
MP_DEFINE_CONST_FUN_OBJ_2(my_add_obj, my_add);

const mp_obj_type_t mp_type_my_type;

const mp_rom_map_elem_t mp_module_my_mod_globals_table[] = {
    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_my_mod) },
    { MP_ROM_QSTR(MP_QSTR_my_add), MP_ROM_PTR(&my_add_obj) },
};

MP_DEFINE_CONST_DICT(mp_module_my_mod_globals, mp_module_my_mod_globals_table);

在MicroPython中调用这个函数:

import my_mod
result = my_mod.my_add(5, 3)
print(result)  # 输出应该是 8

请注意,实际的C代码和调用过程可能根据你的MicroPython端口和具体需求有所不同。

MicroPython C模块类型

在MicroPython中使用C扩展进行功能增强的两种常见方式:模块扩展和模块+类扩展。这两种方式各有优势,适用于不同的场景和需求。下面对这两种方式进行详细解释:

1. 模块扩展

特点

  • 简单直接:扩展组件作为一个模块,通常包含一组相关的函数和常量,可以直接被MicroPython导入和使用。
  • 易于使用:用户只需要导入模块,就可以访问所有公开的函数和变量,无需额外的实例化操作。

应用场景

  • 当扩展功能相对单一,不需要复杂的状态管理或面向对象的设计时,模块扩展是最直接的选择。
  • 例如,一个用于数学运算的模块,或者一个用于硬件访问的模块,如GPIO控制。

2. 模块+类扩展

特点

  • 面向对象:扩展组件不仅提供了模块级别的功能,还通过类的形式提供了封装和数据抽象。
  • 灵活性和可扩展性:类可以包含属性和方法,允许用户实例化对象,对每个实例进行独立的状态管理和行为定制。
  • 更好的代码组织:类可以组织相关的功能,使得代码结构更加清晰,易于维护和扩展。

应用场景

  • 当扩展组件需要管理复杂的状态,或者提供多样的行为时,模块+类的方式是更好的选择。
  • 例如,一个用于网络通信的模块,可能需要管理连接状态、缓冲区、事件回调等,这时使用类可以更好地封装这些细节。
  • 又如,一个图形库,可能需要不同的图形对象(如点、线、形状等),每个对象有自己的属性和方法,使用类可以清晰地区分和管理这些对象。

在MicroPython中,无论是模块扩展还是模块+类扩展,都需要通过C语言编写底层实现,并使用MicroPython的API来桥接C和Python的调用。一旦实现,这些扩展就可以像普通的Python模块一样被导入和使用,为MicroPython应用带来高性能或硬件访问的能力。

组件扩展原理解析

MicroPython 提供的三个 C 模块实例,以便用户将来编写自己的 C 模块组件。这些实例位于 micropython\examples\usercmodule 目录下,它们分别是 cexamplecppexamplesubpackage C 模块

micropython.mk 文件

# USERMOD_DIR 模块目录的路径,如 cexample/
CEXAMPLE_MOD_DIR := $(USERMOD_DIR)

# 将所有 C 文件添加到 SRC_USERMOD
SRC_USERMOD += $(CEXAMPLE_MOD_DIR)/examplemodule.c

# 如果有自定义编译器选项(例如 -I 添加目录以搜索头文件),
# 则应将这些选项添加到 C 代码的 CFLAGS_USERMOD 和 C++代码的 CXXFLAGS_USERMOD
CFLAGS_USERMOD += -I$(CEXAMPLE_MOD_DIR)

链接了 cexample 对象文件,最终生成了一个的共享库。这个共享库可以被 MicroPython 解释器加载和使用。总的来说,micropython.mk 对于 MicroPython C 模块的作用主要是定义构建规则和编译选项,以用于构建和编译 C 模块。

micropython.cmake 文件

micropython.cmake 是一个 CMake 配置文件,用于构建 MicroPython 模块。它包含了构建模块所需的 CMake 配置指令,例如定义库、添加源文件、设置编译选项等。通过使用 CMake,可以方便地构建和管理 MicroPython 模块的构建过程。

# 创建一个 INTERFACE 库
add_library(usermod_cexample INTERFACE)

# 源文件添加到库中
target_sources(usermod_cexample INTERFACE
    ${CMAKE_CURRENT_LIST_DIR}/examplemodule.c
)

# 将当前目录添加为包含目录
target_include_directories(usermod_cexample INTERFACE
    ${CMAKE_CURRENT_LIST_DIR}
)
# 将我们的 INTERFACE 库链接到 usermod 目标
target_link_libraries(usermod INTERFACE usermod_cexample)

在 CMake 配置文件 micropython.cmake 中,需要定义一个 INTERFACE 库并将源文件关联起来,然后将其链接到 usermod目标。该文件对于 MicroPython C模块的作用是定义 CMake配置,以确保 C 模块能够正确地编译和链接成可执行文件或库,并能够在 MicroPython 环境中正确地运行。

examplemodule.c 文件

模块扩展实现原理
/* 第一部分:添加所需 API 的头文件 */
#include "py/runtime.h"
#include "py/mphal.h"

/* 第二部分:实现功能 */
static mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) {
    /* 通过 Python 获取的第一个整形参数 arg_1 */
    int a = mp_obj_get_int(a_obj);
    /* 通过 Python 获取的第二个整形参数 arg_2 */
    int b = mp_obj_get_int(b_obj);

    /* 处理入参 arg_1 和 arg_2,并向 python 返回整形参数 ret_val */
    return mp_obj_new_int(a + b);
}
/* 使用 MP_DEFINE_CONST_FUN_OBJ_2 宏将函数添加到模块中 */
static MP_DEFINE_CONST_FUN_OBJ_2(example_add_ints_obj, example_add_ints);

...

/* 第三部分:将模块注册到模块列表 */
static const mp_rom_map_elem_t example_module_globals_table[] = {
    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cexample) },
    { MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) },
    { MP_ROM_QSTR(MP_QSTR_Timer),    MP_ROM_PTR(&example_type_Timer) },
    { MP_ROM_QSTR(MP_QSTR_AdvancedTimer),    MP_ROM_PTR(&example_type_AdvancedTimer) },
};
static MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table);

/* 第四部分:定义模块对象 */
const mp_obj_module_t example_user_cmodule = {
    .base = { &mp_type_module },
    .globals = (mp_obj_dict_t *)&example_module_globals,/* 指向字典对象 */
};

/* 第五部分:注册模块以使其在 Python 中可用 */
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule);

examplemodule.c 文件的部分代码,它主要阐述了简单 MicroPython C 模块的模块扩展架构,首先作者把它这个架构划分为四个部分,如下解析:
第一部分:在.c 文件下添加 microPython 相关头文件,可用来引用相关的 API 函数。
第二部分:加法函数,使用 C 语言的方式实现功能,但需要使用 MicroPython API 函数对入参和出参进行转换,入参转换完成后,才能让 C 语言识别,出参转换成功后才能被 MicroPython调用。最后在 MP_DEFINE_CONST_FUN_OBJ_2 宏的作用下,将函数添加到模块中,以便在MicroPython 环境中调用。
第三部分:将模块注册到模块列表,然后在 MP_DEFINE_CONST_DICT 宏的作用下在 C 语言中创建一个常量字典,并将其添加到 MicroPython 模块中,以便在 Python 环境中直接访问和使用这些字典。这对于需要在 MicroPython 模块中定义和共享常量字典的情况非常有用。大家不妨回顾一下字典的作用,它通过键来访问字典中的值(这个值可用来指向某个函数的地址,这样我们根据这个地址调用函数了)。
第四部分:创建一个模块对象,然后对象的成员变量 globals 指向字典对象,接着在MP_REGISTER_MODULE 宏的作用下将模块注册到 MicroPython 系统中,使其可以在 Python 环境中被导入和使用。

上述组件扩展方式是模块扩展,我们可在 Py 脚本下使用模块扩展的形式调用加法函数,如下示例所示:

# 导入模块
import cexample
"""
* @brief 程序入口
* @param 无
* @retval 无
"""
if __name__ == "__main__":
	a = 5
	b = 10
	c = cexample.add_ints(a,b) # 调用自定义模块的加法函数
	print(c) 

这种模块扩展类似于自己定义一个 cexample.py 文件,然后,在此文件下实现多个函数,最后,在 main.py 文件下导入 cexample 模块,并以模块名引用函数。

模块+类扩展原理
/* 添加所需 API 的头文件 */
#include "py/runtime.h"
#include "py/mphal.h"

...

/* (2)定义 Timer 对象实例 */
typedef struct _example_Timer_obj_t {
    /* 所有对象的基础地址 */
    mp_obj_base_t base;
    /* 开始时间的变量 */
    mp_uint_t start_time;
} example_Timer_obj_t;

/* (3)对象的实现方法(函数) */
static mp_obj_t example_Timer_time(mp_obj_t self_in) {
    /* 获取 Timer 句柄 */
    example_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in);

    /* 获取经过的时间,并将其作为 MicroPython 整数返回 */
    mp_uint_t elapsed = mp_hal_ticks_ms() - self->start_time;
    return mp_obj_new_int_from_uint(elapsed);
}
/* 使用 MP_DEFINE_CONST_FUN_OBJ_1 宏将函数添加到模块中 */
static MP_DEFINE_CONST_FUN_OBJ_1(example_Timer_time_obj, example_Timer_time);

/* 构造函数 */
static mp_obj_t example_Timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
    /* 分配新对象并设置类型 */
    example_Timer_obj_t *self = mp_obj_malloc(example_Timer_obj_t, type);

    /* 获取开始时间 */
    self->start_time = mp_hal_ticks_ms();

    /* 返回 Timer 句柄 */
    return MP_OBJ_FROM_PTR(self);
}

/* 将模块注册到对象的模块列表 */
static const mp_rom_map_elem_t example_Timer_locals_dict_table[] = {
    { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&example_Timer_time_obj) },
};
/* 把字典转换成对象 */
static MP_DEFINE_CONST_DICT(example_Timer_locals_dict, example_Timer_locals_dict_table);

...

/* (1)定义了 Timer 类 */
MP_DEFINE_CONST_OBJ_TYPE(
    example_type_Timer,
    MP_QSTR_Timer,
    MP_TYPE_FLAG_NONE,
    make_new, example_Timer_make_new,
    locals_dict, &example_Timer_locals_dict
    );

/* 将模块注册到模块列表 */
static const mp_rom_map_elem_t example_module_globals_table[] = {
    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cexample) },
    { MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) },
    { MP_ROM_QSTR(MP_QSTR_Timer),    MP_ROM_PTR(&example_type_Timer) },
    { MP_ROM_QSTR(MP_QSTR_AdvancedTimer),    MP_ROM_PTR(&example_type_AdvancedTimer) },
};
/* 把模块注册列表注册到 example_module_globals 字典对象当中 */
static MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table);

/* 定义模块对象 */
const mp_obj_module_t example_user_cmodule = {
    .base = { &mp_type_module },
    .globals = (mp_obj_dict_t *)&example_module_globals,/* 指向字典对象 */
};

/* 注册模块以使其在 Python 中可用 */
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule);

Python 语言是面向对象的语言。正因为如此,在 Python 中创建一个类和对象是很容易的。类是用来描述具有相同的属性(变量)和方法(函数)的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。明白了这点,我们可以去看上述的代码到底怎么实现一个 Python 类的。
(1)它定义了一个名为“Timer”的类,这个类包含了一个对实例对象的操作 example_Timer_make_new,以及一个类的方法(函数)example_Timer_locals_dict;
(2)处定义了 Timer 对象实例,它用来获取开始的运行时间;
(3)处就是类的实现方法 example_Timer_time 即运行的函数。如下是模组+类扩展调用示例,如下代码所示:

from cexample import Timer
"""
* @brief 程序入口
* @param 无
* @retval 无
"""
if __name__ == "__main__":
	 tr = Timer() 		# 对象实例(调用 example_Timer_make_new 函数)
	 timer = tr. time() # 调用对象的方法 example_Timer_time 获取运行时间
	 print(timer) 		# 打印运行的时间

C 模块的模块+类扩展实现方式类似于在定义一个 cexample.py 文件,并在该文件中实现一个 Timer 类,然后在该类中实现计算运行时间的方法,最后在 main.py 文件中导入 cexample 模块下的 Timer 类,并使用类名来引用该函数。

2、组件扩展辅助工具

RT-Thread MicroPython C 绑定代码自动生成器

RT-Thread 提供的 MicroPython C 绑定代码自动生成器是一个非常有用的工具,可以帮助开发者快速将 C 语言函数或模块集成到 MicroPython 环境中。通过这个工具,开发者可以轻松添加自己编写的 C 语言函数或者模块到 MicroPython 中,并被 Python 脚本调用。这大大扩展了原版 MicroPython 的能力,并且可以快速实现任何功能。

3、添加C模块驱动扩展组件

乐鑫摄像头驱动库乐鑫 AI 库

移植到子系统 esp-idf 库的 components 目录中

移植到子系统 esp-idf 库的 components 目录中

1. 把扩展组件复制到 MicroPython 源代码

复制 CAMERA、ESP-WHO、IIC、LCD、RGBLCD、SENSOR 文件夹至 D:\Ubuntu_WSL\root\micropython\examples\usercmodule\BSP 目录下

2. 修改 usercmodule 目录下的 micropython.cmake

修改 micropython.cmake 文件,添加编译扩展组件

# This top-level micropython.cmake is responsible for listing
# the individual modules we want to include.
# Paths are absolute, and ${CMAKE_CURRENT_LIST_DIR} can be
# used to prefix subdirectories.

# Add the C example.
include(${CMAKE_CURRENT_LIST_DIR}/cexample/micropython.cmake)

# Add the CPP example.
include(${CMAKE_CURRENT_LIST_DIR}/cppexample/micropython.cmake)

# 添加 IIC 驱动
include(${CMAKE_CURRENT_LIST_DIR}/BSP/IIC/micropython.cmake)

# 添加 CAMERA 驱动
include(${CMAKE_CURRENT_LIST_DIR}/BSP/CAMERA/micropython.cmake)

# 添加 SPI LCD 驱动
include(${CMAKE_CURRENT_LIST_DIR}/BSP/LCD/micropython.cmake)

# 添加 ESP_WHO 乐鑫 AI 驱动
#include(${CMAKE_CURRENT_LIST_DIR}/BSP/ESP-WHO/micropython.cmake)

# 添加 SENSOR 驱动
include(${CMAKE_CURRENT_LIST_DIR}/BSP/SENSOR/micropython.cmake)

# 添加 RGBLCD 驱动
include(${CMAKE_CURRENT_LIST_DIR}/BSP/RGBLCD/micropython.cmake)

有一个重要的点需要关注:ESP_WHO和 LCD 扩展组件不能同时编译。这是因为 ESP_WHO 已经包含了 LCD 驱动,所以这两者不能同时使用。

3. 编译固件

cd micropython/ports/esp32
make USER_C_MODULES=~/micropython/examples/usercmodule/micropython.cmake BOARD=ESP32_GENERIC_S3 BOARD_VARIANT=SPIRAM_OCT

七、引脚定义

《esp32-s3-wroom-1_wroom-1u_datasheet_cn.pdf》
《esp32-s3_datasheet_cn.pdf》

ESP32-S3 微控制器上各引脚的详细功能和用途。下面是根据列表的一个概括:

  1. 电源 §与控制引脚

    • GND (1):接地引脚,用于电路的公共地电位。
    • 3V3 (2):提供 3.3V 电源电压,用于芯片和外设供电。
    • EN (3):使能引脚,控制芯片的开启与关闭。高电平使能芯片,低电平关闭芯片,不得让其浮空。
  2. 多功能 I/O 引脚

    • I/O/T:表示引脚可以被配置为输入(I)、输出(O),(T):可设置为高阻。加粗字体为管脚的默认功能。管脚 28 ∼ 30 的
      默认功能由 eFuse 位决定。
    • TOUCH:触摸感应功能,可以用于实现触摸传感器。
    • IO4 至 IO42:通用输入/输出引脚,具有多种复用功能,包括 RTC GPIO、触摸感应、ADC 输入、SPI、I2C、UART 等。
    • 其中一些引脚还支持差分信号(如 IO47 和 IO48)或作为 JTAG 调试引脚(如 IO42)。
  3. 实时时钟(Real-Time Clock)GPIO

    • RTC_GPIO,即使在 CPU 关闭的情况下,这些引脚也能继续工作,用于低功耗应用。
  4. UART 信号引脚

    • RXD0 (G44)TXD0 (G43):用于 UART 串行通信的接收和发送,也可用作通用 I/O 或时钟输出。
    • 例如:U0TXD, U0RXD, U0RTS, U0CTS, U1TXD, U1RXD, U1RTS, U1CTS
  5. 模拟信号引脚

    • ADC1_CH0 至 ADC1_CH8 和 ADC2_CH0 至 ADC2_CH9:模拟数字转换器的输入通道,用于采集模拟信号。
    • 这些是模拟数字转换器(Analog-to-Digital Converter)的通道,用于将模拟信号转换为数字信号。
  6. 全速 SPI (FSPI)和辅助 SPI (SUBSPI)信号引脚

    • 多个引脚可以配置为 全速 SPI 或辅助 SPI(SUBSPI)的 MOSI、MISO、SCLK、SS、HD、DQS 等信号。
    • 高速串行通信:FSPIHD, FSPICS0, FSPID, FSPICLK, FSPIQ, FSPIWP, FSPIDQS
    • 子系统 SPI 的信号:SUBSPICS0, SUBSPID, SUBSPICLK, SUBSPIQ, SUBSPIWP, SUBSPICLK_P_DIFF, SUBSPICLK_N_DIFF
  7. JTAG(Joint Test Action Group)调试引脚 接口的信号,用于调试和编程

    • MTCK (G39)MTDI (G41)MTDO (G40)MTMS (G42):用于芯片的 JTAG 调试接口。
  8. 其他特殊功能引脚

    • CLK_OUT1 、CLK_OUT2、CLK_OUT3:时钟输出信号,可以提供外部电路所需的时钟频率。
    • USB_DP 和 USB_DM:用于 USB 通信的差分信号引脚(通过 U1CTS 和 U1RTS 引脚间接提及)。
    • USB_D+ (G19):对应 USB_DP(Data Positive),这是 USB 数据线的正向数据线。
    • USB_D- (G20):对应 USB_DM(Data Minus),这是 USB 数据线的负向数据线。
  9. 额外的接地引脚

    • GND (40)EPAD (41):额外的接地引脚,EPAD 还可用于提高芯片的散热性能。

在设计使用 ESP32-S3 的电路时,理解每个引脚的功能和复用能力非常重要,这有助于优化硬件布局和软件配置,以满足项目的需求。

import machine

help(machine)
help(machine.Pin)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咖喱年糕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值