智能家居窗帘步进电机驱动程序:
1. 本驱动使用platform模型进行设计,分为Stepper_Motor_device和Stepper_Motor_driver两个文件
2. 注册杂项设备(misc),主设备号固定是10(misc),从设备号由系统自动分配,加载成功后使用lsmod可以看到:
Stepper_Motor_device
Stepper_Motor_driver
3. 加载driver驱动模块之后初始化成功会输出:
[ 36.605575] entering Stepper_Motor_driver_init
[ 36.605702] entering Stepper_Motor_dirver_probe
4. 本驱动注册成功后生成 /dev/smarthome_steppermotor_control 节点
5. 对 smarthome_lightcontrol 设备节点的操作主要有:
1)打开操作open:打开文件过程中会对GPIO进行初始化
[ 36.609147] Stepper_Motor_dirver_open: gpio init finished!!! //GPIO初始化成功
2)关闭操作close:关闭文件过程中会将用到的所有GPIO置低电平
3) 对文件的读操作read,使用方法:
先定义这样一个结构体类型的变量
static struct motor_info{
unsigned short step_long; //步进电机的步长信息
unsigned short one_round; //步进电机转动一周所需的控制脉冲数
unsigned short pulse_period; //步进电机脉冲周期
unsigned short max_position; //步进电机最大位置(放下窗帘的最大值)
/****** this is important *****/
unsigned short current_position; //步进电机当前的位置值(步进电机每转动一周,该位置值就会加1或减1)
/****************************/
unsigned short min_position; //步进电机最小位置 (收起窗帘的最小值)
};
然后把这个结构的地址放到read函数里面作为缓冲区,对驱动文件进行读操作,就可获得驱动里面包含的关于步进电机的信息。
4)发送命令ioctl:这里使用了_IO的办法对命令进行加密
#define MAGIC_WORD 'P'
#define STEPPER_MOTOR_DOWN_A_STEP _IO(MAGIC_WORD,11) //步进电机正转1周
#define STEPPER_MOTOR_UP_A_STEP _IO(MAGIC_WORD,21) //步进电机反转1周
在ioctl操作过程中,会使用互斥锁对驱动文件进行上锁,避免其他进程或线程同时进行ioctl,打乱时序。操作完成后会解锁。
6. 重构了整个室内机驱动的框架
模块单独调试时请将driver文件里面的SINGLE_MODULE宏修改为1(独立申请内存)
整体调试时请将driver文件里面的SINGLE_MODULE宏修改为0(内存由框架代码统一申请)
7. 开启模块调试信息请将driver文件里面的DEBUG宏修改为1,关闭设为0。
Stepper_Motor_device.c
#include
#include
#include
#include
#define S5PV210_GPH_BASE 0xe0200c00 //read the s5pv210 datasheet!
#define GPH_SIZE 0x6c
void Stepper_Motor_device_release(struct device * pdev);
struct StepperMotor_Plat_Data{
unsigned short step_long;
unsigned short one_round;
unsigned short pulse_period;
unsigned short max_position;
unsigned short current_position;
unsigned short min_position;
};
#define PULSE_PERIOD 25 //ms
#define HIGH_LEVEL_TIME PULSE_PERIOD
#define LOW_LEVEL_TIME (PULSE_PERIOD * 3)
#define INPUT_PERIOD (PULSE_PERIOD * 4)
#define PER_STEP 18
#define ONE_ROUND (360/PER_STEP)
#define DEFAULT_ALL_DOWN 10
#define DEFAULT_ALL_UP 0
static struct StepperMotor_Plat_Data steppermotor_plat_data={
.step_long = PER_STEP,
.one_round = ONE_ROUND,
.pulse_period = PULSE_PERIOD,
.max_position = DEFAULT_ALL_DOWN,
.current_position = DEFAULT_ALL_UP,
.min_position = DEFAULT_ALL_UP,
};
static struct resource Stepper_Motor_resource[]={
[0] = {
.start = S5PV210_GPH_BASE,
.end = S5PV210_GPH_BASE + GPH_SIZE,
.name = "GPH_BASE",
.flags = IORESOURCE_MEM,
},
};
struct platform_device Stepper_Motor_device={
.name = "stepper_motor_drv",
.id = -1,
.dev={
.platform_data=(void*)&steppermotor_plat_data,
.release=Stepper_Motor_device_release,
},
.num_resources = ARRAY_SIZE(Stepper_Motor_resource),
.resource = Stepper_Motor_resource,
};
void Stepper_Motor_device_release(struct device * pdev)
{
printk("entering %s
",__FUNCTION__);
}
static int __init Stepper_Motor_device_init(void)
{
printk("entering %s
",__FUNCTION__);
if( platform_device_register(&Stepper_Motor_device) ){
printk("%s: platform_device_register failed!
",__FUNCTION__);
return -EBUSY;
}
return 0;
}
static void __exit Stepper_Motor_device_exit(void)
{
printk("entering %s
",__FUNCTION__);
platform_device_unregister(&Stepper_Motor_device);
}
module_init(Stepper_Motor_device_init);
module_exit(Stepper_Motor_device_exit);
MODULE_AUTHOR("kinyanderson");
MODULE_DESCRIPTION("Stepper_Motor_device,use for controlling the stepper motor");
MODULE_LICENSE("GPL");
Stepper_Motor_driver.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEBUG 1
#define SINGLE_MODULE 1
#define READING_WAIT_TIME 300
#define MAGIC_WORD 'P'
#define STEPPER_MOTOR_DOWN_A_STEP _IO(MAGIC_WORD,11)
#define STEPPER_MOTOR_UP_A_STEP _IO(MAGIC_WORD,21)
#define GPH0_4_SET_LOWLEVEL(tmp) do{
tmp =ioread32(GPH0_BASE+1);
tmp &= ~(0x1<<4);
iowrite32(tmp,GPH0_BASE+1);
}while(0)
#define GPH0_4_SET_HIGHLEVEL(tmp) do{
tmp =ioread32(GPH0_BASE+1);
tmp |= (0x1<<4);
iowrite32(tmp,GPH0_BASE+1);
}while(0)
#define GPH1_1_SET_LOWLEVEL(tmp) do{
tmp =ioread32(GPH1_BASE+1);
tmp &= ~(0x1<<1);
iowrite32(tmp,GPH1_BASE+1);
}while(0)
#define GPH1_1_SET_HIGHLEVEL(tmp) do{
tmp =ioread32(GPH1_BASE+1);
tmp |= (0x1<<1);
iowrite32(tmp,GPH1_BASE+1);
}while(0)
#define GPH0_3_SET_LOWLEVEL(tmp) do{
tmp =ioread32(GPH0_BASE+1);
tmp &= ~(0x1<<3);
iowrite32(tmp,GPH0_BASE+1);
}while(0)
#define GPH0_3_SET_HIGHLEVEL(tmp) do{
tmp =ioread32(GPH0_BASE+1);
tmp |= (0x1<<3);
iowrite32(tmp,GPH0_BASE+1);
}while(0)
#define GPH0_5_SET_LOWLEVEL(tmp) do{
tmp =ioread32(GPH0_BASE+1);
tmp &= ~(0x1<<5);
iowrite32(tmp,GPH0_BASE+1);
}while(0)
#define GPH0_5_SET_HIGHLEVEL(tmp) do{
tmp =ioread32(GPH0_BASE+1);
tmp |= (0x1<<5);
iowrite32(tmp,GPH0_BASE+1);
}while(0)
#define OP_1(tmp) do{
GPH0_4_SET_HIGHLEVEL(tmp);
mdelay(plat_data_p->pulse_period);
GPH0_4_SET_LOWLEVEL(tmp);
}while(0)
#define OP_2(tmp) do{
GPH1_1_SET_HIGHLEVEL(tmp);
mdelay(plat_data_p->pulse_period);
GPH1_1_SET_LOWLEVEL(tmp);
}while(0)
#define OP_3(tmp) do{
GPH0_3_SET_HIGHLEVEL(tmp);
mdelay(plat_data_p->pulse_period);
GPH0_3_SET_LOWLEVEL(tmp);
}while(0)
#define OP_4(tmp) do{
GPH0_5_SET_HIGHLEVEL(tmp);
mdelay(plat_data_p->pulse_period);
GPH0_5_SET_LOWLEVEL(tmp);
}while(0)
struct StepperMotor_Plat_Data{
unsigned short step_long;
unsigned short one_round;
unsigned short pulse_period;
unsigned short max_position;
unsigned short current_position;
unsigned short min_position;
};
static struct StepperMotor_Plat_Data * plat_data_p;
struct resource * platform_resource;
static volatile unsigned long * GPH_BASE;
//Must caculate the offset carefully!!!
#define GPH0_BASE (GPH_BASE + 0)
#define GPH1_BASE (GPH_BASE + 8)
/*** file_operation_function declare ****/
int Stepper_Motor_driver_open (struct inode * inode_p, struct file *file_p);
long Stepper_Motor_driver_ioctl (struct file *file_p, unsigned int cmd, unsigned long arg);
int Stepper_Motor_driver_close (struct inode *inode_p, struct file *file_p);
ssize_t Stepper_Motor_driver_read (struct file *file_p, char __user *buff, size_t size, loff_t *offset);
static int __devexit Stepper_Motor_driver_remove(struct platform_device * pdev);
static int __devinit Stepper_Motor_dirver_probe(struct platform_device * pdev);
/*** Mutex ***/
struct mutex Stepper_Motor_mutex;
/*** Struct declare ****/
static struct platform_driver Stepper_Motor_driver={
.probe=Stepper_Motor_dirver_probe,
.remove = Stepper_Motor_driver_remove,
.driver = {
.name = "stepper_motor_drv",
.owner = THIS_MODULE,
},
};
static struct file_operations Stepper_Motor_fop={
.open=Stepper_Motor_driver_open,
.unlocked_ioctl=Stepper_Motor_driver_ioctl,
.release=Stepper_Motor_driver_close,
.read=Stepper_Motor_driver_read,
};
static struct miscdevice Stepper_Motor_miscdev = {
.minor = MISC_DYNAMIC_MINOR, //dynamic
.name = "smarthome_steppermotor_control",
.fops = &Stepper_Motor_fop,
};
/*** file_operation_function implement ****/
int Stepper_Motor_driver_open (struct inode * inode_p, struct file *file_p)
{
printk("entering %s
",__FUNCTION__);
unsigned int tmp;
/*nLED_1=EINT4/GPH0_4*/
//GPH0CON[4] [19:16] = 0001
tmp =ioread32(GPH0_BASE+0);
tmp &= ~(0xf<<16);
tmp |= (0x1<<16);
iowrite32(tmp,GPH0_BASE+0);
GPH0_4_SET_LOWLEVEL(tmp);
/*nLED_4=EINT9/GPH1_1*/
//GPH1CON[1] [7:4]=0001
tmp =ioread32(GPH1_BASE+0);
tmp &= ~(0xf<<4);
tmp |= (0x1<<4);
iowrite32(tmp,GPH1_BASE+0);
GPH1_1_SET_LOWLEVEL(tmp);
/*nLED_3=EINT3/GPH0_3*/
//GPH0CON[3] [15:12] = 0001
tmp =ioread32(GPH0_BASE+0);
tmp &= ~(0xf<<12);
tmp |= (0x1<<12);
iowrite32(tmp,GPH0_BASE+0);
GPH0_3_SET_LOWLEVEL(tmp);
/*nLED_4=EINT5/GPH0_5*/
//GPH0CON[5] [23:20]=0001
tmp =ioread32(GPH0_BASE+0);
tmp &= ~(0xf<<20);
tmp |= (0x1<<20);
iowrite32(tmp,GPH0_BASE+0);
GPH0_5_SET_LOWLEVEL(tmp);
plat_data_p->current_position=0;
printk("%s: gpio init finished!!!
",__FUNCTION__);
return 0;
}
ssize_t Stepper_Motor_driver_read (struct file * file_p,char __user * buff, size_t size,loff_t *offset)
{
printk("entering %s
",__FUNCTION__);
unsigned char i;
i=0;
while(copy_to_user(buff,(void *)plat_data_p,sizeof(*plat_data_p))){
msleep(READING_WAIT_TIME);
if(i++ >= 2){
printk("%s: copy_to_user failed!!!
",__FUNCTION__);
return -EBUSY;
}
}
return 0;
}
long Stepper_Motor_driver_ioctl (struct file *file_p, unsigned int cmd, unsigned long arg)
{
/* Locked */
mutex_lock(&Stepper_Motor_mutex);
printk("entering %s
",__FUNCTION__);
unsigned int tmp;
int i;
if(_IOC_TYPE(cmd) != MAGIC_WORD)
return -EINVAL;
switch(cmd){
case STEPPER_MOTOR_DOWN_A_STEP:
if(plat_data_p->current_position < plat_data_p->max_position){
for(i=0;ione_round;i++){
OP_1(tmp);
OP_2(tmp);
OP_3(tmp);
OP_4(tmp);
}
plat_data_p->current_position++;
#if DEBUG
printk("Kernel Debug: plat_data_p->current_position is %d
",
plat_data_p->current_position);
#endif
}
break;
case STEPPER_MOTOR_UP_A_STEP:
if(plat_data_p->current_position > plat_data_p->min_position){
for(i=0;ione_round;i++){
OP_4(tmp);
OP_3(tmp);
OP_2(tmp);
OP_1(tmp);
}
plat_data_p->current_position--;
#if DEBUG
printk("Kernel Debug: plat_data_p->current_position is %d
",
plat_data_p->current_position);
#endif
}
break;
default:
printk("%s: invalid command !!!
",__FUNCTION__);
break;
}
/* Unlocked */
mutex_unlock(&Stepper_Motor_mutex);
return 0;
}
int Stepper_Motor_driver_close (struct inode *inode_p, struct file *file_p)
{
printk("entering %s
",__FUNCTION__);
unsigned int tmp;
GPH0_4_SET_LOWLEVEL(tmp);
GPH1_1_SET_LOWLEVEL(tmp);
GPH0_3_SET_LOWLEVEL(tmp);
GPH0_5_SET_LOWLEVEL(tmp);
return 0;
}
/*** driver_operation ****/
static int __devinit Stepper_Motor_dirver_probe(struct platform_device * pdev)
{
printk("entering %s
",__FUNCTION__);
struct resource * pcheck;
plat_data_p=(struct StepperMotor_Plat_Data *)(pdev->dev.platform_data);
platform_resource=platform_get_resource(pdev,IORESOURCE_MEM,0);
if(NULL == platform_resource){
printk("%s: platform_get_resource failed!
",__FUNCTION__);
goto err1;
}
#if SINGLE_MODULE
pcheck=request_mem_region(platform_resource->start,
platform_resource->end - platform_resource->start + 1,
platform_resource->name);
if(NULL==pcheck){
printk("%s: request_mem_region failed!
",__FUNCTION__);
goto err1; //return device busy!
}
#endif
GPH_BASE=(unsigned long *)ioremap(platform_resource->start,
platform_resource->end - platform_resource->start + 1);
#if DEBUG
printk("%s: GPH_BASE is %p
",__FUNCTION__,GPH_BASE);
printk("%s: GPH0_BASE is %p
",__FUNCTION__,GPH0_BASE);
printk("%s: GPH1_BASE is %p
",__FUNCTION__,GPH1_BASE);
#endif
if( misc_register(&Stepper_Motor_miscdev) ){
printk("%s: misc_register failed!
",__FUNCTION__);
goto err2;
}
/* initing the mutex */
mutex_init(&Stepper_Motor_mutex);
return 0;
err2:
iounmap(GPH_BASE);
#if SINGLE_MODULE
release_mem_region(platform_resource->start,
platform_resource->end - platform_resource->start + 1);
#endif
err1:
return -EBUSY;
}
static int __devexit Stepper_Motor_driver_remove(struct platform_device * pdev)
{
printk("entering %s
",__FUNCTION__);
mutex_destroy(&Stepper_Motor_mutex);
iounmap(GPH_BASE);
#if SINGLE_MODULE
release_mem_region(platform_resource->start,
platform_resource->end - platform_resource->start + 1);
#endif
if( misc_deregister(&Stepper_Motor_miscdev) ){
printk("%s:misc_deregister failed!
",__FUNCTION__);
return -EPERM;
}
return 0;
}
static int __init Stepper_Motor_driver_init(void)
{
printk("entering %s
",__FUNCTION__);
if( platform_driver_register(& Stepper_Motor_driver) ){
printk("%s: driver_register failed!
",__FUNCTION__);
return -EBUSY;
}
return 0;
}
static void __exit Stepper_Motor_driver_exit(void)
{
printk("entering %s
",__FUNCTION__);
platform_driver_unregister(& Stepper_Motor_driver);
}
module_init(Stepper_Motor_driver_init);
module_exit(Stepper_Motor_driver_exit);
MODULE_AUTHOR("kinyanderson");
MODULE_DESCRIPTION("Stepper_Motor_driver,use for controlling the Stepper motor");
MODULE_LICENSE("GPL");
app.c
#include
#include
#include
#define MAGIC_WORD 'P'
#define STEPPER_MOTOR_DOWN_A_STEP _IO(MAGIC_WORD,11)
#define STEPPER_MOTOR_UP_A_STEP _IO(MAGIC_WORD,21)
struct motor_info{
unsigned short step_long;
unsigned short one_round;
unsigned short pulse_period;
unsigned short max_position;
unsigned short current_position;
unsigned short min_position;
};
struct motor_info mi_str;
void turn_all_down(int fd);
void turn_all_up(int fd);
int main(int argc,char **argv)
{
int ret,fd,i=10;
fd = open("/dev/smarthome_steppermotor_control",O_RDWR);
if(fd < 0){
printf("can not open smarthome_steppermotor_control!!!
");
return -1;
}
ret = read(fd,&mi_str,sizeof(mi_str));
if(ret<0){
printf("can not read smarthome_steppermotor_control!!!
");
goto err;
}
printf("step_long is:%d
",mi_str.step_long);
printf("one_round is:%d
",mi_str.one_round);
printf("pulse_period is:%d
",mi_str.pulse_period);
printf("max_position is:%d
",mi_str.max_position);
printf("current_position is:%d
",mi_str.current_position);
printf("min_position is:%d
",mi_str.min_position);
turn_all_down(fd);
turn_all_up(fd);
while(i--)
{
printf("motor down!
");
ioctl(fd,STEPPER_MOTOR_DOWN_A_STEP);
sleep(5);
printf("motor up!
");
ioctl(fd,STEPPER_MOTOR_UP_A_STEP);
sleep(5);
}
printf("the app finished!!!
");
close(fd);
return 0;
err:
close(fd);
return -1;
}
void turn_all_down(int fd)
{
int i;
i=mi_str.current_position;
while(i < mi_str.max_position){
ioctl(fd,STEPPER_MOTOR_DOWN_A_STEP);
read(fd,&mi_str,sizeof(mi_str));
printf("current position is:%d
",mi_str.current_position);
i++;
}
printf("%d motor all down!
",i);
}
void turn_all_up(int fd)
{
int i;
i=mi_str.current_position;
while(i > mi_str.min_position){
ioctl(fd,STEPPER_MOTOR_UP_A_STEP);
read(fd,&mi_str,sizeof(mi_str));
printf("current position is:%d
",mi_str.current_position);
i--;
}
printf("%d motor all up!
",i);
}
Makefile
obj-m += Stepper_Motor_device.o Stepper_Motor_driver.o
KDIR := /home/kinyanderson/final_design/android-kernel-samsung-dev
modules:
make modules -C $(KDIR) M=`pwd`
arm-linux-gcc app.c -o app
clean:
make modules clean -C $(KDIR) M=`pwd`