LPC55S69 IoT Kit专属 Micropython模组和库函数简介

Posted 卓晴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LPC55S69 IoT Kit专属 Micropython模组和库函数简介相关的知识,希望对你有一定的参考价值。

 

§01


Micropython是一个开源项目,目标是在微控制器和小型嵌入式系统上实现Python3.x的语法,和部分标准的Python库,可在资源受限的系统中运行。 Micropython实现了完整的Python3.4语法(包含exceptions, with, yield from等,还实现了Python3.5的async/await关键字)。提供了以下核心的数据类型:str(包含基本的Unicode支持), bytes, bytearray, tuple, list, dict, set, frozenset, array.array, colletions.namedtuple, 类和实例。内置模块包括sys,time和struct等。某些移植项目支持_thread模块(多线程)。请注意,仅针对数据类型和模块实现了Python 3功能的一个子集。

MicroPython可以执行文本形式的脚本或预编译字节码,文本脚本或预编译码都是在设备上的文件系统中,或“冻结”在MicroPython的可执行文件中。

Micropython官方发布的代码和文档,可在micropython.org阅读和下载。

1.1 MicroPython在LCP55S69上移植

Micropython在LPC55S69上的移植工作是在逐飞科技制作的IoT Kit主板上进行开发的。如下图。

▲ 图1.1.1 LPC-Link以及LPC55S69开发板

LPC55S69适合Micropython的主要特点是,她有足够大的存储器:640KB的Flash和320K SRAM。尤其在移植初期,对Micropython不太了解的情况下,可以不必考虑存储限制,想测试什么内容、想怎么实现功能,可以放心地去做,而暂时不必考虑太多的优化和裁剪,待开发成熟后,可以经过适当的裁剪后,轻松地迁移到LPC5500系列中存储容量较小的型号。

1.2 MicroPython的基本运行环境

LPC55S69上实现的Micropython,在USB高速接口上,实现了两个USB-MSC(大容量存储设备),和两个USB-CDC串口设备。

两个USB-MSC分别对应开发板上的SD卡接口和一个扩展的SPI Flash模块,在代码里这个SPI Flash固定使用FlexCOMM3接口(未来可以根据需要配置使用其它接口,或去除它)。

▲ 图1.2.1 SPI Flash

开发时,使用了右图所示的SPI Flash扩展模块,在集成到终端应用中时,应把它直接焊接在PCB板上,这样它上面的文件系统和文件都可以方便地预先设置好。

在系统上电启动时,会先检查SPI Flash是否存在,如果存在则按照Micropython的设定,先执行其中根目录的boot.py和main.py。

当SPI Flash不存在时,则检查是否有SD卡,如果有,则执行根目录下的boot.py和main.py
随后,不管是否执行过SPI Flash或SD卡中的启动文件,将在第一个USB-CDC连接的USB串口窗口显示提示版本信息和micropython的提示符。

这个接口将是Micropython的控制终端REPL。(在其它micropython的系统中,通常REPL是通过UART接口实现的。)

注:两个CDC接口中哪一个是REPL对应的端口,要看Windows加载驱动时先加载哪个,比较快的判断方法是自行试一下,哪个能出现“>>>”提示符。这个测试只需在此开发板第一次连接到你的PC时才需要,以后这个端口的编号就不会变了。

注意:由于系统上电后,往往用户来不及打开串口窗口,而看不到micropython的版本与提示符,但如果一切正常,在连接并打开串口窗口后,应能看到提示符,此时键入Ctrl-D则进行热启动,将能看到启动时显示的版本信息。下图为热启动后显示的内容:

▲ 图1.2.2 REPL串口显示内容

中间那行“Hello World”是main.py输出的信息,随后就是micropython的版本信息和提示符。
USB-HS接口上的第二个USB-CDC串口设备,则可以由用户自由使用,例如输出一些调试信息等。后面相应章节会介绍如何使用它。

在LPC55S69芯片上还有一个USB-FS接口,目前的实现代码中没有用到这个接口,以后可以根据需要修改代码,把它配置为任意USB设备。

1.3 内置Python模块一览

在REPL控制终端输入help(‘modules’)将显示当前系统中预置的模块,如下图所示:

▲ 图1.3.1 内置Python模块一览

其中大部分都是标准micropython的模块,本文不赘述。有以下几个不同的模块,将会在本文后续章节介绍用法:

  • lpc55 这里包含了所有LPC5500片内外设对应的类
  • display 这里包含了所有支持的显示屏对应的类
  • lpc_mem 用于访问LPC5500片内存储区

其中的lpc55模块是移植的主要部分,这个模块对应标准micropython的pyb模块。

1.4. 转换axf文件并烧录到开发板上

首先执行以下命令把axf文件转换为bin文件

arm-none-eabi-objcopy -O ihex lpc55s69_iot_mpy.axf LPC55S69_mpy.hex

然后按住开发板上的ISP按钮的同时,插上USB-HS线至PC(插上USB线后,可以放开ISP按钮),然后执行以下命令进行烧录:

blhost -u 0x1fc9,0x21 -- flash-image LPC55S69_mpy.hex erase

 

§02 存访问模块
lpc_mem


该模块对应标准micropython的machine模块,但做了大幅简化,只保留了与存储器(包括寄存器)访问相关的部分,用户可以通过umachine模块访问原有的其它功能。

注意:umachine模块中有几个与片内硬件模块相关的类,还未来得及测试,暂时不要使用。

Pin, UART和rng与lpc55模块中相同名字的类的用法相同。

▲ 图2.1 help(umachine)显示内容

2.1 内存访问

内存访问是以数组下标的方式操作的,按返回数值的位数,分别有三个数组:mem8,mem16和mem32。

  • 数组mem8的下标可以是任意地址值。
  • 数组mem16的下标必须是2字节对齐的地址值。
  • 数组mem32的下标必须是4字节对齐的地址值。

它们分别返回给定地址的8位、16位或32位的数值。

例如下面右图是地址0x0000 0000开始的MCU向量表的部分数据,左图是操作的结果:

▲ 图2.1.1 MCU向量表格

从上至下操作的结果的说明如下:

  • 129: 字节地址0x0000 0004的十进制数值
  • 0x81: 字节地址0x0000 0004的十六进制数值
  • 8196: 半字地址0x0000 0002的十进制数值
  • 0x2004: 半字地址0x0000 0002的十六进制数值
  • 204963: 字地址0x0000 000C的十进制数值
  • 0x320a3: 字地址0x0000 000C的十六进制数值

2.2 访问寄存器

所有内部寄存器组的基地址和寄存器组中寄存器的偏移地址,都可以以lpc_mem常数的方式使用。

2.2.1 寄存器组基地址

▲ 图2.2.1 寄存器组基地址

如上图,每个模块的寄存器基地址常数都以模块的名字命名,带后缀_NS的常数是以非加密方式访问该模块的地址。(目前的固件没有使能芯片的加密功能,所以访问任意模块时,可以用带_NS后缀或不带这个后缀)

2.2.2 寄存器组内偏移地址

每个寄存器组内的寄存器偏移地址常数,是以模块的名字作为前缀,再加上寄存器的名字构成,如下图:

▲ 图2.2.2 寄存器组内的偏移地址

2.2.3 寄存器访问示例

在逐飞这个LPC55S69开发板上,有一个三色LED,信号线连接如下:

  1. 红色LED .→ PIO1-12
  2. 绿色LED .→ PIO0-27
  3. 蓝色LED .→ PIO1-22

首先初始化各个对应引脚为上拉输出,并熄灭LED:

▲ 图2.2.3 初始化LED引脚

可以用Pin类的函数点亮某个LED:

  • r.value(0):在r引脚上输出0,点亮红色LED

也可以直接操作该引脚对应的寄存器,实现相同目的:

▲ 图2.2.4 直接曹遵引脚对应的寄存器

2.3 谨慎使用lpc_mem

内存访问模块lpc_mem提供了最大的灵活性,让用户可以使用Python脚本直接操作底层寄存器。

使用lpc_mem要十分小心,需要仔细阅读用户手册,搞清楚每个寄存器的用法。

还要避免直接寄存器操作影响到micropython类的操作访问,例如当你用Python脚本操作SPI模块时,如果冒然改变了SPI外设的寄存器内容,有可能会出现不可预料的后果。

如果你对LPC5500的底层非常了解,可以用lpc_mem检查一些底层寄存器的内容,方便功能调试,尤其时修改调试micropython固件时是很有用的。

例如以下这个自定义函数脚本,可以用来显示所有IOCON的寄存器,依此查看所有引脚的配置情况:

▲ 图2.3.1 查看IOCON寄存器

实际操作的效果如下图:

▲ 图2.3.2 实际操作效果

 

§03 设控制模块
lpc55(通用部分)


外设控制模块集合了众多操作片上外设的类和函数,这是micropython与标准Python的主要区别之一,不同的MCU上的micropython实现都会有类似的外设控制模块,例如在pyboard板上的外设控制模块的名称是pyb。

lpc55中的类和函数,其语法和使用方法,与pyb类大体相同,但为了适配LPC5500的功能和内部定义,移植micropython时在不少地方做了调整,本章将介绍与其它Micropython移植基本相同的模块类和函数,后续章节将分别介绍那些LPC5500上特有的模块。

lpc55模块中有一些函数是与标准micropython相同的函数,这些函数与硬件无关,因此它们的语法和功能也和其它micropython的实现相同,请读者直接参考docs.micropython.org中pyb模块的相关描述。

▲ 图3.1 lpc55的相关功能

lpc55模块还有一些与芯片与板上硬件相关的函数和类,下面将分别介绍。

3.1 硬件无关的函数

本节简要地列出lpc55中与pyb中语法与功能相同的函数。

那些没有列在这里,但出现在pyb文档的函数,是暂时没有实现的功能,例如与功耗控制相关的部分等。

3.1.1 info():

输出一些micropython内部信息

本函数打印输出一些固件的内部信息,主要是为固件开发者参考,因此在lpc55中大大简化了输出的内容。

下图是输出的示例:

▲ 图3.1.1 LPC5.info的输出

3.1.2 unique_id():

读出芯片唯一ID

lpc55.unique_id()

该函数返回一个16字节的bytearray(),包含芯片的唯一ID。

▲ 图3.1.2 unique_id()输出

3.1.3 country(code):

设置国家代码。

该函数设置一个内部变量的值,但目前只看到与网络相关的部分用到这个内部变量,不太清楚怎么用。

lpc55.country(code) 设置国家代码,code为2个ASCII字符。

▲ 图3.1.3 使用示例

3.1.4 main(filename):

设置主脚本
lpc55.main(filename)
输入一个脚本文件名字,系统启动时,在boot.py之后将执行这个脚本文件。
如果未用该函数指定执行脚本,则boot.py之后默认执行main.py脚本,如果main.py不存在也不会报错。
只有在boot.py中调用该函数才有意义。

3.1.5 repl_uart(uart):

指定作为REPL的端口
lpc55.repl_uart(uart)
函数的输入参数是一个由lpc55.UART创建的实体,用于指定REPL的端口。

3.1.6 delay(ms):

延迟若干毫秒
lpc55.delay(ms)
接受的输入是一个整数,函数通过内部systick延迟ms毫秒,然后返回。
注:由于micropython语句的执行开销,函数的延迟并不准确,只能作为一个参考。

3.1.7 udelay(us):

延迟若干微秒
lpc55.delay(us)
接受的输入是一个整数,函数通过内部systick延迟us微秒,然后返回。
注:由于micropython语句的执行开销,函数的延迟并不准确,只能作为一个参考。

3.1.8 millis():

返回自开机后的时间
lpc55.millis()
返回自开机后的时间,单位为毫秒。

3.1.9 micros():

返回自开机后的时间
lpc55.micros()
返回自开机后的时间,单位为微秒。

3.1.10 elapsed_millis():

返回当前时间与给定时间的差
lpc55. elapsed_millis(start)
给定一个开始时间,返回当前时间与给定的时间差值,单位为毫秒。
通常该函数与millis()一起使用,可以用来测量某段代码执行的时间。

3.1.11 elapsed_micros():

返回当前时间与给定时间的差
lpc55. elapsed_micros(start)
给定一个开始时间,返回当前时间与给定的时间差值,单位为微秒。
通常该函数与micros()一起使用,可以用来测量某段代码执行的时间。
下图演示了以上4个函数的用法。

▲ 图3.1.4 函数演示结果

3.1.12 mount():

挂载一个存储设备
lpc55. mount(device, mountpoint, *, readonly=False, mkfs=False)
该函数的语法与功能与pyb.mount()一样,请参考docs.micropython.org
例如将挂载SD卡至根目录/sd:lpc55.mount(lpc55.SD, ‘/sd’),下图为执行演示:

▲ 图3.1.5 挂载SD的结果

3.1.13 sync():

同步文件系统
lpc55. sync()
同步所有文件系统。
由于各种内部缓存的缘故,有时候文件系统的物理介质里内容与内部缓存不一致,这个函数将同步缓存与介质的内容。
一般在写入文件系统后,尤其是在关机断电之前,强烈建议使用这个函数进行文件系统同步。

3.2. 芯片内部外设相关类概述

每个芯片内部的外设模块,都有一个Python类封装了对它们的操作函数。本节将逐一介绍已经实现的、与其它Micropython移植相同功能的类和函数,以及它们的使用方法。

下表列出了lpc55模块中所有外设相关类:

▲ 图3.2.1 外设相关的类

3.2.1 rng():

读取一个30位的随机数
lpc55. rng()
返回一个由硬件产生的30位随机数。
右图是一个例子。

▲ 图3.2.2 rng运行示例

3.3. ADC模数转换类及函数

芯片内部有一个16位、采样率为1Msps的ADC模块,芯片外部有10个ADC引脚;还有一些内部通道用于测量内部电压,例如片内温度传感器。

3.3.1 ADC创建函数

class lpc55.ADC(pin, init=False)
创建一个与指定引脚绑定的ADC实体,随后可以通过这个实体读取对应引脚的模拟值。

  • pin可以是一个ADC引脚的名字,如果给出的引脚不是ADC引脚,则抛出ValueError异常。

  • pin也可以是一个整数编号,对应ADC内部通道。

■ 按照LPC55S69用户手册,共有3个内部通道,分别为: 12 = VDD3V3_ADC 13 = Bias_vref_1v from aux_bias module 26 = Temperature sensor

■ 注:内部通道部分未经测试,暂时不要使用

init表示是否需要强制初始化ADC模块,默认为False。在第一次上电时,固件内部会自动初始化,一般不需人工干预。

3.3.2 ADC.deinit()函数

ADC.deinit()
关闭ADC模块,以节省耗电。

注:该函数将关闭ADC模块,所有的ADC引脚都不能再进行转换了,须通过创建函数再次初始化才能继续使用。

3.3.3 ADC.mode():

设置转换模式
ADC.mode(sample=7, average=4)
该函数用于设置进行ADC转换时的一些参数。

. sample用于指定每次转换时的采样时间。默认值为7,即最长的采样时间。

采样时间为(3 + 2sample)个ADC时钟周期,如下表:

. average用于指定执行硬件平均的次数。本参数为2的幂次,实际平均次数为2average次。 average的默认值为4,即执行16次硬件平均。

硬件平均可以有效降低信号噪声,而且节省了软件的开销。
. 当不带参数调用该函数,则返回一个tuple,分别为已经设置的参数。

3.3.4 ADC.read():

读取当前转换数值
ADC.read()
读取ADC引脚上的电压值并返回一个整数,返回值的范围是0~65535。
注:由于各种误差,强烈建议舍弃返回值的最低3~4位,即将返回值右移3 ~ 4位再用。

3.3.5 ADC.read_timed():

按定时器设定频率读取
ADC.read_timed(buf, timer)
按照timer的速率,读出一组数据并存放在buf中。
该函数设置好周期转换后将立即返回,需设置一个回调函数以获知转换的结束。

. buf可以是一个bytearray或array.array,数组中的每个单元应该可以容纳16位或以上位数的整数,如果buf的每个单元只有8位(bytearray的情况),则只取结果的高8位。
. timer是一个CTimer类的实体,定时器周期性地触发ADC转换并读取结果至buf。
. timer也可以是一个整数,给定采样频率,micropython固件将自动使用CTimer4的通道3作为ADC周期采样的触发源。

注1:根据LPC55S69的用户手册,只能使用CTimer1~4的通道3触发ADC转换,应合理配置CTimer。
注2:ADC的触发源还可以是SCT的一些输出端,和其它一些信号,目前的固件暂不支持这些触发源,未来可以根据需要添加相应的配置方式。

3.3.6 ADC.callback():

设置成组转换结束时的回调函数
ADC.callback(func)

. func是一个回调函数,read_timed()函数设置的成组转换结束后,固件将调用这个回调函数,用户可以在这个回调函数处理读取的数据,或设置结束标志。

. 如果没有用这个函数设置回调函数,或func参数空缺或等于None,则ADC.read_timed()函数再转换完指定次数后才返回。

下面是一个完整的使用read_timed()进行周期性ADC转换的例子。

回调函数cb(x)带了一个参数,这是一个整数,表示转换的次数。

注:关于回调函数(中断函数)的用法,尤其是硬中断与软中断的区别,请查看micropython文档:http://docs.micropython.org/en/latest/reference/isr_rules.html

3.3.7 ADC.read_timed_multi():

多通道成组转换
ADC.read_timed_multi((adcx, adcy, …), (bufx, bufy, …), timer, func)
这是一个静态函数(static method),用于从多个ADC通道进行转换。

该函数按timer实体设置的速率,分别从多个ADC通道读取转换值,并存入各自对应的缓冲区。

. 第一个参数是一个tuple,(adcx, adcy, …),按顺序给出转换通道的引脚名字

. 第二个参数也是一个tuple,(bufx, bufy, …), 按照上述引脚名字的顺序给出相应的存储数组,所有的数组长度和单元类型必须相同。数组的设置规则与3.3.5的buf参数相同。

. timer是一个CTimer类的实体,与3.3.5的timer参数意义相同。

. func是一个回调函数,使用方法与3.3.6相同

该函数返回一个整数,表示转换的次数。

下面是一个使用read_timed_multi()的例子:


注:每次调用read_timed_multi(),固件都会自动初始化ADC硬件模块。

3.4. CTimer定时器类及函数

CTimer是LPC5500系列的一个标准定时器,在LPC55S69中有5个CTimer,编号分别为0~4。

CTimer的基本工作原理是一个递增计数器,输入时钟经预分频后作为计数时钟。

每个CTimer有四个通道,每个通道都有一个匹配(比较)寄存器和一个捕获寄存器,目前的固件暂时不支持配置捕获寄存器的操作,以下描述都是关于匹配寄存器的功能。

每个匹配寄存器的数值会实时地与递增计数器比较,使用者可以配置当比较匹配时执行以下动作:

■ 复位递增计数器为零(即重新开始计数),或停止计数
■ 在对应的外部引脚上执行设置、清除或Toggle操作

可以同时配置以上对计数器的操作和对引脚的操作。

每个匹配寄存器还有一个相伴的影子寄存器,当计数器开始计数后,用户不能直接写入匹配寄存器而改变设置,必须通过影子寄存器而间接地修改匹配寄存器。每次复位计数器时,影子寄存器的内容会传送到对应的匹配寄存器中。

以下逐一结束CTimer类和各函数的用法。

3.4.1 CTimer创建函数

class lpc55.CTimer(id, ….) 创建一个CTimer实体。 . id是对应CTimer的编号,可以是0~4之间的整数。 . 如果有其它参数,则直接执行init()函数的初始化。

3.4.2 CTimer.init()初始化函数

CTimer.init(prescale)
配置预分频系数,并初始化CTimer。

. prescale为预分频系数值。
. CTimer的输入时钟为150MHz,计数器的计数时钟频率是150MHz/(prescale+1)

3.4.3 CTimer.deinit()

CTimer.deinit()
关闭CTimer定时器。
不用CTimer定时器时,关闭它可以节省相应的功耗,并释放资源供其它功能使用。

3.4.4 CTimer.counter()读出计数器

CTimer.counter()
读出当前计数器的计数值。

3.4.5 CTimer.enable()使能计数器

CTimer.enable(en=True)
使能计数器开始计数 . en为一个布尔值,缺省时默认为True。 . en=True表示清零计数器并启动计数。 . en=False表示停止计数器的计数。

3.4.6 CTimer.mode()

设置定时器工作模式
CTimer.mode(mode, freq)
设置CTimer的工作模式。

. mode指定工作模式,目前实现了三种模式:MODE_NORMAL,MODE_PWM和MODE_TRIGGER。 . mode=MODE_NORMAL表示用户可以自由设置CTimer的工作方式,见下面说明。

. mode=MODE_PWM用于配置PWM输出,见下面说明。

. mode=MODE_TRIGGER用于配置CTimer作为另一个模块的触发源,例如ADC.read_timed()。

. freq仅用于在MODE_TRIGGER模式下给出触发频率,其它模式时该参数缺省。由于分频系数只能是整数,不一定能准确得到用户要求的触发频率,因此配置触发模式时,该函数返回一个计算得到的最接近频率值。

3.4.7 CTimer.MODE_TRIGGER

触发模式的用法
该模式是一个特殊配置,CTimer的所有四个通道都配置为相同的频率,并产生50%占空比的PWM输出,可以将任一通道对应的引脚配置为输出,并得到%50的PWM波形。
该模式适合于与ADC模块配合使用,例如3.3.6节例子中CTimer部分的配置,可以改为如下方式:

3.4.8 CTimer.channel()

获取CTimerChannel类实体 CTimer.channel(id)

这个函数返回一个CTimerChannel类的实体,用于对相应通道的配置。
. id的取值范围是0~3

CTimerChannel类的函数用于配置相应的通道,根据CTimer.mode()选取的模式不同,在某些模式下不能使用一些函数,对应关系如下表(Y表示可以使用相应函数):

以上是关于LPC55S69 IoT Kit专属 Micropython模组和库函数简介的主要内容,如果未能解决你的问题,请参考以下文章

安装LPC55S69 MicroPython模块是遇到的CDC Interface驱动问题

Microsoft IoT Starter Kit 开发初体验

Microsoft IoT Starter Kit 开发初体验-反馈控制与数据存储

用于互联网连接的 LPC 1769 以太网 MAC

ESP32开发板开源啦 ESP32-IOT-KIT全开源物联网开发板

ESP32开发板开源啦 ESP32-IOT-KIT全开源物联网开发板