Что не так с кодом для ATTiny10?

UserJohn

✩✩✩✩✩✩✩
1 Апр 2024
3
0
Заголовок темы должен отражать содержимое. Исправь или тема будет удалена.
Вот код, который работает на ATTiny13, но не работает на ATTiny10:
C++:
uint16_t note[7]={1911, 1432, 1517, 1432, 956, 956, 1911};
uint8_t i ;
uint32_t ms ;

void setup() {
  pinMode(PB2, OUTPUT);
  i = 0;
  ms = millis();
}
  void loop() {
  ms = millis();
   do {
   digitalWrite(PB2, HIGH);
   delayMicroseconds(note[i]);
   digitalWrite(PB2, LOW);
   delayMicroseconds(note[i]);
      }
    while (millis() - ms < 500);
   ms = millis();
   digitalWrite(PB2, LOW);
   delay(10);
   i++;
   if (i == 7) {
   digitalWrite(PB2, LOW);
   delay(500);
    i = 0;
     }
   }
Что надо изменить?
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
568
138
А каким ядром для 10-й тиньки вы пользуетесь? В видео от "Заметки Ардуинщика" говорится, что ядро Attiny10Core не поддерживает никакие Ардуино функции. Смотреть с 3:45
 

UserJohn

✩✩✩✩✩✩✩
1 Апр 2024
3
0
@viktor1703, Ядро ATTiny10 Core с аддоном из "Заметок". В скетче автора (про диммер), вроде, все команды те-же используются, но у него работает, а у меня - нет...

@viktor1703, Может есть альтернатива массиву, аддон, может, с массивами не работает?
 

poty

★★★★★★✩
19 Фев 2020
3,117
919
@UserJohn, Attiny10 имеет в 2 раза меньше памяти (32 байт) чем 13-ая (64 байт). Скорее всего, просто переполняется стек, так как используются "длинные" переменные (типа ms, занимающей сразу 4 байта) и массив note (7*2=14 байт). Вызов процедуры тратит ещё как минимум 4 байта в памяти (стеке), ну и т.д. Надо оптимизировать код, а лучше - использовать аппаратный таймер для генерации тонов.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
370
112
@poty,
Я удалил свое предыдущее сообщение, т.к. оказывается ATTiny10 сильно отличается от остальных, Proteus непонятно - симулирует ее или нет, и мои советы были непроверенными. Но памяти вроде хватает (на скорою руку загрузил в AtmelStudio, но давно ей не пользовался и могу ошибаться). Константы она оказывается по умолчанию размещает во FLASH и на массив констант память не тратится. Но наверно настройками можно заставить тратить.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
370
112
@bort707,
Опытным. Но я в первый встретил ATtiny10, может это и написано где то, а может настраивается.
Потом прочитал даташит, и хотя он не описывает компилятор, но если это так "прозрачно", то почему бы компилятору не поступать так по умолчанию.
Из даташита на ATtiny10
Constant tables can be allocated within the entire address space of program memory by using load/store
instructions. Since program memory can not be accessed directly, it has been mapped to the data
memory. The mapped program memory begins at byte address 0x4000 in data memory. Although
programs are executed starting from address 0x000 in program memory it must be addressed starting
from 0x4000 when accessed via the data memory.
 

poty

★★★★★★✩
19 Фев 2020
3,117
919
@Bruzzer, приведённая выдержка из datasheet говорит только о том, что можно разместить константы в программной памяти, а не о том, что они там размещаются по умолчанию. Доступ осуществляется через _pgm.
Каким образом Вы определили, что памяти хватает? (Не программной памяти, а памяти данных). Не забывайте, что функции времени (millis, micros) также имеют внутренние переменные.
По факту, нужно по-максимуму убрать вызовы функций, глобальные переменные, использовать только одно-, двухбайтовые вычисления... Для начала ограничить массив 2-3 значениями (или убрать в progmem). Если есть отладчик, можно последить за указателем стека.
 
  • Лойс +1
Реакции: bort707

Bruzzer

★★★✩✩✩✩
23 Май 2020
370
112
Каким образом Вы определили, что памяти хватает?
Я же написал - "На скорую руку загрузил в AtmelStudio" (код из HEX от Ардуино). Запустил там симулятор и посмотрел на пересечение стека и данных. Но поскольку "На скорую руку" то и написал "Вроде хватает".
 

UserJohn

✩✩✩✩✩✩✩
1 Апр 2024
3
0
Вопрос решен на форуме Arduino.ru. Проблема была в переполнении ОЗУ функцией millis в аддоне для ядра ATTiny10 Core.

C++:
uint16_t note[7] = { 1911, 1432, 1517, 1432, 956, 956, 1911 };

void setup() {
  DDRB |= (1 << PB2);
}

void loop() {
  for (uint8_t i = 0; i < 7; i++) {
    uint16_t ms = 0;
    do {
      PORTB |= (1 << PB2);
      for (uint16_t j = note[i]; j > 0; j--) _delay_us(1);
      PORTB &= ~(1 << PB2);
      for (uint16_t j = note[i]; j > 0; j--) _delay_us(1);
      ms += (note[i] / 100) * 2;
    } while (ms < 5000);
  }
  _delay_ms(500);
}
Автор кода форумчанин с ником xDriver. Прекрасно работает...
 
Изменено:

Bruzzer

★★★✩✩✩✩
23 Май 2020
370
112
Поскольку тема называется, что не так с кодом для ATtiny10, оставлю свои наблюдения.
Работа с таймером и задержками в дополнении от Гайвера написана неаккуратно, и даже если памяти хватает, то лучше millis не использовать.
Вместо
C++:
uint32_t millis(void) {
    return (uint32_t)timer0_millis;
Должно быть что то похожее на
C++:
uint32_t millis(void) {
    uint32_t tmpTime;
    uint8_t tmpSREG = SREG;
    cli();
    tmpTime = timer0_millis;
    SREG = tmpSREG;
    return tmpTime;            
}
Сейчас уже не актуальна оптимизация под малые количества памяти. Но если кому это интересно, то посмотреть на работу этого аддона, его особенности (или косяки) а так же особенности (или косяки) настроек компилятора по умолчанию познавательно. Т.к. и аддон маленький (легко изучить), и памяти мало - эффект от экономии может быть весомым.
Я не спец в программировании, поэтому меня несколько удивило, что по умолчанию, на вызов main в любом случае тратится 2 байта на стеке, хотя этот вызов в МК не нужен и возврата из него нет, и что при входе в прерывания, регистр R1 (R17 в случае ATtiny10) сохраняется на стеке, даже если не используется.