Здравствуйте, столкнулся со следующей проблемой. Написал код для attiny 2313 чтобы использовать ее usi как i2c слейв. Прошиваю attiny2313, все работает. Прошиваю attiny2313a, ни чего не работает, из-за того что прерывание по состоянию старт еще не сработало, а ардуино-мастер уже прислал по и2с один-два импульса тактирования. С прерыванием по переполнению счетчика usi тоже все долго. Замерил логическим анализатором: при частоте тактирования 2 МГц время между возникновением условия старт и срабатыванием прерывания составляет порядка 25 микросекунд. Почему так может быть подскажите?
На момент получения сидит в каком-нибудь энергосберегающем режиме, или другом прерывании. Хотя не очень понятно, зачем вам прерывание по старту, и как так вы задержку внутри чипа смогли измерить.
Разобрался, действительно сидит в другом прерывании.Проснулся сегодня утром,прочитал ваше сообщение и сообразил, а вчера все силы ушли чтобы понять, в чем же причина неработающего интерфейса. Прерывание по старту использую чтобы подготовить USI к приему данных по и2с, а задержку определил по осциллограмме, заметил состояние старт, и в момент возникновения прерывания перевел незадействованную ногу в высокое состояние
странно,однако, что на старом чипе все работает, а на 2313a неправильный код не работает. Загвоздка в том, по видимому,что тинька сидит в прерывании от таймера. На таймере сделана задержка, до прерывания usi контроллер совершает циклическое действие, само прерывание от таймера - выполнение всего одной команды sbt, кажется не должно быть долго. Еще предстоит прояснить проблему...
. Переписал код, убрал другие прерывания, оставил только USI, так же как нет ни каких энергосберегающих режимов. От куда может быть задержка? Помогите?
.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
Посмотрел код.Мне понравилось написано красиво и толково.Здесь засад быть не должно.Рискну предположить что проблема в аппаратной части.Тини 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 ; Переполнение охранного таймера
Смутило вот ещё что:отключение аналогово компаратора вроде бы по фен-шую но у вас есть странная функция init: Это ошибка или она что то делает в коде? Код (C++): //---------отключение аналогового компаратора-------------- init: ldi temp, 0x80 out ACSR, temp У меня так: Код (C++): ;--------------------------- Инициализация компаратора ldi temp, 0x80 ; Выключение компаратора out ACSR, temp
Да, DetSimen говорит так, как я делал. Делаю так, потому что прочитал где-то когда-то: ресет самый первый вектор прерывания,он должен быть определен. По таблице прерываний не вижу отличий,но нахожу вашу более информативной. Когда компилил код, стояло Т2313, поставил Т2313А не помогло. Вообще дело было так. Вытравил я плату, спаял, начал отлаживать, отлаживал, отлаживал, все вроде бы работало на этом коде. Потом пошла черная полоса, и все перестало работать(((( Началось с того что я спалил ардуину и Т2313а. Долго думал как так получилось, но не разобрался толком, где тот момент, когда SDA на обоих устройствах сконфигурированы как выходы и на одном 0, на другом 1. Дальше взял другую ардуину и запаял на мою плату новый Т2313А и дальше эта проблема с интерфейсом, много чего перепробовал прежде, чем понял что есть какая-то задержка в прерывании. Сначала думал что проблема просто с чипом, брак попался, тем более чипы были куплены на АЛИ по дешевке и первый запаяный чип был просто нерабочим, я перепаял все оставшиеся 8 - интерфейс тупит. Ну, думаю, Китайцы! Пошел в местный провереный радиомагазин, купил в 5 раз дороже - тоже самое интерфейс тупит. Вобщем, я почти все что мог уже перепробовал,не знаю в чем беда, задержка на т2313а, на простом т2313 ее нет, все работает
Где то есть плавающий баг.Посмотрел еще раз вроде все должно работать но есть пара вопросов по синтаксису у Вас в конце блоки к_мастеру и от_мастера это ведь подпрограммы?Не прерывания?Почему выход из них reti а не ret? Ну и по поводу кЕтайских чипов.Купил я тут давеча пачку Мег8 по смешной цене Наебае оказались с битым ЕЕПРОМ сначала думал сам дурак потом прочитал кажется у DiHalta что есть такие приколы у китайцев и даже идут с битым Флешем это похуже будет.
Мне стало интересно: только ли на 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