бывают ли медлительные прерывания?

Тема в разделе "Микроконтроллеры AVR", создана пользователем A.T.M, 19 авг 2017.

  1. A.T.M

    A.T.M Нерд

    Здравствуйте, столкнулся со следующей проблемой. Написал код для attiny 2313 чтобы использовать ее usi как i2c слейв. Прошиваю attiny2313, все работает. Прошиваю attiny2313a, ни чего не работает, из-за того что прерывание по состоянию старт еще не сработало, а ардуино-мастер уже прислал по и2с один-два импульса тактирования. С прерыванием по переполнению счетчика usi тоже все долго. Замерил логическим анализатором: при частоте тактирования 2 МГц время между возникновением условия старт и срабатыванием прерывания составляет порядка 25 микросекунд. Почему так может быть подскажите?
     
  2. rkit

    rkit Гуру

    На момент получения сидит в каком-нибудь энергосберегающем режиме, или другом прерывании. Хотя не очень понятно, зачем вам прерывание по старту, и как так вы задержку внутри чипа смогли измерить.
     
  3. A.T.M

    A.T.M Нерд

    Разобрался, действительно сидит в другом прерывании.Проснулся сегодня утром,прочитал ваше сообщение и сообразил, а вчера все силы ушли чтобы понять, в чем же причина неработающего интерфейса. Прерывание по старту использую чтобы подготовить USI к приему данных по и2с, а задержку определил по осциллограмме, заметил состояние старт, и в момент возникновения прерывания перевел незадействованную ногу в высокое состояние момент возникновения прерывания плюс sbi portd 0 тактирование 2Мгц.png
     
  4. A.T.M

    A.T.M Нерд

    странно,однако, что на старом чипе все работает, а на 2313a неправильный код не работает. Загвоздка в том, по видимому,что тинька сидит в прерывании от таймера. На таймере сделана задержка, до прерывания usi контроллер совершает циклическое действие, само прерывание от таймера - выполнение всего одной команды sbt, кажется не должно быть долго. Еще предстоит прояснить проблему...
     
  5. A.T.M

    A.T.M Нерд

    .
    Переписал код, убрал другие прерывания, оставил только USI, так же как нет ни каких энергосберегающих режимов. От куда может быть задержка? Помогите?
     
  6. A.T.M

    A.T.M Нерд

    .include "2313def.inc" //подцепим файл описаний названий
    .list //включим листинг
    .equ i2c_addres = 0x01 //задаем и2с адрес
    .equ flag_ron0 = 1 //ЗАДАЕМ ЗНАЧЕНИЯ ДЛЯ КОМАНД S/C BR
    .equ flag_ron1 = 2
    .equ flag_ron2 = 4
    .equ flag_ron3 = 8
    .def flag_ron = r16 //используем 16ый РОН под хранение разных флагов
    // 0 (1) - наличие состояния старт
    // 1 (2) - микросхема выбрана
    // 2 (4) - 0->запись 1->чтение
    // 3 (8)- флаг требования сброса бита квитирования
    .def temp = r17 //обзавем 17-ый регистр темпом
    .def n_oborot = r18 //в 18 РОН будем помещать задание на обороты
    .def sostoyanie = r19 //РОН для хранения состояния дозатора
    // 0x00-электрический пробой
    // 0x01-все хорошо
    // 0x02-дозатор заклинил
    // 0x03-корм слежался

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

    // | | |

    .cseg //выбираем память программ
    .org 0 //устанавливаем указатель
    // текущего адресса на ноль

    //----------*****УСТАНОВКА ВЕКТОРОВ ПРЕРЫВАНИЙ*****------------

    rjmp init
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    rjmp init_start //наличие старта
    rjmp usicount //переполнение счетчика usi
    reti
    reti


    //---------****ИНИЦИАЛИЗАЦИЯ****---------------------------


    //---------отключение аналогового компоратора--------------

    init: ldi temp, 0x80
    out ACSR, temp

    //---------установка указателя стека-----------------------

    ldi temp, RAMEND
    out spl, temp


    //---------инициализация порта D--------------------------

    ldi temp, 0b11111111 //установим порт Д на вывод данных
    out DDRD, temp
    ldi temp, 0b00000000
    out PORTD, temp

    //---------инициализация интерфейса USI--------------------------
    ldi temp, 0xfb
    out portb,temp
    ldi temp, 0b00000100
    out ddrb,temp

    ldi temp,0b11110000 //сбрасываем все флаги и счетчик USI ставим в 0
    out 0x0e,temp //в 0x0e
    ldi temp, (1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)
    out 0x0d,temp // в USICR


    //--------****ОСНОВНОЙ ЦИКЛ****--------------------------

    sei //разрешаем все прерывания
    main: nop

    rjmp main


    //--------*****ПОДПРОГРАММЫ*****--------------------------







    //---------*****ПРЕРЫВАНИЯ*****--------------------------


    init_start: sbi DDRb,7 //подключаем USI sck к пину 7B
    clr flag_ron //сбрасываем РОН флагов на всяк. случай
    sbr flag_ron,flag_ron0 //устанавливаем флаг старта
    sbr flag_ron,flag_ron1 //устанавливаем флаг выбора
    ldi temp,0b10110000 //подготавливаем счетчик для приема,сбрасываем
    out 0x0e,temp // флаг USISIE, освобождая линию sck
    cbi DDRb,7 //отключаем USI sck от пина 7B
    reti



    usicount: sbi DDRb,7 //подключаем контакт 7 к схеме для прижатия шины
    bst flag_ron,3 //освобождаем линию SDA, если это требуется
    brtc uc1

    cbi DDRB,5
    sbi PORTB,5
    cbr flag_ron,flag_ron3 //сбрасываем бит требования сброса асk
    sbrc flag_ron,2 //проверяем:прием или передача?
    rjmp k_masteru //подготавливаем данные если задана передача
    ldi temp,0b01000000 //сбрасываем флаг USIOIF, освобождая тем самым линию sck,
    out 0x0e,temp // записываем в счетчик USI 0, под прием байта данных
    cbi DDRb,7 //выкл пин 7b для освобождения шины
    reti //выходим из прерывания,если задан прием

    uc1: bst flag_ron,1 //проверяем выбрана ли микросхема,если нет,
    brtc vihod // выходим из подпрограммы обработки прерывания
    bst flag_ron,0 //проверяем: адресный пакет или данные?
    brtc ot_mastera //переходим к процедуре обработки данных
    cbr flag_ron,flag_ron0 //сбрасываем флаг старта
    in temp,0x0f //считываем полученные данные по и2с
    bst temp,0 //переносим в РОН флагов принятое значение на
    bld flag_ron,2 // чтение\запись
    addres: lsr temp //проверяем:выбрана ли микросхема?
    cpi temp,i2c_addres
    breq vih_s_ack //устанавливаем соответствующий флаг-РОН
    clr flag_ron // если нет сбрасываем весь РОН флагов
    //-----просто выход
    vihod: ldi temp,0b01110000 //освобождаем линию sck
    out 0x0e,temp
    cbi DDRb,7 //откл схему от пина 7b для освобождения шины
    cbi DDRb,5 //откл схему от пина 5b.тем самым настраиваем SDA на прием
    reti
    //-----выход с потверждением
    vih_s_ack: sbr flag_ron,flag_ron3 //устанавливаем требование сброса бита ack
    sbi DDRB,5 //выход с потверждением бита квитирования
    cbi PORTB,5 // выставляем SDA в 0, сбрасываем флаг USIOIF,
    ldi temp,0b01001110 // освобождая тем самым линию sck, записываем в
    out 0x0e,temp // счетчик USI 14, под фронт и срез тактирования
    cbi DDRb,7 //отключаем USI от пина для освобождения шины
    reti // до след. прерывания

    ot_mastera: bst flag_ron,2 //проверяем: от мастера запрос на чтение или запись?
    brts vihod // если на чтение выходим, бит ack не инетресует // т.к передаем всего один байт
    in n_oborot,0x0f // если на запись, заносим полученый байт в соотв. регистр
    rjmp vih_s_ack

    k_masteru: out 0x0f,sostoyanie //отправляем данные о состоянии
    sbi DDRB,5 //подключаем сдвиговый регистр к контакту B5
    ldi temp,0b01000000 //сбрасываем флаг USIOIF, освобождая тем самым линию sck,
    out 0x0e,temp // записываем в счетчик USI 0, под прием байта данных
    cbi DDRb,7 //выкл пин 7b для освобождения шины
    reti
     
    Airbus нравится это.
  7. Airbus

    Airbus Оракул

    Посмотрел код.Мне понравилось написано красиво и толково.Здесь засад быть не должно.Рискну предположить что проблема в аппаратной части.Тини 2313 и 2313А различаются хотя и не так кардинально.В AVR Studio они тоже стоят особняком.Вы когда код компилите выбираете Т2313 или Т2313А?Ну и таблица векторов прерываний какая то странная я пишу так-попробуйте?
    Код (C++):
    rjmp RESET            ; Reset Handler
    reti;rjmp INT_0            ; Внешнее прерывание 0
    reti;rjmp INT_1            ; Внешнее прерывание 1
    reti;rjmpTIM1_CAPT        ; Прерывание по захвату таймера T1
    reti;rjmpTIM1_COMPA        ; Прерывание по совпадению T1
    reti;rjmpTIM1_OVF        ; Прерывание по переполнению T1
    reti;rjmpTIM0_OVF        ; Прерывание по переполнению T0
    reti;rjmpUSART0_RXC        ; Прерывание UART прием завершен
    reti;rjmpUSART0_DRE        ; Прерывание UART регистр данных пуст
    reti;rjmpUSART0_TXC        ; Прерывание UART передача завершена
    reti;rjmpANA_COMP        ; Прерывание по компаратору
    reti;rjmpPC_INT            ; Прерывание по изменению на любом контакте
    reti;rjmpTIMER1_COMPB        ; Таймер/счетчик 1. Совпадение B
    reti;rjmpTIMER0_COMPA        ; Таймер/счетчик 0. Совпадение A
    reti;rjmpTIMER0_COMPB        ; Таймер/счетчик 0. Совпадение B
    rjmp init_start ; наличие старта
    rjmp usicount ; переполнение счетчика usi
    reti;rjmpEE_READY        ; EEPROM Готовность
    reti;rjmpWDT_OVERFLOW        ; Переполнение охранного таймера
     
     
    Последнее редактирование: 20 авг 2017
    A.T.M нравится это.
  8. Airbus

    Airbus Оракул

    Смутило вот ещё что:отключение аналогово компаратора вроде бы по фен-шую но у вас есть странная функция init: Это ошибка или она что то делает в коде?
    Код (C++):
    //---------отключение аналогового компаратора--------------

    init: ldi temp, 0x80
    out ACSR, temp
    У меня так:
    Код (C++):
    ;--------------------------- Инициализация компаратора

            ldi     temp, 0x80        ; Выключение компаратора
            out        ACSR, temp
     
  9. DetSimen

    DetSimen Гик

    это не функция, это метка. сюда jump или call приходют
     
  10. Airbus

    Airbus Оракул

    Откуда?Отключение компаратора сразу вначале и само по себе.
     
  11. DetSimen

    DetSimen Гик

    Может быть даже с вектора Reset
     
  12. A.T.M

    A.T.M Нерд

    Да, DetSimen говорит так, как я делал. Делаю так, потому что прочитал где-то когда-то: ресет самый первый вектор прерывания,он должен быть определен. По таблице прерываний не вижу отличий,но нахожу вашу более информативной. Когда компилил код, стояло Т2313, поставил Т2313А не помогло. Вообще дело было так. Вытравил я плату, спаял, начал отлаживать, отлаживал, отлаживал, все вроде бы работало на этом коде. Потом пошла черная полоса, и все перестало работать(((( Началось с того что я спалил ардуину и Т2313а. Долго думал как так получилось, но не разобрался толком, где тот момент, когда SDA на обоих устройствах сконфигурированы как выходы и на одном 0, на другом 1. Дальше взял другую ардуину и запаял на мою плату новый Т2313А и дальше эта проблема с интерфейсом, много чего перепробовал прежде, чем понял что есть какая-то задержка в прерывании. Сначала думал что проблема просто с чипом, брак попался, тем более чипы были куплены на АЛИ по дешевке и первый запаяный чип был просто нерабочим, я перепаял все оставшиеся 8 - интерфейс тупит. Ну, думаю, Китайцы! Пошел в местный провереный радиомагазин, купил в 5 раз дороже - тоже самое интерфейс тупит. Вобщем, я почти все что мог уже перепробовал,не знаю в чем беда, задержка на т2313а, на простом т2313 ее нет, все работает
     
  13. Airbus

    Airbus Оракул

    Где то есть плавающий баг.Посмотрел еще раз вроде все должно работать но есть пара вопросов по синтаксису у Вас в конце блоки к_мастеру и от_мастера это ведь подпрограммы?Не прерывания?Почему выход из них reti а не ret? Ну и по поводу кЕтайских чипов.Купил я тут давеча пачку Мег8 по смешной цене Наебае оказались с битым ЕЕПРОМ сначала думал сам дурак потом прочитал кажется у DiHalta что есть такие приколы у китайцев и даже идут с битым Флешем это похуже будет.
     
  14. A.T.M

    A.T.M Нерд

    Это прерывание по переполнению счетчика USI
     
    Последнее редактирование: 27 авг 2017
  15. A.T.M

    A.T.M Нерд

    Мне стало интересно: только ли на USI прерывания имеют задержку? Написал код, с использованием прерывания по изменению на контакте pcint

    Код (C++):
    //----------псевдокомпнды управления---------------------

    .include "2313def.inc"        //подцепим файл описаний названий

    .def temp       = r17        //обзавем 17-ый регистр темпом


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

                .cseg                                //выбираем память программ
                .org            0                    //устанавливаем указатель
                                                        // текущего адресса на ноль

    //----------*****УСТАНОВКА ВЕКТОРОВ ПРЕРЫВАНИЙ*****------------

                rjmp RESET ; Reset Handler
                reti;rjmp INT_0; Внешнее прерывание 0
                reti;rjmp INT_1; Внешнее прерывание 1
                reti;rjmpTIM1_CAPT; Прерывание по захвату таймера T1
                reti;rjmpTIM1_COMPA; Прерывание по совпадению T1
                reti;rjmpTIM1_OVF; Прерывание по переполнению T1
                reti;rjmpTIM0_OVF; Прерывание по переполнению T0
                reti;rjmpUSART0_RXC; Прерывание UART прием завершен
                reti;rjmpUSART0_DRE; Прерывание UART регистр данных пуст
                reti;rjmpUSART0_TXC; Прерывание UART передача завершена
                reti;rjmpANA_COMP; Прерывание по компаратору
                rjmp PC_INT; Прерывание по изменению на любом контакте
                reti;rjmpTIMER1_COMPB;Таймер/счетчик 1. Совпадение B
                reti;rjmpTIMER0_COMPA; Таймер/счетчик 0. Совпадение A
                reti;rjmpTIMER0_COMPB; Таймер/счетчик 0. Совпадение B
                reti;rjmp;init_start;  наличие старта
                reti;rjmp;usicount;переполнение счетчика usi
                reti;rjmpEE_READY; EEPROM Готовность
                reti;rjmpWDT_OVERFLOW; Переполнение охранного таймера

    //---------****ИНИЦИАЛИЗАЦИЯ****---------------------------


    //---------отключение аналогового компоратора--------------

    RESET:        ldi             temp, 0x80          
                         out                ACSR, temp          

    //---------установка указателя стека-----------------------

                ldi             temp, RAMEND      
                out                spl, temp          


    //---------инициализация порта D--------------------------              
               
                ldi                temp, 0b11111111    //установим порт Д на вывод данных
                out                DDRD, temp          
                ldi                temp, 0b00000000  
                out                PORTD, temp      

    //--------****ОСНОВНОЙ ЦИКЛ****--------------------------
                sbi        ddrb,0                        //конфигурация контрольного пина
                cbi        portb,0
                ldi        temp,0x20                    //включаем внешнее прерывание типа
                out        gimsk,temp                    //    pcint
                ldi        temp,0x01                    //указываем контакт pcint0 (pb0)
                out        PCMSK,temp                    //    для срабатывания прервывания
                sei                                    //разрешаем все прерывания
                sbi        portb,0                        //пинаем пин, вызывая прерывание              
    main:        nop                                    //ковыряем в носу
                rjmp    main


    //--------*****ПОДПРОГРАММЫ*****--------------------------


    //---------*****ПРЕРЫВАНИЯ*****--------------------------


    PC_INT: sbi        portd,0 //импульс
            CBI        PORTD,0
            reti


     
     
  16. A.T.M

    A.T.M Нерд

    так же есть задержка порядка 25 микросекунд Безымянный.png
     
  17. A.T.M

    A.T.M Нерд

    На всякий случай контроллер снял с платы IMG_20170827_190926.jpg
     
  18. A.T.M

    A.T.M Нерд

    Разобрался! Записал единичку в fuse-бит ckdiv8 и все заработало:cool::cool::D:D:rolleyes::rolleyes: