0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

pikascript GPIO接口如何基于rtt pin设备实现呢?

冬至子 来源:IcyFeather 作者:IcyFeather 2023-08-07 17:47 次阅读

介绍

Pikascript 是 RT-Thread 软件包中心 - 编程语言 中的一个包,是一个对单片机友好的轻量级 python 脚本支持工具,类似 micropython。

在 Pikascript 中,架构如下:

1.jpg

对于不同的平台,我们需要手动为平台适配 pika_hal 的设备抽象层接口。今天以 packages/pikascript-latest/pikaRTDevice/pika_hal_RTT_GPIO.c 为例,讲解 Pikascript GPIO 接口如何基于 RT-Thread Pin 设备 rt-thread/components/misc/pin.c 实现。

讲解

模型如下:

1.jpg

所有设备均遵循类 linux 文件的编程模型,所有类型的设备均使用 pika_dev 结构体来作为设备句柄。

pika_dev 类型定义:

typedef struct {
PIKA_HAL_DEV_TYPE type;
PIKA_BOOL is_enabled;
void* ioctl_config;
void* platform_data;
} pika_dev;

在 RT-Thread 的文档中可以得知,应用程序通过 RT-Thread 提供的 PIN 设备管理接口来访问 GPIO,相关接口如下所示:

1.jpg

// 通过设备名,返回 pin num
rt_base_t rt_pin_get(const char *name);
// 通过 pin num,返回该 pin 的数据
int rt_pin_read(rt_base_t pin);
// 把 value 电平信息写到对应 pin 上
void rt_pin_write(rt_base_t pin, rt_base_t value);
// 把 pin 的模式设置为 mode
void rt_pin_mode(rt_base_t pin, rt_base_t mode)
所以经过分析,不难看出我们在 open 中要通过 rt_pin_get() 获取引脚编号,获取设备信息;在 read 中要通过 rt_pin_read() 读取引脚电平;在 write 中要通过 rt_pin_write() 设置引脚电平。

在 pika_hal_RTT_GPIO.c 中,我们一共有 7 个接口要实现:

int pika_hal_platform_GPIO_open(pika_dev* dev, char* name);
int pika_hal_platform_GPIO_close(pika_dev* dev);
int pika_hal_platform_GPIO_read(pika_dev* dev, void* buf, size_t count);
int pika_hal_platform_GPIO_write(pika_dev* dev, void* buf, size_t count);
int pika_hal_platform_GPIO_ioctl_enable(pika_dev* dev);
int pika_hal_platform_GPIO_ioctl_disable(pika_dev* dev);
int pika_hal_platform_GPIO_ioctl_config(pika_dev* dev, pika_hal_GPIO_config* cfg);
下面我们依次进行讲解。

dev->platform_io 中存储的数据
首先定义一个结构体 platform_data_GPIO 用来存在 dev->platform_data 中,由上面对 rtt pin 接口的简单调用分析可知,只需要 pin 的数据:

typedef struct platform_data_GPIO {
uint32_t pin_num;
} platform_data_GPIO;
pika_hal_platform_GPIO_open
函数的原型为: int pika_hal_platform_GPIO_open(pika_dev* dev, char* name);

参数

pika_dev* dev: 要操作的设备句柄
char* name: GPIO 设备名
函数功能:

根据 GPIO 设备名,找到对应的 GPIO 设备的 pin
把设备 pin 数据存在 dev->platform_data 里面
实现:

int pika_hal_platform_GPIO_open(pika_dev* dev, char* name) {
// 打印当前信息
rt_kprintf("rn=%s==%s=%d=name:%s==rn", FILE , FUNCTION , LINE ,name);
// 打印一下日志信息,当前正在打开哪个设备
__platform_printf("Open: %s rn", name);
// 调用 pikaMalloc 分配内存,创建一个 platform_data_GPIO 结构体,用来存放这个 GPIO 设备的信息
platform_data_GPIO* data = pikaMalloc(sizeof(platform_data_GPIO));
// 在 RT_USING_PIN 这个宏定义存在时,通过 rt_pin_get 函数获取这个 GPIO 设备的引脚号,存放在 platform_data_GPIO 结构体的 pin_num 成员中。
#ifdef RT_USING_PIN
data->pin_num = rt_pin_get(name) ;
#endif
// 将创建的 platform_data_GPIO 结构体赋值给 dev->platform_data
dev->platform_data = data;
return 0;
}
pika_hal_platform_GPIO_close
函数的原型为:int pika_hal_platform_GPIO_close(pika_dev* dev);

参数:
pika_dev* dev: 要操作的设备句柄

函数功能:
清除这个 GPIO 设备的信息,即清空 dev->platform_data 中的数据

实现:

int pika_hal_platform_GPIO_close(pika_dev* dev) {
rt_kprintf("rn=%s==%s=%d===rn", FILE , FUNCTION , LINE );
// 如果现在有 GPIO 设备数据,就清空
if (NULL != dev->platform_data) {
pikaFree(dev->platform_data, sizeof(platform_data_GPIO));
dev->platform_data = NULL;
}
return 0;
}
pika_hal_platform_GPIO_read
函数的原型为:int pika_hal_platform_GPIO_write(pika_dev* dev, void* buf, size_t count);

参数:
pika_dev dev:要操作的设备句柄
void buf:读取缓冲区
size_t count:读取数据长度,对于 GPIO、ADC 这样只能读取单个数据的设备,长度为 sizeof(uint32_t)

函数功能:

根据之前存到 dev->platform_data 中的 pin num 数据,调用 rt_pin_read() 函数来获取该 pin 的数据
把读取到的数据存到 buf 缓冲区中
实现:

int pika_hal_platform_GPIO_read(pika_dev* dev, void* buf, size_t count) {
// 获取之前存放的platform_data_GPIO结构体指针
platform_data_GPIO* data = dev->platform_data;
uint32_t level;
rt_kprintf("rn=%s==%s=%d=gpio:%d==rn", FILE , FUNCTION , LINE ,data->pin_num);
#ifdef RT_USING_PIN
// 根据 pin num 读取电平
level = rt_pin_read(data->pin_num);
#endif
// 只有可能是 0 或 1
if (level != 1 && level != 0) {
return -1;
}
// 把 &level 处的 count 个(sizeof(uint32_t) 个)数据拷贝到 buf 缓存区,memcpy 函数不关心 buf 和 src 指向的内存是什么类型,它只根据 count 拷贝内存
memcpy(buf, &level, count);
return 0;
}
注意:
在文档中指出,GPIO 设备 read 时读取的数据 count 应该为 sizeof(uin32_t),在 pika_hal_platform_GPIO_read 中,level 的类型设置为 uint32_t,这是和文档要求一致的。而给 level 赋值的 rt_pin_read() 函数的返回类型为 int,这里进行了一个隐式类型转换。

pika_hal_platform_GPIO_write
函数的原型为:int pika_hal_platform_GPIO_write(pika_dev* dev, void* buf, size_t count);

参数:
pika_dev dev:要操作的设备句柄
oid buf:写入缓冲区
size_t count:写入数据长度,对于 GPIO、ADC 这样只能读取单个数据的设备,长度为 sizeof(uint32_t)

函数功能:
1.根据之前存储的 dev->platform_data 信息获取 pin num
2.获取之前 buf 中存储的电平信息
3.把电平信息写到对应 pin 上

实现:

int pika_hal_platform_GPIO_write(pika_dev* dev, void* buf, size_t count) {
// 获取之前 platform_data 数据
platform_data_GPIO* data = dev->platform_data;
// 获取 buf 缓存区存储的高低电平信息
uint32_t level = 0;
memcpy(&level, buf, count);
// 把电平写到对应 pin 上
#ifdef RT_USING_PIN
if (level == 0) {
rt_pin_write(data->pin_num, PIN_LOW);
return 0;
}
if (level == 1) {
rt_pin_write(data->pin_num, PIN_HIGH);
return 0;
}
#endif
return 0;
}
pika_hal_platform_GPIO_ioctl_enable
函数的原型为:int pika_hal_platform_GPIO_ioctl_enable(pika_dev* dev);

参数:
pika_dev* dev:被操作的设备句柄

函数功能:
这个函数其实对应的是 pika_hal_ioctl(pika_dev* dev, PIKA_HAL_IOCTL_ENABLE) 这里的情况,使能了这个配置函数
所以要初始化一下 GPIO 的 pin num、输入输出模式、推挽模式、波特率等数据

实现:

目前只实现了打印日志

int pika_hal_platform_GPIO_ioctl_enable(pika_dev* dev) {
platform_data_GPIO* data = dev->platform_data;
rt_kprintf("rn=%s==%s=%d=pin_num:%x==rn", FILE , FUNCTION , LINE ,data->pin_num);
/* TODO /
return 0;
}
pika_hal_platform_GPIO_ioctl_disable
函数的原型为:int pika_hal_platform_GPIO_ioctl_disable(pika_dev
dev);

参数:
pika_dev* dev:被操作的设备句柄

函数功能:
这个函数其实对应的是 pika_hal_ioctl(pika_dev* dev, PIKA_HAL_IOCTL_DISABLE) 这里的情况

实现:

同 enable 部分,disable 也只是打印了日志

int pika_hal_platform_GPIO_ioctl_disable(pika_dev* dev) {
rt_kprintf("rn=%s==%s=%d===rn", FILE , FUNCTION , LINE );
platform_data_GPIO* data = dev->platform_data;
return -1;
}
pika_hal_platform_GPIO_ioctl_config
函数的原型为:int pika_hal_platform_GPIO_ioctl_config(pika_dev* dev, pika_hal_GPIO_config* cfg);

参数:
pika_dev dev:被操作的设备句柄
pika_hal_GPIO_config cfg:GPIO 配置,具体定义如下:

typedef struct {
PIKA_HAL_GPIO_DIR dir;//输入输出
PIKA_HAL_GPIO_PULL pull;//推挽模式
PIKA_HAL_GPIO_SPEED speed;//数据传输速率
void (event_callback)(pika_dev dev, PIKA_HAL_GPIO_EVENT_SIGNAL signal);//事件回调函数
PIKA_HAL_GPIO_EVENT_SIGNAL event_callback_filter;//上升沿还是下降沿
//事件回调是否使能
PIKA_HAL_EVENT_CALLBACK_ENA event_callback_ena;
} pika_hal_GPIO_config;
函数功能:
1.对输入输出进行讨论,分为 PIKA_HAL_GPIO_DIR_OUT、PIKA_HAL_GPIO_DIR_IN 两种
2.对推挽模式进行讨论,分为 PIKA_HAL_GPIO_PULL_NONE、PIKA_HAL_GPIO_PULL_UP、PIKA_HAL_GPIO_PULL_DOWN 三种
3.讨论事件回调是否使能、是否设置了回调函数
4.讨论回调函数是上升沿触发还是下降沿触发(PIKA_HAL_GPIO_EVENT_SIGNAL_RISING 以及 PIKA_HAL_GPIO_EVENT_SIGNAL_FALLING)

实现:

现有实现中并没有管回调函数的部分,所以相对简单

RT-Thread 文档中关于 void rt_pin_mode(rt_base_t pin, rt_base_t mode); 函数的 mode 可选项为:

#define PIN_MODE_OUTPUT 0x00 /* 输出 /
#define PIN_MODE_INPUT 0x01 /
输入 /
#define PIN_MODE_INPUT_PULLUP 0x02 /
上拉输入 /
#define PIN_MODE_INPUT_PULLDOWN 0x03 /
下拉输入 /
#define PIN_MODE_OUTPUT_OD 0x04 /
开漏输出 */
所以最外层讨论输入输出,内层讨论上拉下拉即可。

int pika_hal_platform_GPIO_ioctl_config(pika_dev* dev,
pika_hal_GPIO_config* cfg) {
rt_kprintf("rn=%s==%s=%d=dir:%d==rn", FILE , FUNCTION , LINE ,cfg->dir);
platform_data_GPIO* data = dev->platform_data;
uint8_t pinMode = 0;
// 对 cfg 中各项分类讨论,从而确定 pinMode
switch (cfg->dir) {
case PIKA_HAL_GPIO_DIR_IN:
switch(cfg->pull)
{
case PIKA_HAL_GPIO_PULL_UP:
pinMode = PIN_MODE_INPUT_PULLUP;
break;
case PIKA_HAL_GPIO_PULL_DOWN:
pinMode = PIN_MODE_INPUT_PULLDOWN;
break;
default:
pinMode = PIN_MODE_INPUT;
}
break;
case PIKA_HAL_GPIO_DIR_OUT:
pinMode = PIN_MODE_OUTPUT;
break;
default:
pinMode = PIN_MODE_OUTPUT;
}
// 将 pin 的模式设置为 pinMode
#ifdef RT_USING_PIN
rt_pin_mode(data->pin_num, pinMode);
#endif
return 0;
}
Todo

作者也在阅读源码的过程中发现了一些问题:

1.对失败的情况有时候没有做讨论,如 pika_hal_platform_GPIO_open 函数中,显然 rt_pin_get() 是可能获取不到的,此时应该返回 -1 表示出错并打印有关日志信息,但现有代码中没有这部分处理

2.pika_hal_platform_GPIO_ioctl_config 中没有配置为开漏模式的情况,这意味着无法使用 pikascript 脚本将 GPIO 模式设置为开漏模式。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 存储器
    +关注

    关注

    38

    文章

    7483

    浏览量

    163757
  • 缓冲器
    +关注

    关注

    6

    文章

    1921

    浏览量

    45472
  • GPIO
    +关注

    关注

    16

    文章

    1204

    浏览量

    52049
  • python
    +关注

    关注

    56

    文章

    4792

    浏览量

    84621
  • RTThread
    +关注

    关注

    8

    文章

    132

    浏览量

    40858
收藏 人收藏

    评论

    相关推荐

    基于GPIO模拟的SPI接口驱动设计与实现

    SPI总线是我们常用的串行设备接口,一般情况下我们都会适应硬件SPI接口,但有些时候当硬件端口不足时,我们也希望可以使用软件来模拟SPI硬件接口,特别是要求不是很高的时候。在这一篇中我
    发表于 12-07 16:21 6329次阅读
    基于<b class='flag-5'>GPIO</b>模拟的SPI<b class='flag-5'>接口</b>驱动设计与<b class='flag-5'>实现</b>

    如何通过RT-Thred提供的pin设备管理接口来操作GPIO

    PIN设备的操作方法应用程序通过RT-Thred提供的pin设备管理接口来操作GPIO,函数
    发表于 01-12 07:01

    RT-Thread PIN设备学习资料分享

    一、PIN 设备学习 PIN 设备RTT 最简单的一个设备,通过
    发表于 03-29 11:12

    RT Thread PIN组件的物理操作

    。RT HAL HAL interface 用于MCU 和RTT特定的 PIN接口之间的解耦最后由MCU 官方HAL库实现PIN 组件的物理
    发表于 05-16 16:03

    怎样通过RT-Thread提供的PIN设备管理接口来访问GPIO

    :访问 PIN 设备应用程序通过 RT-Thread 提供的 PIN 设备管理接口来访问 GPIO
    发表于 07-15 11:16

    RTT系统初始化后_hw_pin指针总是为空这是为什么

    RTT Studio建立项目,设备是STM32WB55 Nucleo。按照RTT的流程,在rtthread_startup()函数中已经有对board的各种接口的初始化。main()
    发表于 08-12 11:08

    GPIO设备接口主要有哪些功能

    的功能,程序会自动配置这些引脚。pinmux table 位于 bsp/board/xxx_board 目录下 pinmux_config.h 文件。通过标准的 GPIO 设备接口配置引脚,缺点是只能
    发表于 08-18 17:18

    使用RTT设备框架PIN设备去设置边沿触发无法关闭这是什么原因

    我手上有两个光电传感器。使用STM32外部中断,边沿触发(上升沿和下降沿都触发)反馈传感器有没有被碰到。使用cube+裸机编程没有问题.使用RTT设备框架PIN设备去设置边沿触发(上
    发表于 09-06 10:57

    使用RT-Thread与N32G457实现SPI接口的驱动设计

    前言参加创新“芯”引擎 | 国民技术N32G457 RT-Thread设计大赛,使用到了spi但是,spi接口使用rtt的还是头一次,所以还是学习。在使用spi的时候使用RT-Th
    发表于 09-23 11:42

    pikascript移植报错不知道是哪里的问题?

    想在fm33lx基础上应用pikaScript做脚本开发,通过env添加了pikaScript的软件包,工程里也出现了对应的文件,但是在编译的时候提示错误,不知道哪里的问题,请大咖指教。
    发表于 05-05 11:49

    TD-SCDMA RTT的空间接口技术综述

    TD-SCDMA RTT的空间接口技术综述:
    发表于 05-21 13:22 20次下载
    TD-SCDMA <b class='flag-5'>RTT</b>的空间<b class='flag-5'>接口</b>技术综述

    STM32 通用GPIO模拟I2C实现

    STM32 模拟I2C实现#通用GPIO模拟I2C通信实现样例1 GPIO初始化``#ifdef HW_I2C1 //硬件I2C初始化//PA8-I2C1_SCLGPIO_Struct
    发表于 11-29 15:21 29次下载
    STM32 通用<b class='flag-5'>GPIO</b>模拟I2C<b class='flag-5'>实现</b>

    为什么要在芯片中配置GPIO

    为什么要在芯片中配置GPIO 作为一种基础的控制接口GPIO(General Purpose Input/Output)即通用输入输出端口,可用于控制数字
    的头像 发表于 09-13 15:28 1184次阅读

    RTT_Draco的外置uart接口(TXD,RXD)怎么配置和使用

    RTT_Draco的外置uart接口(TXD,RXD)怎么配置和使用? RT-Thread的RTT_Draco是一款高性能的MCU芯片,它提供了外置UART
    的头像 发表于 01-16 17:11 1029次阅读

    gpio接口是干什么的 gpio四种输入输出模式怎么选择

    这些引脚的电平状态,实现与外部设备的通信和交互。GPIO接口在嵌入式系统、物联网设备、树莓派项目等领域有着广泛的应用,为电子
    的头像 发表于 10-06 16:07 2460次阅读