RK3308编写pwm驱动

查看kernel的dts文件:

./build.sh kernel 

在这里插入图片描述
在文件目录Z:\kernel\arch\arm64\boot\dts\rockchip下找到rk3308b-roc-cc-plus-amic_emmc然后在里面添加pwm配置,如下所示:配置了一个pwm10

 pwm-roll {
            status = "okay";
            compatible = "pwm-roll";
            pwms = <&pwm10 0 25000 0>;
        };

在这里插入图片描述

在下面添加有&符号后面添加一个:

&pwm10 {
    status = "okay";
    pinctrl-names = "active";
    pinctrl-0 = <&pwm10_pin_pull_down>;
};

在这里插入图片描述

在Z:\kernel\drivers(自己创建的文件夹):
创建一个如下的文件夹:
在这里插入图片描述
Z:\kernel\drivers的makefile最后添加:

obj-y += (自己文件夹名字)/pwm_roll/

切换到:
在这里插入图片描述
除了pwm_roll文件以外都可以在drivers文件中找到,复制过来后只用修改Makefile和Kconfig,将其串联进kernel中:
Makefile文件如下

obj-y += pwm_roll.o

Kconfig文件如下

config PWM_ROLL
	bool "PWM_ROLL"
	default y
	depends on PWM_SYSFS
	---help---
	   Serial Port Transmitter support

编写pwm_roll.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pwm.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/roll.h>
#include <linux/of_irq.h>
#include <linux/irq.h> 
#include <linux/interrupt.h>
#include <linux/errno.h>
static struct pwm_roll roll_pwm;

static const struct of_device_id pwm_roll_match[] = {
	{ .compatible = "pwm-roll", },
	{ },
};
MODULE_DEVICE_TABLE(of, pwm_roll_match);
static ssize_t pwm_roll_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
	
	int tmp,ret;
	void __user *argp = (void __user *)arg;
    switch(cmd)
	{
	  case  ROLL_PWM_SET_PERIOD:	
	    pwm_disable(roll_pwm.pwm);
 		printk("roll_pwm_SET_DUTY.");
 		ret =copy_from_user(&tmp, argp, sizeof(int));
 		if(ret)
 		{
 		   printk("copy_to_user failed.");
 		   return -EINVAL;
 		}	
 		//频率= 1000,000,000 /time
 		roll_pwm.period_ns =(int)( ROLL_PWM_PERIOD/tmp); 
 		roll_pwm.period = tmp;
 		pwm_set_period(roll_pwm.pwm,roll_pwm.period_ns);
        pwm_enable(roll_pwm.pwm);
        printk("ROLL_PWM_SET_PERIOD. =%d hz,period_ns = %dns\n",roll_pwm.period,roll_pwm.period_ns);
	  		break;
	  case ROLL_PWM_SET_DUTY:
 		ret =copy_from_user(&tmp, argp, sizeof(int));
		 printk("ret%d\n",ret);
 		if(ret)
 		{
  		   printk("copy_to_user failed.");
 		   return -EINVAL;	
 		}
		 
 		if(abs(tmp) > roll_pwm.period_ns)
 		{printk("temp%d\n",tmp);
		 roll_pwm.duty_cycle = abs(tmp); 
			pwm_config(roll_pwm.pwm, roll_pwm.period_ns, roll_pwm.period_ns);	
 		}
 		else
 		{printk("temp%d\n",tmp);
 		  roll_pwm.duty_cycle = abs(tmp); 
 		  pwm_config(roll_pwm.pwm, roll_pwm.duty_cycle, roll_pwm.period_ns);	
 		}	
 		

 		printk("ROLL_PWM_SET_PDUTY = %d ns.\n",roll_pwm.duty_cycle);
	  		break;
	  case ROLL_PWM_GET_DUTY: 
	  	ret = copy_to_user(argp, &roll_pwm.duty_cycle, sizeof(unsigned int));
	  	if(ret)
	  	{
 		   printk("copy_to_user failed.");
 		   return -EINVAL;
	  	}	
 		printk("ROLL_PWM_GET_DUTY %d ns\n.",roll_pwm.duty_cycle);

	  		break;
	  case ROLL_PWM_GET_PERIOD:
	    ret = copy_to_user(argp, &roll_pwm.period, sizeof(unsigned int));
	  	if(ret)
	  	{
 		   printk("copy_to_user failed.\n");
 		   return -EINVAL;
	  	}	
 		printk("ROLL_PWM_GET_PERIOD %d hz.\n",roll_pwm.period);
	  		break;
	  case ROLL_PWM_ENABLE:
 		printk("ROLL_PWM_ENABLE.\n");
 		pwm_config(roll_pwm.pwm, 0, roll_pwm.period_ns);
		pwm_enable(roll_pwm.pwm);
	  		break;
	  case ROLL_PWM_DISABLE:

	  	pwm_config(roll_pwm.pwm, 0, roll_pwm.period_ns);
	  	pwm_disable(roll_pwm.pwm);

 		printk("ROLL_PWM_DISABLE.\n");

	  		break;
	}
    return 0;
}
static int roll_pwm_open(struct inode *inode, struct file *filp)
{
	  printk("roll pwm open \n");
	  return 0;
}
static int roll_pwm_release(struct inode *inode, struct file *filp)
{
	  printk("roll pwm release \n");
	  return 0;
}
static ssize_t roll_pwm_read(struct file *filp, char __user *buf, size_t len, loff_t *pos)
{ 
    printk("roll pwm read \n");
    return 0;
}

static ssize_t roll_pwm_write(struct file *filp, const char __user *buf, size_t len, loff_t *pos)
{
	printk("roll pwm write len=%ld\n",len);
    return 0;
}

static struct file_operations ROLL_PWM_fops = {
	.owner = THIS_MODULE,
	.open  = roll_pwm_open,
	.release = roll_pwm_release,
	.write = roll_pwm_write,
	.read = roll_pwm_read,
	.unlocked_ioctl = pwm_roll_ioctl,
};

struct miscdevice ROLL_PWM_dev =
{
	.minor = MISC_DYNAMIC_MINOR,
	.fops = &ROLL_PWM_fops,
	.name = "roll_pwm",
};
static int pwm_roll_probe(struct platform_device *pdev)
{
	
	int ret =0;
    struct pwm_device *pwm;
	static struct pwm_roll *roll = &roll_pwm;
	struct device *dev;
	dev =&pdev->dev;
	if(!dev->of_node)
	{
		dev_err(dev,"dev->of_node is not \n");
		return -ENODEV;
	}
	pwm = devm_pwm_get(dev, NULL);
	if(IS_ERR(pwm))
	{
		dev_err(dev,"get pwm error\n");
		// goto ROLL_IRQ_ERROR;	
	}
	ret = pwm_adjust_config(pwm);
	if(ret)
	{
		misc_register(&ROLL_PWM_dev);
		//goto ROLL_IRQ_ERROR;
	}
	pwm_set_period(pwm,10000);
	pwm_enable(pwm);
	roll->period = (int)(ROLL_PWM_PERIOD/10000);
	roll->duty_cycle = 0;
	roll->period_ns = 10000;
	roll->pwm = pwm;
	ret =misc_register(&ROLL_PWM_dev);
	if(ret != 0)
	{
		dev_err(dev,"failed misc register\n");	
		//goto ROLL_MISC_ERROR;
	}	
	return 0;
}

static struct platform_driver roll_driver = {
	.probe = pwm_roll_probe,
	.driver = {
		.name	= "pwm-roll",
		.of_match_table = of_match_ptr(pwm_roll_match),
	},
};
module_platform_driver(roll_driver);
MODULE_DESCRIPTION("PWM ROLL");
MODULE_AUTHOR("Y <sean@mess.org>");
MODULE_LICENSE("GPL");

roll.h如下:该文件放在Z:\kernel\include\linux下

#include <linux/pwm.h>

#define ROLL_PWM_SET_DUTY          _IOW('Y', 0x11, unsigned int)     //设置占空比
#define ROLL_PWM_SET_PERIOD        _IOW('Y', 0x12, unsigned int)	  //设置频率
#define ROLL_PWM_GET_DUTY          _IOR('Y', 0x13, unsigned int)	  //获取当前占空比
#define ROLL_PWM_GET_PERIOD        _IOR('Y', 0x14, unsigned int)     //获取频率 
#define ROLL_PWM_ENABLE            _IO('Y',  0x17)					  //开启pwm
#define ROLL_PWM_DISABLE           _IO('Y',  0x18)					  //关闭pwm

#define ROLL_PWM_PERIOD 			1000000000		//用于计算 频率 = 1000,000,000 /time 
struct pwm_roll {
	unsigned int period;		  //频率
	unsigned int duty_cycle;	  //占空比	
	unsigned int period_ns; 	  //占空比周期
	struct pwm_device *pwm;
};

然后运行./build.sh重新进行编译,将我们得到的镜像烧录到RK3308的板子上。
编写运行程序demo.c:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>

#define ROLL_PWM_SET_DUTY          _IOW('Y', 0x11, unsigned int)     //设置占空比
#define ROLL_PWM_SET_PERIOD        _IOW('Y', 0x12, unsigned int)     //设置频率
#define ROLL_PWM_GET_DUTY          _IOR('Y', 0x13, unsigned int)     //获取当前占空比
#define ROLL_PWM_GET_PERIOD        _IOR('Y', 0x14, unsigned int)     //获取频率 


#define ROLL_PWM_ENABLE            _IO('Y',  0x15)                   //开启pwm
#define ROLL_PWM_DISABLE           _IO('Y',  0x16)                   //关闭pwm

#define DEV_NAME "/dev/roll_pwm"
int main(int argc, char *argv[])
{       
    int fd;
    int duty, period;
    if(argc <2)
    {
        printf("no value\n");
        return 1;
    }
    printf("argc =%d\n",argc);
    fd = open(DEV_NAME,O_RDWR);
    if(fd < 0)
    {
        printf("hello world\n");
    }
    switch (*(argv[1] +1))
    {
        case 'p':
            period=atoi(argv[2]); 
            ioctl(fd, ROLL_PWM_SET_PERIOD, &period);
            printf("period = %d\n",period);
        break;
        case 'd':
            duty=atoi(argv[2]);
            ioctl(fd, ROLL_PWM_SET_DUTY, &duty);
            printf("duty =%d\n",duty);
            break;
        case 'a':
            ioctl(fd, ROLL_PWM_GET_PERIOD, &period);
            printf("get period =%d\n",period);    
            break;
        case 'b':
            ioctl(fd, ROLL_PWM_GET_DUTY, &duty);
            printf("get duty =%d\n",duty);  
            break;  
        default:
            break;
    }
    close(fd);
    return 0;
}

这个的运行方法参照led的运行方法:https://blog.csdn.net/Wu996/article/details/120632573
使用demo -p 10000设置周期
使用demo -d 500000设置占空比
使用demo -a 查看周期
使用demo -b 查看设置的周期
最后用cat sys/kernel/debug/pwm就可以查看我们设置的pwm了
在这里插入图片描述
这样一个完成的pwm就设置好了,使用示波器会呈现一个方波

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

曾许人间第一流.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值