2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1, 2, 3
 
 Re: Странное поведение fuses в atmega8a
Сообщение27.04.2025, 13:35 
Заслуженный участник


20/08/14
12141
Россия, Москва
Кстати совет про другой проц/МК - хорош: скажем среда ардуино поддерживает STM32F103, а это уже честный 32-битный проц, с быстрым доступом к памяти (вместо 3 такта на байт в AVR - это же мрак!), с DMA и на uart и на i2c, с частотой до 72МГц, аппаратным умножением и делением, бывают со встроенным аппаратным USB, по цене как avr меги. Правда от 5В не работает, и встроенной eeprom (для настроек) нет.

Хотя по моему и мега вполне справится с задачей если сделать аккуратно на прерываниях (приём по i2c и суммирование в массиве, uart можно оставить и как есть, без прерываний, но только в главном цикле). И даже кварца типа 3МГц хватит (а от 8МГц должно остаться 2/3 свободного времени).

 Профиль  
                  
 
 Re: Странное поведение fuses в atmega8a
Сообщение28.04.2025, 01:02 


15/12/22
235
Dmitriy40 в сообщении #1683916 писал(а):
Прерывание по I2C есть конечно: "18 0x011 TWI Two-wire Serial Interface".
Как им пользоваться смотрите описание работы TWI, например на стр.167 Figure 21-10 для записи данных в I2C, стр.171 Table 21-3 как реагировать на разные события при передаче. Со стр.173 раздел 21.6.3 о приёме, на стр.175 подробно статус и реакции. Все отсылки по текущему выложенному pdf
.

спасибо Dmitriy40, похоже просто я не разобрался до конца, использую аппаратный TWI а соответствующие прерывания - нет, это конечно ненормально, теперь думаю разберусь.

-- 28.04.2025, 01:22 --

Помнится, я тут спрашивал, почему minipro стирает fuses. Опытным путём разобрался. Пожалуй выложу здесь, а то про него в инете почти ничего не написано. Прошивать нужно так:
Код:
minipro -p ${MCU} -z -e -w ${TARGET}.hex -c code

опция -z просто проверяет все ли пины подключены, -e запрещает стирать чип (без неё то fuses и выставляются по дефолту), - w указывает что выполняется запись, ${TARGET}.hex - это файл прошивки, -c code указывает, что записывается область программ.

установленные fuses можно считать командой:
Код:
minipro -p ${MCU} -r fuses.conf -c config

если что то не устраивает, файл fuses.conf можно подправить как нужно, и записать командой:
Код:
minipro -p ${MCU} -z -u -e -w fuses.conf -c config

опция -u это разблокировка, с ней будто бы получается надёжнее, но у меня прошивалось и без неё.

ещё старание чипа (если он вдруг залочен):
Код:
minipro -p ${MCU} -E


* это всё для весьма популярного программатора TL866 под Linux.

-- 28.04.2025, 01:37 --

Dmitriy40 в сообщении #1683945 писал(а):
совет про другой проц

да, stm сейчас в моде, но я с ними не работал, а с avr опыт довольно большой, так что пока позволяют возможности,буду обходиться ими, если уж совсем никак - придётся изучать stm.

Dmitriy40 в сообщении #1683945 писал(а):
среда ардуино поддерживает STM32F103

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

 Профиль  
                  
 
 Re: Странное поведение fuses в atmega8a
Сообщение28.04.2025, 22:25 


15/12/22
235
Dmitriy40
есть ещё вопрос, я тут обнаружил, что atmega8a у меня потребляет больше 10 мА, это вообще нормально по Вашему?

 Профиль  
                  
 
 Re: Странное поведение fuses в atmega8a
Сообщение28.04.2025, 23:47 
Заслуженный участник


20/08/14
12141
Россия, Москва
Missir в сообщении #1684243 писал(а):
я тут обнаружил, что atmega8a у меня потребляет больше 10 мА, это вообще нормально по Вашему?
Вот уж я точно без понятия. В pdf есть данные по току потребления на разных частотах, но это только тот ток, что утекает внутрь кристалла, к нему добавляется ток через выходные пины в лог.1 если они на что-то нагружены - а этого Вы не показывали.
По графику если 3.3В продолжить до 16МГц, будет около 6мА. Плюс включенный таймер и I2C (и UART), легко на 1-2мА потянет. Плюс это typical значения, максимально допустимые могут быть и вдвое больше. Так что в 10мА ничего особо странного нет, это не 50мА.

 Профиль  
                  
 
 Re: Странное поведение fuses в atmega8a
Сообщение29.04.2025, 03:13 


15/12/22
235
Dmitriy40
в общем я переписал код как положено, во внешнем прерывании толко старт i2c, остальное в прерывании TWI, посмотрел примеры в инете, вот что получилось

код: [ скачать ] [ спрятать ]
Используется синтаксис C

ISR(INT0_vect)
{    
    TWCR=(1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // START
    send_uart('A');
}

ISR(TWI_vect)
{   static uchar n;
    static union {uchar byts[2]; short v;} num;
    switch(TWSR & 0xF8)
    {
       case 0x08: send_uart('B'); TWDR = GY521<<1; TWCR = (1<<TWINT) | (1<<TWEN); break;
       case 0x10: send_uart('C'); TWDR = (GY521<<1)|0x01; TWCR = (1<<TWINT) | (1<<TWEN); n=0; break;
       case 0x18: send_uart('D'); TWDR = 0x3B; TWCR = (1<<TWINT) | (1<<TWEN); break;
       case 0x28: send_uart('E'); TWCR=(1<<TWINT) | (1<<TWSTA) | (1<<TWEN); break;      // START
       case 0x40: send_uart('F'); if (n & 0x01)                                      // REC
                  { if (n == 13) TWCR = (1<<TWINT)|(1<<TWEN);           // END
                  else TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);           // NO END
                  num.byts[0]=TWDR; vals[n>>1]=num.v;
                  }
                  else { TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA); num.byts[1]=TWDR; }
                  n++;  break;
       case 0x50: send_uart('G'); TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO); d=1; break; // STOP i2c
    }
}

 

в принципе тот же самый алгоритм, буквы по uart отправляю для проверки,
приходит только буква А, внешнее прерывание срабатывает, а прерывание TWI - ни разу. Быть может Вы знаете в чём может быть дело?

 Профиль  
                  
 
 Re: Странное поведение fuses в atmega8a
Сообщение29.04.2025, 11:45 
Заслуженный участник


20/08/14
12141
Россия, Москва
Missir
Поставьте send_uart() сразу по входу в TWI_vect() - может оно срабатывает, только статус не попадает на указанные. А скорее вообще не срабатывает так как не разрешено, см. ниже.
Потом замените отсылку буквы на отсылку регистра TWSR без обработки дальше (только send_uart_str(sprintf("%02X,",TWSR)) и всё, выход).
Потом верните обработку статуса - должны увидеть как именно перещёлкиваются статусы.

Вы забыли разрешить прерывания от TWI (TWIE в TWCR), все записи в TWCR его обнуляют.
Кроме того, сброс флага прерывания TWINT в TWCR надо делать в начале обработчика - до реакции на TWSR, иначе от записи в TWDR может успеть возникнуть новое прерывание с другим статусом, которое Вы и сбросите последующей записью в TWCR (ну или писать в TWDR после записи в TWCR). Например командой TWCR|=1<<TWINT; в самом начале прерывания, а потом уже разбираться с TWSR.


Ещё hint: вызов обработчика довольно затратный (call+rjmp+reti это уже 9 тактов, плюс сохранение и восстановление регистров если компилятор это делает), потому если нужна максимальная скорость обмена по I2C за счёт всего остального, то можно обернуть весь код обработчика в цикл do { ... } while TWCR&(1<<TWINT); - так он будет непрерывно обрабатывать все возникающие прерывания если они успеют выставиться до выхода из обработчика (например сигналы stat и stop).

 Профиль  
                  
 
 Re: Странное поведение fuses в atmega8a
Сообщение29.04.2025, 18:21 


15/12/22
235
Dmitriy40
в силу своей ограниченности понял наверное не всё и сделал пока вот так:
код: [ скачать ] [ спрятать ]
Используется синтаксис C
ISR(INT0_vect)
{    
    send_uart('A');
    TWCR=(1<<TWIE) | (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // START
}

ISR(TWI_vect)
{   static uchar n;
    static union {uchar byts[2]; short v;} num;

    send_uart('q');
    switch(TWSR & 0xF8)
    {
       case 0x08: send_uart('B'); TWDR = GY521<<1; TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEN); break;
       case 0x10: send_uart('C'); TWDR = (GY521<<1)|0x01; TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEN); n=0; break;
       case 0x18: send_uart('D'); TWDR = 0x3B; TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEN); break;
       case 0x28: send_uart('E'); TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); break;      // START
       case 0x40: send_uart('F'); if (n & 0x01)                                      // REC
                  { if (n == 13) TWCR = (1<<TWIE) | (1<<TWINT)|(1<<TWEN);           // END
                  else TWCR = (1<<TWIE) | (1<<TWINT)|(1<<TWEN)|(1<<TWEA);           // NO END
                  num.byts[0]=TWDR; vals[n>>1]=num.v;
                  }
                  else { TWCR = (1<<TWIE) | (1<<TWINT)|(1<<TWEN)|(1<<TWEA); num.byts[1]=TWDR; }
                  n++;  break;
       case 0x50: send_uart('G'); TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO); d=1; break; // STOP i2c
    }
}
 


при включении по uart вывод такой:
Цитата:
AqBqDqEqCqFqG +000000 +000000 +0000A00 +000000 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA......


т.е. правильно проходит весь цикл, но почему то всего 1 раз, потом прерывание TWI работать перестаёт, ну и числа почему то нулевые, хотя vals глобальный массив типа volatile

 Профиль  
                  
 
 Re: Странное поведение fuses в atmega8a
Сообщение29.04.2025, 20:24 
Заслуженный участник


20/08/14
12141
Россия, Москва
Missir
Оказывается я ошибся (спутал с UART, где запись/чтение в/из UDR инициирует передачу/приём), надо сначала обработать TWDR (прочитать или записать), а уже потом сбрасывать TWINT в TWCR. Соответственно чтения у Вас в неправильном порядке.

Далее, по 0x40 (это момент когда девайс ответил правильным ACK) надо запустить чтение байтов с выдачей ACK (или без ACK если осталось последний байт прочитать), но сами байты будут приходить по 0x50 кроме последнего (который без ACK), последний байт по 0x58 и там же выдавать stop.

Т.е. по идее должна быть такая последовательность событий:
даём start,
0x08 (ушёл start, посылаем адрес с битом записи),
0x18 (ушёл адрес, посылаем регистр 0x38),
0x28 (ушёл байт данных, посылаем repeat start),
0x10 (ушёл повторный старт, посылаем адрес с битом чтения),
0x40 (ушёл адрес, запускаем приём байтов с ACK),
12 раз 0x50 (пришёл байт с ACK, повторяем снова с ACK),
0x50 (пришёл 13-й байт с ACK, повторяем снова уже без ACK),
0x58 (пришёл 14-й байт без ACK, посылаем stop).
В итоге 13 байтов принимаются по 0x50, последний по 0x58.

Почему не запускается в следующие разы я не знаю.
Уберите приём вообще и выдавайте стоп сразу в 0x28 - будет ли перезапускаться по таймеру.

Hint: в union можно было забрать не v[], а сразу val[] (или как 7 слов или как 14 байтов) - и просто читать в него 14 байтов в нужном порядке.

 Профиль  
                  
 
 Re: Странное поведение fuses в atmega8a
Сообщение29.04.2025, 21:41 


15/12/22
235
Dmitriy40 в сообщении #1684381 писал(а):
Уберите приём вообще и выдавайте стоп сразу в 0x28 - будет ли перезапускаться по таймеру

представляете, теперь работает постоянно:
Цитата:
AqBqDqE +000000 +000000 +000000 +AqBqDqE000000

до стоп доходит как положено, видимо что то при считывании

-- 29.04.2025, 21:50 --

Dmitriy40
но прироста производительности я что то не вижу. Между внешними прерываниями основной цикл успевает вывести всего 3 числа из 7,
в то время как в варианте с while(!(TWCR & (1<<TWINT))) {}; всё выводится отлично (сейчас частота внешних прерываний 20 гц)

 Профиль  
                  
 
 Re: Странное поведение fuses в atmega8a
Сообщение30.04.2025, 00:13 
Заслуженный участник


20/08/14
12141
Россия, Москва
Missir в сообщении #1684393 писал(а):
в то время как в варианте с while(!(TWCR & (1<<TWINT))) {}; всё выводится отлично
И уверены что тогда не было потерь прерываний таймера? У Вас всего один символ выводился дольше чем прерывания были (9600/10<1кГц)! Я ведь предлагал замерить сколько реально проходит прерываний таймера за минуту (символов A в консоли).

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 40 ]  На страницу Пред.  1, 2, 3

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: Bing [bot]


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group