由于步进电机用到了I/O端口,而在ARM9中操纵端口要用虚拟地址而非实际的物理地址,所以要修改内核代码。
修改文件内核源代码中间的smdk.c,在结构体
static struct map_desc smdk_io_desc] __initdata = {
{ vCS8900_BASE, pCS8900_BASE, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 },
{ vCF_MEM_BASE, pCF_MEM_BASE, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 },
{ vCF_IO_BASE, pCF_IO_BASE, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 },
LAST_DESC
};
中添加一行数组元素{ 0xd3000000, 0x28000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 },则步进电机的物理地址0x28000006对应的虚拟地址为0xd3000006,在驱动程序中应对这个地址进行操纵。
定义全局变量num和status用来控制步进电机的速度和方向:
static int num=1;
static enum{off,clockwise,anticlockwise} status=off;
定义步进电机的整步模式正转脉冲表:
unsigned char pulse_table[] =
{
0x05, 0x09, 0x0a, 0x06,
};
定义时钟节拍函数time_tick()
static void time_tick(unsigned long data)
{
static int i=0;
switch(status)
{
case off: break;
case clockwise:
if(++i==num){
i=0;
if( row == 4 ) row = 0;
(*(char *)0xd3000006)=pulse_table[row++];
}
ttimer.expires=jiffies+1;
add_timer(&ttimer);
break;
case anticlockwise:
if(++i==num){
i=0;
if( row == -1 ) row = 3;
(*(char *)0xd3000006)=pulse_table[row--];
}
ttimer.expires=jiffies+1;
add_timer(&ttimer);
break;
case default: break;
}
}
在time_tick()函数中判定步进电机的状态,是停止、正转还是反转。若是正转,则按正向顺序发送脉冲,并添加定时器ttimer;若是反转,则按反向顺序发送脉冲,并添加定时器ttimer;若是停止则不再发送脉冲,也不再添加定时器。
在stepper_module_init()函数中申请I/O端口,并初始化定时器ttimer:
if(check_region(0x28000006, 1)) //看该I/O端口是否已经被占用
{
printk("The stepper port is used by another module.\n");
return -1;
}
request_region(0x28000006, 1, DEVICE_NAME); //申请该I/O端口
init_timer(&ttimer); //初始化定时器ttimer
ttimer.function=time_tick; //填写定时器处理函数为time_tick()
编写ioctl函数用来接收应用程序对于步进电机的控制。
int device_ioctl( struct inode *inode, struct file *file, unsigned int ioctl_num,
unsigned long ioctl_param)
{
struct stepper * s;
/* 根据实际程序中的不同需求更改ioctl函数的调用*/
switch (ioctl_num)
{
case IOCTL_SET_MSG:
s = (struct stepper*) ioctl_param;
switch (s->CmdID)
{
case 0: /*开始*/
status=clockwise;
ttimer.expires=jiffies+1; //开启定时器
add_timer(&ttimer);
break;
case 1: status=off; break; /*停止*/
case 2: /*反转*/
if(status==clockwise){ status=anticlockwise; }
if(status==anticlockwise){ status=clockwise; }
break;
case 3: if(num!=1)num--; break; /*加速*/
case 4: num++; break; /*减速*/
}
}
return 0;
};
通过s指针得到stepper结构中的表示命令类型的参数,根据该参数判定命令类型,0是start起动,1是stop停止,2是reverse反向,3是up电机加速,4是down电机减速,通过改变全局变量num和status来控制电机。电机的起动是通过在start分支中起动一个定时器ttimer,然后在定时器处理函数time_tick中发送步进电机脉冲,并重新添加定时器,从而实现步进电机的转动。