Ник:
Пароль:

Контакты

E-mail: info@starterkit.ru
тел.: +7 922 680-21-73
тел.: +7 922 680-21-74
Телеграм: t.me/starterkit_ru

Способы оплаты

User Info


Добро пожаловать,
Guest

Регистрация или входРегистрация или вход
Потеряли пароль?Потеряли пароль?

Ник:
Пароль:

ПользователейПользователей:1
Поисковых ботовПоисковых ботов:3
ГостейГостей:1

ОбновитьПодробнееВсегоВсего:5
Форум » starterkit.ru » Embedded Linux
Таймер и значение счетчика AT91_TC_CV
Maxizar
Добавлено 12.07.2011 17:36 Редактировалось 12.07.2011 17:38
0
Сообщение: 1
Maxizar
0

Пункты: 424
Регистрация: 04.07.2011
Собственно код модуля:

Код

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <mach/at91_tc.h>
#include <asm/uaccess.h>

//g++ -Wall -c "%f"
//g++ -Wall -o "%e" "%f"

struct file_operations at91adc_fops;

void __iomem *at91tc0_base;
struct clk *at91tc0_clk;

/************************************************************************************
| Timer counter 0 ISR:
*************************************************************************************/
static int status;
static int Counter;
static int y=0;

static irqreturn_t at91tc0_isr(int irq, void *dev_id)
{
// Read TC0 status register to reset RC compare status.
status = ioread32(at91tc0_base + AT91_TC_SR);

if(y<10)
{
y++;
Counter = ioread32(at91tc0_base + AT91_TC_CV);//
printk(KERN_INFO "Counter = %d\n", Counter);
}
else {
y=20;
//printk(KERN_INFO "Init 1000\n");
//Counter = ioread32(at91tc0_base + AT91_TC_CV);//
//printk(KERN_INFO "Counter = %d\n", Counter);
//clk_disable(at91tc0_clk);
}

return IRQ_HANDLED;
}

int init_at91clk(void)
{
printk(KERN_INFO "Init 0\n");
int ret=0;
//Initialize Timer Counter module 0. The following two lines set the appropriate
//PMC bit for TC0. Easier than mapping PMC registers and then setting the bit.
at91tc0_clk = clk_get(NULL, // Device pointer - not required.
"tc0_clk"); // Clock name.

printk(KERN_INFO "Init 1\n");
clk_enable(at91tc0_clk);
printk(KERN_INFO "Init 2\n");

// Map TC0 registers to the current address space.
at91tc0_base = ioremap_nocache(AT91SAM9260_BASE_TC0, // Physical address
64); // Number of bytes to be mapped.
if (at91tc0_base == NULL)
{
printk(KERN_INFO "at91adc: TC0 memory mapping failed\n");
ret = -EACCES;
return ret;
}

printk(KERN_INFO "Init 3\n");
// Configure TC0 in waveform mode, TIMER_CLK1 and to generate interrupt on RC compare.
// Load 50000 to RC so that with TIMER_CLK1 = MCK/2 = 50MHz, the interrupt will be
// generated every 1/50MHz * 50000 = 20nS * 50000 = 1 milli second.
// NOTE: Even though AT91_TC_RC is a 32-bit register, only 16-bits are programmble.

iowrite32(50000, (at91tc0_base + AT91_TC_RC));
iowrite32((AT91_TC_WAVE | AT91_TC_WAVESEL_UP_AUTO), (at91tc0_base + AT91_TC_CMR));
iowrite32(AT91_TC_CPCS, (at91tc0_base + AT91_TC_IER));
printk(KERN_INFO "Init 4\n");

// Install interrupt for TC0.
ret = request_irq(AT91SAM9260_ID_TC0, // Interrupt number
at91tc0_isr, // Pointer to the interrupt sub-routine
0, // Flags - fast, shared or contributing to entropy pool
"at91adc", // Device name to show as owner in /proc/interrupts
NULL); // Private data for shared interrupts

if (ret != 0)
{
printk(KERN_INFO "at91adc: Timer interrupt request failed\n");
ret = -EBUSY;
return ret;
}
printk(KERN_INFO "Init 5\n");
iowrite32((AT91_TC_SWTRG | AT91_TC_CLKEN), (at91tc0_base + AT91_TC_CCR));//timer start

printk(KERN_INFO "at91adc: Timer starting adn Module louded\n");
return 0;
}


void exit_at91clk(void)
{
clk_disable(at91tc0_clk);

// Free TC0 IRQ.
free_irq(AT91SAM9260_ID_TC0, // Interrupt number
NULL); // Private data for shared interrupts

iounmap(at91tc0_base);
printk(KERN_INFO "at91adc: Unloaded module\n");
}

module_init(init_at91clk);
module_exit(exit_at91clk);

MODULE_LICENSE("GPL");



Код был найден на просторах Интернета, но пришлось чуть переписать для своей платы...

Код макефайла, для компиляции:

Код

# Если KERNELRELEASE определен, вызов был произведен из
# из системы сборки ядра и мы можем пользоваться её языком.
ifneq ($(KERNELRELEASE),)
obj-m := firstmodule.o
obj-m := at91clk.o

# Иначе, вызов был из командной строки;
# вызываем систему сборки.
else

#KERNELDIR ?= /lib/modules/$(shell uname -r)/build #/home/xxx/buildroot-2011.05/output/build/linux-2.6.33/
KERNELDIR ?= /home/xxx/buildroot-2011.05/output/build/linux-2.6.33/

PWD := $(shell pwd)
default:
$(MAKE) ARCH=arm CROSS_COMPILE=/home/xxx/buildroot-2011.05/output/host/usr/bin/arm-unknown-linux-uclibcgnueabi- -C $(KERNELDIR) M=$(PWD) modules


endif


в этом участке кода:
Код

if(y<10)
{
y++;
Counter = ioread32(at91tc0_base + AT91_TC_CV);//
printk(KERN_INFO "Counter = %d\n", Counter);
}

я ждал, что получу вывод в консоль типа такого:
Код

1
2
3
4
5
...

а получаю какие то непонятные значения...
Ведь AT91_TC_CV это значение счетчика? или я все перепутал..
Как мне получить значение счетчика таймера?
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 12.07.2011 18:36 Редактировалось 13.07.2011 00:38 Сообщение: 2
sasamy
4.71

Пункты: 83567
Регистрация: 14.08.2009
Цитата

я ждал, что получу вывод в консоль типа такого:


Типа такого и не должно быть

When WAVSEL = 10, the value of TC_CV is incremented from 0 to the value of RC, then auto-
matically reset on a RC Compare
. Once the value of TC_CV has been reset, it is then
incremented and so on.

AT91_TC_WAVESEL_UP_AUTO (2 << 13)

значение счетчика должно колебаться в зависимости от латентности прерывания, но если брать идеальный случай значение счетчика в обработчике должно быть 0.
Спуститься к концу Подняться к началу
Персональная информация
Maxizar
Добавлено 13.07.2011 12:07 Редактировалось 13.07.2011 12:25 Сообщение: 3
Maxizar
0

Пункты: 424
Регистрация: 04.07.2011
Точно, если ставить скажем бит остановки после срабатывания то
получим как раз число 50000, все как и положенно. А если считывать как говорится в процессе работы, то да счетчик начинает очень круто плавать, потому что мы считываем а он уже насчитал там кучу всего....

По счетчику я вроде как понял Спасибо.

Но все это было сделано, чтобы посчитать минимальное время срабатывания. Идея была такой:
Включаем таймер и измеряем счетчик и как только мы перестаем успевать измерять его тобишь значения начинают плавать, то мы как бы перешли предел....
Но получается что с этим счетчиком мы так не посчитаем...
А может есть аналог rdtsc для АРМ (at91sam9g20-ek)
Тогда бы мы смогли как раз это время и проверить... скажем срабатыват таймер первый раз через 100 тактов, второй раз через 100 (+-5%) и.т.д значит мы успеваем обработать нашу процедуру все ок... (в предположении что таймер срабатывает через 100 тактов) если же нет (второй или какой то раз вошли в процедуру через 200 тактов), то получается что вышли за пределы, так как получается наложение...

Ведь у нас при обработки прерывания , пока не выйдем из процедуры прерывания, нового прерывания не будет я ведь правильно понимаю?
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 13.07.2011 13:20 Сообщение: 4
sasamy
4.71

Пункты: 83567
Регистрация: 14.08.2009
Цитата

Но все это было сделано, чтобы посчитать минимальное время срабатывания. Идея была такой:
Включаем таймер и измеряем счетчик и как только мы перестаем успевать измерять его тобишь значения начинают плавать, то мы как бы перешли предел....
Но получается что с этим счетчиком мы так не посчитаем...


Я честно говоря ничего не понял - что вы хотите измерять, какой предел и что посчитать - как-нибуть почетче сформулируйте что хотите сделать :)
Спуститься к концу Подняться к началу
Персональная информация
Maxizar
Добавлено 13.07.2011 14:02 Сообщение: 5
Maxizar
0

Пункты: 424
Регистрация: 04.07.2011
Да чет и правда мутно написал :)
Давайте на живом примере: Вот скажем в Windows есть таймер которому можно задать время аж 1 милиСек. Но как известно он всре равно будет срабатывать через ~15 МилСек. Так как 15 для таймер предельное значение.
Каким образом мы можем подсчитать это минимальное время срабатывания? нам необходим счетчик который скажем считает такты процессора для Интел это rdtsc вот если этот счетчик записывать в момент срабатывания таймера, то мы можем четко сказать через сколько срабатывает таймер... (имя ряд значений скажем 10 срабатываний таймера и для каждого записали значение rdtsc)

Теперь что касается АРМ. я хочу посчитать минимальное время за которое успеет обработаться прерывание и при этом не будет такой ситуации когда мы еще обрабатываем процедуру прерывания, а генерится новое прерывание.

PS. ммм чет все равно мутно :(
Спуститься к концу Подняться к началу
Персональная информация
Форум » starterkit.ru » Embedded Linux