OSDev http://osdev.su/ |
|
Проблема с таймером - срабатывает только один раз http://osdev.su/viewtopic.php?f=7&t=1115 |
Страница 1 из 1 |
Автор: | gdt [ 15 сен 2015, 15:10 ] |
Заголовок сообщения: | Проблема с таймером - срабатывает только один раз |
Всем привет! Таймер срабатывает только один раз. Проверка работы: вызов из main.c Код: void kernel_main() { asm volatile ("sti"); // включить прерывания init_timer(50); } В терминале увидим однократное срабатывание. А должно повторяться с частотой 50Hz Код: Timer tick counter=0 если вызвать прерывание самостоятельно, допустим, три раза Код: void kernel_main() { // 0x20 = 32 = IRQ0 asm volatile ("int $0x20"); asm volatile ("int $0x20"); asm volatile ("int $0x20"); } Уто успех это означает, что каллбэк работает, а вот с делителем частоты что-то не то. Код: Timer tick counter=0 Timer tick counter=1 Timer tick counter=2 Код(JamesM's kernel development tutorials) Код: /*---------------------------------------------- // Обработчик прерывания IRQ0 //--------------------------------------------*/ static void timer_callback(registers_t regs) { print_text("Timer tick counter="); print_dec_value tick); tick++; } /*---------------------------------------------- // Инициализация таймера //--------------------------------------------*/ void init_timer(u32int frequency) { u32int divisor; /* Делитель частоты */ u8int low; /* Младший байт делителя */ u8int high; /* Старший байт делителя */ /* Регистрируем в системе обработчик для IRQ0 */ register_interrupt_handler(IRQ0, &timer_callback); /* Расчитываем делитель по заданной частоте */ divisor = 1193180/frequency; /* Задаем режим работы таймера */ outb(0x43, 0x36); /* Разбираем делитель на байты */ low = (u8int) (divisor & 0xFF); high = (u8int) ((divisor >> 8) & 0xFF); /* Отсылаем делитель в канал 0 PIT */ outb(0x40, low); outb(0x40, high); } Использую qemu-system-i386 и VirtualBox |
Автор: | pavia [ 15 сен 2015, 21:45 ] |
Заголовок сообщения: | Re: Проблема с таймером - срабатывает только один раз |
Существенных ошибок не видно. Из не существенных тут отсутствует проверка на переполнение. divisor = 1193180/frequency; Если frequency=1, то divisor выйдет за 65535. То, что осталось за кадром. Должен быть бесконечный цикл. EOI должен быть отправляться в нужный PIC, иначе внешние прерывания не будут генерироваться. |
Автор: | gdt [ 15 сен 2015, 23:31 ] |
Заголовок сообщения: | Re: Проблема с таймером - срабатывает только один раз |
pavia писал(а): Должен быть бесконечный цикл. EOI должен быть отправляться в нужный PIC, иначе внешние прерывания не будут генерироваться. Ничего из этого не понял, но на всякий случай добавил в kernel_main() Код: while(true){} и все заработало. Эпично я сфейлил. Правда пришлось выключить -O2 оптимизацию у gcc - с ней тоже не работает, ну тут я представляю куда копать и дизассемблер мне в помощь. Спасибо, pavia! |
Автор: | pavia [ 16 сен 2015, 10:33 ] |
Заголовок сообщения: | Re: Проблема с таймером - срабатывает только один раз |
1) Первую строчку вы поняли. То что нужен бесконечный цикл Код: while(true){} А вообще вы не внимательно прочитали 2 статью. Там этот цикл есть. Код: start: push ebx ; Load multiboot header location ; Execute the kernel: cli ; Disable interrupts. call main ; call our main() function. jmp $ ; Enter an infinite loop, to stop the processor ; executing whatever rubbish is in the memory ; after our kernel! Последней строчкой jmp $ входим в бесконечный цикл, для предотвращения выполнения мусора лежащего в памяти после ядра. 2) Что касается второй строчки про EOI. В 5 главе всё описано: http://www.jamesmolloy.co.uk/tutorial_h ... 20PIT.html Система прерываний в персональных компьютерах довольно сложная и запутанная. Существует два PIC контролёра. Которые расположены в северном мосте. Они отвечают за внешние прерывания процессора от устройств: таймер, COM-порт, USB-контролер хоста и тд. Если есть внешние, то есть и внутренние. Такие как исключение при деление на 0, ошибка защиты, конец стека, страничная ошибка и тд. Так вот PIC буферизирует прерывания от внешних устройств. Как только он отправил сигнал о прерывании в процессор PIC начинает блокировать все оставшиеся прерывания. Ждет пока процессор не освободиться. Как только процессор освободиться он должен послать сигнал EOI (End-of-Interupt) - конец прерывания. Если его не послать, то вы не получите больше прерываний. При этом проверка с Int 20h будет работать. Так как в данном случае это будет уже внутреннее прерывание. И как я говорил что контроллеров PIC два, то нужно отправить в нужный. А работают они каскадом. Поэтому в одном случае конец прерывания посылается ведущему. Во втором случае ведущему затем ведомому. 3) Помимо того что контроллер прерываний PIC работает с блокировкой. Внешние устройства точно также работают с блокировкой, не все. Им тоже надо послать сигнал о конце прерывания. У таймера это делать не нужно, так как мы выбрали такой режим где нет блокировки outb(0x43, 0x36); Тут младшая цифра - отвечает за режим. Код: 6d=0110b ^^^- 3 режим http://ru.osdev.wikia.com/wiki/Программируемый_интервальный_таймер У контроллера i8042, сброс совмещён с чтением сканкода 60h. И так далее. |
Автор: | SII [ 16 сен 2015, 15:04 ] |
Заголовок сообщения: | Re: Проблема с таймером - срабатывает только один раз |
pavia писал(а): Существует два PIC контролёра. Которые расположены в северном мосте Контроллеры прерываний расположены в южном мосте, а не в северном. Северный мост -- это сопряжение между процессором, памятью и системной шиной (PCI Express на сколько-нибудь современных ПК), сейчас он является составной частью микросхемы процессора. Ну а южный -- всяческая периферия (контроллеры SATA, USB и т.д. и т.п.), в том числе PICи. |
Автор: | pavia [ 16 сен 2015, 15:36 ] |
Заголовок сообщения: | Re: Проблема с таймером - срабатывает только один раз |
У нас сейчас холодно. Вот и попутал. |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ |