海思步進電機驅動
阿新 • • 發佈:2019-01-05
hisi_motor.c
#include <linux/module.h> //所有模組都需要的標頭檔案 #include <linux/kernel.h> #include <linux/fs.h> //檔案系統有關的,結構體file_operations也在fs標頭檔案定義 #include <linux/init.h> //init和exit相關巨集 #include <linux/delay.h> #include <linux/irq.h> #include <asm/uaccess.h> //linux中的使用者態記憶體互動函式,copy_from_user(),copy_to_user()等 #include <asm/irq.h> //linux中斷定義 #include <asm/io.h> #include <linux/sched.h> //宣告printk()這個核心態的函式 #include <linux/interrupt.h> //包含與中斷相關的大部分巨集及結構體的定義,request_irq()等 #include <linux/device.h> // #include <linux/poll.h> #include <linux/slab.h> #include <linux/gfp.h> #include "hisi_motor.h" static struct hrtimer MotorTimer; ktime_t kt; static unsigned char motorr_timer_flag = 0; int major; static struct class *motordrv_class; static struct device *motordrv_dev; static struct fasync_struct *button_async; //定義一個結構 struct motor_desc{ //定義結構體 unsigned int mux_ofset_addr; //複用暫存器偏移地址 unsigned int mux_val; //複用寄存的設定值 unsigned int gpio_base_addr; //gpio暫存器基址 unsigned char bit; //對gpio寄存進行位操作時用,範圍bit7~bit0 }; struct motor_desc led_motor_desc = {GPIO1_7_MUX_CTRL_REG_OFFSET, 0x00, GPIO01_BASE, 7}; struct motor_desc motors_desc[] = { //定義一個結構體陣列 {GPIO7_5_MUX_CTRL_REG_OFFSET, 0x01, GPIO07_BASE, 5}, {GPIO7_4_MUX_CTRL_REG_OFFSET, 0x01, GPIO07_BASE, 4}, {GPIO7_3_MUX_CTRL_REG_OFFSET, 0x01, GPIO07_BASE, 3}, {GPIO7_2_MUX_CTRL_REG_OFFSET, 0x01, GPIO07_BASE, 2}, {GPIO2_0_MUX_CTRL_REG_OFFSET, 0x00, GPIO02_BASE, 0}, {GPIO2_1_MUX_CTRL_REG_OFFSET, 0x00, GPIO02_BASE, 1}, {GPIO2_2_MUX_CTRL_REG_OFFSET, 0x00, GPIO02_BASE, 2}, {GPIO2_3_MUX_CTRL_REG_OFFSET, 0x00, GPIO02_BASE, 3}, }; #if 0 {1, 0, 0, 0}, {1, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 1}, {0, 0, 0, 1}, {1, 0, 0, 1} #endif /*motorr pwm data CCW (nishizhen)*/ unsigned int CCW_data [8][4] = { {0, 0, 0, 1}, {0, 0, 1, 1}, {0, 0, 1, 0}, {0, 1, 1, 0}, {0, 1, 0, 0}, {1, 1, 0, 0}, {1, 0, 0, 0}, {1, 0, 0, 1} }; /*motorr pwm data CW (shunshizhen)*/ unsigned int CW_data [8][4] = { {0, 0, 0, 1}, {1, 0, 0, 1}, {1, 0, 0, 0}, {1, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 1} }; /********************************************************************************************************* *功能:設定引腳複用 *引數:無 *返回值:無 **********************************************************************************************************/ static void gpio_mux_ctrl_set(void) { unsigned int i; for(i=0; i<sizeof(motors_desc)/sizeof(motors_desc[0]); i++){ GPIOWRITEREG(MUX_CTRL_REG_BASE+motors_desc[i].mux_ofset_addr, motors_desc[i].mux_val); } } /********************************************************************************************************* *功能:GPIO相關暫存器設定 *引數:base_addr-->基地址, offset_addr-->偏移地址, bit-->位, val-->值 *返回值:無 **********************************************************************************************************/ static void gpio_reg_set(unsigned int base_addr, unsigned int offset_addr, unsigned char bit, unsigned char flag) { unsigned int value; unsigned int val = 0; unsigned int addr = 0; #if 0 if(val > 1){ printk("<val> input error!"); } if(bit > 7){ printk("<bit> input error!"); } value = ((GPIO_READ_REG(base_addr, offset_addr) & (~(1<<bit))) | (val<<bit)); GPIO_WRITE_REG(base_addr,offset_addr,value); #endif addr = GPIODATA(base_addr, bit); if(flag) { val = 1 << bit; } else { val = 0; } GPIOWRITEREG(addr,val); } /********************************************************************************************************* *功能:讀取GPIO相關暫存器 *引數:base_addr-->基地址, offset_addr-->偏移地址, bit-->位, val-->值 *返回值:無 **********************************************************************************************************/ static void gpio_reg_read(unsigned int base_addr, unsigned int offset_addr, unsigned char bit) { unsigned int value; if(bit > 7){ printk("<bit> input error!"); } value = ((GPIO_READ_REG(base_addr, offset_addr) & (~(1<<bit)))); printk("gpio_reg_read value: %d\n",value); } /********************************************************************************************************* *功能:GPIO方向設定 *引數:base_addr-->基地址, offset_addr-->偏移地址, bit-->位, val-->值 0:輸入 1:輸出 *返回值:無 **********************************************************************************************************/ static void gpio_dir_set(unsigned int base_addr, unsigned int offset_addr, unsigned char bit, unsigned char flag) { //gpio_reg_set(base_addr,offset_addr,bit,val); unsigned int val = 0; unsigned int addr = 0; int ret; addr = GPIODIR(base_addr); val = GPIOREAD_REG(addr); if(flag) { val |= 1 << bit; } else { val &= ~(1 << bit); } GPIOWRITEREG(addr,val); } /********************************************************************************************************* *功能:GPIO相關暫存器組設定 *引數:無 *返回值:無 **********************************************************************************************************/ static void gpio_reg_group_set(void) { unsigned int i; for(i=0; i<sizeof(motors_desc)/sizeof(motors_desc[0]); i++){ gpio_dir_set(motors_desc[i].gpio_base_addr, GPIO_DIR, motors_desc[i].bit, 1); //0:輸入 1:輸出 printk("gpio_dir_set motors_desc[%d]: %x %x bit: %d value 1\n",i,motors_desc[i].gpio_base_addr,GPIO_DIR,motors_desc[i].bit); } } /********************************************************************************************************* *功能:設定引腳上的電平 *引數:base_addr-->基地址, offset_addr-->偏移地址, bit-->位, val-->值 0:低電平 1:高電平 *返回值:無 **********************************************************************************************************/ static void gpio_data_set(unsigned int base_addr, unsigned int offset_addr, unsigned char bit, unsigned char val) { gpio_reg_set(base_addr,offset_addr,bit,val); } /********************************************************************************************************* *功能:設定電機1正轉 *引數: *返回值:無 **********************************************************************************************************/ static void set_motor1_ccw(void) { int i,j; for(i=0;i<8;i++) { for(j=0;j<4;j++) { gpio_data_set(motors_desc[j].gpio_base_addr,GPIO_DATA,motors_desc[j].bit,CCW_data[i][j]); printk("gpio_data_set %x %x %d %d\n",motors_desc[j].gpio_base_addr,GPIO_DATA,motors_desc[j].bit,CCW_data[i][j]); } } } #if 1 static int run_pats = 512; static unsigned int i = 0; static unsigned int j = 0; static struct hrtimer hr_timer; static struct work_struct wq_hrtimer; static ktime_t ktime; static unsigned int interval=5000; /* unit: us */ struct timespec uptimeLast; static unsigned int count=0; #define COUNT_INTERVAL 4000 unsigned long long diff_tv(struct timespec start, struct timespec end) { return (end.tv_sec-start.tv_sec)*1000000000+(end.tv_nsec-start.tv_nsec); } enum hrtimer_restart my_hrtimer_callback( struct hrtimer *timer ) { #if 1 if(run_pats > 0) { for (i=0; i<4; i++) { gpio_data_set(motors_desc[i].gpio_base_addr,GPIO_DATA,motors_desc[i].bit,CCW_data[j][i]); //printk("gpio_data_set %x %x %d %d\n",motors_desc[i].gpio_base_addr,GPIO_DATA,motors_desc[i].bit,CCW_data[j][i]); } } if (run_pats > 0 ) { j ++; if (j >= 8) { j = j - 8; } else { } //run_pats --; } #endif //kt = ktime_set(5, 1*1); /* 0 sec, 1 ms 定時1毫秒*/ kt = ktime_set( interval/1000000, (interval%1000000)*1000 ); schedule_work(&wq_hrtimer); return HRTIMER_NORESTART; } static void wq_func_hrtimer(struct work_struct *work) { struct timespec uptime; hr_timer.function = my_hrtimer_callback; ktime = ktime_set( interval/1000000, (interval%1000000)*1000 ); hrtimer_start(&hr_timer, ktime, HRTIMER_MODE_REL ); /* print time every COUNT_INTERVAL*interval second*/ if(count%COUNT_INTERVAL==0) { do_posix_clock_monotonic_gettime(&uptime); printk(KERN_INFO"hrtimer:%9lu sec, %9lu ns, interval_delay=%lu ns\n", (unsigned long) uptime.tv_sec, uptime.tv_nsec, (unsigned long)(diff_tv(uptimeLast, uptime)-interval*1000*COUNT_INTERVAL) \ /COUNT_INTERVAL); uptimeLast=uptime; } count++; } static int motorr_timer_init( void ) { struct timespec uptime; printk(KERN_INFO"HR Timer module installing\n"); hrtimer_init( &hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL ); ktime = ktime_set( interval/1000000, (interval%1000000)*1000 ); hr_timer.function = my_hrtimer_callback; hrtimer_start( &hr_timer, ktime, HRTIMER_MODE_REL ); do_posix_clock_monotonic_gettime(&uptime); uptimeLast = uptime; printk(KERN_INFO"hrtimer:%9lu sec, %9lu ns\n", (unsigned long) uptime.tv_sec, uptime.tv_nsec ); INIT_WORK(&wq_hrtimer, wq_func_hrtimer); return 0; } #else /********************************************************************************************************* *功能:定時器中斷函式 *引數:struct hrtimer *timer *返回值:0 **********************************************************************************************************/ static int run_pats = 512; static unsigned int i = 0; static unsigned int j = 0; static unsigned int interval=5000; enum hrtimer_restart motorr_timer_handler(struct hrtimer *timer) { //set_motor1_ccw(); #if 1 if(run_pats > 0) { for (i=0; i<4; i++) { gpio_data_set(motors_desc[i].gpio_base_addr,GPIO_DATA,motors_desc[i].bit,CCW_data[j][i]); //printk("gpio_data_set %x %x %d %d\n",motors_desc[i].gpio_base_addr,GPIO_DATA,motors_desc[i].bit,CCW_data[j][i]); } } if (run_pats > 0 ) { j ++; if (j >= 8) { j = j - 8; } else { } //run_pats --; } #endif //kt = ktime_set(5, 1*1); /* 0 sec, 1 ms 定時1毫秒*/ kt = ktime_set( interval/1000000, (interval%1000000)*1000 ); hrtimer_forward(timer, timer->base->get_time(), kt); printk(KERN_INFO"hrtimer handler!\n"); return HRTIMER_RESTART; } /********************************************************************************************************* *功能:定時函式初始化 *引數: *返回值:0 **********************************************************************************************************/ static int motorr_timer_init(void) { kt = ktime_set( interval/1000000, (interval%1000000)*1000 ); //kt = ktime_set(5, 1*1); /* 0 sec, 1 ms 定時1毫秒*/ hrtimer_init(&MotorTimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hrtimer_start(&MotorTimer, kt, HRTIMER_MODE_REL); MotorTimer.function = motorr_timer_handler;//hrtimer 的回撥函式 ,這一句的邏輯應該是直接接在init後面吧 return 0; } #endif /********************************************************************************************************* *功能:模組開啟函式 *引數: *返回值:無 **********************************************************************************************************/ static int motor_drv_open(struct inode *inode, struct file *file) { //gpio_reg_group_set(); //motorr_timer_init(); return 0; } /********************************************************************************************************* *功能:模組關閉函式 *引數: *返回值:無 **********************************************************************************************************/ int motor_drv_close(struct inode *inode, struct file *file) //出鏈,禁止中斷 { return 0; } /********************************************************************************************************* *功能:模組非同步通知函式 *引數: *返回值:無 **********************************************************************************************************/ static int motor_drv_fasync (int fd, struct file *filp, int on) { printk("driver: motor_drv_fasync\n"); //為了說明次函式被呼叫增加一條列印語句 return fasync_helper (fd, filp, on, &button_async); //初始化定義的結構體 } static struct file_operations motor_drv_fops = { .owner = THIS_MODULE, // 這是一個巨集,推向編譯模組時自動建立的__this_module變數 .open = motor_drv_open, .release = motor_drv_close, .fasync = motor_drv_fasync, //使用者程式用非同步通知的時候才會用到fasync }; /********************************************************************************************************* *功能:模組載入函式 *引數: *返回值:無 **********************************************************************************************************/ static int motor_drv_init(void) { gpio_mux_ctrl_set(); //引腳複用設定 gpio_reg_group_set(); motorr_timer_init(); #ifndef DEBUG gpio_data_set(led_motor_desc.gpio_base_addr,GPIO_DATA,led_motor_desc.bit,0); #endif major = register_chrdev(0, "motor_drv", &motor_drv_fops); //自動分配主裝置號 motordrv_class = class_create(THIS_MODULE, "motor_drv"); motordrv_dev = device_create(motordrv_class, NULL, MKDEV(major, 0), NULL, "motor"); // 裝置節點 /dev/buttons return 0; } static void motor_timer_exit(void) { //hrtimer_cancel(&MotorTimer); hrtimer_cancel(&hr_timer ); return; } /********************************************************************************************************* *功能:模組解除安裝函式 *引數: *返回值:無 **********************************************************************************************************/ static void motor_drv_exit(void) { unregister_chrdev(major, "motor_drv"); device_unregister(motordrv_dev); class_destroy(motordrv_class); motor_timer_exit(); printk("motor drive is rmmod!!\n"); } module_init(motor_drv_init); module_exit(motor_drv_exit); MODULE_DESCRIPTION("Motors Driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Hisilicon");
hisi_motor.h
#ifndef __BTN_DRV_H__ #define __BTN_DRV_H__ #ifdef __cplusplus #if __cplusplus extern "C" { #endif #endif /* __cplusplus */ /**************引腳複用暫存器************/ #define MUX_CTRL_REG_BASE 0x200F0000 #define GPIO7_2_MUX_CTRL_REG_OFFSET 0x0E8 #define GPIO7_3_MUX_CTRL_REG_OFFSET 0x0EC #define GPIO7_4_MUX_CTRL_REG_OFFSET 0x0F0 #define GPIO7_5_MUX_CTRL_REG_OFFSET 0x0F4 #define GPIO2_0_MUX_CTRL_REG_OFFSET 0x010 #define GPIO2_1_MUX_CTRL_REG_OFFSET 0x014 #define GPIO2_2_MUX_CTRL_REG_OFFSET 0x018 #define GPIO2_3_MUX_CTRL_REG_OFFSET 0x01C #define GPIO1_7_MUX_CTRL_REG_OFFSET 0x098 /***********GPIO基址********************/ #define GPIO13_BASE 0x20210000 #define GPIO12_BASE 0x20200000 #define GPIO11_BASE 0x201F0000 #define GPIO10_BASE 0x201E0000 #define GPIO09_BASE 0x201D0000 #define GPIO08_BASE 0x201C0000 #define GPIO07_BASE 0x201B0000 #define GPIO06_BASE 0x201A0000 #define GPIO05_BASE 0x20190000 #define GPIO04_BASE 0x20180000 #define GPIO03_BASE 0x20170000 #define GPIO02_BASE 0x20160000 #define GPIO01_BASE 0x20150000 #define GPIO00_BASE 0x20140000 /**************GPIO相關暫存器*************/ #define GPIO_DATA 0x000 #define GPIO_DIR 0x400 #define GPIO_IS 0x404 #define GPIO_IBE 0x408 #define GPIO_IEV 0x40c #define GPIO_IE 0x410 #define GPIO_RIS 0x414 #define GPIO_MIS 0x418 #define GPIO_IC 0x41c /*************GPIO中斷號*****************/ #define GPIO02_7_DATA (GPIO02_BASE + GPIO_DATA) #define GPIO01_1_DATA (GPIO01_BASE + GPIO_DATA) #define GPIO02_3_DATA (GPIO02_BASE + GPIO_DATA) #define GPIO02_4_DATA (GPIO02_BASE + GPIO_DATA) #define GPIO11_0_DATA (GPIO11_BASE + GPIO_DATA) #define GPIO11_4_DATA (GPIO11_BASE + GPIO_DATA) #define GPIO11_7_DATA (GPIO11_BASE + GPIO_DATA) #define GPIO01_2_DATA (GPIO01_BASE + GPIO_DATA) #define GPIO09_2_DATA (GPIO09_BASE + GPIO_DATA) #define GPIO09_4_DATA (GPIO09_BASE + GPIO_DATA) //讀寫寫暫存器 #define GPIODIR(gpio_group_reg_base) ((gpio_group_reg_base) + 0x400) #define GPIODATA(gpio_group_reg_base, gpio_offset) ((gpio_group_reg_base) + 0x000) + (1 << ((gpio_offset) + 2)) #define GPIOWRITEREG(addr, value) (*(volatile unsigned int *)((unsigned int)ioremap_nocache(addr,0x800)) = (value)) #define GPIOREAD_REG(base_addr) (*(volatile unsigned int *)((unsigned int)ioremap_nocache(base_addr,0x800))) #define GPIO_WRITE_REG(base_addr,offset_addr, value) (*(volatile unsigned int *)((unsigned int)ioremap_nocache(base_addr,0x800) + offset_addr) = (value)) #define GPIO_READ_REG(base_addr,offset_addr) (*(volatile unsigned int *)((unsigned int)ioremap_nocache(base_addr,0x800) + offset_addr)) #ifdef __cplusplus #if __cplusplus } #endif #endif /* __cplusplus */ #endif /* __BTN_DRV_H__ */
moto_drv_test.c
#include <stdio.h> #include <signal.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> int fd; int main(int argc, char *argv[]) { int flag; fd = open("/dev/motor", O_RDWR); if (fd < 0) { printf("can't open!\n"); } while (1) { sleep(1000); } return 0; }