Linux应用层使用mmap内存映射控制IO寄存器

1、概述

这段代码中采用了使用mmap函数映射IO寄存器来控制IO的方法,可视为应用层上最快速的IO控制方式之一。

在第三节代码中有ADS8361芯片的时序控制代码,经过多次测试,每次采集所需的时间约为38微秒,共进行了78次IO控制操作,平均每次IO控制操作耗时约为0.5微秒。

2、原理

使用内存映射时条件和初始化:

(1.)内核中释放用到这些IO的设备树节点;

(2.)先手动添加,或在应用层通过程序,将引脚导出(寄存器不对时使用的);

(3.)使用mmap函数将GPIO寄存器映射到虚拟内存;

(4.)通过寄存器设置GPIO引脚复用,设置GPIO的输入输出等参数;

(5.)或者手动添加,在应用层通过程序,设置GPIO的输入输出等参数;

使用内存映射时的寄存器地址,就和STM32一样。但要注意偏移地址!!!

对指针偏移不理解的宝子们看👇

C语言的指针偏移_c语言指针偏移怎么写_颜一书的博客-CSDN博客

3、代码

#include <sys/mman.h>
#include<stdio.h>          /* 标准输入输出定义 */
#include<stdlib.h>         /* 标准函数库定义 */
#include<unistd.h>         /* Unix 标准函数定义 */
#include<sys/types.h> 
#include<sys/stat.h> 
#include<fcntl.h>          /* 文件控制定义 */
#include<termios.h>        /* PPSIX 终端控制定义 */
#include<string.h>
#include <sys/time.h>
#include <ctype.h>

#include <linux/gpio.h>

/**
    ADC_CLOCK          GPIO0-B5         GRF--H:4~6=0    pinx =L- 13
    ADC_DATA_A0        GPIO0-C5         GRF--H:4~6=0    pinx =H- 5
    ADC_DATA_B         GPIO4-D0         GRF--L:0~2=0    pinx =H- 8
    ADC_BUSY           GPIO0-C7         GRF--H:12~14=0  pinx =H- 7  
    ADC_CONVS          GPIO4-C2         GRF--L:8~10=0   pinx =H- 2
    M0                 GPIO4-D1         GRF--L:4~6=0    pinx =H- 9
    M1                 GPIO4-C7         GRF--H:12~14=0  pinx =H- 7
    A0                 GPIO4-C3         GRF--L:12~14=0  pinx =H- 3
**/

volatile unsigned int *  PMU_GRF_GPIO0;
volatile unsigned int *  PMU_GRF_GPIO4;
volatile unsigned int *  REGGPIO0;
volatile unsigned int *  REGGPIO4;
#define PMU_GRF_GPIO0_BASEADDR    0XFDC20000
#define PMU_GRF_GPIO4_BASEADDR    0XFDC60000
#define GPIO0_REG_BASEADDR        0XFDD60000
#define GPIO4_REG_BASEADDR        0XFE770000

volatile unsigned int *  PMU_GRF_GPIO0;
volatile unsigned int *  PMU_GRF_GPIO4;
volatile unsigned int *  REGGPIO0;
volatile unsigned int *  REGGPIO4;

#define PMU_GRF_GPIO0A_IOMUX_L      0X0000U
#define PMU_GRF_GPIO0A_IOMUX_H      0X0004U
#define PMU_GRF_GPIO0B_IOMUX_L      0X0008U
#define PMU_GRF_GPIO0B_IOMUX_H      0X000CU
#define PMU_GRF_GPIO0C_IOMUX_L      0X0010U
#define PMU_GRF_GPIO0C_IOMUX_H      0X0014U
#define PMU_GRF_GPIO0D_IOMUX_L      0X0018U
#define PMU_GRF_GPIO0D_IOMUX_H      0X001CU

#define PMU_GRF_GPIO4A_IOMUX_L      0X0060U
#define PMU_GRF_GPIO4A_IOMUX_H      0X0064U
#define PMU_GRF_GPIO4B_IOMUX_L      0X0068U
#define PMU_GRF_GPIO4B_IOMUX_H      0X006CU
#define PMU_GRF_GPIO4C_IOMUX_L      0X0070U
#define PMU_GRF_GPIO4C_IOMUX_H      0X0074U
#define PMU_GRF_GPIO4D_IOMUX_L      0X0078U
#define PMU_GRF_GPIO4D_IOMUX_H      0X007CU

#define GPIO0_DATA_L                0X0000U
#define GPIO0_DATA_H                0X0004U
#define GPIO0_DIR_L                 0X0008U
#define GPIO0_DIR_H                 0X000CU
#define GPIO0_INT_L                 0X0010U
#define GPIO0_INT_H                 0X0014U
#define GPIO0_EXT_PORT              0X0070U

#define GPIO4_DATA_L                0X0000U
#define GPIO4_DATA_H                0X0004U
#define GPIO4_DIR_L                 0X0008U
#define GPIO4_DIR_H                 0X000CU
#define GPIO4_INT_L                 0X0010U
#define GPIO4_INT_H                 0X0014U
#define GPIO4_EXT_PORT              0X0070U

enum
{
    ADC_CLOCK=0,
    ADC_DATA_A,
    ADC_DATA_B,
    ADC_BUSY,
    ADC_CONVST,
    M0,
    M1,
    A0,
};

struct gpio_t 
{
    unsigned char gpio;
    char number[10];
    char direction[100];
    char gpio_path[100];
    int  fd;
};

struct gpio_t ADC_collect[8]=
{
    {ADC_CLOCK ,"13" ,"out","",0},
    {ADC_DATA_A,"21" ,"in" ,"",0},
    {ADC_DATA_B,"152","in" ,"",0},
    {ADC_BUSY  ,"23" ,"in" ,"",0},
    {ADC_CONVST,"146","out","",0},
    {M0,"153","out","",0},
    {M1,"151","out","",0},   
    {A0,"147","out","",0},
};

/**
  * 函数名称    __raw_writel(unsigned int data, volatile unsigned int *reg)
  * 函数功能    往指定地址写数据
  * 输入参数    unsigned int data :写入的数据
                volatile unsigned int *reg:要写入数据的地址
  * 函数返回值  无
  */
void __raw_writel(unsigned int data, volatile unsigned int *reg)
{
    *reg=data;
}

/**
  * 函数名称    __raw_readl( volatile unsigned int *reg)
  * 函数功能    从指定地址读数据
  * 输入参数    volatile unsigned int *reg:要读取数据的地址
  * 函数返回值  读取的数据
  */
unsigned int __raw_readl( volatile unsigned int *reg)
{
    unsigned int data=0;
    data=*reg;
    return data;
}

/**
函數名:    ADC_GPIO_Init
函數功能:  初始化ADC模塊引脚的GPIO
輸入:      无
輸出:      无
**/
void ADC_GPIO_Init(void)
{
    unsigned int temp=0U;
    /*引脚用途模式*/
    /*ADC_CLOCK*/
    temp=__raw_readl(PMU_GRF_GPIO0+PMU_GRF_GPIO0B_IOMUX_H);
    temp = temp | 0xffff0000;
    __raw_writel(temp,PMU_GRF_GPIO0+PMU_GRF_GPIO0B_IOMUX_H);
    temp = temp & (~(0x0000000FU<<4U));
    __raw_writel(temp,PMU_GRF_GPIO0+PMU_GRF_GPIO0B_IOMUX_H);

    /*ADC_DATA_A0*/
    temp=__raw_readl(PMU_GRF_GPIO0+PMU_GRF_GPIO0C_IOMUX_H);
    temp = temp | 0xffff0000;
    __raw_writel(temp,PMU_GRF_GPIO0+PMU_GRF_GPIO0C_IOMUX_H);
    temp = temp & (~(0x0000000fU<<4U));
    __raw_writel(temp,PMU_GRF_GPIO0+PMU_GRF_GPIO0C_IOMUX_H);

    /*ADC_DATA_B*/
    temp=__raw_readl(PMU_GRF_GPIO4+PMU_GRF_GPIO4D_IOMUX_L);
    temp = temp | 0xffff0000;
    __raw_writel(temp,PMU_GRF_GPIO4+PMU_GRF_GPIO4D_IOMUX_L);
    temp = temp & (~(0x0000000fU<<0U));
    __raw_writel(temp,PMU_GRF_GPIO4+PMU_GRF_GPIO4D_IOMUX_L);

    /*ADC_BUSY*/
    temp=__raw_readl(PMU_GRF_GPIO0+PMU_GRF_GPIO0C_IOMUX_H);
    temp = temp | 0xffff0000;
    __raw_writel(temp,PMU_GRF_GPIO0+PMU_GRF_GPIO0C_IOMUX_H);
    temp = temp & (~(0x0000000fU<<12));
    __raw_writel(temp,PMU_GRF_GPIO0+PMU_GRF_GPIO0C_IOMUX_H);

    /*ADC_CONVS*/
    temp=__raw_readl(PMU_GRF_GPIO4+PMU_GRF_GPIO4C_IOMUX_L);
    temp = temp | 0xffff0000;
    __raw_writel(temp,PMU_GRF_GPIO4+PMU_GRF_GPIO4C_IOMUX_L);
    temp = temp & (~(0x0000000fU<<8));
    __raw_writel(temp,PMU_GRF_GPIO4+PMU_GRF_GPIO4C_IOMUX_L);

    /*M0*/
    temp=__raw_readl(PMU_GRF_GPIO4+PMU_GRF_GPIO4D_IOMUX_L);
    temp = temp | 0xffff0000;
    __raw_writel(temp,PMU_GRF_GPIO4+PMU_GRF_GPIO4D_IOMUX_L);
    temp = temp & (~(0x0000000fU<<4U));
    __raw_writel(temp,PMU_GRF_GPIO4+PMU_GRF_GPIO4D_IOMUX_L);

    /*M1*/
    temp=__raw_readl(PMU_GRF_GPIO4+PMU_GRF_GPIO4C_IOMUX_H);
    temp = temp | 0xffff0000;
    __raw_writel(temp,PMU_GRF_GPIO4+PMU_GRF_GPIO4C_IOMUX_H);
    temp = temp & (~(0x0000000fU<<12U));
    __raw_writel(temp,PMU_GRF_GPIO4+PMU_GRF_GPIO4C_IOMUX_H);

    /*A0*/
    temp=__raw_readl(PMU_GRF_GPIO4+PMU_GRF_GPIO4C_IOMUX_L);
    temp = temp | 0xffff0000;
    __raw_writel(temp,PMU_GRF_GPIO4+PMU_GRF_GPIO4C_IOMUX_L);
    temp = temp & (~(0x0000000fU<<2U));
    __raw_writel(temp,PMU_GRF_GPIO4+PMU_GRF_GPIO4C_IOMUX_L);


    /*引脚输入输出模式  可省略与下面重复*/
    /*ADC_CLOCK  OUT*/
    temp=__raw_readl(REGGPIO0+GPIO0_DIR_L);
    temp = temp | 0xffff0000;
    __raw_writel(temp,REGGPIO0+GPIO0_DIR_L);
    temp = temp | ((0x00000001U<<13U));
    __raw_writel(temp,REGGPIO0+GPIO0_DIR_L);

    /*ADC_DATA_A0  INT*/
    temp=__raw_readl(REGGPIO0+GPIO0_DIR_H);
    temp = temp | 0xffff0000; 
    __raw_writel(temp,REGGPIO0+GPIO0_DIR_H);
    temp = temp & (~(0x00000001U<<5U));
    __raw_writel(temp,REGGPIO0+GPIO0_DIR_H);

    /*ADC_DATA_B INT*/
    temp=__raw_readl(REGGPIO4+GPIO4_DIR_H);
    temp = temp | 0xffff0000; 
    __raw_writel(temp,REGGPIO4+GPIO4_DIR_H);
    temp = temp & (~(0x00000001U<<8U));
    __raw_writel(temp,REGGPIO4+GPIO4_DIR_H);

    /*ADC_BUSY INT*/
    temp=__raw_readl(REGGPIO0+GPIO0_DIR_H);
    temp = temp | 0xffff0000; 
    __raw_writel(temp,REGGPIO0+GPIO0_DIR_H);
    temp = temp & (~(0x00000001U<<7U));
    __raw_writel(temp,REGGPIO0+GPIO0_DIR_H);

    /*ADC_CONVS OUT*/
    temp=__raw_readl(REGGPIO0+GPIO0_DIR_H);
    temp = temp | 0xffff0000; 
    __raw_writel(temp,REGGPIO0+GPIO0_DIR_H);
    temp = temp | ((0x00000001U<<4U));
    __raw_writel(temp,REGGPIO0+GPIO0_DIR_H);

    /*M0 OUT */
    temp=__raw_readl(REGGPIO4+GPIO4_DIR_H);
    temp = temp | 0xffff0000; 
    __raw_writel(temp,REGGPIO4+GPIO4_DIR_H);
    temp = temp | ((0x00000001U<<9U));
    __raw_writel(temp,REGGPIO4+GPIO4_DIR_H);

    /*M1 OUT*/
    temp=__raw_readl(REGGPIO4+GPIO4_DIR_H);
    temp = temp | 0xffff0000;
    __raw_writel(temp,REGGPIO4+GPIO4_DIR_H);
    temp = temp | ((0x00000001U<<7U));
    __raw_writel(temp,REGGPIO4+GPIO4_DIR_H);

    /*A0 OUT*/
    temp=__raw_readl(REGGPIO0+GPIO0_DIR_H);
    temp = temp | 0xffff0000; 
    __raw_writel(temp,REGGPIO4+GPIO4_DIR_H);
    temp = temp | ((0x00000001U<<14U));
    __raw_writel(temp,REGGPIO0+GPIO0_DIR_H);

    /*DISABLE INT*/
    /*ADC_CLOCK */
    temp=__raw_readl(REGGPIO0+GPIO0_INT_L);
    temp = temp | 0xffff0000;
    temp = temp & (~(0x00000001U<<13U));
    __raw_writel(temp,REGGPIO0+GPIO0_INT_L);

    /*ADC_DATA_A0 */
    temp=__raw_readl(REGGPIO0+GPIO0_INT_H);
    temp = temp | 0xffff0000;
    temp = temp & (~(0x00000001U<<5U));
    __raw_writel(temp,REGGPIO0+GPIO0_INT_H);

    /*ADC_DATA_B*/
    temp=__raw_readl(REGGPIO4+GPIO4_INT_H);
    temp = temp | 0xffff0000;
    temp = temp & (~(0x00000001U<<8U));
    __raw_writel(temp,REGGPIO4+GPIO4_INT_H);

    /*ADC_BUSY */
    temp=__raw_readl(REGGPIO0+GPIO0_INT_H);
    temp = temp | 0xffff0000;
    temp = temp & (~(0x00000001U<<7U));
    __raw_writel(temp,REGGPIO0+GPIO0_INT_H);

    /*ADC_CONVS */
    temp=__raw_readl(REGGPIO0+GPIO0_INT_H);
    temp = temp | 0xffff0000;
    temp = temp & (~(0x00000001U<<4U));
    __raw_writel(temp,REGGPIO0+GPIO0_INT_H);

    /*M0  */
    temp=__raw_readl(REGGPIO4+GPIO4_INT_H);
    temp = temp | 0xffff0000;
    temp = temp & (~(0x00000001U<<9U));
    __raw_writel(temp,REGGPIO4+GPIO4_INT_H);

    /*M1 */
    temp=__raw_readl(REGGPIO4+GPIO4_INT_H);
    temp = temp | 0xffff0000;
    temp = temp & (~(0x00000001U<<7U));
    __raw_writel(temp,REGGPIO4+GPIO4_INT_H);

    /*A0 */
    temp=__raw_readl(REGGPIO0+GPIO0_INT_H);
    temp = temp | 0xffff0000;
    temp = temp & (~(0x00000001U<<14U));
    __raw_writel(temp,REGGPIO0+GPIO0_INT_H);
}

/**
函數名:    set_ADC_CLOCK
函數功能:  设置ADC_CLOCK的输出值
輸入:      status: 输出的状态;0--低;1--高
輸出:      无
**/
void set_ADC_CLOCK(unsigned char status)
{
    unsigned int temp=0U;
    temp=__raw_readl(REGGPIO0+GPIO0_DATA_L);
    // temp = temp | ((0x00000001U<<(13U+16U))); 
    temp = temp | (0xffff0000U); 
    if(status==0U)
    {
        // temp = temp & (~(0x00000001U<<13U));
        temp = temp & (0xffffdfffU);
    }
    else
    {
        // temp = temp | (0x00000001U<<13U);    
        temp = temp | (0x00002000U); 
    }
    __raw_writel(temp,REGGPIO0+GPIO0_DATA_L);
}

/**
函數名:    set_ADC_CONVS
函數功能:  设置ADC_CONVS的输出值
輸入:      status: 输出的状态;0--低;1--高
輸出:      无
**/
void set_ADC_CONVS(unsigned char status)
{
    unsigned int temp=0U;
    temp=__raw_readl(REGGPIO4+GPIO4_DATA_H);
    temp = temp | ((0x00000001U<<(2U+16U))); 
    if(status==0U)
    {
        // temp = temp & (~(0x00000001U<<2U));
        temp = temp & (0xfffffffbU);
    }
    else
    {
        // temp = temp | (0x00000001U<<2U);
        temp = temp | (0x00000004U);

    }
    __raw_writel(temp,REGGPIO4+GPIO4_DATA_H);
}

/**
函數名:    set_ADC_M0
函數功能:  设置ADC_M0的输出值
輸入:      status: 输出的状态;0--低;1--高
輸出:      无
**/
void set_ADC_M0(unsigned char status)
{
    unsigned int temp=0U;
    temp=__raw_readl(REGGPIO4+GPIO4_DATA_H);
    temp = temp | ((0x00000001U<<(9U+16U))); 
    if(status==0U)
    {
        // temp = temp & (~(0x00000001U<<9U));
        temp = temp & (0xfffffdffU);
    }
    else
    {
        // temp = temp | (0x00000001U<<9U);
        temp = temp | (0x00000200U);

    }
    __raw_writel(temp,REGGPIO4+GPIO4_DATA_H);
}

/**
函數名:    set_ADC_M1
函數功能:  设置ADC_M1的输出值
輸入:      status: 输出的状态;0--低;1--高
輸出:      无
**/
void set_ADC_M1(unsigned char status)
{
    unsigned int temp=0U;
    temp=__raw_readl(REGGPIO4+GPIO4_DATA_H);
    temp = temp | ((0x00000001U<<(7U+16U))); 
    if(status==0U)
    {
        // temp = temp & (~(0x00000001U<<7U));
        temp = temp & (0xffffff7fU);
    }
    else
    {
        // temp = temp | (0x00000001U<<7U);
        temp = temp | (0x00000080U);
    }
    __raw_writel(temp,REGGPIO4+GPIO4_DATA_H);
}

/**
函數名:    set_ADC_A0
函數功能:  设置ADC_A0的输出值
輸入:      status: 输出的状态;0--低;1--高
輸出:      无
**/
void set_ADC_A0(unsigned char status)
{
    unsigned int temp=0U;
    temp=__raw_readl(REGGPIO4+GPIO4_DATA_H);
    temp |=  0xffff0000U;
    if(status==0U)
    {
        // temp = temp & (~(0x00000001U<<3U));
        temp = temp & (0xfffffff7U);
    }
    else
    {
        // temp = temp | (0x00000001U<<3U);    
        temp = temp | (0x00000008U); 
    }
    __raw_writel(temp,REGGPIO4+GPIO4_DATA_H);
}

/**
函數名:    get_ADC_DATA_A0
函數功能:  获取ADC的A0引脚的值
輸入:      无 
輸出:      获取的状态;0--低;1--高
**/
unsigned char get_ADC_DATA_A0(void)
{
    unsigned int temp=0U;
    temp=__raw_readl(REGGPIO0+GPIO0_EXT_PORT);
    return ((temp>>21U) & 0x00000001U);
}

/**
函數名:    get_ADC_DATA_B0
函數功能:  获取ADC的B0引脚的值
輸入:      无 
輸出:      获取的状态;0--低;1--高
**/
unsigned char get_ADC_DATA_B0(void)
{
    unsigned int temp=0U;
    temp=__raw_readl(REGGPIO4+GPIO4_EXT_PORT);
    return ((temp>>24U) & 0x00000001U);
}

/**
函數名:    get_ADC_BUSY
函數功能:  获取ADC的BUSY引脚的值
輸入:      无 
輸出:      获取的状态;0--低;1--高
**/
unsigned char get_ADC_BUSY(void)
{
    unsigned int temp=0U;
    temp=__raw_readl(REGGPIO0+GPIO0_EXT_PORT);
    return ((temp>>23U) & 0x00000001U);
}

/**
  * 函数名称    void ADC_init(void)
  * 函数功能    ads8361 adc采集模块引脚初始化
  * 输入参数    way:采集几路adc
  * 函数返回值  无
  */
void ADC_init(unsigned char way)
{
    int fd;
    unsigned int time_cnt=0;
    unsigned int temp=0;


    /* 打开 /dev/mem 设备*/
    fd = open("/dev/mem", O_RDWR | O_SYNC);
    if (fd == -1) 
    {
        return ;
    }
    /* 映射 GPIO 寄存器到内存*/
    PMU_GRF_GPIO0 = (volatile unsigned int *)mmap(NULL, 0X1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PMU_GRF_GPIO0_BASEADDR);
    if (PMU_GRF_GPIO0 == MAP_FAILED) 
    {
        close(fd);
        return ;
    }
    PMU_GRF_GPIO4 = (volatile unsigned int *)mmap(NULL, 0X1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PMU_GRF_GPIO4_BASEADDR);
    if (PMU_GRF_GPIO4 == MAP_FAILED) 
    {
        close(fd);
        return ;
    }
    REGGPIO0 = (volatile unsigned int *)mmap(NULL,  0X1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO0_REG_BASEADDR);
    if (REGGPIO0 == MAP_FAILED) 
    {
        close(fd);
        return ;
    }
    REGGPIO4 = (volatile unsigned int *)mmap(NULL,  0X1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO4_REG_BASEADDR);
    if (REGGPIO4 == MAP_FAILED) 
    {
        close(fd);
        return ;
    }
    ADC_GPIO_Init();

    gpio_init(ADC_collect,ADC_CLOCK);
    gpio_init(ADC_collect,ADC_DATA_A);
    gpio_init(ADC_collect,ADC_DATA_B);
    gpio_init(ADC_collect,ADC_BUSY);
    gpio_init(ADC_collect,M0);
    gpio_init(ADC_collect,M1);
    gpio_init(ADC_collect,A0);
    gpio_init(ADC_collect,ADC_CONVST);

    set_ADC_CLOCK(0);
    set_ADC_CONVS(0);

    if(way==2U)
    {
        set_ADC_M0(0);
        set_ADC_M1(0);
    }
    else
    {
        set_ADC_M0(1);
        set_ADC_M1(0);
    }
}

/**
  * 函数名称    void ADC_collection2(void)
  * 函数功能    ADC采集功能,2路ADC采集功能(将采集到的4路ADC电压值放在voltage_A1,voltage_B1;)
  * 输入参数    无
  * 函数返回值  无
  */
void ADC_collection2(void)
{
    unsigned short data[2]={0U,0U};
    unsigned char i,j;

    set_ADC_CLOCK(1);
    set_ADC_A0(0);
    set_ADC_CONVS(1);
    // delay_ns(1);
    set_ADC_CLOCK(0);
    // delay_ns(1);

    set_ADC_CLOCK(1);
    // delay_ns(1);
    set_ADC_CLOCK(0);
    // delay_ns(1);
    set_ADC_CLOCK(1);
    // delay_ns(1);
    set_ADC_CLOCK(0);
    // delay_ns(1);

    for(i=0U;i<16U;i++)
    {
        data[0] <<= 1;
        data[1] <<= 1;
        set_ADC_CLOCK(1);
        // delay_ns(1);
        set_ADC_CLOCK(0);
        if(get_ADC_DATA_A0()==1)
        {
            data[0]++;
        }
        if(get_ADC_DATA_B0()==1)
        {
            data[1]++;
        }
        // delay_ns(1);
    }

    set_ADC_CLOCK(1);
    // delay_ns(1);
    set_ADC_CLOCK(0);
    // delay_ns(1);
    set_ADC_CLOCK(1);
    // delay_ns(1);
    set_ADC_CLOCK(0);
    // delay_ns(1);

    while(get_ADC_BUSY()==1)
    {
        ;
    }
    set_ADC_CONVS(0);

    voltage_A1=jisuan(data[0]);//需要优化
    voltage_B1=jisuan(data[1]);//需要优化

    return;
}

4、总结

这种操作方法目前是接触到驱动开发的操作IO最快的方法了。欢迎大佬留言指导!!!

还有,并不是所有寄存器都可以操作的,在内核上配置的SPI节点,在应用层可以正常使用的,但对其进行寄存器操作,发现不可控。对于这点宝子们先用下面的指令试试寄存器可以控制不,省的写了半天代码,最后是配置问题导致不能用,那可是要命的。

最后,补充一下操作指令:

/* 应用层操作IO */
cd /sys/class/gpio                                          查看gpio设置,文件,配置
echo 149 > export           	                            将相应的gpio引脚从内核层导入到用户层
echo "in" > direction   echo "out" > direction          	设置gpio的输入/输出方向
cat value           	                                    获取或者控制gpio的状态
echo 1 > value  echo 0 > value         	                    设置输出高电平/输出低电平

/* 直接通过寄存器操作IO */
io -4 -r 寄存器地址                                         通过指令读取寄存器(例:io -4 -r  0xfdd60000)
io -4 -w 寄存器地址 数据                                    通过指令设置寄存器(例:io -4 -w 0xfdd60000 0x11111111)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值