基于S3C6410的小车制作(四)

有了硬件之后,就需要软件来控制。我在Tiny6410上使用的是linux系统,为了实现硬件控制,就得编写相应的驱动和软件。

在驱动方面,linux系统自身支持USB摄像头和Wifi网卡,只需要我编写电机驱动模块的驱动和D8253的驱动


在控制电机的时候,我使用了两路PWM时钟,这样我们通过改变PWM的占空比来实现速度控制。同时还得有一路GPIO来控制电机的方向。

可见电机驱动的关键就是配置两路PWM时钟


#define EFORCE_GPIO_PWM0 S3C64XX_GPF(14) 
#define EFORCE_GPIO_PWM1 S3C64XX_GPF(15)

#define EFORCE_GPIO_DIR0 S3C64XX_GPN(4)
#define EFORCE_GPIO_DIR1 S3C64XX_GPN(5)
#define EFORCE_PWM_FREQ 10000
#define EFORCE_PWM_PRE 10

以上定义了两路PWM信号和两路控制信号的GPIO接口,PWM的频率和分频


void pwm0_stop( void )
{
	s3c_gpio_cfgpin(EFORCE_GPIO_PWM0, S3C_GPIO_OUTPUT);
	s3c_gpio_setpin(EFORCE_GPIO_PWM0, 0);
}
void pwm1_stop( void )
{
	s3c_gpio_cfgpin(EFORCE_GPIO_PWM1, S3C_GPIO_OUTPUT);
	s3c_gpio_setpin(EFORCE_GPIO_PWM1, 0);
}
以上两个函数为停车函数。如果我们想停止电机转动,就得使得PWM为0


static void set_pwm0( __u32 value)
{
	unsigned long tcon;
	unsigned long tcnt;
	unsigned long tcfg1;
	unsigned long tcfg0;

	struct clk *clk_p;
	unsigned long pclk;
	s3c_gpio_cfgpin(EFORCE_GPIO_PWM0, S3C_GPIO_SFN(2));
	tcon = __raw_readl(S3C_TCON);
	tcfg1 = __raw_readl(S3C_TCFG1);
	tcfg0 = __raw_readl(S3C_TCFG0);

	tcfg0 &= ~S3C_TCFG_PRESCALER0_MASK;
	tcfg0 |= (EFORCE_PWM_PRE - 1) << S3C_TCFG_PRESCALER0_SHIFT;

	tcfg1 &= ~S3C_TCFG1_MUX0_MASK;
	tcfg1 |= S3C_TCFG1_MUX0_DIV1;

	__raw_writel(tcfg1, S3C_TCFG1);
	__raw_writel(tcfg0, S3C_TCFG0);

	clk_p = clk_get(NULL, "pclk");
	pclk  = clk_get_rate(clk_p);
	tcnt  = (pclk/EFORCE_PWM_PRE)/EFORCE_PWM_FREQ;

	if (value >= tcnt) {
		printk("PWM Warning: value too large\n");
		value = tcnt - 1;
	}
	tcon &= ~(S3C_TCON_T0DEADZONE|S3C_TCON_T0INVERT|S3C_TCON_T0MANUALUPD|S3C_TCON_T0RELOAD|S3C_TCON_T0START);
	if (value) {
		__raw_writel(tcnt, S3C_TCNTB(0));
		__raw_writel(value, S3C_TCMPB(0));
		s3c_gpio_setpull(EFORCE_GPIO_PWM0, S3C_GPIO_PULL_NONE);

		//disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0
		tcon |= S3C_TCON_T0MANUALUPD|S3C_TCON_T0RELOAD|S3C_TCON_T0START;
		__raw_writel(tcon, S3C_TCON);

		tcon &= ~S3C_TCON_T0MANUALUPD;			//clear manual update bit
		__raw_writel(tcon, S3C_TCON);
	}
	else {
		pwm0_stop();
	}
}
static void set_pwm1( __u32 value)
{
	unsigned long tcon;
	unsigned long tcnt;
	unsigned long tcfg1;
	unsigned long tcfg0;

	struct clk *clk_p;
	unsigned long pclk;
	s3c_gpio_cfgpin(EFORCE_GPIO_PWM1, S3C_GPIO_SFN(2));
	tcon = __raw_readl(S3C_TCON);
	tcfg1 = __raw_readl(S3C_TCFG1);
	tcfg0 = __raw_readl(S3C_TCFG0);

	tcfg0 &= ~S3C_TCFG_PRESCALER0_MASK;
	tcfg0 |= (EFORCE_PWM_PRE - 1) << S3C_TCFG_PRESCALER0_SHIFT;

	tcfg1 &= ~S3C_TCFG1_MUX1_MASK;
	tcfg1 |= S3C_TCFG1_MUX1_DIV1;
	__raw_writel(tcfg1, S3C_TCFG1);
	__raw_writel(tcfg0, S3C_TCFG0);

	clk_p = clk_get(NULL, "pclk");
	pclk  = clk_get_rate(clk_p);
	tcnt  = (pclk/EFORCE_PWM_PRE)/EFORCE_PWM_FREQ;

	if (value >= tcnt) {
		printk("PWM Warning: value too large\n");
		printk("PWM Warning: max value %lu\n", tcnt - 1);
		value = tcnt - 1;
	}
	tcon &= ~(S3C_TCON_T1INVERT|S3C_TCON_T1MANUALUPD|S3C_TCON_T1RELOAD|S3C_TCON_T1START);
	if (value) {
		__raw_writel(tcnt, S3C_TCNTB(1));
		__raw_writel(value, S3C_TCMPB(1));
		s3c_gpio_setpull(EFORCE_GPIO_PWM0, S3C_GPIO_PULL_NONE);
		tcon |= S3C_TCON_T1MANUALUPD|S3C_TCON_T1RELOAD|S3C_TCON_T1START;
		__raw_writel(tcon, S3C_TCON);

		tcon &= ~S3C_TCON_T1MANUALUPD;			//clear manual update bit
		__raw_writel(tcon, S3C_TCON);
	}
	else {
		pwm1_stop();
	}
}

以上两个函数用以设置PWM计数器的占空比。

#define D8253_TIMER0_PA 0x18000000
#define D8253_TIMER1_PA 0x18000001
#define D8253_TIMER2_PA 0x18000002
#define D8253_TIMERCTL_PA 0x18000003
#define D8253_DELAY 10
#define D8253_TIMER0_IRQ 19
#define D8253_TIMER1_IRQ 20

以上程序定义了D8253的地址 ,中断号。需要注意的是,D8253的地址取决于所在的片选信号,而且,D8253只有两个地址线,连到最低位上。


cs1 = __raw_readl(S3C64XX_SROM_BW) &
				~(S3C64XX_SROM_BW__CS_MASK << S3C64XX_SROM_BW__NCS1__SHIFT);
	cs1 |= ((0 << S3C64XX_SROM_BW__DATAWIDTH__SHIFT) |
			(1 << S3C64XX_SROM_BW__WAITENABLE__SHIFT) |
			(1 << S3C64XX_SROM_BW__BYTEENABLE__SHIFT)) <<
							   S3C64XX_SROM_BW__NCS1__SHIFT;
	__raw_writel(cs1, S3C64XX_SROM_BW);
	__raw_writel((0 << S3C64XX_SROM_BCX__PMC__SHIFT) |
			 (15 << S3C64XX_SROM_BCX__TACP__SHIFT) |
			 (1 << S3C64XX_SROM_BCX__TCAH__SHIFT) |
			 (1 << S3C64XX_SROM_BCX__TCOH__SHIFT) |
			 (24<< S3C64XX_SROM_BCX__TACC__SHIFT) |
			 (5 << S3C64XX_SROM_BCX__TCOS__SHIFT) |
			 (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1);


以上程序用以初始化S3C6410 SROM设置,使其支持D8253, 这些数值都要经过查阅D8253手册和S3C6410手册进行定值。

        err = request_irq(IRQ_EINT(D8253_TIMER0_IRQ), timer_override, IRQ_TYPE_EDGE_RISING,
			d8253_timer0_irq.name, (void *)&d8253_timer0_irq);

	err = request_irq(IRQ_EINT(D8253_TIMER1_IRQ), timer_override, IRQ_TYPE_EDGE_RISING,
			d8253_timer1_irq.name, (void *)&d8253_timer1_irq);

配置中断


case EFORCE_SET_TIMER:
			disable_irq(IRQ_EINT(D8253_TIMER0_IRQ));
			disable_irq(IRQ_EINT(D8253_TIMER1_IRQ));
			if (!data.value0) {
				data.value0 --;
			}
			if (!data.value1) {
				data.value1 --;
			}
//			printk("value0: %u\tvalue1:%u\n", data.value0, data.value1);
			tval0_h = data.value0 >> 16;
			tval1_h = data.value1 >> 16;
			tval0_l = data.value0 & 0xffff;
			tval1_l = data.value1 & 0xffff;
			writeb(0x30, d8253_ctl);
			udelay(D8253_DELAY);
			writeb(tval0_l & 0xff, d8253_timer0);
			udelay(D8253_DELAY);
			writeb(tval0_l >> 8, d8253_timer0);
			udelay(D8253_DELAY);
			writeb(0x70, d8253_ctl);
			udelay(D8253_DELAY);
			writeb(tval1_l & 0xff, d8253_timer1);
			udelay(D8253_DELAY);
			writeb(tval1_l >> 8, d8253_timer1);
			udelay(D8253_DELAY);
			enable_irq(IRQ_EINT(D8253_TIMER0_IRQ));
			enable_irq(IRQ_EINT(D8253_TIMER1_IRQ));
			break;
		case EFORCE_GET_TIMER:
			writeb(0x00, d8253_ctl);
			udelay(D8253_DELAY);
			data.time0 = jiffies;
			tval0_l =  readb(d8253_timer0);
			udelay(D8253_DELAY);
			tval0_l += readb(d8253_timer0) << 8;
			udelay(D8253_DELAY);
			writeb(0x40, d8253_ctl);
			udelay(D8253_DELAY);
			data.time1 = jiffies;
			tval1_l = readb(d8253_timer1);
			udelay(D8253_DELAY);
			tval1_l +=  readb(d8253_timer1) << 8;
			udelay(D8253_DELAY);
			data.value0 = (tval0_h << 16) + tval0_l;
			data.value1 = (tval1_h << 16) + tval1_l;
			data.stop_flag = stop;
			err = copy_to_user((d8253_data __user *)arg, &data, sizeof(d8253_data));
			if (err) {
				printk("error copy to user space");
				return -EFAULT;
			}
			break;

设置和读取D8253数值


完整代码已上传资源里

http://download.csdn.net/detail/gt945/4063933

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值