Современные технологии автоматизации» («СТА») —  журнал для квалифицированных специалистов по промышленной автоматизации Форум СТА — современные технологии автоматизации Домашняя страница
Домашняя страница форума CTA Домашняя страница форума CTA > II. АСУТП и SCADA > Архив
  Активные темы Активные темы
  FAQ FAQ  Искать в форуме   Зарегистрироваться Зарегистрироваться  Вход в систему Вход в систему

Проблема с ком-портом на контроллерах типа ADAM-5510M или бага в RDC R8800.

 Ответить Ответить
Автор
Сообщение
Rashid Смотреть выпадающим
Новичок
Новичок


Присоединился: 09 Сентябрь 2005
Категория: Russian Federation
Online Status: Offline
Публикации: 8
Свойства публикации Свойства публикации   Ответить, цитируя автора - Rashid Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Тема сообщения: Проблема с ком-портом на контроллерах типа ADAM-5510M или бага в RDC R8800.
    Опубликовано: 13 Сентябрь 2005 17:37

Проблема

При инициировании приемо-передачи данных от центрального компьютера контроллеру, программа в контроллере, написанная полностью на ассемблере и не содержащая чужого кода, повисала. Время, через которое происходило зависание зависило от двух факторов: частоты приемо-передачи и НЕКОЕГО СЛУЧАЙНОГО ФАКТОРА. То есть при зафиксированной частоте приемо-передачи, время, через которое система могла зависнуть, варьировалось от секунд до нескольких минут.

Анализ и решение вкратце

Система зависала из-за порчи системных данных моим обработчиком прерывания от  ком-порта.

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

Несоответствие сегмента данных происходило из-за того, что параллельно с моей программой каждые 55 мс вызывался обработчик прерывания от таймера 0, написанный фирмой Advantech, в котором разрешались вложенные прерывания до восстановления регистра сегмента данных.

Во время работы обработчика прерывания от таймера 0 после разрешения прерываний происходило прерывание от ком-порта и включался мой обработчик, который имел дело с некорректным сегментом данных, т.к. последний не был еще восстановлен.

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

Поэтому на контроллерах ADAM-5510, в которых стоит Amd188Em данная проблема отсутствует. Процессоры же RDC R8800, которые стоят в контроллерах ADAM-5510M, ADAM-5510E данную спецификацию НАРУШАЮТ, тем самым не являясь полным аналогом Amd188Em.

Поскольку изменить обработчик фирмы Advantech невозможно (обработчик защищен от записи), то существует несколько решений:

  • устанавливать регистр сегмента данных в обработчике прерывания от ком-порта принудительно в нужное значение;
  • запретить вообще прерывания от таймера 0, если он не используется в программе;
  • написать свой разработчик и перенаправлять вектор на него до того, как будут разрешаться все остальные прерывания и запускаться главный цикл программы;

ПРИ ИСПОЛЬЗОВАНИИ СТАНДАРТНЫХ БИБЛИОТЕК ПРОБЛЕМА ОТСУТСТВУЕТ, т.к. стандартный обработчик от ком-порта принудительно устанавливает требуемый сегмент данных.

ПРИ ПРОГРАММИРОВАНИИ БЕЗ ИСПОЛЬЗОВАНИЯ БИБЛИОТЕК ПРОБЛЕМА - некорректное поведение инструкции sti и соответственно стандартного обработчика прерывания от таймера 0, входящего в состав операционной системы - РАСПРОСТРАНЯЕТСЯ НА ВСЕ ОБРАБОТЧИКИ ПРЕРЫВАНИЯ И НЕ ОБЯЗАТЕЛЬНО МОЖЕТ БЫТЬ СВЯЗАНА С КОМ-ПОРТОМ. 

Основные выводы

1. Инструкция STI процессора RDC R8800 НАРУШАЕТ СПЕЦИФИКАЦИЮ Amd188Em.

2. Стандартный обработчик прерывания от таймера 0, входящий в состав ОС фирмы Advantech не учитывает данный факт и может приводить к некорректному поведению пользовательских программ, которые полагаются на корректное значение регистра сегмента данных ds.

Вопросы к аудитории и экспертам

1) Сталкивался ли кто-либо с подобным?

2) Есть ли у кого-либо замечания по поводу написанного (возможно я что-то не так понимаю или где-то ошибаюсь)?

В случае необходимости могу выслать полностью исходники на ассемблере + документацию. Программа в com-формате занимает 2.5 кБ. 

Замечания

В процессе сужения области поиска на контроллере ADAM-5510E из-за очередного зависания контроллер приказал долго жить - теперь после его включения при загрузке появляется надпись "Sector not found. Error finding drive A. Abort, Retry, Fail?"

Все остальные испытания были продолжены на контроллере ADAM-5510M.

Поэтому как только в процессе анализа проблемы стало ясно, что зависания происходят из-за некорректного сегмента данных, зависания были заменены на включение индикатора COMM, чтобы не испортить еще один контроллер, а именно: если сегмент данных в обработчике прерывания от ком-порта не соответствовал корректному, включался индикатор COMM, после чего сегмент данных устанавливался в корректное значение принудительным образом.

Более подробно

1. Программа системы управления была максимально сокращена до минимально необходимой части, были оставлены:

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

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

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

Мой обработчик прерывания от ком-порта использует внутренние данные, расположенные в том же сегменте, что и код, т.е. ds = cs, где
     ds - регистр адреса сегмента данных,
     cs - регистр адреса сегмента кода.

При этом мой обработчик НИКАК НЕ НАСТРАИВАЛ РЕГИСТР СЕГМЕНТА ДАННЫХ, полагая, что он совпадает с регистром сегмента кода.

Данное предположение работает до тех пор, ПОКА НЕТ ЧУЖОГО РАБОТАЮЩЕГО КОДА.

Отсюда был сделан вывод, что кто-то изменяет регистр сегмента данных перед вызовом моего обработчика.

3. Были проанализированы управляющие регистры для всех источников прерывания, и выяснено, что одновременно с моей программой работают 2 таймера: таймер 0 и таймер 2.

Таймер 2 является опорным для таймера 0, срабатывая каждые 258 мкс.  При этом прерывание для таймера 2 не генерится (соответственно отсутствует обработчик).

Обработчик прерывания от таймера 0 вызывается каждые 55 мс (213 * 258 мкс) и обновляет так называемый регистр тиков таймера, а также вызывает пользовательский обработчик таймера 1Ch (DOS), в котором прописана одна инструкция iret. (Пользователь DOSа может переопределить обработчик 1Ch).

После дизассемблирования дампа области памяти, где находится обработчик прерывания от таймера 0, было получено:

;----------------------------------------------------------------
; timer0_isr
;----------------------------------------------------------------
;
; Обработчик прерывания от таймера 0
;
; 0040:006C - 4-байтовый счетчик тиков таймера
; 0040:0070 - флаг переполнения таймера
;
; константа 1800B0h = 1573040 определяет число тиков в сутки,
; за секунду происходит ~18.2 тика или иначе тик происходит
; каждые 55 мс.
;
;----------------------------------------------------------------

PROC     timer0_isr

   push ax
   push cx
   push ds

   mov ax, 0040h
   mov ds, ax                    ; СЕГМЕНТ ДАННЫХ МЕНЯЕТСЯ на 0040
                                       ; 0040 - СИСТЕМНАЯ ОБЛАСТЬ

   inc [ WORD ds:006Ch ]

   jnz @@skip_inc_hi

   inc [ WORD ds:006Eh ]

@@skip_inc_hi:

   mov cx, [ ds:006Eh ]

   cmp cx, 18h
   jl @@skip_reset_count
   jg @@reset_count

   mov cx, [ ds:006Ch ]
   cmp cx, 0B0h
   jle @@skip_reset

@@reset_count:

   call timer0_reset_count

   inc [ WORD ds:0070h ]

@@skip_reset_count:

   int 1Ch                          ; НЕЯВНО ЗАПРЕЩАЮТСЯ ВСЕ ПРЕРЫВАНИЯ

   push dx

   mov dx, 0FF22h
   mov ax, 8000h
   out dx, ax

   pop dx

   sti                                 ; РАЗРЕШАЮТСЯ ВЛОЖЕННЫЕ ПРЕРЫВАНИЯ

; ТОЧКА КРАХА!!?

   pop ds                           ; ВОССТАНАВЛИВАЕТСЯ СЕГМЕНТ ДАННЫХ

; НО СОГЛАСНО ДОКУМЕНТАЦИИ НА МИКРОПРОЦЕССОР AMD188EM ОБРАБОТЧИК ВЛОЖЕННОГО ПРЕРЫВАНИЯ
; ПОЛУЧИТ УПРАВЛЕНИЕ ТОЛЬКО *ПОСЛЕ* ВЫПОЛНЕНИЯ СЛЕДУЮЩЕЙ (!) ЗА КОМАНДОЙ STI ИНСТРУКЦИИ!!!

   pop cx
   pop ax

   iret 

ENDP     timer0_isr

;----------------------------------------------------- timer0_isr


;----------------------------------------------------------------
; timer0_reset_count
;----------------------------------------------------------------
;
; Обнуляет счетчик тиков таймера.
;
;----------------------------------------------------------------

PROC     timer0_reset_count

   xor ax, ax

   mov [ ds:006Ch ], ax
   mov [ ds:006Eh ], ax

   retn 

ENDP     timer0_reset_count

;--------------------------------------------- timer0_reset_count

Из приведенного кода видно, что регистр сегмента данных восстанавливается ПОСЛЕ ТОГО КАК РАЗРЕШАЮТСЯ ВЛОЖЕННЫЕ ПРЕРЫВАНИЯ! ОДНАКО НИ ОДИН ОБРАБОТЧИК ПРЕРЫВАНИЯ НЕ МОЖЕТ БЫТЬ ВЫЗВАН СРАЗУ ПОСЛЕ ИНСТРУКЦИИ STI СОГЛАСНО ДОКУМЕНТАЦИИ НА МИКРОПРОЦЕССОР.

Т.к. на контроллере ADAM-5510 стоит микропроцессор AMD188EM, то там
зависание не наблюдается. Однако, на контроллере ADAM-5510M стоит другой микропроцессор RDC R8800 - аналог (?) AMD188EM.

4. Для начала, чтобы убедиться в том, что сегмент данных портится обработчиком прерывания от таймера, при старте был отключен таймер 0. Зависания прекратились.

Далее, чтобы убедиться в том, что крах (точнее начало краха) происходит именно там, где указано выше в листинге, в обработчик прерывания от ком-порта были добавлены инструкции (выключение таймера 0 при старте программы при этом было убрано):

   если ds изменился (ds <> cs), то
          включить индикатор COMM
          сохранить значение ds (_ds = ds)
   извлечь из стека адрес возврата и запомнить его в _cs:_ip
          установить флаг краха

          сделать ds корректным (ds = cs)
   конец если

В главном цикле, в случае появления флага краха, в терминал выводились _ds, _cs:_ip

В результате испытания, через случайный промежуток времени система "повисла" - зажгла индикатор COMM (повисание не произошло, т.к. ds устанавливался в корректное значение принудительно), а в терминале был выведен адрес ТОЧКИ КРАХА, т.е. того места с которого был вызван обработчик прерывания от ком-порта.

ds оказался равным 0040, а точка краха пришлась на инструкцию pop ds, т.е. перед тем как выполнить инструкцию pop ds в обработчике прерывания от таймера 0, обработчик прервался и был вызван мой обработчик от ком-порта, который уже имел дело с некорректным ds.

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

Данные испытания проводились многократно. Система всегда "зависала" именно в вышеуказанной точке краха.

Дополнения (уточнения)

1. Вся программа была написана на ассемблере и транслировалась в com-формат.

2. ТОЧКА КРАХА является условным названием, т.к. очевидно, что в данной точке никакого краха или зависания не происходит, а лишь начинается "дорога к смерти", поскольку регистр ds еще не восстановлен. Повиснет система гораздо позже - все зависит от того, куда записываются данные в обработчике прерывания от ком-порта, и насколько важные данные они затрут.

3. Данная проблема отсутствует на ADAMах-5510, т.к. там стоят микроконтроллеры Amd188Em, которые (к счастью) соответствуют документации (по крайней мере в том, что касается инструкции STI).

4. Данная проблема актуальна также и для ADAM-5510E, т.к. там то же ядро, что и в ADAM-5510M.

Наверх
 Ответить Ответить

Переход на форум Права доступа на форуме Смотреть выпадающим

Bulletin Board Software by Web Wiz Forums® version 9.64
Powered by Web Wiz Forums Free Express Edition
Copyright ©2001-2009 Web Wiz