在mm32f3270为micropython创建Pin模块(1)
苏勇,2021年8月
Requirements
最终期望实现的效果是,在REPL界面能运行如下脚本:
from machine import Pin
pin0 = Pin(22)
UART0 = Pin(pin0, af=PIN_AF_1)
pin1 = Pin(23, mode=PIN_MODE_1, drive=PIN_DRIVE_1)
pin1.high()
pin1.low()
pin1.value([0])
print("pin1 value:" + pin1.value())
类对象方法实例化,类方法定义,位置参数和关键字参数的传参等问题,都可以参考之前的文章,套用workflow予以解决。但是对于引脚的编号,需要在编写相应代码(引脚映射表格)时考虑一下。另外,编写Pin基本功能的同时,也尽量考虑一下在分析代码过程中暂时放过的AF类和IRQ类。
一点长远的考虑,timer的类原本是在minimal中的,它对硬件的依赖并不复杂,短时间也考虑实现出来。这样,最后闪小灯的脚本就应该是:
from machine import Pin
from machine import Timer
pin0 = Pin(22)
timer0 = Timer(0)
while True:
pin0.high()
timer0.sleep(10)
pin0.low()
timer0.sleep(10)
涉及到mimxrt的源文件有:
- machine_pin.c
- pin.h
- pin.c
代码框架
在“ports/mm32”目录下创建“machine_pin.c”,此文件专用于存放pin类的实现,是“modmachine.c”总类的下属。之后尽量把所有Pin模块实现相关的代码都放在这一个源文件中。
-
在“machine_pin.c”文件中编写与底层无关的框架代码,见附件。
-
把“machine_pin.c”文件加到Makefile文件中:
- 在“SRC_C”中添加“machine_pin.c \\” - 在“SRC_QSTR”中添加“machine_pin.c \\”。
-
在“modmachine.c”中,登记Pin模块为machine模块的下属:
- 在文件接近开始的地方引用已经定义好的Pin类对象:
extern const mp_obj_type_t machine_pin_type;
这句话原来是定义在“modmachine.h”文件中的,但是在我移植中,我不想创建这个文件了。反正使用命令行编译工具,让源文件尽量少一点,相关代码都放在“machine_pin.c”中。
- 在“machine_module_globals_table[]”中登记Pin类:
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) },
工程里,试着编一下,OK。再下载运行。。。
HARDFAULT !!! HARDFAULT !!! HARDFAULT !!!
复位后可以正常打印输出log,但是一运行python语句就完蛋。试过了降主频(之前有一次在MM32F3270上运行micropython碰到Hardfault就是这么解决的)但仍不起作用,回滚到之前调通过的版本重新下载,还是没改善。担心是板子的问题,之前调通过的MM32F3277G7P的板子还放在办公室,家里这块MM32F3277G8P的板子以前没用过,这次出状况,周末也不方便去办公室拿板子。由于micropython奇葩的编译方式,还没办法在线调试,无法在源代码中定位出问题的语句。。。
从周六下午纠结到周天晚上,期间遇到一些事情:
- 半夜出门扔西瓜皮,回来下楼到工作间里打电脑游戏,凌晨3点钟。
- 早上8点被宝宝叫起来数小青蛙和圈圈。困。
- 家里拖鞋开胶了。
- 下午带宝宝出门去超市,车子刚开到超市门口,看到超市开始赶人不让进了,直接原路返回。
- 回家之后给天台铺了一小块地板。
- 晚饭之后给兔子洗笼子,让兔子在天台上跑了一会,再给它洗了个澡。宝宝看兔子,念叨爸爸洗兔子比洗宝宝还上心。
- 洗完兔子顺带也给自己冲了冲。
明天又要上班了。还是逃不掉的,收收心,耐住性子,这破事还得解决。周日晚上在楼上卧室打开电脑,继续看代码。
在ozone里逐行跟踪汇编语句,一点点看,终于找到案发现场了,是在一个strcmp()函数中挂掉。但这是个标准库函数,又不涉及操作硬件,估计是编译器选项、链接库或者芯片内核的bug。再次试过了给3270降主频、给内核加电压、调整预读取缓存都不起作用。那就看能不能跳过这些语句,看call_stack,最后定位的点在“lib/mp-readline/readline.c”文件中的“readline_process_char()”函数中,处理回车那块,将已收到的命令压入历史记录里:
int readline_process_char(int c) {
size_t last_line_len = rl.line->len;
int redraw_step_back = 0;
bool redraw_from_cursor = false;
int redraw_step_forward = 0;
if (rl.escape_seq == ESEQ_NONE) {
if (CHAR_CTRL_A <= c && c <= CHAR_CTRL_E && vstr_len(rl.line) == rl.orig_line_len) {
// control character with empty line
return c;
} else if (c == CHAR_CTRL_A) {
// CTRL-A with non-empty line is go-to-start-of-line
goto home_key;
#if MICROPY_REPL_EMACS_KEYS
} else if (c == CHAR_CTRL_B) {
// CTRL-B with non-empty line is go-back-one-char
goto left_arrow_key;
#endif
...
} else if (c == '\r') {
// newline
mp_hal_stdout_tx_str("\r\n");
/* Andrew to get rid of hardfault on mm32. */
//readline_push_history(vstr_null_terminated_str(rl.line) + rl.orig_line_len);
return 0;
}
...
}
我把“readline_push_history()”那句mask掉之后,重新编译,下载,运行,正常。
但是按“up”键调用history的时候还是跳Hardfault。
此处猜测可能是保存history的内存的分配情况还是有问题。考虑到history可能涉及到的地方比较多,我试着找了找能不能通过某个用户选项把history相关的功能都关掉,未果,只好人工mask掉这一句,并且祈祷尽量别碰到使用history的场景。现在重点在于把底层调通,软件的部分后面再专门抽出时间追一下。
在micropython的REPL里,已经可以看到Pin模块被注册到machine模块下面了:
MicroPython v1.16 on 2021-08-22; MB_F3270 with MM32F3277G7P
>>> dir(machine)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name not defined
>>> import machine
>>> dir(machine)
['__name__', 'Pin', 'freq', 'mem16', 'mem32', 'mem8']
>>> import machine.Pin
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: module not found
>>> from machine import Pin
>>> pin0 = Pin()
>>> print(pin0)
None
>>>
从log中可以看出,当需要引用Pin模块时,不能直接使用“import machine.Pin”,但可以使用“from machine import Pin”。
这篇文章里杂事太多,烦了。分篇,明天继续。
曾经听过某人说兔子不能喝水。。。
END