为DC-01开发板移植MicroPython

前言

想想自己为啥很长时间都没有写博客了,可能是写报告写的有点叛逆了,简称“恐报征”。本来就是自己做笔记,为啥为难自己呢?

关于这个板子

由于“信息系统设计”课程,老师定了一批全新的开发板,基本没有什么社区可以参考,除了厂家的一些样例程序,再无其他。可是这个板子搭载的也是STM32F407这样的高端处理器。总还是有一些高级的玩法。

由于前期不知道为啥Wifi模块自杀了,老师也给我换了新的,不过实在无法理解这个大而全的板子设计工程师的脑回路,全集成在一张板子上,可能是没有考虑到故障排除和维修的成本了,不过也可能是我多虑了,毕竟人家公司可是真金白银的花钱在研制了,再怎么说也总比拿钱去炒房有经济效益。

全家福

折腾MircoPython

实在是被这个辣鸡Wifi模块搞害怕了,直接基于模板开发容易陷入同质化的竞争,听了大佬的建议尝试一下用Python编写脚本,毕竟整点老师看不懂的东西容易博得欢心。

根据我搜索引擎专精的特性,解决问题分两步:找到一般解决方式;根据实际情况解决问题。

一般情况

直接搜索mircopython stm32移植找到一些看着还算靠谱的博客,总结如下:

  • 下载代码 —— 使用Git从Github仓库上宕下来就好了
  • 复制模板 —— 把ports/stm32/boards/STM32F4DISC拷一份,作为模板修改
  • 下载子模块 —— git submodule update --init
  • 编译 —— WSL环境make
  • 烧录 —— ST-Link

实际情况

毕竟这块板子非等闲之辈,怎么可能直接可以用呢?

针脚定义

各个阵脚的定义,到处全局搜索,查看需要定义的宏,还有就是可以使用的宏。分别定义好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#define MICROPY_HW_BOARD_NAME       "DC-01"
#define MICROPY_HW_MCU_NAME "STM32F407"

#define MICROPY_HW_HAS_SWITCH (0)
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
#define MICROPY_HW_ENABLE_DAC (1)
#define MICROPY_HW_ENABLE_USB (0)

// HSE is 8MHz
#define MICROPY_HW_CLK_PLLM (8)
#define MICROPY_HW_CLK_PLLN (336)
#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
#define MICROPY_HW_CLK_PLLQ (7)

// UART config
#define MICROPY_HW_UART1_TX (pin_A9)
#define MICROPY_HW_UART1_RX (pin_A10)
// #define MICROPY_HW_UART2_TX (pin_A2)
// #define MICROPY_HW_UART2_RX (pin_A3)
#define MICROPY_HW_UART3_TX (pin_B10)
#define MICROPY_HW_UART3_RX (pin_B11)
#define MICROPY_HW_UART4_TX (pin_C10)
#define MICROPY_HW_UART4_RX (pin_C11)
#define MICROPY_HW_UART5_TX (pin_C12)
#define MICROPY_HW_UART5_RX (pin_D2)
#define MICROPY_HW_UART6_TX (pin_C6)
#define MICROPY_HW_UART6_RX (pin_C7)

#define MICROPY_HW_UART_REPL PYB_UART_5
#define MICROPY_HW_UART_REPL_BAUD 115200

// I2C busses
// #define MICROPY_HW_I2C1_SCL (pin_B6)
// #define MICROPY_HW_I2C1_SDA (pin_B7)
// #define MICROPY_HW_I2C2_SCL (pin_B10)
// #define MICROPY_HW_I2C2_SDA (pin_B11)

// SPI busses
#define MICROPY_HW_SPI1_NSS (pin_A15)
#define MICROPY_HW_SPI1_SCK (pin_B3)
#define MICROPY_HW_SPI1_MISO (pin_B4)
#define MICROPY_HW_SPI1_MOSI (pin_B5)

// CAN busses
#define MICROPY_HW_CAN1_TX (pin_A13)
#define MICROPY_HW_CAN1_RX (pin_A12)
// #define MICROPY_HW_CAN2_TX (pin_B13)
// #define MICROPY_HW_CAN2_RX (pin_B12)

// USRSW is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN (pin_A0)
#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING)
#define MICROPY_HW_USRSW_PRESSED (1)

// LEDs
#define MICROPY_HW_LED1 (pin_F9)
#define MICROPY_HW_LED2 (pin_F10)
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))

// USB config
#define MICROPY_HW_USB_FS (MICROPY_HW_ENABLE_USB)
#define MICROPY_HW_USB_MSC (0)
#define MICROPY_HW_USB_HID (0)
#define USBD_CDC_RX_DATA_SIZE (256)
#define USBD_CDC_TX_DATA_SIZE (256)

// Bluetooth config
#define MICROPY_HW_BLE_UART_ID (PYB_UART_1)
#define MICROPY_HW_BLE_UART_BAUDRATE (115200)

// Ethernet via RMII
#define MICROPY_HW_ETH_MDC (pin_C1)
#define MICROPY_HW_ETH_MDIO (pin_A2)
#define MICROPY_HW_ETH_RMII_REF_CLK (pin_A1)
#define MICROPY_HW_ETH_RMII_CRS_DV (pin_A7)
#define MICROPY_HW_ETH_RMII_RXD0 (pin_C4)
#define MICROPY_HW_ETH_RMII_RXD1 (pin_C5)
#define MICROPY_HW_ETH_RMII_TX_EN (pin_G11)
#define MICROPY_HW_ETH_RMII_TXD0 (pin_G13)
#define MICROPY_HW_ETH_RMII_TXD1 (pin_G14)
#define MICROPY_HW_ETH_REST (pin_D3)

编译遇到如下问题:

1
2
3
4
5
6
7
8
9
10
eth.c:38:25: fatal error: lwip/etharp.h: No such file or directory
#include "lwip/etharp.h"
^
compilation terminated.
network_lan.c:34:24: fatal error: lwip/netif.h: No such file or directory
#include "lwip/netif.h"
^
compilation terminated.
../../py/mkrules.mk:88: recipe for target 'build-HIBOARD/genhdr/qstr.i.last' failed

参照其他的开启了ETH的板子配置文件,得知由于没有启动这个库的编译开关,所以出错。在板子目录下的Makefile里添加MICROPY_PY_LWIP = 1开启就可以了。

编译遇到如下问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
boards/HIBOARD/mpconfigboard.h:59:38: error: 'pin_F9' undeclared here (not in a function)
#define MICROPY_HW_LED1 (pin_F9)
^
led.c:54:26: note: in expansion of macro 'MICROPY_HW_LED1'
{{&pyb_led_type}, 1, MICROPY_HW_LED1},
^~~~~~~~~~~~~~~
boards/HIBOARD/mpconfigboard.h:60:38: error: 'pin_F10' undeclared here (not in a function)
#define MICROPY_HW_LED2 (pin_F10)
^
led.c:56:26: note: in expansion of macro 'MICROPY_HW_LED2'
{{&pyb_led_type}, 2, MICROPY_HW_LED2},
^~~~~~~~~~~~~~~
../../py/mkrules.mk:63: recipe for target 'build-HIBOARD/led.o' failed
make: *** [build-HIBOARD/led.o] Error 1

反过头去了解了一下,发现针脚需要先在pins.csv里定义,遂全部按照PA1这样定义,后发现可以重复定义,把一些特殊的GPIO定义上特殊的名字,问题解决。

再次编译,有遇到如如下问题:

1
2
3
4
5
6
7
8
9
10
11
12
build-HIBOARD/frozen_content.c:137:5: error: redeclaration of enumerator 'MP_QSTR_SOL_SOCKET'
MP_QSTR_SOL_SOCKET,
^~~~~~~~~~~~~~~~~~
In file included from ../../py/obj.h:33:0,
from ../../py/objint.h:30,
from build-HIBOARD/frozen_content.c:15:
build-HIBOARD/genhdr/qstrdefs.generated.h:834:6: note: previous definition of 'MP_QSTR_SOL_SOCKET' was here
QDEF(MP_QSTR_SOL_SOCKET, (const byte*)"\x0f\xdf\x0a" "SOL_SOCKET")
^
../../py/qstr.h:41:23: note: in definition of macro 'QDEF'
#define QDEF(id, str) id,

然后去看了build-HIBOARD/genhdr/qstrdefs.generated.h发现并没有这一行代码,遇事不决清一波缓存,问题解决。

至此,编译成功。

以太网模块适配

上版测试后发现,以太网模块无法驱动,对照其他的官方支持板子的电路图,查看接线区别。发现一根本来应该使用硬件控制的,日常拉高的重置接口,在这个板子上直接接到了GPIO的一个口。

为了发现这个错误可以说是煞费苦心了,在MicroPython代码中添加调试输出,疯狂参照官方给的Rj45使用样例的逻辑修改模块,对照着令人眼瞎的接线图,发现了这一个需要拉高的操作。

修改ports\stm32\eth.c文件,在eth_mac_init函数的开始添加拉高操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifdef MICROPY_HW_ETH_REST
GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.Pin = MICROPY_HW_ETH_REST->pin_mask;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;

HAL_GPIO_Init(MICROPY_HW_ETH_REST->gpio, &GPIO_InitStructure);

mp_hal_pin_low(MICROPY_HW_ETH_REST);
mp_hal_delay_ms(50);
mp_hal_pin_high(MICROPY_HW_ETH_REST);
#endif

成功点亮以太网接口。

其他模块

告辞,又不是不能用,虽然没定义了蓝牙的接口,还没时间搞。

最终结果

使用ampy这个工具上传http_server.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
try:
import usocket as socket
except:
import socket

from network import LAN

CONTENT = b"""\
HTTP/1.0 200 OK
Hello #%d from MicroPython!
"""


def main(micropython_optimize=False):
l = LAN()
l.active(1)
l.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
s = socket.socket()
# Binding to all interfaces - server will be accessible to other hosts!
ai = socket.getaddrinfo("0.0.0.0", 8080)
print("Bind address info:", ai)
addr = ai[0][-1]
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(5)
print("Listening, connect your browser to http://<this_host>:8080/")
counter = 0
while True:
res = s.accept()
client_sock = res[0]
client_addr = res[1]
print("Client address:", client_addr)
print("Client socket:", client_sock)
client_stream = client_sock.makefile("rwb")
print("Request:")
req = client_stream.readline()
print(req)
while True:
h = client_stream.readline()
if h == b"" or h == b"\r\n":
break
print(h)
client_stream.write(CONTENT % counter)
client_stream.close()
client_sock.close()
counter += 1
print()


main()

访问http://192.168.0.4:8080得到结果:

截图

我觉得单凭这一块就可以交差了。

结尾

这个板子售价950+,买点就是“我们板子一应俱全”,感觉设计板子的人可能是这门课老师的学生,设计的板子和老师的报告有异曲同工之妙。