《在 APM32F427 上运行 Python》https://bbs.21ic.com/icview-3501089-1-1.html
介绍了移植 PikaPython 到 APM32F427 的基础功能,本文介绍 GPIO 驱动移植,目标:点灯。
引入新的必要的包
上一篇文章中,我们在 pikapython\\requestment.txt 加入了当时必须的两个包(或者称之为”模块“)。在运行包管理器后,内容被追加了版本信息,变成:
复制
pikascript-core==v1.13.4
PikaStdLib==v1.13.4
为了实现点灯,我们增加两个新的包: PikaStdDevice 和 time,内容变更为:
复制
pikascript-core==v1.13.4
PikaStdLib==v1.13.4
PikaStdDevice
time
再次运行包管理器 pikaPackage.exe,完成后也是会追加合适的版本信息,内容为:
复制
pikascript-core==v1.13.4
PikaStdLib==v1.13.4
PikaStdDevice==v2.4.6
time==v0.2.2
这4个包是点灯必须的。下面将会增加针对 APM32F427 的自定义包。
加入针对 APM32F427 的模块
新建文本文件 pikapython\\apm32f4_pika.pyi,内容:
复制
# apm32f4_pika.pyi
from PikaObj import *
import PikaStdDevice
class GPIO(PikaStdDevice.GPIO):
…
class UART(PikaStdDevice.UART):
…
这是声明了两个类:GPIO 和 UART。
稍后编写 py 脚本的时候,是可以直接使用 apm32f4_pika.GPIO 实例化相应的类。
修改 pikapython\\requestment.txt,把 apm32f4_pika 追加到文件末尾:
复制
pikascript-core==v1.13.4
PikaStdLib==v1.13.4
PikaStdDevice==v2.4.6
time==v0.2.2
apm32f4_pika
运行 rust-msc-latest-win10.exe,生成必要的内容,可以看到程序的输出类似:

红色框出可以看到有5个包,与 requestment.txt 的内容一一对应。
在 pikascript-api 文件夹下新增了3个文件:
- apm32f4_pika.h
- apm32f4_pika_GPIO.h
- apm32f4_pika_UART.h
这几个文件的内容不用关系,它们是自动生成的,也不需要编辑修改。下面开始编写驱动。
编写驱动
在 pikascript-lib 文件夹下,创建 apm32f4_pika 文件夹,GPIO/UART 的驱动就放在这个文件夹下。简单起见,我们先把全部驱动的代码放在 pikapython\\pikascript-lib\\apm32f4_pika\\apm32f4_pika.c 这个源文件里:
复制
#include "BaseObj.h"
#include "dataStrs.h"
#include "pika_hal.h"
#include "board.h"
#include "apm32f427xx.h"
#include <stdint.h>
#include <string.h>
struct platform_data_GPIO
{
int port;
int pin;
};
static GPIO_T *const gpios[] = {
GPIOA,
GPIOB,
GPIOC,
GPIOD,
GPIOE,
GPIOF,
GPIOG,
GPIOH,
};
// 把字符串类型的 Pin 脚名称解析为 port/pin 编号
static int get_io_port_and_pin(const char *name, int *port, int *pin)
{
char ch = 0;
if (name[0] != 'P' && name[0] != 'p')
{
return -1;
}
int res = sscanf(name + 1, "%c%d", &ch, pin);
if (res != 2)
{
return -1;
}
if (ch >= 'A' && ch <= 'Z')
{
*port = ch – 'A';
}
else if (ch >= 'a' && ch <= 'z')
{
*port = ch – 'a';
}
else
{
return -1;
}
if (*port < 0 || *port > 7 || *pin < 0 || *pin > 15)
{
return -1;
}
return 0;
}
// 打开 GPIO 设备
int pika_hal_platform_GPIO_open(pika_dev *dev, char *name)
{
int port, pin;
int res = get_io_port_and_pin(name, &port, &pin);
if (res != 0)
{
return -1;
}
// 申请一个 GPIO 数据结构体
struct platform_data_GPIO *data = pikaMalloc(sizeof(struct platform_data_GPIO));
data->pin = pin;
data->port = port;
// 驱动数据指向生成的 GPIO 数据结构体
dev->platform_data = data;
return 0;
}
// 关闭 GPIO 设备
int pika_hal_platform_GPIO_close(pika_dev *dev)
{
if (NULL != dev->platform_data)
{
pikaFree(dev->platform_data, sizeof(struct platform_data_GPIO));
dev->platform_data = NULL;
}
return 0;
}
// 读取 GPIO
int pika_hal_platform_GPIO_read(pika_dev *dev, void *buf, size_t count)
{
struct platform_data_GPIO *gpio_data = dev->platform_data;
uint32_t level = (gpios[gpio_data->port]->IDATA >> gpio_data->pin) & 1;
memcpy(buf, &level, count);
return 0;
}
// 设置 GPIO
int pika_hal_platform_GPIO_write(pika_dev *dev, void *buf, size_t count)
{
struct platform_data_GPIO *gpio_data = dev->platform_data;
uint32_t level = 0;
memcpy(&level, buf, count);
if (level == 0)
{
gpios[gpio_data->port]->BSCL |= (1 << gpio_data->pin);
}
else
{
gpios[gpio_data->port]->BSCH |= (1 << gpio_data->pin);
}
return 0;
}
// 使能 GPIO 设备,暂时保持空
int pika_hal_platform_GPIO_ioctl_enable(pika_dev *dev)
{
(void)dev;
return 0;
}
// 禁用 GPIO 设备,暂时保持空
int pika_hal_platform_GPIO_ioctl_disable(pika_dev *dev)
{
(void)dev;
return 0;
}
// 配置 GPIO 设备
int pika_hal_platform_GPIO_ioctl_config(pika_dev *dev,
pika_hal_GPIO_config *cfg)
{
struct platform_data_GPIO *gpio_data = dev->platform_data;
if (cfg->dir == PIKA_HAL_GPIO_DIR_OUT)
{
// 配置为 输出
gpios[gpio_data->port]->MODE = (gpios[gpio_data->port]->MODE & (~(3 << (gpio_data->pin * 2)))) | (1 << (gpio_data->pin * 2));
}
else
{
// 否则为 输出
gpios[gpio_data->port]->MODE = gpios[gpio_data->port]->MODE & (~(3 << (gpio_data->pin * 2)));
}
gpios[gpio_data->port]->PUPD = gpios[gpio_data->port]->PUPD & (~(3 << (gpio_data->pin * 2)));
switch (cfg->pull)
{
case PIKA_HAL_GPIO_PULL_UP: // 上拉
gpios[gpio_data->port]->PUPD |= (1 << (gpio_data->pin * 2));
break;
case PIKA_HAL_GPIO_PULL_DOWN: // 下拉
gpios[gpio_data->port]->PUPD |= (2 << (gpio_data->pin * 2));
break;
default:
break;
}
return 0;
}
// 提供 ms 延时
void pika_platform_sleep_ms(uint32_t ms)
{
ms_delay(ms);
}
驱动写完了,把它加入 keil 工程。
需要注意的是,pikascript-lib 目录下因为我们新增的两个包 PikaStdDevice 和 time 都自动生成了相应的源文件,也都需要加入到 keil 工程一起编译。
运行
编译成功,下载程序到开发板。
为了测试新增的包,编写一个测试程序,让 LED2 闪烁 50 次:
复制
import PikaStdLib
import PikaStdDevice
import apm32f4_pika
import time
mem = PikaStdLib.MemChecker()
print('mem.max :')
mem.max()
print('mem.now :')
mem.now()
led2 = apm32f4_pika.GPIO()
led2.setPin('PF0')
led2.setMode('out')
led2.enable()
led2.low()
for i in range(0,50):
print(i)
led2.low()
time.sleep_ms(500)
led2.high()
time.sleep_ms(500)
print('over')
因为目前的工程尚未集成文件系统,所以我们不能直接运行这个脚本。好在 PikaPython 项目提供了 pikaStudio 这个工具,可以通过串口发送并执行脚本。下载连接:https://gitee.com/Lyon1998/pikapython/attach_files/1285327/download
下载并执行这个程序:

在红色框处选择串口,波特率并打开。复位一次设备,就能在终端看到串口输出的内容:

勾选红色框处的复选框,把刚才准备好的 py 脚本拖进去~
从图可以看到执行期间串口输出的计数值。下面放一个视频,看看闪灯的效果:
https://bbs.21ic.com/forum.php?mod=attachment&aid=MjQ1NDY4OHxkMGQyYmYxY3wxNzcyMjQ3NzE4fDB8
小结
PikaPython 提供了统一的驱动模式,只需要在 .pyi 文件声明支持的类,运行 **rust-msc-latest-win10.exe** 后就可以生成相应的程序框架。开发工程师就只需要完成具体的驱动开发就可以达成目标。总体来说还是很方便的。
APM32F427 大存储、高主频的特性,也给 PikaPython 提供了一个非常合适的运行平台, 大家快来试试呀~
@21小跑堂




———————
作者:wangqy_ic
链接:https://bbs.21ic.com/icview-3501181-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。