Перейти к содержанию
    

Пишу прогу на c++, переопределяю прерывание от системного таймера на функцию например NewInt08(...). Устанавливаю частоту таймера

( outportb( 0x40, (char) cnt );

outportb( 0x40, (char)( cnt >> 8 ) ); ).

Т.е. функция обработчик прерывания NewInt08(...) вызывается с той частотой с которой мне нужно (например 160 Hz). В обработчике снимаются данные и записываются на диск.

Всё вродеб хорошо, но возникает проблема. Например при 160Hz после 100минут всё виснет наглухо. :cranky: Если убрать запись на диск, то программа проработала 5 часов без сбоев, далее просто выключил.

Вопрос, в чём проблема? Не успевают обрабатыватся и записыватся данные и стек прерываний со временем переполняется? тогда можно ли его очищать?

Или недопустимо записывать данные из прерываний? Тогда почему и какие могут быть решения проблемы?

Пробовал уменьшать частоту при 150hz работает минут 140, при 100hz жадл 3 часа потом выключил.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Куда катиться этот мир?! Программы для МК на C++. На нём обычные программы и то писать на мой взгляд не стоит.

 

Попробуем разобраться для начала вот в каком вопросе: почему Вы так уверены, что каждый на этом форуме понимает:

1) о каком контроллере идёт речь в Вашем сообщении.

2) О каком компиляторе идёт речь в Вашем сообщении.

3) Как Вы узнаёте о том, что программа работает если она ничего никуда не пишет.

4) Какая скорость записи на Ваш «диск». Почему приведённые данные для частоты прерываний никак не помогают узнать объём записываемых данных и скорость их записи?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот так я делал...работало всегда (старый добрый Borland v3) Похоже проблема с записью на диск. Точно знаю, что запись как таковая всегда откладывается до заполнения некоего буфера - отсюда и тормоза.

asEXAMPLE.rar

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Пишу прогу на c++, переопределяю прерывание от системного таймера на функцию например NewInt08(...). Устанавливаю частоту таймера

( outportb( 0x40, (char) cnt );

outportb( 0x40, (char)( cnt >> 8 ) ); ).

 

Программа под ДОС. Запускать без загрузки каких-либо резидентных программ пытались (особенно дисковой направленности)? Старый вектор обрабатываете до или после своего модуля? Ваш модуль гарантировано с запасом укладывается в цикл прерывания?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1) о каком контроллере идёт речь в Вашем сообщении.

Речь идёт о компьютере сборщике: модуль центрального процессора Fastwel CPU 686 E (процессор Geode GX1- 300 МГц), модуль аналогового ввода-вывода AI16-5A (АЦП). На компе стоит урезаная вин98 (Будет дос).

 

2) О каком компиляторе идёт речь в Вашем сообщении.

Borland C++ version 3.1. (Попробую скомпилять этим Borland C++ v5.02)

 

3) Как Вы узнаёте о том, что программа работает если она ничего никуда не пишет.

Узнать о том, что идёт опрос схем можно по мерцанию диодов. Да и вобще если из программы удаляется только строка записи на диск и программа не виснет, то это уже по-моему говорит о том, что она работает (при условии что она и в режиме записи работает довольно долгое время).

 

4) Какая скорость записи на Ваш «диск». Почему приведённые данные для частоты прерываний никак не помогают узнать объём записываемых данных и скорость их записи?

Скорость записы 20Mb/sec. За один тик таймера записывается 60bytes. Т.е. при частоте 160hz - 9600b/sec.

 

Тестировал время работы обработчика NewInt08(), за секунду выполняется 165-175 раз (естественно с записью). Даже при установке 200hz, программа работает минут 40. Обработчик прерывания от таймера при

 

Куда катиться этот мир?! Программы для МК на C++. На нём обычные программы и то писать на мой взгляд не стоит.

Подскажите на чём писать такие программы?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1) о каком контроллере идёт речь в Вашем сообщении.

На компе стоит урезаная вин98 (Будет дос).

 

Под "чистым" ДОСом пробовали?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вобще под "чистым" досом с записью работает гораздо меньше времени, чем под виндой. Без записи работает отлично.

"Точно знаю, что запись как таковая всегда откладывается до заполнения некоего буфера - отсюда и тормоза." Так и есть, даже судя по диоду обращения к жёсткому диску. Т.е. стоит попробовать заставить данные записыватся на диск каждые 160hz?

 

Скомпилял под Borland C++ v5.02, эффект примерно такойже.

 

"Старый вектор обрабатываете до или после своего модуля?"

Старый вектор обрабатывается после моей процедуры.

Вот урезанный код обработки прерывания.

void interrupt NewInt08(...)

{

static cnt = 0;

disable(); // запрет прерываний

 

cnt++; // считаем сколько пропускать до вызова старого обработчика

 

readallchannel(); // функция считывания и записи данных с АЦП

 

if ( cnt >= BIOSTimerSpeed ) // true => вызвать старый обработчик

{

 

gettime (&t); // читаем текущее время

docommonwrite( (char *) &t,4,'t'); // запись текущего времени

cnt = 0;

 

enable(); // востановление прерываний

SvInt08(); // вызов старого обработчика прерывания

 

}

else

{

enable(); // востановление прерываний

outportb(0x20,0x20); //конец прерывания

}

 

}

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Куда катиться этот мир?! Программы для МК на C++. На нём обычные программы и то писать на мой взгляд не стоит.

  Подскажите на чём писать такие программы?

 

Ну в начале я думал Вы под МК собираетесь на C++ програмировать. :-)

Если говорить о ПК, то мой выбор — чистый C или ObjectiveC. Наличие объектов может приводить к печальным последствиям по быстродействию. Всякие опрашивающие вещи точно стоит писать на Си/asm.

 

Что касается виндоуз и прочего ДОС есть две мысли:

1) написать запись на диск на ассемблере.

2) Поиграться в что-то под названием smartdrive (в windows/dos я не копенгаген, но помоему это и есть та самая буферизирующая сущность).

 

Есть ещё третий путь: поставить FreeBSD и написать всё под неё. :-D

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Куда катиться этот мир?! Программы для МК на C++. На нём обычные программы и то писать на мой взгляд не стоит.

  Подскажите на чём писать такие программы?

 

Ну в начале я думал Вы под МК собираетесь на C++ програмировать. :-)

Если говорить о ПК, то мой выбор — чистый C или ObjectiveC. Наличие объектов может приводить к печальным последствиям по быстродействию. Всякие опрашивающие вещи точно стоит писать на Си/asm.

На чем основано такое заявление? Я вот вполне успешно пишу на С++ в том числе и для МК. По оверхеду почти то же самое, что и на С. Надо просто знать средство и уметь им пользоваться. А безобразную программу можно на любом языке наделать, в т.ч. и на асме. На нем даже проще.

 

Кстати, где Вы видели ObjectiveC для МК? Для какого МК, если не секрет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

      enable();                      // востановление прерываний

      outportb(0x20,0x20);      //конец прерывания

    }

 

}

 

 

А зачем Вы контроллер превываний дергаете перед выходом?. Это же уже сделано в старом обработчике. По-моему (могу ошибаться) прерывания с диска имеют более высокий приоритет, чем таймер. Поэтому запрет прерываний в таймерной секции с последующим EOI по-моему может при определенном стечении обстоятельств вызвать потерю прерывания с диска. Попробуйте убрать обращение к контроллеру преряваний.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

void interrupt NewInt08(...)

{

    static cnt = 0;

    disable();                  //  запрет прерываний

 

Дизайбл делать не надо - и так уже дизэйбл, на аппаратном уровне

 

      cnt++;                            // считаем сколько пропускать  до вызова старого обработчика

 

        readallchannel();      // функция считывания и записи данных с АЦП

     

  if ( cnt >= BIOSTimerSpeed )  // true => вызвать старый обработчик

    {

 

        gettime (&t);                                // читаем текущее время

        docommonwrite( (char *) &t,4,'t');  // запись текущего времени

        cnt = 0;

                 

        enable();                    // востановление прерываний

энэйбл тут - это подозрительно.

Это даст возможность вложенных прерываний.

Это очень тонкий момент, лучше так не делать.

 

 

        SvInt08();                    // вызов старого обработчика прерывания

 

    }

  else

    {

      enable();                      // востановление прерываний

      outportb(0x20,0x20);      //конец прерывания

 

Это ...."полный привет".. !!! :blink:

 

Дело в том, что обращение к интеррапт-контроллеру

само по себе может вызвать аппаратное шевеление вывода INT.

Что приведет к генерации дополнительного прерывания.

В таких случаях вполне возможна непрерывная генерация.

Основанная не неверно написанном обработчике прерываний.

Кроме того - энейбл совершенно бесполезен в конце обработчика.

Так же, как бесполезен дизэйбл в начале обработчика. :biggrin:

Ибо после окончания обработчика он (энейбл) будет сделан аппаратно...

:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На самом деле енавле и дизабле хоть ставь хоть нет эффект тотже. Сначала их не было, потом начал всякие эксперименты ставить. Так что проблема не в этом :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На самом деле енавле и дизабле хоть ставь хоть нет эффект тотже. Сначала их не было, потом начал всякие эксперименты ставить. Так что проблема не в этом  :(

 

Эффект все-таки "не тот же".

По крайней мере процедура выполняется медленнее.

Кроме того, результат в таких случаях носит вероятностный

характер.

"Это надо знать точно". Ни понять, не заосциллографировать

(чуть язык не сломал :) ) тут ничего не удасться.

 

docommonwrite( (char *) &t,4,'t'); // запись текущего времени

cnt = 0;

 

enable(); // востановление прерываний

Это не будет работать потому, что энейбл и дизэйбл - это

разрешение/запрещение прерываний центральному процессору.

Кстати, лучше делать так:

 

asm sti; // enable

asm cli; // disable

 

Но система прерываний (в Вашей программе) не приведена в исходное

состояние. Это значит, никаких прерываний не будет .Независимо

от их разрешения.

 

        enable();                    // востановление прерываний

        SvInt08();                    // вызов старого обработчика прерывания

А вот это, видимо, Ваша проблема.

Дело в том, что прерывания "активизируются" командой INTx.

Вот как она работает:

asm pushf; !!

asm cli;

asm call dword ptr [4*x]

 

А заканчивается прерывание командой IRET, которая:

asm pop ip

asm pop cs

asm popf

 

Точнее вы и сами можете почитать. <_<

 

Поэтому нельзя просто так вызвать старый обработчик.

надо что-то вроде:

asm pushf;

OldVector ();

 

При этом надо быть уверенным, что адрес старого обработчика

спасен как (far *)

 

Я бы посоветовал вам сделать (для начала) прерывание по рыбе:

void interrupt some_routine (void)

{

// для начала сбросим систему прерываний:

RESET_MASTER_IC // это outportb (0x20,0x20);

// RESET_SLAVE_IC // это outportb (oxA0,0x20); - если используется слэйв

.

.

// тело обработчика

.

.

}

 

И фсе !

Если это будет работать устойчиво, тогда можно будет ставить

еще эксперименты.

 

:excl: В любом случае, все операции с контроллерами прерываний

должны производиться когда DISABLE !!!!! :excl:

:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А зачем Вы контроллер превываний дергаете перед выходом?. Это же уже сделано в старом обработчике. По-моему (могу ошибаться) прерывания с диска имеют более высокий приоритет, чем таймер. Поэтому запрет прерываний в таймерной секции с последующим EOI по-моему может при определенном стечении обстоятельств вызвать потерю прерывания с диска. Попробуйте убрать обращение к контроллеру преряваний.

Т.к. прерывания от таймера у меня возникают не 18.2 раза в секунду, а столько сколько мне нужно

(в зависимости от count:

outportb( 0x40, (char) count);

outportb( 0x40, (char)( count >> 8 ) );

задаётся частота возникновения прерываний от таймера),

то и стандартный обработчик таймера я вызываю не всегда. В переменной BIOSTimerSpeed хранится число прерываний котороые я должен пропустить прежде чем вызвать стандартный обработчик.

 

if ( cnt >= BIOSTimerSpeed )

{

cnt = 0;

SvInt08();

 

}

else

{

outportb(0x20,0x20);

}

 

Поэтому, если не вызван стандартный обработчик то нужно outportb(0x20,0x20);

Прерывание с диска имеют более низкий приоритет, чем от таймера. Однако возможно изменение приоритетов в рамках приоритетного кольца. Попробую поизменять приоритеты...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но система прерываний (в Вашей программе) не приведена в исходное

состояние. Это значит, никаких прерываний не будет .Независимо

от их разрешения.

 

        enable();                     // востановление прерываний

        SvInt08();                    // вызов старого обработчика прерывания

А вот это, видимо, Ваша проблема.

Дело в том, что прерывания "активизируются" командой INTx.

Вот как она работает:

asm pushf; !!

asm cli;

asm call dword ptr [4*x]

 

SvInt08 = getvect( 8 );

Поэтому вызов старого обработчика сводится к обычному вызову процедуры

SvInt08(); Не вижу здесь ничего плохого.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...