timer.c:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/clk/sunxi.h>
#include <linux/delay.h>
#ifdef CONFIG_ARCH_SUN3I
#include <asm/sched_clock.h>
#include <linux/clocksource.h>
#endif
#define TIMER_IRQ_EN_REG 0x00
#define TIMER_IRQ_EN(val) (1 << val)
#define TIMER_IRQ_ST_REG 0x04
#define TIMER_IRQ_ST(val) (1 << val)
#define TIMER_CTL_REG(val) (0x10 * val + 0x10)
#define TIMER_CTL_ENABLE (1 << 0)
#define TIMER_CTL_AUTORELOAD (1 << 1)
#define TIMER_CTL_MODE_MASK (1 << 7)
#define TIMER_CTL_PERIODIC (0 << 7)
#define TIMER_CTL_ONESHOT (1 << 7)
#define TIMER_INTVAL_REG(val) (0x10 * val + 0x14)
#define TIMER_CNTVAL_REG(val) (0x10 * val + 0x18)
#define TIMER_IRQ 14 //timer1 irq
static int timer_nr = 1;
//static void __iomem *timer_base = 0x01c20c00;
static void __iomem *timer_base = 0xF1C20C00;
//#define HZ 100
static irqreturn_t timer_handler(int irq, void *dev_id)
{
u32 val = 0;
u32 rate = 24000000;
u32 prescale = 16;
writel(rate / (prescale * HZ),
timer_base + TIMER_INTVAL_REG(timer_nr));
writel(TIMER_IRQ_ST(timer_nr), timer_base + TIMER_IRQ_ST_REG);
val = readl(timer_base + TIMER_CTL_REG(timer_nr));
// writel(val | TIMER_CTL_ENABLE | TIMER_CTL_PERIODIC, timer_base + TIMER_CTL_REG(timer_nr));
writel(val | TIMER_CTL_ENABLE | TIMER_CTL_PERIODIC | TIMER_CTL_ONESHOT, timer_base + TIMER_CTL_REG(timer_nr));
// printk(">");
return IRQ_HANDLED;
}
int init_timer_module(void)
{
u32 rate = 24000000;
u32 prescale = 16;
int ret, irq;
u32 val;
printk("HZ = %d \n", HZ);
printk("rate / (prescale * HZ) = %d \n", rate / (prescale * HZ));
writel(rate / (prescale * HZ),
timer_base + TIMER_INTVAL_REG(timer_nr));
/* set clock source to HOSC, 16 pre-division */
val = readl(timer_base + TIMER_CTL_REG(timer_nr));
val &= ~(0x07 << 4);
val &= ~(0x03 << 2);
val |= (4 << 4) | (1 << 2);
writel(val, timer_base + TIMER_CTL_REG(timer_nr));
val = readl(timer_base + TIMER_CTL_REG(timer_nr));
printk("222 val = 0x%X\n ", val);
/* set mode to auto reload */
val = readl(timer_base + TIMER_CTL_REG(timer_nr));
writel(val | TIMER_CTL_AUTORELOAD, timer_base + TIMER_CTL_REG(timer_nr));
val = readl(timer_base + TIMER_CTL_REG(timer_nr));
printk("333 val = 0x%X\n ", val);
// ret = setup_irq(irq, &sunxi_timer_irq);
// if (ret)
// pr_warn("failed to setup irq %d\n", irq);
// if (request_irq(14, (irq_handler_t )timer_handler, IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL ,
if (request_irq(14, (irq_handler_t )timer_handler, 0,
"sunxi_timer1", NULL))
{
printk("irq request failure\n");
return -1;
}
/* Enable timer interrupt */
val = readl(timer_base + TIMER_IRQ_EN_REG);
writel(val | TIMER_IRQ_EN(timer_nr), timer_base + TIMER_IRQ_EN_REG);
printk("555 val = 0x%X\n", val);
return 0;
}
void release_timer_module(void)
{
free_irq(14, NULL);
return;
}
module_init(init_timer_module);
module_exit(release_timer_module);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("whycan");
Makefile
obj-m = timer.o
编译指令:
ARCH=arm CROSS_COMPILE=${PWD}/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-arm9-musl/toolchain/bin/arm-openwrt-linux-muslgnueabi- make -C ${PWD}/lichee/linux-3.10/ M=${PWD}/modules/timer
只触发了一次中断:
root@TinaLinux:/# insmod /tmp/timer.ko
module is already loaded - timer
root@TinaLinux:/#
root@TinaLinux:/# lsmod
8723bs 1500733 0
gc0308 9903 0
ov2640 10760 0
snd_mixer_oss 11988 1 snd_pcm_oss
snd_pcm_oss 30646 0
snd_seq_device 4506 0
timer 1084 0
vfe_io 26420 3 vfe_v4l2
vfe_v4l2 204719 0
videobuf2_core 21778 1 vfe_v4l2
videobuf2_dma_contig 7789 1 vfe_v4l2
videobuf2_memops 1260 1 videobuf2_dma_contig
root@TinaLinux:/#
root@TinaLinux:/#
root@TinaLinux:/# cat /proc/interrupts
CPU0
13: 724 sun3i_irq sunxi_timer
14: 1 - sunxi_timer1
38: 1 sun3i_irq PIN_GRP
39: 0 sun3i_irq PIN_GRP
40: 0 sun3i_irq PIN_GRP
101: 5413 sun3i_irq 1c02000.dma-controller
103: 0 sun3i_irq cedar_dev
104: 155 sun3i_irq uart1
105: 22 sun3i_irq twi0
106: 17980 sun3i_irq spi0
107: 43 sun3i_irq sunxi-mmc
108: 4424 sun3i_irq lcd
109: 0 sun3i_irq dispaly
113: 0 sun3i_irq csi_irq
114: 99 sun3i_irq sunxi_usb_udc
115: 0 sun3i_irq sunxikbd
Err: 0
离线
我想了一下, 有两个原因, 定时器中断函数清除状态寄存器那里
1. 没有加锁
2. timer0 没有先读出寄存器数据再写
离线
原因找到没有?我也是这个情况
离线