Im triyng to develop a kernel module which have a triple timer counter 0 (TTC0) in zync microzed board. But it takes some time (nearly 10 to 15 seconds) to start. The timer is configured as give interrupts in ~250ms. Here is the sample code. In here I have set the clock setup register (0x01F) for set the prescaler, mode configuration register (0x022) for start the counter and set interval mode , interval value (424) and interrupt enable (0x01).
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/signal.h>
MODULE_LICENSE("GPL");
#define IRQ_NUM 42 // interrupt line
#define TIMER_BASE 0xF8001000
#define TIMER_SIZE 0x0000FFFF
#define LOAD_VAL 424 // address load value ~0.25 sec
#define TTC1_CLOCK_CONTROL 0xF8001000
#define TTC1_COUNTER_CONTROL 0xF800100C
#define TTC1_COUNTER_VALUE 0xF8001018
#define TTC1_INTERVAL_COUNTER_VALUE 0xF8001024
#define TTC1_INTERRUPT_REGISTER 0xF8001054
#define TTC1_INTERRUPT_ENABLE 0xF8001060
unsigned long *pTIMER_TTC_CLOCK_CONTROL; // pointer to timer clock control register
unsigned long *pTIMER_TTC_COUNTER_CONTROL; // pointer to timer counter control register
unsigned long *pTIMER_INTERVAL_VALUE; // pointer to timer Interval load register
unsigned long *pTIMER_COUNTER_VALUE; // pointer to timer Counter load register
unsigned long *pTIMER_INTERRUPT_ENABLE; // pointer to timer Interrupt enable register
unsigned long *pTIMER_INTERRUPT_REGISTER; // pointer to timer Interrupt register load register
#define DEVICE_NAME "ttc" // device name
#define TTC_MAJOR 22 // device major number // 22
#define BUF_LEN 80 // max buffer length
#define SUCCESS 0 // success return value
//unsigned long *pSYSCALL_Virtual; // base address
static int intcount;
static irqreturn_t irq_handler(int irq,void*dev_id);
// init module
static int __init mod_init(void)
{
unsigned long temp;
printk(KERN_ERR "Init TTC module. \n");
if (request_irq(IRQ_NUM,irq_handler,0x00, DEVICE_NAME, NULL)) //request timer interrupt
{
printk(KERN_ERR "Not Registered IRQ. \n");
return -EBUSY;
}
printk(KERN_ERR "Registered IRQ. \n");
pTIMER_TTC_CLOCK_CONTROL = ioremap_nocache(TTC1_CLOCK_CONTROL,0x4); // map timer clk control register
pTIMER_TTC_COUNTER_CONTROL = ioremap_nocache(TTC1_COUNTER_CONTROL,0x4); // map timer counter control register
pTIMER_COUNTER_VALUE = ioremap_nocache(TTC1_COUNTER_VALUE,0x4); // map timer count register
pTIMER_INTERVAL_VALUE = ioremap_nocache(TTC1_INTERVAL_COUNTER_VALUE,0x4); // map timer interval value register
pTIMER_INTERRUPT_ENABLE = ioremap_nocache(TTC1_INTERRUPT_ENABLE,0x4); // map timer interrupt control register
pTIMER_INTERRUPT_REGISTER = ioremap_nocache(TTC1_INTERRUPT_REGISTER,0x4); // map timer interrupt register
iowrite32(LOAD_VAL, pTIMER_INTERVAL_VALUE); // place load value in load register
temp = ioread32(pTIMER_INTERVAL_VALUE); // debug: read load value to check
printk("Load value: %lu.\n",temp); // debug: print the read load value
ioread32(pTIMER_COUNTER_VALUE);
iowrite32(0x00000022,pTIMER_TTC_COUNTER_CONTROL); // start the timer
iowrite32(0x00000001,pTIMER_INTERRUPT_ENABLE); // enable interrupts
iowrite32(0x0000001F,pTIMER_TTC_CLOCK_CONTROL); // set the pre-scale
// value,no load,enable IRQ,enable Timer
intcount = 0; // set interrupt count to 0, driver will unload on 100 interrupts
return SUCCESS;
}
// exit module
static void __exit mod_exit(void)
{
iowrite32(0x00000023,pTIMER_TTC_COUNTER_CONTROL);
iowrite32(0x00000000,pTIMER_INTERRUPT_ENABLE);
iowrite32(0x00000000,pTIMER_TTC_CLOCK_CONTROL);
iounmap(pTIMER_TTC_CLOCK_CONTROL); // unregister timer hardware
iounmap(pTIMER_TTC_COUNTER_CONTROL);
iounmap(pTIMER_COUNTER_VALUE);
iounmap(pTIMER_INTERVAL_VALUE);
iounmap(pTIMER_INTERRUPT_ENABLE);
iounmap(pTIMER_INTERRUPT_REGISTER);
free_irq(IRQ_NUM, NULL); // unregister timer interrupt
printk(KERN_ERR "Exit ttc Module. \n"); // print unload message
}
static irqreturn_t irq_handler(int irq,void*dev_id)
{
unsigned long temp;
unsigned long timervalue;
timervalue = ioread32(pTIMER_COUNTER_VALUE); // Read Timer/Counter Register
printk( KERN_EMERG "Interrupt! Timer counter value : %lu Cycles and %d counts\n",(timervalue-LOAD_VAL), intcount); // Display timer value
temp = ioread32(pTIMER_INTERRUPT_REGISTER); // clear timer IRQ
intcount++;
if (intcount>=100){ // after 100 interrupts
printk("100 interrupts have been registered.\nDisabling timer");// print timer status message
//iowrite32(0x00000050,pTIMER_TCSR0); //disable timer;
iowrite32(0x00000023,pTIMER_TTC_COUNTER_CONTROL);
iowrite32(0x00000000,pTIMER_INTERRUPT_ENABLE);
iowrite32(0x00000000,pTIMER_TTC_CLOCK_CONTROL);
}
return IRQ_HANDLED;
}
module_init(mod_init);
module_exit(mod_exit);
MODULE_INFO(intree, "Y");
your help is appreciated.
User contributions licensed under CC BY-SA 3.0