hisi_motor.c
#include //所有模块都需要的头文件
#include
#include //文件系统有关的,结构体file_operations也在fs头文件定义
#include //init和exit相关宏
#include
#include
#include //linux中的用户态内存交互函数,copy_from_user(),copy_to_user()等
#include //linux中断定义
#include
#include //声明printk()这个内核态的函数
#include //包含与中断相关的大部分宏及结构体的定义,request_irq()等
#include //
#include
#include
#include
#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基地址, 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(" input error!");
}
if(bit > 7){
printk(" input error!");
}
value = ((GPIO_READ_REG(base_addr, offset_addr) & (~(1<基地址, 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(" input error!");
}
value = ((GPIO_READ_REG(base_addr, offset_addr) & (~(1<基地址, 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基地址, 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
#include
#include
#include
#include
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;
}