使用Python语言开发max78000微控制器 - 在max78000fthr开发板上移植和使用MicroPython
苏勇,2022年12月
使用Python语言开发max78000微控制器 - 在max78000fthr开发板上移植和使用MicroPython
摘要
项目介绍
项目设计思路
一些开发工作和问题
为max78000开发精简的Keil的设备支持包
为max78000开发arm-mcu-sdk驱动程序及样例
尝试max78000fthr板载调试器的问题
使用max78000的UART中断
为max78000fthr启用max20303电源管理芯片
为max78000移植MicroPython
附件
在max78000上使用Python语言编程
下载MicroPython固件到max78000微控制器
实验:第一个程序hello_world
实验:使用数学函数类模块math和cmath
实验:使用Pin类模块实现按键控灯
实验:使用Pin类模块和time类模块控制小灯闪烁
实验:使用SoftI2C类模块访问I2C总线设备
实验:使用SoftSPI类模块进行回环通信测试
实验:使用mem方法直接访问内存空间
总结与展望
参考文献
摘要
本项目为开发max78000微控制器创建了一系列的工具,包括精简的Keil设备支持包和SDK,最终将max78000适配到原生MicroPython项目中,在启用了MicroPython内核之后,启用了Pin类、time类、math/cmath类、SoftI2C类、SoftSPI类,用户可在REPL中使用Python语言对max78000编程,降低了用户使用max78000微控制器的门槛,提供了一种易用的开发体验。
项目介绍
Python,是一种面向对象的解释型计算机程序设计语言,它是纯粹的自由软件,源代码和解释器CPython遵循GPL(GNU General Public License)协议。Python的设计目标之一是让代码具备高度的可阅读性。它设计时尽量使用其它语言经常使用的标点符号和英文单字,让代码看起来整洁美观。它不像其他的静态语言如C、Pascal那样需要重复书写声明语句,也不像它们的语法那样经常有特殊情况和意外。总之,Python是一种简单易用的、能够运行在多个平台下的计算机编程语言。
而MicroPython,是跑在MCU(微控制器)上的Python,通过内置的解释器执行py文件或者py命令,就可以让微控制器运行了。MicroPython和Python编程语言一样,在任何板子上都可以使用通用的API控制硬件底层,比如点亮 LED 灯、读取传感器信息、LCD显示字符串、控制电机、连接网络、连接蓝牙等等。
如果说Arduino让创客摆脱了各种编程环境配置,那么Micropython直接让创客摆脱了底层。命令行和解释执行,都是C语言所不具备的优势,运行Micropython的微控制器,就类似一台完整的电脑,开发者用python文件和命令行,轻松控制这台电脑中的一切。
本项目拟将在max78000微控制器(Arm Cortex-M4内核)上移植MicroPython软件,实现用Python对max78000进行开发的预期目标。当完成完整的MicroPython移植后,开发者将能够通过命令行终端,使用Python语句对max78000微控制器进行编程。
项目设计思路
笔者在过往的项目中,完成过在多个平台上对MicroPython的适配。为了在一款微控制器芯片上适配MicroPython,需要准备一些材料:
- 一个简洁可靠的驱动软件包。驱动程序包是软件与微控制器硬件的桥梁,这是必要的。在原生的MicroPython开发过程中,使用原生的makefile管理项目,因此希望驱动软件包中的文件尽量简明清晰。MicroPython软件的规模相对于一般的微控制器工程要大不少,集成调试相对麻烦,因此需要预先在简单工程中验证驱动软件包可以在armgcc工具链的支持下可以正常工作。
- 在Windows操作系统中使用msys2作为运行环境,搭建仿Linux的开发环境,以及安装armgcc的工具链。原生的MicroPython开发环境是Linux,但笔者大部分熟悉好用的工具都在Windows系统平台上,所以就勉为其难折腾一下子,把Linux的开发环境搬到Windows上了。在Windows上搭建MicroPython开发环境的过程,可以参见帖子《基于Windows系统搭建micropython原生开发环境》(https://blog.csdn.net/suyong_yq/article/details/112797556)
- 根据之前自己撰写的《MicroPython内核开发笔记》中记录的过程,在MicroPython项目的代码仓库中,逐步添加代码,调试通过。
- 先启用串口终端建立用户同MicroPython内核的人机交互,然后启用硬件Pin类模块的支持,再启用系统定时器time类模块、数学计算库math类模块等,之后再试着启用softi2c和softspi等模块。
- 启用MicroPython的文件系统,同图形化开发环境Thonny IDE适配,可以极大地提升开发者的使用体验。
一些开发工作和问题
实际在搜集资料的过程中,遇到了一些意想不到的“麻烦”,也急剧增大了工作量。甚至中途因为电脑故障送修,还耽搁了一周的时间。但是最终排除万难,一一克服,最终基本完成开发目标。
为max78000开发精简的Keil的设备支持包
目前max78000fthr板子的开源项目很多,但大多是基于eclipse和armgcc工具链的,很多微控制器的开发者(包含我)在Windows下更熟悉Keil等传统开发工具。但原生的max78000的Keil工具包比较大,不仅仅包含了keil的设备支持文件,还包含了IAR的设备支持文件,以及原本验证软件的完整代码包。另外,在兼容设备max32655设备支持包中附带的样例工程是基于AC5的,而新版的Keil已经彻底抛弃AC5编译器,仅支持AC6编译器。好吧,总之,还需要重新为max78000芯片做一个Keil的设备支持包。如图x所示。
图x max78000在Keil中的设备支持包
从图x中可以看出,相对于兼容型号max32655的设备设备支持包有将近100MB的大小,而我新创建的max78000的设备支持包仅有59KB。
在创建Keil设备支持包的过程中,一个非常细小的下载选项困扰笔者很久,但最终得以解决。在下载配置对话框中,Reset的类型,默认是“autodetect”,需要改成“VECTRESET”才能正常下载。
图x 为max78000fthr板载调试器配置复位方式
为max78000开发arm-mcu-sdk驱动程序及样例
maxim/ADI原生提供的驱动软件包稍显复杂,只是在支持max78000的软件包中,出现了大量不相干的驱动程序源文件。猜测可能是maxim开放了内部多产品内部电路的软件包,代码风格不统一,存在交叉引用,读起来有点费劲。于是乎,我痛下决心通读了手册,手写SDK。自己手头上用来做SDK架构设计实验的软件项目arm-mcu-sdk有足够的包容性,可以作为max78000驱动软件包的容器。然后,就重建的芯片设备头文件、svd文件、启动代码 、链接命令文件,以及GPIO、CLOCK、UART、I2C等驱动程序。
图x arm-mcu-sdk中max78000的驱动
图x arm-mcu-sdk中max78000fthr板子上适配的样例工程
arm-mcu-sdk是一个为使用Arm Cortex-M处理器内核的微控制器开发的通用SDK软件仓库,包含了方便的项目生成器和大量的通用样例工程,是笔者早年验证SDK软件架构的实验项目,本身也是比较有趣的。但因为本次开发活动的主题在于移植MicroPython,此处就不再详细展开。有兴趣的开发者可以通过附件中提供的下载链接获取到arm-mcu-sdk专门为max78000fthr开发板打包的SDK软件包,其中包含了完整的max78000微控制器的启动代码、驱动程序和一些易于阅读和使用的样例工程,可以用作学习和继续完善max78000微控制器软件,也可以基于这个SDK进行二次开发。
尝试max78000fthr板载调试器的问题
max78000fthr板载的daplink调试器中集成的CDC串口功能似乎不大稳定,在使用笔者新编写的UART驱动,同PC机上的串口调试终端软件通信,使用9600波特率就是正常的,但使用115200波特率通信,在PC的串口终端界面中显示就是乱码。这就直接导致了后续适配Thonny IDE的时候会有一些麻烦,因为Thonny IDE使用串口同MicroPython通信时,固定使用115200波特率进行通信。后续如果时间够用,就试着解一些115200波特率的问题。在活动交流群中听一些开发者说也遇到了类似的情况,但更新半载调试器的固件可能会有所改善。
我在更新板载调试器固件的时候参考了谢娘蓝桥的帖子《MAX78000FTHR 板卡入门》(https://blog.csdn.net/xinshuwei/article/details/126943186),其中有最新固件文件的下载链接和操作方法。我更新固件后得到,可以在daplink虚拟磁盘的DETAIL.TXT文件中看到版本信息如下:
# DAPLink Firmware - see https://mbed.com/daplink
Unique ID: 04441701e3e4036800000000000000000000000097969906
HIC ID: 97969906
Auto Reset: 1
Automation allowed: 1
Overflow detection: 1
Page erasing: 1
Daplink Mode: Interface
Interface Version: 0256
Git SHA: a209a92c65513989f86ac7ff32c1bec27082eee0
Local Mods: 0
USB Interfaces: MSD, CDC, HID, WebUSB
Interface CRC: 0xb61afbb5
Remount count: 0
URL: http://www.maximintegrated.com/max78000fthr
但比较遗憾的时候,更新固件后,仍未解决UART使用115200波特率通信乱码的问题。好吧,暂时也只能先用9600波特率进行人机交互,继续推进主要功能的开发工作。
另外,我还尝试使用向daplink虚拟磁盘中拖拽固件的方式向max78000下载程序,但实际不成功,电脑也会卡在这个地方,如图x所示。看起来尚未支持这个功能。
图x max78000fthr的daplink暂未支持拖拽下载
使用max78000的UART中断
max78000微控制器的UART外设模块的中断机制同笔者常用的其它微控制器也有些许不同。通常情况下,当使用FIFO时,会设计FIFO的发送空中断和接收有数中断,可在中断服务程序中自动为发送或接收过程续命(向FIFO中送数或从FIFO中拿数)。但是,max78000的UART的发送过程中似乎仅有一个半缓冲区中断可用,这就意味着使用中断方式建立UART通信要用一些非常规的做法。例如,在发送过程中,软件不能一下子向FIFO中写太多数,否则FIFO溢出,后续写入的数据可能会被丢掉,但也不能写得太慢,如果UART发送数据的速度比向FIFO中写数的速度快,则无法触发发送FIFO半中断,不能在中断服务程序中自动续数。接收过程中,看起来只有“Receive FIFO Threshold“中断可用,如果能将Threshold设定为1,倒是有机会简化成常规用法。至于“Receive FIFO Overrun”中断,几乎可以等同为一个错误状态中断,不会在常规通信过程中使用了。如非必要,暂时先用轮询方式使用UART。
图x max78000的UART中断事件
实际上,在后续的开发过程中,我仅使用了可以验证正常工作的9600波特率和轮询方式收发,进行基本的通信过程。原本计划适配Thonny IDE作为MicroPython的上位机编程环境,但原生的Thonny IDE约定使用115200波特率,如此,暂时仅能使用REPL的方式体验Python编程了。
为max78000fthr启用max20303电源管理芯片
max78000fthr开发板上使用了max20303电源管理芯片管理了大量外扩电路的供电系统,包括SD卡插座的供电。max20303使用i2c总线同max78000微控制器通信,max78000通过i2c总线配置max20303工作,控制各外扩电路系统供电。
图x max20303电源管理芯片
说起来,在各种微控制器的外设总线引擎中,笔者最不想搞的就是i2c外设了。i2c是一个协议引擎,但又不如CAN、ENET或者SDIO那样有比较完整的功能子模块,被实现得很轻量级,也就意味着需要大量的软件介入配合电路系统才能完成功能。在笔者计划的MicroPython移植项目中,硬件i2c本也不是一个必要实现的类模块,但需要SD卡插座,需要基于SD卡启用文件系统。可max78000fthr板子上的SD插座偏偏用了一个一个max20303芯片控制供电,max20303是一个比较复杂的电源管理芯片,需要使用i2c通信。总之,为了给SD卡插座供电,笔者不得不手写了硬件I2C驱动,通读了max20303的手册并编写驱动代码。其实,很长一段时间,笔者一直忍着没有把max20303的芯片吹下来然后直接把SD卡插座的供电引脚直接连到3.3V供电信号上。
在arm-mcu-sdk中设计的max20303i2c样例工程中,通过max78000的硬件i2c模块同max20303通信,实现了控制max20303闪烁PMIC RGB小灯闪烁、控制PMICMIPC0/1/2/3/4供电引脚的功能。更进一步,在启用了PMICMIPC0(SDVDDENN)控制信号后,可为SD卡插座供电。在arm-mcu-sdk中设计的sdspibasic样例工程中,使用gpio模拟的spi通信引擎,移植了sdspi组件,启用了软件访问SD卡的的功能。图x中展示了在max78000fthr板上运行sdspibasic样例工程中的输出情况。
图x sdspi_basic样例工程
sdspi_basic样例工程运行后,在串口终端界面中的输出信息可以看到,max78000同max20303通信成功,并为SD卡插座启动供电,识别到大约32GB的SD卡容量。
为max78000移植MicroPython
移植MicroPython的工作是在我自己的代码仓库micropython-su完成的。micropython-su基于MicroPython v1.6,但是适配了MIcroPython社区尚未支持的平台,包括一些国产的MCU的平台,例如灵动微电子的MM32F3(Arm Cortex-M3内核)和MM32F5(ArmChina MC1内核),并且保持关键内核功能的更新。目前,micropython-su项目已经在gitee代码托管站开源。
micropython-su项目中的芯片都是在arm-mcu-sdk中支持的,因此,在micropython-su项目中适配已经支持了arm-mcu-sdk的max78000就比较方便了。除了向micropython-su中添加arm-mcu-sdk中关于max78000的启动代码、驱动程序,以及板子配置远吗之外,需要在ports目录下创建max78000目录,专门存放max78000平台的移植工程。
实际上,由于目前使用UART的115200波特率和接收中断的问题,支持Thonny IDE的目前暂时无法实现,因此文件系统的功能暂时也用不上了。此时的移植过程,选择了没有支持文件系统,仅使用REPL的工程模板。我从ke18f的工程作为基础,改为适配max78000平台,依次调整项目目录中的文件,如表x所示。
表x 在micropython-su项目中移植max78000平台的文件清单
中间还处理了一些零碎的小问题,调试代码,查缺补漏等等。最后在msys2环境中编译成功,编译过程持续时间大约为2分钟,在命令行终端中输入信息如下所示。
Andrew@Andrew-PC MSYS /d/gitrepos/micropython-su/micropython-1.16/ports/max78000
# make BOARD=max78000fthr
Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.
mkdir -p build-max78000fthr/genhdr
GEN build-max78000fthr/genhdr/mpversion.h
GEN build-max78000fthr/genhdr/moduledefs.h
GEN build-max78000fthr/genhdr/qstr.i.last
GEN build-max78000fthr/genhdr/qstr.split
GEN build-max78000fthr/genhdr/qstrdefs.collected.h
QSTR updated
GEN build-max78000fthr/genhdr/qstrdefs.generated.h
mkdir -p build-max78000fthr/boards/max78000fthr/
mkdir -p build-max78000fthr/drivers/bus/
mkdir -p build-max78000fthr/extmod/
mkdir -p build-max78000fthr/lib/embed/
mkdir -p build-max78000fthr/lib/libc/
mkdir -p build-max78000fthr/lib/libm/
mkdir -p build-max78000fthr/lib/maxim-mcu/max78000/devices/max78000/
mkdir -p build-max78000fthr/lib/maxim-mcu/max78000/drivers/
mkdir -p build-max78000fthr/lib/mp-readline/
mkdir -p build-max78000fthr/lib/timeutils/
mkdir -p build-max78000fthr/lib/utils/
mkdir -p build-max78000fthr/py/
CC ../../py/mpstate.c
CC ../../py/nlr.c
...
CC ../../lib/libm/wf_tgamma.c
CC ../../lib/libm/ef_sqrt.c
CC ../../drivers/bus/softspi.c
AS ../../lib/utils/gchelper_m3.s
CC ../../lib/maxim-mcu/max78000/devices/max78000/startup_max78000.S
LINK build-max78000fthr/firmware.elf
text data bss dec hex filename
121540 212 8564 130316 1fd0c build-max78000fthr/firmware.elf
在最初适配了micropython内核启用REPL之后,后来陆续添加了help()函数支持、Pin类模块、time类模块、数学计算库math和cmath类模块、SoftI2C类模块、SoftSPI类模块。
现在,终于基本完成任务,可以试着在max78000fthr板子上玩一下MicroPython了。如图x所示。
图x 在max78000fthr开发板运行MicroPython
附件
- max78000芯片设备的Keil设备支持包
https://download.csdn.net/download/suyong_yq/87240086
- arm-mcu-sdk为max78000芯片单独打包的代码包
https://download.csdn.net/download/suyong_yq/87240093
- 包含对max78000支持的MicroPython源码仓库(开源)
https://gitee.com/suyong_yq/micropython-su.git
- max78000fthr开发板上移植的MicroPython固件
https://download.csdn.net/download/suyong_yq/87241836
在max78000上使用Python语言编程
目前在max78000芯片移植的MicroPython的是v1.6版本,但仍兼容MicroPython最新版本中对Python功能的实现。基于MicroPython使用Python语言在微控制器上编程的方法,可参见MicroPython官方的开发文档:
- MicroPython内核使用指南:https://docs.micropython.org/en/latest/library/index.html
- MicroPython硬件相关的类模块:https://docs.micropython.org/en/latest/library/machine.html
下载MicroPython固件到max78000微控制器
对于MicroPython的开发者,如果先从源码编译max78000的MicroPython固件,需要从gitee的代码仓库中克隆micropython-su的源码包,然后在本地搭建开发环境,可参见《基于Windows系统搭建micropython原生开发环境》(https://blog.csdn.net/suyong_yq/article/details/112797556)。
对于MicroPython和开发板的玩家,可以跳过自行编译的过程,使用附件中提供的预编译固件文件,借助于Keil工程将MicroPython固件文件下载到max78000fthr开发板上,可参见《使用DAP-Link单独下载可执行文件到MM32F5微控制器》(https://blog.csdn.net/suyong_yq/article/details/125041701)。或者也可以使用openocd等工具,替代Keil,下载独立的固件文件到单片机。
接下来,就让我们我们开始使用Python在max78000fthr上进行编程吧。
实验:第一个程序hello_world
程序员在学习一门编程语言或者调试设备的时候,通常会使用能够打印“hello world”的第一个程序验证开发环境能够正常工作,这也是建立人机交互的基础。在MicroPython中,仅使用print()函数即可实现该功能。下面的操作均在MicroPython的REPL(Read-Eval-Print Loop) 交互式编程环境中进行。
MicroPython v1.16 on 2022-12-04; MAX78000FTHR with MAX78000
Type "help()" for more information.
>>> print('hello world')
hello world
>>>
再试一下基本的创建变量的功能。
>>> a=2
>>> a**2
4
>>> b=4
>>> a+b
6
>>>
再试一下Python语言专属的for循环的用法。
>>> for i in range(10):
... print(i)
...
0
1
2
3
4
5
6
7
8
9
>>>
注意,for循环语句后面输入冒号“:”后回车,MicroPython会自动缓存接下来的语句,根据Python的语法规则,需要自行输入空格完成缩进。当输入缩进代码片段完成后,再在空行中输入回车即可表示完成输出缩进代码段过程。
实验:使用数学函数类模块math和cmath
根据Python的语法规则,使用math模块之前,需要先导入该模块,才能正常使用。
>>> import math
>>> dir(math)
['__name__', 'pow', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'copysign', 'cos', 'degrees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'isfinite', 'isinf', 'isnan', 'ldexp', 'log', 'modf', 'pi', 'radians', 'sin', 'sqrt', 'tan', 'trunc']
>>>
通过dir()函数,可以看到math模块下已经支持大量的数学函数,这里随便试几个函数。
>>> math.e
2.718282
>>> math.pi
3.141593
>>> for i in range(10):
... print(math.sin(0.5*i))
...
0.0
0.4794255
0.841471
0.997495
0.9092974
0.5984721
0.14112
-0.3507832
-0.7568025
-0.9775301
>>>
类似地,也可以试试复数的数学函数库cmath。
>>> import cmath
>>> dir(cmath)
['__name__', 'cos', 'e', 'exp', 'log', 'phase', 'pi', 'polar', 'rect', 'sin', 'sqrt']
>>> cmath.e
2.718282
>>> cmath.pi
3.141593
>>> d=1+2j
>>> d
(1+2j)
>>> cmath.polar(d)
(2.236068, 1.107149)
>>> cmath.sqrt(d)
(1.27202+0.7861515j)
>>>
实验:使用Pin类模块实现按键控灯
Pin类模块可以与硬件电路建立联系,从微控制器芯片的引脚上读取或者输出电平信号。如图x所示,本实验中,将通过P02引脚连接的按键控制P21引脚连接的绿色LED灯亮灭。
图x max78000fthr板上的按键和小灯
在REPL中输入如下代码:
MicroPython v1.16 on 2022-12-04; MAX78000FTHR with MAX78000
Type "help()" for more information.
>>> from machine import Pin
>>> dir(Pin)
['value', 'IN_FLOATING', 'IN_PULLDOWN', 'IN_PULLUP', 'OUT_OPENDRAIN', 'OUT_PUSHPULL', 'high', 'init', 'low']
>>> btn0 = Pin('P0_2', mode=Pin.IN_PULLUP)
>>> led0 = Pin('P2_1', mode=Pin.OUT_PUSHPULL, value=1)
>>> while True:
... led0(btn0())
...
本实验代码执行的逻辑如下:
- 导入machine类中的Pin类。
- 使用dir()函数参看Pin类的属性,可以看到Pin类下面有很多属性方法(例如init、high、low)和一些属性常量(例如INPULLUP、OUTPUSHPULL)。
- 使用Pin类的实例化方法,创建一个btn0的对象,绑定到P0_2引脚,配置为输入模式带上拉电阻。
- 使用Pin类的实例化方法,创建一个led0的对象,绑定到P2_1引脚,配置为输出模式带推挽。
- 在while循环中,不断查询btn0对应按键引脚读回的电平信号,并以此配置led0对应LED灯引脚的输出电平。这里使用了Python风格的简化写法,如果开发者希望使用更基础的编程语句,也可以逐步操作,类似于下面的写法。
while True:
btn_in = btn0()
if btn_in == 0:
led0.low()
else:
led0.high()
程序执行后,板子上的LED灯都是灭的,当按下SW1按键后,绿色LED亮,松开SW1按键后,绿色LED灯灭。实验成功。
特别注意,开始执行while死循环之后,CPU就被while循环的程序占用了,不再等待串口来的数据,因此REPL不能再同用户进行交互了。此时只能通过复位开发板停止程序重新启动REPL。
在本实验中,首次使用到了machine类。machine类是MicroPython约定的控制硬件相关的类的集合,包含了本实验中使用的Pin类,以及其它同硬件相关的类模块或者属性方法。用户也可以通过dir()方法查看当前开发板上已经支持的硬件相关类模块的资源。
MicroPython v1.16 on 2022-12-04; MAX78000FTHR with MAX78000
Type "help()" for more information.
>>> import machine
>>> dir(machine)
['__name__', 'Pin', 'SoftI2C', 'SoftSPI', 'freq', 'mem16', 'mem32', 'mem8', 'reset']
>>> machine.freq()
100000000
﨧icroPython v1.16 on 2022-12-04; MAX78000FTHR with MAX78000
Type "help()" for more information.
>>>
实验中,通过machine.freq()查看微控制器当前运行程序的主频是100MHz,甚至可以用machine.reset()函数给硬件复位。
实验:使用Pin类模块和time类模块控制小灯闪烁
在本实验中,将引入time类模块,使用它提供的延时方法,周期控制连接LED小灯的引脚输出高低电平,实现闪烁小灯的功能。
MicroPython v1.16 on 2022-12-04; MAX78000FTHR with MAX78000
Type "help()" for more information.
>>> from machine import Pin
>>> import time
>>> dir(time)
['__name__', 'sleep', 'sleep_ms', 'sleep_us', 'ticks_add', 'ticks_cpu', 'ticks_diff', 'ticks_ms', 'ticks_us']
>>> led0 = Pin('P2_1', mode=Pin.OUT_PUSHPULL, value=1)
>>> for i in range(10):
... led0.low()
... time.sleep_ms(400)
... led0.high()
... time.sleep_ms(400)
...
>>>
本实验代码执行的逻辑如下:
- 导入machine类模块的Pin类。
- 导入time类模块。
- 使用dir()函数查看time类模块中可用的属性方法,其中就包括延时毫秒的方法sleep_ms()。
- 使用Pin类模块的属性方法实例化一个led0对象,绑定了P2_1引脚,控制电路板上的绿色LED小灯。
- 使用for循环,执行10次操作800ms周期的闪烁小灯的操作,400ms亮,400ms灭。
运行程序后,板子上的绿色LED小灯即开始闪烁,在此期间REPL不能响应用户输入。闪烁10次后,REPL出现提示符,用户可以继续输入命令。
实验:使用SoftI2C类模块访问I2C总线设备
MicroPython中的SoftI2C类模块是一个非常有趣的硬件相关的类模块。顾名思义,这是一个i2c通信模块,能够实现i2c通信协议,同外部电路进行i2c通信。这也是一个使用gpio模拟的软件i2c模块,相对于硬件i2c绑定在特定的引脚上,gpio模拟的软件i2c可以使用任意的gpio引脚建立i2c通信,这对于MicroPython的玩家无疑提供了巨大的便利。随便找两个gpio引脚接口连接外部的i2c模块,而不需要为i2c专门预留固定的引脚。另外,软件模拟的i2c可以实现更完整的i2c通信协议,而不同芯片上的硬件i2c引擎,因电路系统实现方式不同,能够适配的功能也不尽相同,兼容性不好。
本实验试着访问max78000fthr板子上i2c总线上的max20303芯片上的内容,展示SoftI2C类模块的用法。max78000fthr板子上的i2c总线设备的电路图如图x所示。
图x max78000fthr板上的i2c1引脚
在REPL中输入程序如下:
MicroPython v1.16 on 2022-12-04; MAX78000FTHR with MAX78000
Type "help()" for more information.
>>> from machine import Pin
>>> from machine import SoftI2C
>>> dir(SoftI2C)
['readinto', 'start', 'stop', 'write', 'init', 'readfrom', 'readfrom_into', 'readfrom_mem', 'readfrom_mem_into', 'scan', 'writeto', 'writeto_mem', 'writevto']
>>> i2c0 = SoftI2C(sda=Pin('P0_17'), scl=Pin('P0_16'))
>>> i2c0.scan()
[24, 40]
>>>
这段程序中,通过SoftI2C类模块的实例化方法创建了一个i2c0对象,其中指定了sda引脚为P016,scl引脚为P017。这里没有指定波特率,默认为100khz。实际上,由于是软件模拟的时序,所以指定通信速率不一定准确,并且i2c总线有时钟同步线,指定准确的通信速率意义不大,只能说在条件允许的情况下越快越好。
这里使用SoftI2C的scan()方法,扫描到i2c总线上有两个从机设备,24和40,其中40就是max20303的7位地址号(手册中对应于0x50和0x51的7位地址),如图x所示。
图x max20303手册中关于i2c从机设备地址的说明
继续输入语句,试着读一下max20303的寄存器。
>>> i2c0.readfrom_mem(40, 0, 32)
b'\x02\x02\x00\x00\x00\x00\x16\x08\x00\x00\x00\x00\x00\x00@\x01\x04\x04\x04\x04\x00\x00\x00\x03\x03\x00\x00\x00\x00\x00\x00\x00'
>>> i2c0.readfrom_mem(40, 6, 4)
b'\x16\x08\x00\x00'
>>>
readfrommem()方法的第一个参数是从设备地址,第二个参数是读内存的开始地址,第三个参数是读数据的数量。i2c0.readfrommem(40, 0, 32)语句读出来的32个数中,从0开始编址,6号地址和7号地址上有非零数,分别为0x16和0x08。再使用i2c0.readfrom_mem(40, 6, 4)语句,专门读出来6号地址和7号地址上的数 ,为0x16和0x08,与上一句读出来的内容相符。
更多关于SoftI2C的用法,如果不想阅读MicroPython源码的话,也可以参见MicroPython开发者手册中关于I2C类模块的介绍,见https://docs.micropython.org/en/latest/library/machine.I2C.html。
实验:使用SoftSPI类模块进行回环通信测试
max78000fthr板子上的SPI设备用起来稍微有点复杂,对接SD卡插座的SPI接口,还需要通过i2c配置max20303才能启用电源,或者变身为QSPI模式才能同QSPI接口的SRAM通信。这里为了简单完成SoftSPI通信实验,使用两根引出的引脚作为SPI的MOSI和MISO信号线,可以通过杜邦线短接实现自收自发的回环实验,同时,将CS和CLK信号线绑定到LED灯上,可以观察通过观察小灯的闪烁情况判断SPI的通信情况。
图x max78000fthr板上实验SoftSPI的引脚
在REPL中输入如下程序:
MicroPython v1.16 on 2022-12-04; MAX78000FTHR with MAX78000
Type "help()" for more information.
>>> from machine import Pin
>>> from machine import SoftSPI
>>> import time
>>> dir(SoftSPI)
['read', 'readinto', 'write', 'LSB', 'MSB', 'deinit', 'init', 'write_readinto']
>>>
>>> spi0=SoftSPI(baudrate=2000, sck='P2_1', mosi='P2_6', miso='P2_7')
>>> buf=bytes((0x55, 0x11))
>>> while True:
... spi0.write(buf)
... time.sleep_ms(200)
... print(spi0.read(1, 0x55))
...
b'\xff'
b'\xff'
b'\xff'
b'\xff'
b'\xff'
b'\xff'
b'\xff'
b'\xff'
b'U'
b'U'
b'U'
b'U'
b'U'
b'U'
b'U'
b'U'
b'U'
b'U'
b'U'
b'U'
b'\xff'
b'\xff'
当程序运行时,spi0对象实例启动收发过程。在while循环中,spi0.write()方法向总线上发送buf包含的数串,spi0.read()方法向总线上发数的同时从总线上收数。在实验中,一开始mosi和miso对应的两个引脚P26和P27是断开的,miso信号被上拉,所以收到的数是0xff,当用螺丝刀(我想起来了洗脑神曲《螺丝刀》的旋律)或者杜邦线将这两个引脚短接在一起后,mosi上传输的数据接入到miso,显示收到的数是0xff,也就是大写字符“U”的ASCII码值。
更多关于SoftSPI类模块的用法,可以参见MicroPython开发手册中关于SPI类模块的介绍,https://docs.micropython.org/en/latest/library/machine.SPI.html。
实验:使用mem方法直接访问内存空间
MicroPython的machine类模块中,还提供了一系列mem方法,允许用户使用Python语言直接访问微控制器系统的内部存储。众所周知,除了通用内存之外,绝大多数微控制器关联硬件外设的特殊功能寄存器也是映射在通用存储空间的,这就为跳过硬件类模块而直接用Python对硬件外设编程提供了可能。
本实验中,将演示使用mem方法读取内存内容的操作方法。
在REPL中编写如下程序:
>>> MicroPython v1.16 on 2022-12-04; MAX78000FTHR with MAX78000
Type "help()" for more information.
>>> import machine
>>> dir(machine)
['__name__', 'Pin', 'SoftI2C', 'SoftSPI', 'freq', 'mem16', 'mem32', 'mem8', 'reset']
>>> machine.mem32[0x10000000]
536936448
>>> hex(machine.mem32[0x10000000])
'0x20010000'
>>> hex(machine.mem32[0x10000004])
'0x1001622d'
>>>
从程序执行过程可以看出,0x10000000开始存放的中断向量表:第一个表项的内容为栈顶地址,刚好是SRAM的上限地址;第二个表项的内容为复位向量的入口,应该位于0x10000000到之后的10080000之间地址上,这里看到的'0x1001622d'也是合理的。
清华大学自动化系的卓晴老师曾经写过文章《通过mem32函数来提高MM32 MicroPython 输出PWM 频率的精度》(https://blog.csdn.net/zhuoqingjoking97298/article/details/122792626),讲述了mem系列方法的具体应用。
总结与展望
max78000微控制器使用Arm Cortex-M4处理器内核,最高主频可达100MHz,集成512KB Flash和128KB SRAM存储资源和常用的外设模块,系统资源比较丰富,可用于常规的IOT应用开发,也可用于AI边沿计算的低负载应用。本项目在max78000微控制器平台上完成了一些开发工作:
- 为max78000微控制器创建了精简的Keil设备支持包,并适配了AC6编译器,适配了Windows操作系统下最常用的微控制器开发环境。
- 向通用Arm微控制器SDK项目arm-mcu-sdk中集成了max78000微控制器,创建了易于阅读和使用的驱动程序(clock、gpio、uart)和样例工程(uartbasic、uartinterrupt、gpiobasic、helloworld、max20303i2c、sdspibasic等),用户可在此基础上学习和继续开发max78000微控制器。
- 在原生的MicroPython项目中集成了max78000微控制器,在启用MicroPython内核的基础之上,启用了Pin类、time类、math/cmath类、SoftI2C类、SoftSPI类,用户可在REPL中使用Python语言对max78000编程,降低了用户使用max78000微控制器的门槛,提供了一种易用的开发体验。
在执行项目开发的过程中,也遇到了一些问题,希望后续有机会能够继续解决:
- UART串口的115200波特率问题。目前通过daplink使用的UART串口只能使用9600波特率。这个可能是板载调试器的固件的问题,也可能是arm-mcu-sdk中为之编写驱动程序的问题。max78000fthr板子的外扩插座中引出了UART2,这个问题可以通过换用UART2排查,如果是驱动问题,UART2应该能复现,可以进一步调试
- UART串口的中断应用。UART外设模块没有发送缓冲区空中断,不影响使用,毕竟发送的节奏是掌握在主微控制器这边。但接收过程中,UART没有原生的接收缓冲区有数中断,但提供了一个接收阈值中断,如果可以灵活配置接收阈值为1,就可以等价于接收缓冲区有数中断,届时可以再调一下。
如果解决了UART的问题,就可以方便地为MicroPython适配Thonny IDE图形界面编程环境,可以进一步提升开发者的编程体验。
另外,我最开始向arm-mcu-sdk中集成max78000微控制器,启用裸机开发的支持,也是向深度研究一下芯片上集成的CNN硬件卷积模块,这是面向AI应用的一个很有趣的技术实现。当然,这应该是另一个故事了,值得期待啊。
再另外,max78000fthr羽毛开发板设计电路的集成度非常高,小小的板子上,除了板载调试器和性能不错的主微控制器之外,还集成了SD卡插座、外扩SRAM、摄像头模组、音频codec和耳机插孔,布局紧凑,小巧精悍,后续还想再玩一下音频、图像相关的应用。
参考文献
- 《基于max78000的智能边缘应用设计大赛》(https://www.eetree.cn/page/analog-max78000)
- 《MAX78000FTHR 板卡入门》(https://blog.csdn.net/xinshuwei/article/details/126943186)
- 《MicroPython内核使用指南》(https://docs.micropython.org/en/latest/library/index.html)
- 《MicroPython硬件相关的类模块》(https://docs.micropython.org/en/latest/library/machine.html)
- 《基于Windows系统搭建micropython原生开发环境》(https://blog.csdn.net/suyong_yq/article/details/112797556)。
- 《使用DAP-Link单独下载可执行文件到MM32F5微控制器》(https://blog.csdn.net/suyong_yq/article/details/125041701)
- 《MicroPython的I2C类模块介绍》(https://docs.micropython.org/en/latest/library/machine.I2C.html)
- 《MicroPython的SPI类模块介绍》(https://docs.micropython.org/en/latest/library/machine.SPI.html)
- 《在mm32f3270为micropython创建Pin模块(1)》(https://blog.csdn.net/suyong_yq/article/details/119860197)
- 《在mm32f3270为micropython移植utime模块》(https://blog.csdn.net/suyong_yq/article/details/119879649)
- 《在mm32f3270上为micropython创建SPI模块》(https://blog.csdn.net/suyong_yq/article/details/121375703)
- 《MicroPython中I2C模块的设计与实现(1) - machinei2c框架的机制》(https://blog.csdn.net/suyongyq/article/details/123834945)
- 《手工打造基于MM32F5微控制器的MicroPython开发板》(https://blog.csdn.net/suyong_yq/article/details/125905933)
- 《测试MM32F3277-MicroPython 2021-11-17 版本》(https://blog.csdn.net/zhuoqingjoking97298/article/details/121372618)
- 《MindMotion MM32F3277 SoftI2C功能测试》(https://blog.csdn.net/zhuoqingjoking97298/article/details/121538923)
END