linux省去驱动直接从应用层寄存器操作

2024-03-10 05:59

本文主要是介绍linux省去驱动直接从应用层寄存器操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这个外设的功能已经在zynq sdk裸机下验证通过,如果这个外设没有用到中断,我们可以通过linux下映射寄存器的方法,将这个裸机下的程序直接移植到linux下使用,这样就可以省去硬件开发驱动的工作。

一,linux内存映射

二,原理图

三,linux应用层代码解析

1,pl_gpio.h

#ifndef PL_GPIO_H
#define PL_GPIO_H
#include <stdint.h>typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#define XGPIO_CHAN_OFFSET  8
#define XGPIO_DATA_OFFSET	0x0   /**< Data register for 1st channel */
#define XGPIO_TRI_OFFSET	0x4   /**< I/O direction reg for 1st channel */
#define XGPIO_DATA2_OFFSET	0x8   /**< Data register for 2nd channel */
#define XGPIO_TRI2_OFFSET	0xC   /**< I/O direction reg for 2nd channel */
#define XGPIO_GIE_OFFSET	0x11C /**< Glogal interrupt enable register */
#define XGPIO_ISR_OFFSET	0x120 /**< Interrupt status register */
#define XGPIO_IER_OFFSET	0x128 /**< Interrupt enable register */typedef uintptr_t UINTPTR;typedef struct 
{UINTPTR BaseAddress;	/* Device base address */u32 IsReady;		/* Device is initialized and ready */int InterruptPresent;	/* Are interrupts supported in h/w */int IsDual;		/* Are 2 channels supported in h/w */
} XGpio;#define XGpio_Out32 Xil_Out32
#define XGpio_In32  Xil_In32#define XGpio_WriteReg(BaseAddress, RegOffset, Data) \XGpio_Out32((BaseAddress) + (RegOffset), (u32)(Data))#define XGpio_ReadReg(BaseAddress, RegOffset) \XGpio_In32((BaseAddress) + (RegOffset))#define XIL_COMPONENT_IS_READY     0x11111111U
#define XPAR_AXI_GPIO_1_BASEADDR 0x800A0000/*The following constant is used to determine which channel of the GPIO is* used for the LED if there are 2 channels supported.*/
#define LED_CHANNEL 1#define LED 0x01   /* Assumes bit 0 of GPIO is connected to an LED  */void XGpio_SetDataDirection(XGpio *InstancePtr, unsigned Channel,u32 DirectionMask);
void XGpio_DiscreteWrite(XGpio * InstancePtr, unsigned Channel, u32 Data);
void XGpio_DiscreteClear(XGpio * InstancePtr, unsigned Channel, u32 Mask);
#endif

  pl_gpio.c 

#include "pl_gpio.h"
static inline u32 Xil_In32(UINTPTR Addr)
{return *(volatile u32 *) Addr;
}
static inline void Xil_Out32(UINTPTR Addr, u32 Value)
{
#ifndef ENABLE_SAFETYvolatile u32 *LocalAddr = (volatile u32 *)Addr;*LocalAddr = Value;
#elseXStl_RegUpdate(Addr, Value);
#endif
}void XGpio_SetDataDirection(XGpio *InstancePtr, unsigned Channel,u32 DirectionMask)
{XGpio_WriteReg(InstancePtr->BaseAddress, ((Channel - 1) * XGPIO_CHAN_OFFSET) + XGPIO_TRI_OFFSET,DirectionMask);
}void XGpio_DiscreteWrite(XGpio * InstancePtr, unsigned Channel, u32 Data)
{XGpio_WriteReg(InstancePtr->BaseAddress,((Channel - 1) * XGPIO_CHAN_OFFSET) + XGPIO_DATA_OFFSET,Data);
}void XGpio_DiscreteClear(XGpio * InstancePtr, unsigned Channel, u32 Mask)
{u32 Current;unsigned DataOffset;//Calculate the offset to the data register of the GPIO  */DataOffset = ((Channel - 1) * XGPIO_CHAN_OFFSET) + XGPIO_DATA_OFFSET;//Read the contents of the data register, merge in Mask and write back resultsCurrent = XGpio_ReadReg(InstancePtr->BaseAddress, DataOffset);Current &= ~Mask;XGpio_WriteReg(InstancePtr->BaseAddress, DataOffset, Current);
}

2,ps_gpio.h

#ifndef PS_GPIO_H
#define PS_GPIO_H
#include <stdint.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#define XGPIOPS_SIX    6U
#define XPAR_PSU_GPIO_0_BASEADDR 0xFF0A0000extern u64 config_baseaddr;void XGpioPs_SetDirectionPin(u32 Pin, u32 Direction);
#endif

   ps_gpio.c

#include "ps_gpio.h"
u64 config_baseaddr;
#define XGPIOPS_DATA_LSW_OFFSET  0x00000000U  /* Mask and Data Register LSW, WO */
#define XGPIOPS_DATA_MSW_OFFSET  0x00000004U  /* Mask and Data Register MSW, WO */
#define XGPIOPS_DATA_OFFSET      0x00000040U  /* Data Register, RW */
#define XGPIOPS_DATA_RO_OFFSET	 0x00000060U  /* Data Register - Input, RO */
#define XGPIOPS_DIRM_OFFSET      0x00000204U  /* Direction Mode Register, RW */
#define XGPIOPS_OUTEN_OFFSET	 0x00000208U  /* Output Enable Register, RW */#define XGPIOPS_DATA_MASK_OFFSET 0x00000008U  /* Data/Mask Registers offset */
#define XGPIOPS_DATA_BANK_OFFSET 0x00000004U  /* Data Registers offset */
#define XGPIOPS_REG_MASK_OFFSET  0x00000040U  /* Registers offset */static inline u32 Xil_In32(u64 Addr)
{return *(volatile u32 *) Addr;
}static inline void Xil_Out32(u64 Addr, u32 Value)
{volatile u32 *LocalAddr = (volatile u32 *)Addr;*LocalAddr = Value;
}#define XGpioPs_ReadReg(BaseAddr, RegOffset)		\Xil_In32((BaseAddr) + (u64)(RegOffset))#define XGpioPs_WriteReg(BaseAddr, RegOffset, Data)	\Xil_Out32((BaseAddr) + (u64)(RegOffset), (u32)(Data))void XGpioPs_GetBankPin(u8 PinNumber, u8 *BankNumber, u8 *PinNumberInBank)
{u32 XGpioPsPinTable[XGPIOPS_SIX] = {0};/*This structure defines the mapping of the pin numbers to the banks when* the driver APIs are used for working on the individual pins.*/XGpioPsPinTable[0] = (u32)25; /* 0 - 25, Bank 0 */XGpioPsPinTable[1] = (u32)51; /* 26 - 51, Bank 1 */XGpioPsPinTable[2] = (u32)77; /* 52 - 77, Bank 2 */XGpioPsPinTable[3] = (u32)109; /* 78 - 109, Bank 3 */XGpioPsPinTable[4] = (u32)141; /* 110 - 141, Bank 4 */XGpioPsPinTable[5] = (u32)173; /* 142 - 173 Bank 5 */*BankNumber = 0U;while (*BankNumber < XGPIOPS_SIX) {if (PinNumber <= XGpioPsPinTable[*BankNumber]) {break;}(*BankNumber)++;}if (*BankNumber == (u8)0) {*PinNumberInBank = PinNumber;}else {*PinNumberInBank=(u8)((u32)PinNumber%(XGpioPsPinTable[*BankNumber-(u8)1]+ (u32)1));}
}void XGpioPs_SetDirectionPin(u32 Pin, u32 Direction)
{u8 Bank;u8 PinNumber;u32 DirModeReg;// Get the Bank number and Pin number within the bankXGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);DirModeReg = XGpioPs_ReadReg(config_baseaddr,((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) + XGPIOPS_DIRM_OFFSET);if (Direction!=(u32)0) // Output Direction{ DirModeReg |= ((u32)1 << (u32)PinNumber);} else   //Input Direction{DirModeReg &= ~ ((u32)1 << (u32)PinNumber);}XGpioPs_WriteReg(config_baseaddr,((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +XGPIOPS_DIRM_OFFSET, DirModeReg);
}void XGpioPs_SetOutputEnablePin(u32 Pin, u32 OpEnable)
{u8 Bank;u8 PinNumber;u32 OpEnableReg;// Get the Bank number and Pin number within the bank XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);OpEnableReg = XGpioPs_ReadReg(config_baseaddr,((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) + XGPIOPS_OUTEN_OFFSET);if (OpEnable != (u32)0) //Enable Output Enable{  OpEnableReg |= ((u32)1 << (u32)PinNumber);} else  //Disable Output Enable  {OpEnableReg &= ~ ((u32)1 << (u32)PinNumber);}XGpioPs_WriteReg(config_baseaddr,((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) + XGPIOPS_OUTEN_OFFSET, OpEnableReg);
}void XGpioPs_WritePin(u32 Pin, u32 Data)
{u32 RegOffset;u32 Value;u8 Bank;u8 PinNumber;u32 DataVar = Data;// Get the Bank number and Pin number within the bankXGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);if (PinNumber > 15U) {// There are only 16 data bits in bit maskable registerPinNumber -= (u8)16;RegOffset = XGPIOPS_DATA_MSW_OFFSET;} else {RegOffset = XGPIOPS_DATA_LSW_OFFSET;}/*Get the 32 bit value to be written to the Mask/Data register where* the upper 16 bits is the mask and lower 16 bits is the data.*/DataVar &= (u32)0x01;Value = ~((u32)1 << (PinNumber + 16U)) & ((DataVar << PinNumber) | 0xFFFF0000U);XGpioPs_WriteReg(config_baseaddr,((u32)(Bank) * XGPIOPS_DATA_MASK_OFFSET) +RegOffset, Value);
}

3,main.c

<1>关于gpio寄存器地址,都是从vivado导出后的sdk gpio例程中复制出来,开发思路也应该是这样,先用sdk裸机程序验证。很多外设和 PL端的 IP,sdk会生成好操作的方法和操作的地址,这样就不需要我们再去找对应关系。

<2>打开/dev/mem,使用选项O_SYNC向外部写入数据通常数据是写入到cache缓冲,O_SYNC将确保数据写入至外设才返回,需要注意这里的O_SYNC,只会影响写操作,对读无影响。

<3>msync的调用:如果需要向外设一次写入比较多的数据,此时如果调用O_SYNC,将会严重影响系统的性能,此时如果不使用O_SYNC,而是在写完数据后,调用msync,这样会提升写的性能。
<4>读操作一致性问题:如果需要读外设的数据,因为cache的存在,应用中取到的数据是cache中的数据,而不是外设的最新状态,此时读到的可能是一个错误的值。

#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include "ps_gpio.h"
#include "pl_gpio.h"
int main(void)
{int mem_fd;XGpio Gpio;mem_fd = open("/dev/mem", O_RDWR | O_SYNC);if (mem_fd < 0){printf("open /dev/mem failed\r\n");return 0;}Gpio.BaseAddress = (u64)mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, XPAR_AXI_GPIO_1_BASEADDR );if((u64)MAP_FAILED == Gpio.BaseAddress){printf("mmap fail\r\n");}XGpio_SetDataDirection(&Gpio, LED_CHANNEL, ~LED);while(1){/* Set the GPIO output to be low. */XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, LED);usleep(500000);/* Set the GPIO Output to High. */XGpio_DiscreteClear(&Gpio, LED_CHANNEL, LED);msync((void *)Gpio.BaseAddress, 1024, MS_ASYNC);usleep(500000);}return 0;
}

 

这篇关于linux省去驱动直接从应用层寄存器操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/793276

相关文章

Linux内核定时器使用及说明

《Linux内核定时器使用及说明》文章详细介绍了Linux内核定时器的特性、核心数据结构、时间相关转换函数以及操作API,通过示例展示了如何编写和使用定时器,包括按键消抖的应用... 目录1.linux内核定时器特征2.Linux内核定时器核心数据结构3.Linux内核时间相关转换函数4.Linux内核定时

Linux镜像文件制作方式

《Linux镜像文件制作方式》本文介绍了Linux镜像文件制作的过程,包括确定磁盘空间布局、制作空白镜像文件、分区与格式化、复制引导分区和其他分区... 目录1.确定磁盘空间布局2.制作空白镜像文件3.分区与格式化1) 分区2) 格式化4.复制引导分区5.复制其它分区1) 挂载2) 复制bootfs分区3)

Go异常处理、泛型和文件操作实例代码

《Go异常处理、泛型和文件操作实例代码》Go语言的异常处理机制与传统的面向对象语言(如Java、C#)所使用的try-catch结构有所不同,它采用了自己独特的设计理念和方法,:本文主要介绍Go异... 目录一:异常处理常见的异常处理向上抛中断程序恢复程序二:泛型泛型函数泛型结构体泛型切片泛型 map三:文

MySQL基本表查询操作汇总之单表查询+多表操作大全

《MySQL基本表查询操作汇总之单表查询+多表操作大全》本文全面介绍了MySQL单表查询与多表操作的关键技术,包括基本语法、高级查询、表别名使用、多表连接及子查询等,并提供了丰富的实例,感兴趣的朋友跟... 目录一、单表查询整合(一)通用模版展示(二)举例说明(三)注意事项(四)Mapper简单举例简单查询

Nginx概念、架构、配置与虚拟主机实战操作指南

《Nginx概念、架构、配置与虚拟主机实战操作指南》Nginx是一个高性能的HTTP服务器、反向代理服务器、负载均衡器和IMAP/POP3/SMTP代理服务器,它支持高并发连接,资源占用低,功能全面且... 目录Nginx 深度解析:概念、架构、配置与虚拟主机实战一、Nginx 的概念二、Nginx 的特点

MySQL 数据库进阶之SQL 数据操作与子查询操作大全

《MySQL数据库进阶之SQL数据操作与子查询操作大全》本文详细介绍了SQL中的子查询、数据添加(INSERT)、数据修改(UPDATE)和数据删除(DELETE、TRUNCATE、DROP)操作... 目录一、子查询:嵌套在查询中的查询1.1 子查询的基本语法1.2 子查询的实战示例二、数据添加:INSE

Linux服务器数据盘移除并重新挂载的全过程

《Linux服务器数据盘移除并重新挂载的全过程》:本文主要介绍在Linux服务器上移除并重新挂载数据盘的整个过程,分为三大步:卸载文件系统、分离磁盘和重新挂载,每一步都有详细的步骤和注意事项,确保... 目录引言第一步:卸载文件系统第二步:分离磁盘第三步:重新挂载引言在 linux 服务器上移除并重新挂p

使用Python在PDF中绘制多种图形的操作示例

《使用Python在PDF中绘制多种图形的操作示例》在进行PDF自动化处理时,人们往往首先想到的是文本生成、图片嵌入或表格绘制等常规需求,然而在许多实际业务场景中,能够在PDF中灵活绘制图形同样至关重... 目录1. 环境准备2. 创建 PDF 文档与页面3. 在 PDF 中绘制不同类型的图形python

Java 操作 MinIO详细步骤

《Java操作MinIO详细步骤》本文详细介绍了如何使用Java操作MinIO,涵盖了从环境准备、核心API详解到实战场景的全过程,文章从基础的桶和对象操作开始,到大文件分片上传、预签名URL生成... 目录Java 操作 MinIO 全指南:从 API 详解到实战场景引言:为什么选择 MinIO?一、环境

Linux下屏幕亮度的调节方式

《Linux下屏幕亮度的调节方式》文章介绍了Linux下屏幕亮度调节的几种方法,包括图形界面、手动调节(使用ACPI内核模块)和外接显示屏调节,以及自动调节软件(CaliseRedshift和Reds... 目录1 概述2 手动调节http://www.chinasem.cn2.1 手动屏幕调节2.2 外接显