基于 platform 平台的驱动框架

本文介绍了一种基于Linux-3.5内核的步进电机驱动框架实现方法,该框架适用于FriendlyArmTiny4412开发板。通过平台驱动模型支持门和窗两种设备上的步进电机控制,并实现了定时器驱动的电机旋转。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于 platform 平台的驱动框架实现


现步进电机的驱

一套驱动支持多个设备

软件环境:Linux-3.5内核 

硬件环境:FriendlyArm Tiny4412 开发板 / Exynos 4412 SOC / ARM cortex A9


Makefile


obj-m		:= window_dev.o door_dev.o bj_drv.o

MYKERNEL	:= /home/flyme/soc/linux-3.5-millet/

all: bjioctl.h
	make -C $(MYKERNEL) M=`pwd` modules
	sudo cp bj_drv.ko window_dev.ko door_dev.ko /fsroot

clean:
	make -C $(MYKERNEL) M=`pwd` clean 

bjioctl.h


#ifndef _BJ_H_
#define _BJ_H_

#define BJMAC 'J'

#define BJCW   _IOW(BJMAC, 0, int)
#define BJCCW  _IOW(BJMAC, 1, int)
#define BJSTOP _IOW(BJMAC, 2, int)

#endif // _BJ_H_


door_dev.c


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static void door_release (struct device* pdev) {
	
}

static struct resource devsrc[] = {
	{
		.start = EXYNOS4_GPB(4),
		.end   = EXYNOS4_GPB(7),
		.flags = IORESOURCE_MEM,
		.name  = "door_base",
	},
};

static struct platform_device door_dev = {
	.resource = devsrc,
	.id = 1,
	.num_resources = ARRAY_SIZE(devsrc),
	.name = "door_motor",
	.dev = {
		.release = door_release,
	},
};

module_driver(door_dev, platform_device_register, platform_device_unregister);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wanghaomaker");
MODULE_VERSION("door motor 3.0");
MODULE_DESCRIPTION("It is a motor device module for door");

window_dev.c


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static void window_release (struct device* pdev) {

}

static struct resource devsrc[] = {
	{
		.start = EXYNOS4_GPJ0(3),
		.end   = EXYNOS4_GPJ0(6), 
		.flags = IORESOURCE_MEM,
		.name  = "window_base",
	},
};

static struct platform_device window_dev = {
	.resource = devsrc, 
	.id = 0,
	.num_resources = ARRAY_SIZE(devsrc),
	.name = "window_motor",
	.dev = {
		.release = window_release,
	},
};

module_driver(window_dev, platform_device_register, platform_device_unregister);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wanghaomaker");
MODULE_VERSION("window motor 3.0");
MODULE_DESCRIPTION("It is a motor device module for window");

bj_drv.c


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "bjioctl.h"

#define STEP	ARRAY_SIZE(beat_code)
#define DEVCNT  2
/*
#define BJBASE  0x11400000 // GPJ0base 
#define BJCON   0x0240     // GPJ0con
#define BJDAT   0x0244     // GPJ0dat
*/
enum { OFF, ON };

static unsigned char beat_code[] = { // 步进电机节拍对应的 IO 控制代码
	0x09, 0x03, 0x06, 0x0C
};
/*
static unsigned char beat_code[] = { // 步进电机节拍对应的 IO 控制代码
	0x09, 0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08
};
*/
static int msec = 5;
static int enperied = 1;
static int major = 50;

struct motor {
	u32 start;
	u32 end;
	int minor;
	long beats;
	struct cdev cdev;
	struct class *class;
	struct timer_list timer;
};

struct motor motor[DEVCNT];
/*
static u32 start = 0;
static u32 end = 0;
static int devnum = 0;
static struct cdev cdev;
static struct class *class = NULL;
static struct timer_list timer;
*/
static void set_mytimer(int minor, u32 sec);
static void service_timer(unsigned long data);

static void motor_start(int minor, signed long angle);
static void motor_stop(int minor);
static int  motor_turn(int minor);

static void service_timer(unsigned long data) {
	int minor = (int)data;

	if (enperied)
		mod_timer(&motor[minor].timer, jiffies + msec*HZ/1000);
	
	if (motor_turn(minor)) 
		enperied = 0;
}

static void set_mytimer(int minor, u32 sec) {
	setup_timer(&motor[minor].timer, service_timer, (unsigned long)minor);
	motor[minor].timer.expires = jiffies + sec*HZ/1000;

	add_timer(&motor[minor].timer);
}

static long 
my_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 
{
	int minor = ((struct motor *)filp->private_data)->minor;

	if (arg < 0) 
		return -EINVAL;

	if (_IOC_TYPE(cmd) == BJMAC) {
		switch (_IOC_NR(cmd)) {
			default:
				return -EINVAL;
			case 0:
				motor_start(minor, arg);
				break;
			case 1:
				motor_start(minor, -1 * arg);
				break;
			case 2:
				motor_stop(minor);
				break;
		}
	}		

	return 0;
}

static int my_open (struct inode *inodp, struct file *filp) {
	filp->private_data = container_of(inodp->i_cdev, struct motor, cdev);
	return 0;
}

static int my_release (struct inode *inodp, struct file *filp) {
	return 0;
}

static struct file_operations fops = {
	.owner = THIS_MODULE,
	.open = my_open,
	.unlocked_ioctl = my_unlocked_ioctl,
	.release = my_release,
};

static int bj_probe(struct platform_device *pdev)
{
	int ret;
	int i = 0;
	int devnum = 0;
	struct resource *pres;
	struct device *device = NULL;
	struct class *class = NULL;

	motor[pdev->id].minor = pdev->id;
	printk("--- driver %d device ---\n", pdev->id);
	pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	motor[pdev->id].start = pres->start;
	motor[pdev->id].end   = pres->end;
	
	class = class_create(THIS_MODULE, pdev->name); 
	if (IS_ERR(class)) 
		return PTR_ERR(class);
	printk("--- class create %s ---\n", pdev->name);
	
	for (i = pres->start; i <= pres->end; i++) {
		if ((ret = gpio_request(i, "motor")) < 0) 
			goto error0;
		
		gpio_direction_output(i, OFF);
	}
	printk("--- %d gpio request ---\n", pres->start);
	
	devnum = MKDEV(major, pdev->id);
	printk("--- devnum is %d ---\n", devnum);
	
	ret = register_chrdev_region(devnum, 1, pdev->name);
	if (ret < 0) {
		ret = -EINVAL;
    	goto error0;
	}
	printk("--- register %d ---\n", devnum);
	
	cdev_init(&motor[pdev->id].cdev, &fops);
	if ((ret = cdev_add(&motor[pdev->id].cdev, devnum, 1)) < 0) 
		goto error1;
	printk("--- cdev add %d ---\n", devnum);

	device = device_create(class, NULL, devnum, NULL, pdev->name);
	if (IS_ERR(device)) {
		ret = PTR_ERR(device);
		goto error2;
	}
	motor[pdev->id].class = class;
	printk("--- device create %s ok! ---\n", pdev->name);

	return 0;

error2:
	cdev_del(&motor[pdev->id].cdev);

error1: 
    unregister_chrdev_region(devnum, 1);

error0:
	class_destroy(class);
	for ( ; i >= pres->start; i--) 
		gpio_free(i);
	
	return ret;	
}

static int bj_remove(struct platform_device *pdev) 
{
	int i = 0;
	int devnum = 0;
	struct resource *pres; 
	struct class *class = motor[pdev->id].class;
	
	pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);

	devnum = MKDEV(major, pdev->id);
	device_destroy(class, devnum);
	cdev_del(&motor[pdev->id].cdev);

	for (i = pres->start; i <= pres->end; i++)
		gpio_free(i);

	cdev_del(&motor[pdev->id].cdev);
	unregister_chrdev_region(devnum, 1);
	class_destroy(class);

	printk("--- cdev %s die! ---\n", pdev->name);
	
	return 0;
}

static struct platform_device_id millet_tables[] = {
    { "door_motor", },
    { "window_motor", },
};

static struct platform_driver bj_drv = {
    .id_table = millet_tables,
	.driver= {
		.name = "bj_motor",
	},
	.probe  = bj_probe,
	.remove = bj_remove,
};

module_platform_driver(bj_drv);

static void motor_start(int minor, signed long angle) {	
	motor[minor].beats = (angle * 4076 / 2) / 360; // 实测为 4076 拍转动一圈
	set_mytimer(minor, msec);
	enperied = 1;
}

static void motor_stop(int minor) {
	motor[minor].beats = 0;
	del_timer_sync(&motor[minor].timer);
	enperied = 1;
}

static int motor_turn(int minor)
{
	int i = 0, j = 0;
	int ret = 0;
	static unsigned char index[DEVCNT] = {0}; 
	long beats[DEVCNT] = {0};
	beats[minor] = motor[minor].beats;

	if (beats[minor] != 0) {
		if (beats[minor] > 0) { 
			index[minor]++;	
			index[minor] = index[minor] & (STEP - 1); // (STEP==4)?0x3:0x7
			motor[minor].beats--;				
		} else {					
			index[minor]--; 				
			index[minor] = index[minor] & (STEP - 1);
			motor[minor].beats++; 				
		}
		for (i = motor[minor].start, j = 0; i <= motor[minor].end; i++, j++) {
			if (beat_code[index[minor]] & (0x1 << j))
				gpio_set_value(i, ON);
			else 
				gpio_set_value(i, OFF);
		}
		ret = 0;
	} else 
		ret = 1;

	return ret;
}

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wanghaomaker");
MODULE_VERSION("bj motor 3.0");
MODULE_DESCRIPTION("It is a motor driver module");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值