[嵌入式Linux驱动]S5PV210的步进电机Linux驱动程序

2019-07-12 15:25发布

智能家居窗帘步进电机驱动程序: 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`