1.驱动层
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <linux/dma-mapping.h>
//ax_pwm@80000000
#define AX_PWM_ADDR (0X80000000)
volatile unsigned int * ax_pwm_freq_addr;
volatile unsigned int * ax_pwm_duty_addr;
dma_addr_t axidma_handle;
volatile unsigned int * axidma_addr;
int major;
static struct class *pwm_class = NULL;
static int pwm_open(struct inode *inode,struct file *file);
static ssize_t pwm_write(struct file *file,const char __user *buf, size_t count,loff_t *ppos);
static ssize_t pwm_read(struct file *file,char __user *buf,size_t size,loff_t *ppos);
/*
*file_operations 结构数据,沟通内核与操作系统桥梁
*
* */
static struct file_operations pwm_lops=
{
.owner = THIS_MODULE,
.read = pwm_read,
.open = pwm_open,
.write = pwm_write,
};
/*
* 初始化,用于module init
*
* */
static int __init pwm_init(void)
{
major=register_chrdev(0,"pwm_dev",&pwm_lops);
pwm_class= class_create(THIS_MODULE,"pwm_dev");
device_create(pwm_class,NULL,MKDEV(major,0),NULL,"pwm_dev");
printk("major dev number= %d",major);
ax_pwm_freq_addr = ioremap(AX_PWM_ADDR + 0x0, 4);
ax_pwm_duty_addr = ioremap(AX_PWM_ADDR + 0x04, 4);
printk("ax_pwm_freq_addr=%0x04\n",ax_pwm_freq_addr);
printk("ax_pwm_duty_addr=%0x04\n",ax_pwm_duty_addr);
return 0;
}
/*
*退出 用于 module exit
*
* */
static void __exit pwm_exit(void)
{
unregister_chrdev(major,"pwm_dev");
device_destroy(pwm_class,MKDEV(major,0));
class_destroy(pwm_class);
iounmap(ax_pwm_duty_addr);
iounmap(ax_pwm_freq_addr);
}
/*
*open 接口函数
*
* */
static int pwm_open(struct inode *inode,struct file *file)
{
int err;
printk("pwm open\n");
return 0;
}
/*
* write 接口函数
*
* */
static ssize_t pwm_write(struct file *file,const char __user *buf, size_t count,loff_t *ppos)
{
printk("pwm write start !\n");
char*after;
unsigned long para = 0;
para = simple_strtoul(buf,&after,10);
printk("para=%ld\n",para);
para = 100 - para;
unsigned int freq_val = (unsigned int)((4294967296.0 / 100000000) * 500);
//unsigned int duty = (unsigned int)(4294967296 * para);//有变量,就不能有小数
unsigned int duty = 4294967296 * para / 100;
printk("duty=%ld\n",duty);
//0是最亮,所以是1-percent. add by iverson.deng 2023/9/13
//unsigned int duty = (unsigned int)(4294967296 * 0.95);
iowrite32(freq_val,ax_pwm_freq_addr);
iowrite32(duty,ax_pwm_duty_addr);
printk("dma write is over!\n");
return 0;
}
/*
* read 接口函数
*DMA读取数据是按照32bit读取的
* */
static ssize_t pwm_read(struct file *file,char __user *buf,size_t size,loff_t *ppos)
{
return 0;
}
module_init(pwm_init);
module_exit(pwm_exit);
MODULE_AUTHOR("iverson@pwm");
MODULE_DESCRIPTION("pwm driver");
MODULE_ALIAS("linux axi pwm driver");
MODULE_LICENSE("GPL");
交叉编译 Makefile
modname:=pwm_driver
obj-m:=$(modname).o
PWD :=$(shell pwd)
MAKE :=make
KERNELDIR = /home/iversondeng/workspace/alinx/petalinux/ubootandkernel/linux-xlnx-xilinx-v2020.1
CROSS_COMPILE=aarch64-xilinx-linux-
ARCH=arm64
all:
$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf $(modname).ko *.o *mod* \.*cmd *odule* .tmp_versions
.PHONY: all clean
2.应用层测试
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
void delay(void)
{
int i,j;
for(i=0;i<20000;i++)
for(j=0;j<10000;j++);
}
unsigned int readarray[128];
int main(int argc , char ** argv)
{
int fd;
int i = 0;
int j = 0;
fd = open("/dev/pwm_dev",O_RDWR);
if(fd < 0)
{
printf("can not open file\n");
while(1);
}
else
{
printf("open file sucuss\n");
}
delay();
if(argc <= 1) return;
j = atoi(argv[1]);
if(!(j >= 0 && j <= 100)) return;
write(fd,argv[1],1);
close(fd);
printf("pwm test over!\n");
return 0;
}
交叉编译
$CC pwm_test.c -o pwm_test -O2 -w