2014 dxdy logo

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

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




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


20/08/14
12140
Россия, Москва
Кстати совет про другой проц/МК - хорош: скажем среда ардуино поддерживает 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
234
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
234
Dmitriy40
есть ещё вопрос, я тут обнаружил, что atmega8a у меня потребляет больше 10 мА, это вообще нормально по Вашему?

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


20/08/14
12140
Россия, Москва
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
234
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
12140
Россия, Москва
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
234
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
12140
Россия, Москва
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 байтов в нужном порядке.

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

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



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

Сейчас этот форум просматривают: нет зарегистрированных пользователей


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

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