一个字符驱动示例 -- 微秒级别周期 反转GPIO

文章描述了一位开发者在尝试以微秒级别频率翻转GPIO信号时遇到的问题及解决方案。开始时,由于使用sleep函数和system调用导致的开销,频率无法达到期望值。之后,将操作移至内核驱动,使用udelay函数,成功提高了频率并实现了稳定的GPIO翻转。
摘要由CSDN通过智能技术生成

仅作为自我记录的一个demo
本次GPIO以微妙级别频率的反转实验有以下几个启示:

  1. 一开始在应用层做延时,来实现2微妙周期,占空比50%的GPIO反转,发现波形的频率一直上不去,只能在25hz徘徊,后来索性去掉延时,发现最高也就只能到发现只能到达6.5us周期,一开始是认为system函数内有系统调用,开销比较大,但是后来一想再大应该超不过200ns,后来向组内大佬请求帮助,大佬说sleep函数会引起睡眠,造成进程切换,这个开销是很大的,特别是us级别的延时,得不偿失。另外,一开始操作gpio是用system来执行echo操作gpio,这个过程本质是execvp了进程,也有一定开销。应该用file操作sysfs的文件。
  2. 后来将延时操作迁移到linux内核驱动,这次不加延时,最高可以跑到120ns的周期,我想应该还能跑到更高,因为这个demo是开启一个内核线程去执行的。
  3. 最后,将延时操作换为对时间的读取,使用gettimeofday函数,这个函数的精度刚好是us级别,通过在while循环里判断两次读取时间查是否大于等于1来反转gpio,到这个做法好像不太行,输出的波形不稳定,频率在不断变化:
    在这里插入图片描述
  4. 放弃3中的做法后,可以尝试的方法还有内核定时器,udelay函数可以尝试。看看尝试了udelay的效果:在这里插入图片描述
    效果还行,最终就选择了这个方案。
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/mutex.h>
#include <linux/pagemap.h>
#include <linux/kthread.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/module.h>

#define ENTER() printk(KERN_DEBUG "%s() Enter", __func__)
#define EXIT() printk(KERN_DEBUG "%s() Exit", __func__)
#define ERR(fmt, args...) printk(KERN_ERR "%s()-%d: " fmt "\n", __func__, __LINE__, ##args)
#define DBG(fmt, args...) printk(KERN_DEBUG "%s()-%d: " fmt "\n", __func__, __LINE__, ##args)

/*
 * toggle the gpio output value every 1us
*/

#define GPIO_PORTB_BASE 0xF244C000
#define GPIOB_DATA_OFF  0x0
#define GPIOB_DIR_OFF   0x4

#define IOMUX_BASE      0xF0040500
#define DRIVER_ABLT_R2R_OFF 0x00
#define PINCTRL_OFF         0x2C
#define GPIO_FUNC_NUM   8
#define DRIVER_SET_VAL  1
#define GPIO_PIN_NUM    4
#define PIN_MUX_BIT_WIDTH 4
#define PIN_DRV_BIT_WIDTH 1

#define TOGGLE_SPAN_IN_US 1

static unsigned int *gpio_handler;
static unsigned int *iomux_handler;
static struct task_struct *test_kthread = NULL;  

static void pinctrl(void *handler)
{
    unsigned int *pinctrl_banke = (unsigned int *)(handler + PINCTRL_OFF);
    unsigned int *driver_banke = (unsigned int *)(handler + DRIVER_ABLT_R2R_OFF);

    // PE4 set func 8
    *pinctrl_banke = (unsigned int)(GPIO_FUNC_NUM << (GPIO_PIN_NUM * PIN_MUX_BIT_WIDTH));

    // PE4 driver ability set 2ma
    *driver_banke = (unsigned int)(DRIVER_SET_VAL << (GPIO_PIN_NUM * PIN_DRV_BIT_WIDTH));
}

static void gpio_cfg(void *handler)
{
    unsigned int *gpio_dir_base = (unsigned int *)(handler + GPIOB_DIR_OFF);

    //set gpiob1 direction output 
    *gpio_dir_base = 0x02;
}

inline void gpio_set_high(void *handler)
{
    unsigned int * gpio_dat_base = (unsigned int *)(handler + GPIOB_DATA_OFF);

    //set gpiob1 output high
    *gpio_dat_base = 0x02;
}

inline void gpio_set_low(void *handler)
{
    unsigned int * gpio_dat_base = (unsigned int *)(handler + GPIOB_DATA_OFF);

    //set gpiob1 output low
    *gpio_dat_base = 0x00;
}

static int gpio_toggle_thread(void* data)
{
    static volatile unsigned int flg = 0;
    ENTER();   
    
    gpio_handler = ioremap(GPIO_PORTB_BASE, 8);
    iomux_handler = ioremap(IOMUX_BASE, 50);

    pr_err("gpio_toggle_thread start \r\n");
 
    pinctrl(iomux_handler);
    gpio_cfg(gpio_handler);

    while(!kthread_should_stop())
    {
        if(flg == 0)
        {
            gpio_set_high(gpio_handler);
            flg = 1;
        } else {
            gpio_set_low(gpio_handler);
            flg = 0;
        }
        udelay(1);
    }

    EXIT();
    return 0;
}

int __init gp_toggle_init(void)
{
    ENTER();

    test_kthread = kthread_run(gpio_toggle_thread, NULL, "gpio-toggle");  
    if(!test_kthread) {
        ERR("kthread_run fail");
		return -ECHILD;       
    }

    EXIT();
    return 0;
}

void __exit gp_toggle_exit(void)
{
	ENTER();
	if (test_kthread) {
		DBG("kthread_stop");
		kthread_stop(test_kthread); //停止内核线程
		test_kthread = NULL;
	}
   
	EXIT();    
    return;
}

module_init(gp_toggle_init);
module_exit(gp_toggle_exit);
MODULE_LICENSE("GPL");
Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值