栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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

一,linux内存映射

二,原理图

三,linux应用层代码解析

1,pl_gpio.h

#ifndef PL_GPIO_H
#define PL_GPIO_H
#include 

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   
#define XGPIO_TRI_OFFSET	0x4   
#define XGPIO_DATA2_OFFSET	0x8   
#define XGPIO_TRI2_OFFSET	0xC   
#define XGPIO_GIE_OFFSET	0x11C 
#define XGPIO_ISR_OFFSET	0x120 
#define XGPIO_IER_OFFSET	0x128 


typedef uintptr_t UINTPTR;

typedef struct 
{
    UINTPTR BaseAddress;	
    u32 IsReady;		
    int InterruptPresent;	
    int IsDual;		
} 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


#define LED_CHANNEL 1

#define LED 0x01   

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_SAFETY
    volatile u32 *LocalAddr = (volatile u32 *)Addr;
    *LocalAddr = Value;
#else
    XStl_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 results
    Current = 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 
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 0xFF0A0000
 extern 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  
#define XGPIOPS_DATA_MSW_OFFSET  0x00000004U  
#define XGPIOPS_DATA_OFFSET      0x00000040U  
#define XGPIOPS_DATA_RO_OFFSET	 0x00000060U  
#define XGPIOPS_DIRM_OFFSET      0x00000204U  
#define XGPIOPS_OUTEN_OFFSET	 0x00000208U  

#define XGPIOPS_DATA_MASK_OFFSET 0x00000008U  
#define XGPIOPS_DATA_BANK_OFFSET 0x00000004U  
#define XGPIOPS_REG_MASK_OFFSET  0x00000040U  

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};
    
    XGpioPsPinTable[0] = (u32)25; 
    XGpioPsPinTable[1] = (u32)51; 
    XGpioPsPinTable[2] = (u32)77; 
    XGpioPsPinTable[3] = (u32)109; 
    XGpioPsPinTable[4] = (u32)141; 
    XGpioPsPinTable[5] = (u32)173; 

    *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 bank
    XGpioPs_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 bank
    XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);
    if (PinNumber > 15U) 
    {
        // There are only 16 data bits in bit maskable register
        PinNumber -= (u8)16;
        RegOffset = XGPIOPS_DATA_MSW_OFFSET;
    } 
    else 
    {
        RegOffset = XGPIOPS_DATA_LSW_OFFSET;
    }

    
    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 
#include 
#include 
#include 
#include 
#include 
#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 failedrn");
        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 failrn");
    }
    XGpio_SetDataDirection(&Gpio, LED_CHANNEL, ~LED);
    while(1)
    {
        
        XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, LED);
        usleep(500000);
        
        XGpio_DiscreteClear(&Gpio, LED_CHANNEL, LED);
        msync((void *)Gpio.BaseAddress, 1024, MS_ASYNC);
        usleep(500000);
    }
    return 0;
}

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/883802.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号