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

news2024/9/27 17:37:34

仅作为自我记录的一个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");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/809141.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

96. Python基础教程:多个异常的处理方法(2个except语句)

【目录】 文章目录 96. Python基础教程:多个异常的处理方法(2个except语句)1. 2个except语句练习-分苹果2. except (异常类型1,异常类型2) as 别名 【正文】 96. Python基础教程:多个异常的处理方法(2个except语句) 1. 2个except语句练习-分苹果 任务目标写一个模拟幼儿园老师…

TCP网络通信编程之netstat

【netstat指令】 【说明】 &#xff08;1&#xff09;Listening 表示某个端口在监听 &#xff08;2&#xff09;如果有一个外部程序&#xff08;客户端&#xff09;连接到该端口&#xff0c;就会显示一条连接信息 &#xff08;3&#xff09;指令netstat -anb 可以参看是那个…

分库分表之基于Shardingjdbc+docker+mysql主从架构实现读写分离(二)

说明&#xff1a;如果实现了docker部署mysql并完成主从复制的话再继续&#xff0c;本篇文章主要说明springboot配置实现Shardingjdbc进行读写分离操作。 如果没实现docker部署mysql实现主从架构的话点击我 Shardingjdbc配置介绍&#xff08;版本&#xff1a;5.3.2&#xff09;…

04-树6 Complete Binary Search Tree(C++)

思路 先排序&#xff08;冒泡排序&#xff09; 用数组建一棵空树&#xff08;用数组&#xff0c;填好左右儿子&#xff09; 中序遍历填数&#xff08; Tree::travIn() &#xff09; 顺序输出即为层次遍历&#xff08; Tree::travLevel() &#xff09; code # include <…

三步问题(力扣)n种解法 JAVA

目录 题目&#xff1a;1、dfs:2、dfs 备忘录&#xff08;剪枝&#xff09;&#xff1a;&#xff08;1&#xff09;神器 HashMap 备忘录&#xff1a;&#xff08;2&#xff09;数组 memo 备忘录&#xff1a; 3、动态规划&#xff1a;4、利用 static 的储存功能&#xff1a;&…

C++ - stack 和 queue 模拟实现 -认识 deque 容器 容器适配器

stack模拟实现 用模版实现 链式栈 和 顺序栈 对于stack 的实现&#xff0c;有两种方式&#xff0c;一种是连续空间存储的顺序栈&#xff0c;一种是不连续空间存储的链式栈&#xff0c;在C当中如果要使用两种不同的栈的话&#xff0c;实现方式是不一样的&#xff0c;他们的底层逻…

Transformer背景介绍

目录 Transformer的诞生Transformer的优势Transformer的市场 Transformer的诞生 论文地址 Transformer的优势 Transformer的市场

【MySQL】事务管理

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《零基础入门MySQL》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录 &#x1f449;CU…

使用mediapipe训练手指数字识别

mediapipe手指数字识别 本文是从0开始创建一个识别手势的机器学习模型&#xff0c;为了识别手势&#xff0c;采用mediapipe模型&#xff0c;这个模型会返回手指的位置&#xff0c;之后再通过训练一个模型将这些位置分类得到手势 一、导入依赖 import cv2 import numpy as np…

分库分表之基于Shardingjdbc+docker+mysql主从架构实现读写分离(一)

说明&#xff1a;请先自行安装好docker再来看本篇文章&#xff0c;本篇文章主要实现通过使用docker部署mysql实现读写分离&#xff0c;并连接数据库测试。第二篇将实现使用Shardingjdbc实现springboot的读写分离实现。 基于Docker去创建Mysql的主从架构 #创建主从数据库文件夹…

小黑子—JavaWeb:第四章 Request与Response

JavaWeb入门4.0 1. Request(请求)& Response (响应)2. Request2.1 Request 继承体系2.2 Request 获取请求数据2.2.1 通用方式获取请求参数2.2.2 IDEA模板创建Servlet2.2.3 请求参数中文乱码处理2.2.3 - I POST解决方案2.2.3 - II GET解决方案 2.3 Request 请求转发 3. Resp…

常见网关对比

常见网关对比 目前常见的开源网关大致上按照语言分类有如下几类&#xff1a; Nginxlua &#xff1a;OpenResty、Kong、Orange、Abtesting gateway 等 Java &#xff1a;Zuul/Zuul2、Spring Cloud Gateway、Kaazing KWG、gravitee、Dromara soul 等 Go &#xff1a;Janus、fa…

简单学会MyBatis原生API注解

&#x1f600;前言 本篇博文是关于MyBatis原生API&注解的使用&#xff0c;希望能够帮助到你&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;您…

2023深圳杯数学建模B题

B题 电子资源版权保护问题 版权又称著作权&#xff0c;包括发表权、署名权、修改权、保护作品完整权、复制权、发行权、出租权、展览权、表演权、放映权、广播权、信息网络传播权、摄制权、改编权、翻译权、汇编权及应当由著作权人享有的其他权利。 在计算机网络广泛应用的今…

39.手机导航

手机导航 html部分 <div class"phone"><div class"content"><img class"active" src"./static/20180529205331_yhGyf.jpeg" alt"" srcset""><img src"./static/20190214214253_hsjqw…

基于 ThinkPHP 5.1(稳定版本) 开发wms 进销存系统源码

基于ThinkPHP 5.1&#xff08;LTS版本&#xff09;开发的WMS进销存系统源码 管理员账号密码&#xff1a;admin 一、项目简介 这个系统是一个基于ThinkPHP框架的WMS进销存系统。 二、实现功能 控制台 – 权限管理&#xff08;用户管理、角色管理、节点管理&#xff09; – 订…

BUUCTF——reverse3 适合新手的关于base64加密算法代码的分析

作为一个逆向小白&#xff0c;学了点加密算法就来BUU找点乐子&#xff0c;前7题蛮简单的&#xff0c;然后做到了reverse3&#xff0c;典型的base64加密算法&#xff0c;让我折腾了好久&#xff0c;写篇博客记录一下 顺便说下很多博客并没有对这里的加密算法进行代码上的分析&a…

秋招备战笔试Day1

目录 单选 1. 在 Java 中&#xff0c;存放字符串常量的对象属于&#xff08; &#xff09;类对象。 2.已知如下类定义&#xff1a; 如下哪句可以正确地加入子类中&#xff1f; 3. 下列选项中属于面向对象编程主要特征的是&#xff08;&#xff09; 4.关于下列程序段的输出结…

并发编程可能出现的核心问题

2.1非可见性 如果主内存里有个静态变量flagfalse&#xff0c;然后线程A和B在工作内存都需要操作flag&#xff0c;线程A是while(!false){}&#xff0c;而线程B将flag改为true&#xff0c;但是由于线程A和线程B之间工作内存互相不可见&#xff0c;线程A就会陷入死循环。 2.2指令…

排序链表——力扣148

文章目录 题目描述法一 自顶向下归并排序法二&#xff09;自底向上归并排序 题目描述 题目的进阶问题要求达到 O(nlogn) 的时间复杂度和 O(1) 的空间复杂度&#xff0c;时间复杂度是 O(nlogn) 的排序算法包括归并排序、堆排序和快速排序&#xff08;快速排序的最差时间复杂度是…