在mm32f3270为micropython创建Pin模块(1)

本文讲述了作者在将MicroPython移植到MM32F3270芯片时,创建Pin模块的步骤和遇到的困难。作者实现了Pin模块的基本功能,包括引脚配置、模式设置等,并尝试添加Timer模块以实现闪灯功能。然而在运行过程中遇到了Hardfault问题,经过汇编级调试,发现错误出现在标准库的strcmp函数中。屏蔽该函数调用后,虽然解决了运行时的问题,但在使用历史记录时仍会触发Hardfault。文章以日常琐事穿插其中,展现了作者耐心细致的调试过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在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模块实现相关的代码都放在这一个源文件中。

  1. 在“machine_pin.c”文件中编写与底层无关的框架代码,见附件。

  2. 把“machine_pin.c”文件加到Makefile文件中:

     - 在“SRC_C”中添加“machine_pin.c \\”
     - 在“SRC_QSTR”中添加“machine_pin.c \\”。
    
  3. 在“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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值