обработка IRQ

Assembler programming questions
  • VaStaNi
    В том то и дело что универсальности пока не получается. Я, например, сделал обработку мыши как следует, а тут пару дней назад узнал от человека, что модем перестал работать, придется совмещать старый и новый код, так как менять все и сразу тяжело.

    Heavyiron
    Хех ну ты сказанул! Когда два чела не имеющих отношения к компам начинают обсуждать третьего, который комперами занимается, то одним кручением у виска дело не ограничивается. Что уж говорить о том, что говорят нормальные продвинутые юзвери про нас маньяков железа и кода. ;-)
  • Serge wrote: На самом деле микросхема UART достаточно умна и не дергает CPU все время.
    После чтения соответствующего Interrupt Identification Register прерывание будет сброшено.
    ЕДИНОЖДЫ! Единожды ДА, сброшено, что и отображено в первой части "действия в лицах" :). Хочешь разобраться или проверить, так давай! Только факты приводи, ссылки, детали и все станет на свои места. А если сразу непонятно, с первого раза, так я не отказываюсь "резжевать" любой подробный момент, ничего зазорного и стыдного в том нет. Когда то давным давно, мой любимый преподаватель физики приводил цитату: "Если ты знаешь, ЧТО не понимаешь, то это первый шаг к пониманию!".
    А про "ум" UART, это перебор! Тупой он и прямой... ну как пробка! :)
  • О тупости UART

    When the CPU accesses the IIR. the UART freezes all interupts
    and indicates the higest priority pending interrupt
    to the CPU. While this CPU access is occuring, the UART records new
    interrupts, but does not change its current indication until the access
    is complete.

    говоря по-русски:
    когда мы обрабатываем прерывание UART надо

    1. считать IIR, проверить бит 0, если он установлен в 1
    то есть прерывание UART, если 0 то обработку можно закончить

    2. проверяем биты 1,2,3 и обрабатываем исключения.

    3. возвращаемся к п.1

    если бит 1 установлен в 1, а биты 2 и 3 в 0 то Transmitter Holding
    Register пуст ( или опустело FIFO передатчика в FIFO режиме)
    прерывание сбрасывается чтением IRR (что уже произошло) или записью
    байта в THR (или FIFO передатчика). В следующий раз прерывание от
    THR (FIFO) появится только после того как в него будут записаны данные и он
    снова опустеет.

    Источники:

    National Semiconductor
    PC16550D Universal Asynchronous Reciever/Transmitter with FIFOs

    качать с http://www.datasheetarchive.com в строке поиска набрать PC16550D
  • Во! Уже пошел интересный творческий, я надеюсь, диалог (не люблю споры).
    Итак. Сложилось впечатление непонимания именно с твоей стороны. Аргументирую.
    1. Я говрил именно о ПРИЧИНЕ периодических запросов IRQ к процессору, причем указав, конкретно, что речь и проблематика, именно с режимом прерывания опустошение буфера Tx UART.
    2. Описывал общую временную статистику состояния этого буфера.
    3. Берем мануалы. У меня нет конкретно National Semiconductor, у меня сейчас под рукой, Texas Instruments и EXARвские, но суть от этого не пострадает. Итак, IIR - не что иное, как регистр статуса, причины прерывания, который можно рассматривать как флаговый прерываний.
    По отношению к данному вопросу это флаг "1" в бите 1 этого регистра. Т.е. грамотно писаный обработчик прерываний от UART (COM) в самом начале кода (после всех сохранений, PUSH и инитов нужного) сортирует, вернее сказать анализирует эти биты В ПОРЯДКЕ ПРИОРИТЕТОВ IIR как флаги.
    Мануал гласит (у меня открыта сводная таблица по IIR это "Table 5. Interrupt Control Functions")

    INTERRUPT TYPE_|_INTERRUPT SOURCE_|__INTERRUPT RESET METHOD
    ______________|_________________|_________________________
    Transmitter_____| Transmitter_______|_Reading the interrupt identification
    holding________|__holding__________|_register (IIR) (if source of interrupt)
    register________|_register__________|_or writing into the transmitter
    empty_________|__empty__________|_holding register (THR)

    То есть понимаем буквально, что источником (SOURCE) возникновения ЭТОГО бита в IIR является причина: Transmitter holding register empty т.е. пуст! А занчит IRQ будет генерироваться соответствующим выходным сигналом UART пока он ИМЕЕНО ПУСТ!, а пуст он, читать топик выше, сколько времени...
    Сброс, говоришь, ну сбросил, если прочитан IIR или послал... но речь именно в том, что не посылаем мы в него постоянно, т.к. ОБЩАЯ пауза ЗНАЧИТЕЛЬНО превышает само времы передачи чего либо в UART!
    А следовательно имеется состояние именно Transmitter holding register empty ---> генерация нового IRQ! Т.е. сколько не сбрасывай его (пока именно данный тип прерывания активирован) он опять спросит своим IRQ :) : "Эй, начальник! У тебя есть данные передачи для меня?" ;)
    4. Ты пишешь п." 3. возвращаемся к п.1" Зачем возвращаемся????
    Постоянно в еще одном кольце CPU`шных задач проверять биты IIR, чтобы он "не скучал" и дабы не пропустить момент, когда.... т.е. PIO!??? А зачем тогда вообще IRQ?
    5. Я мог кое что и подзабыть, память моя далеко не идеал...+ драйвер долизывыал (все эти фичи и борьба с ними, доки...) где то пол-года назад, так что если очень надо и досконально я могу поднять работы и еще раз препроверить на реальном драйвере и реальном железе. Если очень надо или твои аргументы будут убедительны - сделаю.
  • 1. считать IIR, проверить бит 0, если он установлен в 1
    то есть прерывание UART, если 0 то обработку можно закончить
    небольшая поправка.

    UART сохраняет прерывания от нескольких источников и выдает их в порядке приоритетов (ошибка паритета/разрыв линии, приемник полон, таймаут в режиме FIFO, передатчик пуст, статус модема)

    пока запустится обработчик IRQ может (теоретически) произойти несколько событий.
    UART позваляет обработать их все за один вызов. Если бит 0 установлен в 1 то остаются еще необработанные исключения и мы можем обработать их все за один вызов. это лучше чем
    mov al, EOI
    out 21h, al
    и мы снова получаем запрос IRQ
    потому я и говорю, что UART не глупа.
    То есть понимаем буквально, что источником (SOURCE) возникновения ЭТОГО бита в IIR является причина: Transmitter holding register empty т.е. пуст! А занчит IRQ будет генерироваться соответствующим выходным сигналом UART пока он ИМЕЕНО ПУСТ!, а пуст он, читать топик выше, сколько времени...
    в том то и дело что не пока он ИМЕННО ПУСТ. THR генерирует прерывание не все время пока пуст,а только один раз - когда становится пустым . Прерывание сбрасывается чтением IRR (оно третье в списке по приоритету и может понадобится несколько считываний - см. выше) или записью байта в THR
    в следующий раз прерывание появится только после того как THR будет заполнен и снова опустеет. Фактически это прерывание наступает по фронту события а не по уровню.
  • Serge wrote:UART сохраняет прерывания от нескольких источников и выдает их в порядке приоритетов (ошибка паритета/разрыв линии, приемник полон, таймаут в режиме FIFO, передатчик пуст, статус модема) пока запустится обработчик IRQ может (теоретически) произойти несколько событий.
    UART позваляет обработать их все за один вызов. Если бит 0 установлен в 1 то остаются еще необработанные исключения и мы можем обработать их все за один вызов. это лучше чем
    mov al, EOI
    out 21h, al
    и мы снова получаем запрос IRQ
    потому я и говорю, что UART не глупа.
    Да я и не против такой обработки, тем более что это демонстрируют хорошие исходники, хотя я 0 бит не считаю нужным использовать, я анализирую и обрабатываю в порядке приоритета все остальные флаги при любои входе в обработчик. Ну ладно, раз это интеллект UART, ты считаешь, пусть будет так. :)
    Serge wrote:
    То есть понимаем буквально, что источником (SOURCE) возникновения ЭТОГО бита в IIR является причина: Transmitter holding register empty т.е. пуст! А занчит IRQ будет генерироваться соответствующим выходным сигналом UART пока он ИМЕЕНО ПУСТ!, а пуст он, читать топик выше, сколько времени...
    в том то и дело что не пока он ИМЕННО ПУСТ. THR генерирует прерывание не все время пока пуст,а только один раз - когда становится пустым . Прерывание сбрасывается чтением IRR (оно третье в списке по приоритету и может понадобится несколько считываний - см. выше) или записью байта в THR
    в следующий раз прерывание появится только после того как THR будет заполнен и снова опустеет. Фактически это прерывание наступает по фронту события а не по уровню.
    Где про одноразовость, несколько считываний, фронт можно прочитать? Это реально пробовал или по докам цитируешь?
    То что ты описал, пожалуй триггерным эффектом зовётся, а не фронтом. Т.е. хош сказать раз погасил и взведется он снова только после записи в порт и ег дальнейшего опустошения. Я был бы очень рад такому его поведению, хотя я мог что то и упустить и не понять, т.к. мой инглиш very bad! :) Но что то смутно мне подсказывают воспоминания при отладке, что не зря я это таким макаром порешил с режимом этим общаться. Вероятно перепроверить придется таки...
  • Практика критерий истины.
    Вот маленькая програмка.
    отправляет строку АТ комманд модему и принимает ответ

    cmd_str - АТ команды для модема
    можно пробовать разные варианты

    мдем подлючен к сом1 прерывание по дефолту

    запускать можно в WIN и в DOS но в WIN результаты могут отличаться
    в конце дает статистику сколько байт отправлено и сколько THR_пуст прерываний было
    FIFO отключен специально

    0х0а в конце АТ команды используется как терминатор строки для
    функции send

    include 'proc32.inc'

    format MZ
    heap 0
    stack 8000h
    entry main:start


    THR equ 0x3f8 ;0x2F8
    IER equ 0x3f9 ;0x2F9
    IIR equ 0x3fa ;0x2Fa
    LCR equ 0x3FB ;0x2FB
    MCR equ 0x3FC ;0x2FC
    IRQ_VEC equ 0x0C ;0x0B

    RATE equ 12; 9600 bps

    IDLE equ 0;
    TRANSMIT equ 1;

    segment main use16

    use16

    start:
    mov ax,_data
    mov ds, ax
    mov es, ax

    mov ss,ax
    mov sp, 0x2000
    mov bp, sp

    mov dx,_logo
    mov ah,9
    int 21h

    call disable_uart_intr
    call disable_FIFO
    call set_mode

    lea ax, [inp_buffer]
    mov [inp_ptr], ax

    call set_handler

    call enable_uart_intr
    call enable_com_irq

    lea ax, [inp_buffer]
    mov [inp_ptr], ax
    xor ax, ax
    mov [inp_count], ax
    mov [out_count], ax
    mov [trhe_count], ax

    lea ax, [cmd_str]
    call send_str

    mov dx, _trans
    mov ah,9
    int 21h
    mov dx, cmd_str
    mov ah,9
    int 21h
    mov dx, _rec
    mov ah,9
    int 21h
    mov dx, _anykey
    mov ah,9
    int 21h

    mov ah, 0
    int 16h
    call restore_handler

    mov dx, _msg_rec
    mov ah,9
    int 21h
    mov dx, inp_buffer
    mov ah,9
    int 21h

    mov dx, _t_bytes
    mov ah,9
    int 21h
    mov di, inp_buffer
    mov bx, [out_count]
    call word2str
    mov dx, inp_buffer
    mov ah,9
    int 21h

    mov dx, _msg_trhe
    mov ah,9
    int 21h
    mov di, inp_buffer
    mov bx, [trhe_count]
    call word2str
    mov dx, inp_buffer
    mov ah,9
    int 21h

    mov ah,4ch
    int 21h

    align 4
    proc disable_uart_intr

    mov edx, IER
    xor eax,eax
    out dx, al
    ret
    endp

    align 4
    proc enable_com_irq
    cli
    in al, 21h
    and al, 011100111b ;размаскируем irq3 и irq4
    out 21h, al
    sti
    ret
    endp

    align 4
    proc enable_uart_intr
    mov dx, IER
    mov ax, 0x03 ;приемник полон передатчик пуст
    out dx, al
    ret
    endp

    proc set_mode

    mov dx, LCR
    in al, dx
    or al, 80h
    out dx, al

    mov dx, THR
    mov al, RATE
    out dx, al

    inc dx
    xor al, al
    out dx, al

    mov dx, LCR
    mov al, 3
    out dx, al

    mov dx, MCR
    mov al,0bh
    out dx, al

    ret
    endp

    proc set_handler

    push es
    mov ax, 0
    mov es, ax

    mov bx, IRQ_VEC
    shl bx, 2

    mov ax, [es:bx]
    mov [old_offset], ax
    mov ax, [es:bx+2]
    mov [old_seg], ax

    cli
    lea ax, [com_handler]
    mov [es:bx], ax
    mov ax, cs
    mov [es:bx+2], ax
    sti

    pop es

    ret
    endp

    proc restore_handler

    push es
    mov ax, 0
    mov es, ax

    mov bx, 0x30

    cli
    mov ax, [old_offset]
    mov [es:bx], ax

    mov ax, [old_seg]
    mov [es:bx+2], ax
    sti

    pop es

    ret
    endp

    align 4
    proc send_str

    mov [out_ptr], ax
    mov [out_count], 0
    mov [mode], TRANSMIT
    mov si, ax
    mov al, [si]
    mov dx, THR
    out dx, al

    sti

    .l1: cmp [mode], TRANSMIT ;надо вставить проверку на таймаут
    jnz .l2
    hlt
    jmp .l1

    .l2:

    ret
    endp

    align 4
    proc send

    add [trhe_count], 1
    cmp [mode], TRANSMIT
    jne .exit

    mov si, [out_ptr]
    add si, 1
    mov [out_ptr], si
    add [out_count], 1
    mov al, [si]
    cmp al, 0ah
    jz .trans_end

    mov dx, THR
    out dx, al

    .exit:
    ret

    .trans_end:
    mov [mode], IDLE

    ret
    endp

    align 4
    proc recieve

    mov si,[inp_ptr]
    mov dx, THR
    in al, dx
    mov [si], al
    add [inp_ptr], 1
    add [inp_count], 1

    ret
    endp

    align 4
    proc com_handler
    cli
    pusha
    push ds
    push es

    mov ax,_data
    mov ds, ax

    xor ax, ax
    mov dx, IIR
    in al, dx
    mov [iir_save], al

    and ax, 0110b

    cmp ax, 2 ;передатчик пуст
    jnz .m1

    call send

    jmp .l2

    .m1:
    cmp ax, 4 ; приемник заполнен
    jnz .l2
    call recieve
    jmp .l2


    .l2:
    mov al, 20h
    out 20h, al

    pop es
    pop ds
    popa
    sti
    iretw
    endp

    align 4
    proc disable_FIFO
    mov dx, IIR
    xor al, al
    out dx, al
    ret
    endp

    proc word2str

    rol bx, 4
    call conv
    rol bx, 4
    call conv
    rol bx, 4
    call conv
    rol bx, 4
    call conv
    mov byte [di], 24h
    ret
    endp

    proc conv
    mov al, bl
    and ax, 0x0f
    aaa
    adc al, 0x30
    db 0xd5
    db 0x10
    mov [di], al
    add di, 1
    ret
    endp

    segment _data use16
    align 4
    old_offset dw ?
    old_seg dw ?
    row dw 0

    mode dd 0
    out_ptr dw 0
    out_count dw 0
    iir_save db 0

    trhe_count dw 0

    inp_ptr dw 0
    inp_count dw 0

    align 4
    inp_buffer dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24000000h

    _logo db ' init uart... ',0Dh, 0Ah,24h

    cmd_str db 'AT', 0Dh, 0ah,24h
    ;cmd_str db 'ATQ0V1E0', 0dh, 0ah , 24h
    ;cmd_str db 'AT+GMM', 0dh, 0ah, 24h

    _trans db 0dh, 0ah,' transmit command $'
    _rec db 0dh, 0ah, ' recieve data... please wait, then$'
    _anykey db 0dh, 0ah, ' press any key...$'
    _msg_rec db 0dh, 0ah, ' recieve message',0dh,0ah, 24h
    _t_bytes db 0dh, 0ah, ' bytes transmitted $'
    _msg_trhe db 0dh, 0ah, ' total trhe interrupts $'
  • Serge, беру свои словесные выкладки назад по поводу ПОВТОРНОГО и ПОВТОРЯЮЩЕГОСЯ запроса IRQ по причине пустого буфера Tx. На выходных поднял, слапал еще более упрощенный вариант чем у тебя, правда был, и убедился. Да, ты прав, БОЛЬШОЕ СПАСИБО за такой интересный нюанс, поправку!!! Это вообще отлично.
    Еще поправлюсь, кажется выше я говорил про дефолтный обьем FIFO=16байтам, так вот, я перепутал. При настройках исходно он оказался =1 байту, т.е. аналого самого тупого UART времен XT(ох и любят они эту совместимость с динозаврами). Доки в принципе все говорят КАК сделать иное, но беглое решение тем, кто интересуется могу привести, коль уж тут про всякие подробности потрохов пошло... Итак, обьем FIFO устанавливается, так же, как и скорость, т.е. с предваритеьным включением доступа в порту 0x..FB кратко и лениво, напраимер, так:
    mov dx, 0x3F8 ;COM1 base port
    add dx, 3 ;=0x3FB
    mov al, 0x80
    out dx, al ; включить доступ
    dec dx ;=0x3FA
    mov al, 0xF1 ;включить МАКСИМАЛЬНЫЕ FIFO обьемы в обоих направлениях
    out dx, al
    ; далее следеут классика установки скоростной константы делителя в портах 0x..F8 и 0x..F9
  • VaStaNi

    Почитал еще раз мануалы.

    FIFO включается установкой в 1 бита 0 в регистр 0x..FA а биты 6 и 7
    задают порог при котором выдается прерывание приемник полон

    биты 7 6 уровень триггера

    0 0 1 байт
    0 1 4 байт
    1 0 8 байт
    1 1 14 байт

    запись 1 в бит 1 очищает FIFO приемника
    запись 1 в бит 2 очищает FIFO передатчика
    биты 4 и 5 зарезервированы, но это может зависить от
    реализации

    ещё FIFO приемника может выдавать прерывание по таймауту
    если в буфере есть данные, а мы их не читали (или не было принято
    данных) за время необходимое для передачи 4 байт

    бит 7 в регистре 0x..FB - это защелка для установки делителя
    частоты устанвливаем в 1 пишем в 0x..F8 0x..F9 делитель
    частоты и снова сбрасываем в 0.

    И еще раньше писал про бит 0 в IIR оказалось все наоборот
    если он 0 то есть прерывание, а если 1 то нет. Странная логика.
  • Serge wrote: Странная логика.
    :) да, уж! Как говорит один мой знакомый в таких случаях: "Курите, Шура мануалы!" (как ни странно люди на перкурах много мыслят бывает, общаются, перетирают интересующие темы...) :)
  • Who is online

    Users browsing this forum: No registered users and 6 guests