ATtiny85 и работа с EEPROM

dizzel
Offline
Зарегистрирован: 21.03.2016

Имеется скромный проект из данного МК и набора из шести светодиодов WS2812, которыми он управляет. Это подсветка. Режимов у подсветки целый набор. В один прекрасный вечер решил, что информацию о режиме подсветки будет удобнее хранить в ПЗУ, чтобы каждый раз при выкл/вкл подстветка продолжала работать в том режиме, когда отрубили питание.

Написал код. Проверил на макете с Attiny85. Вроде все ок. Но вот при работе в реальных условиях режим часто либо не восстанавливается (леды не горят и нет реакции на нажатие кнопки), либо режим перескакивает на другой (чаще +1, но бывает и больше).

Спасает обнуление ЕЕПРОМа и запись прошивки по новой, но чтобы с этим не мучится в сетап добавил пару строк:

if (EEPROM.read(addr) > NUM_PATTERNS || EEPROM.read(addr) < 0)
{
EEPROM.write(addr,0);
}
Теперь перепрошивать не нужно, а режим тупо сбрасывается на ноль. Следовательно происходит что-то с инфой в конкретном адресе (адрес - переменная addr присвоен тип int и значение 0) ЕЕПРОМа. Раз срабатывает этот кусок кода, значит по адресу находится какое-то неприемлемое значение и режим улетает куда-то за пределы, а чтобы этого этого не происходило присваиваем ему ноль, если такая хрень случается.

В loop у меня сидит функция startShow (EEPROM.read(addr)), которая на основе прочитанного из addr зажигает тот или иной режим подсветки, которых от 0 до 14 (NUM_PATTERNS). 0 - выкл.


Для каждого режима подсветки написана отдельная функция. В каждой из них обрабатывается нажатие кнопки, которая перебирает режимы от 0 до 14. Нажатие кнопки также сидит в своей функции. Вот она:
boolean chkBtn(int buttonState) {
if (buttonState == HIGH && (millis() - mark) > BTN_DELAY) {
mark = millis();
pattern = EEPROM.read(addr);
pattern++;
if (pattern > NUM_PATTERNS) {pattern = 0;}
EEPROM.write(addr, pattern);
return true;
}
else { return false; }
}

Здесь она соответственно считывает из ЕЕПРОМа данные о режиме, записывает их во временную переменную pattern (тип byte), прибавляет к ней единичку, проверяет не вылетели ли мы за пределы, а если да то начинаем отсчет с начала, если ок, то записываем переменную в ЕЕПРОМ.

При изучении глюка выяснилось, что на макетке тоже не все так радостно. В лучшем случае режим работы подсветки работал (корректно восстанавливался) 5 раз из 10 включений.

Однако если залить эту самую прошивку в Atmega328 (Arduino NANO) глюка нет. Чую что не правильно работаю с ЕЕПРОМом (юзаю стандартную библиотеку из Arduino IDE), глюк в прошивке. Правда есть одно но. Тини работает в очень скромной "обвязке" - 2 кондера по питанию 0,1мкф, 100мкф и все. А Atmega328 располагается на нашпигованой плате.

Помогите советом...

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

1. Код надо приводить полностью. Например, мне кажется, у Вас ошибка в строке №6, но по этому куску уверенно не скажешь.

2. Как установлен фьюз EESAVE?

dizzel
Offline
Зарегистрирован: 21.03.2016

Большое спасибо за мысль с фьюзом. Как он стоит сейчас не вспомню, но как только будет возможность проверью и отпишусь. Сответственно тогда и скину код.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

и никада не пиши в AVR EEPROM ничего значимого с адреса 0, протухает время от времени. Пиши начиная хотя бы с 0x10.

sadman41
Offline
Зарегистрирован: 19.10.2016

DetSimen пишет:

и никада не пиши в AVR EEPROM ничего значимого с адреса 0, протухает время от времени. Пиши начиная хотя бы с 0x10.

Семён, развенчание этих сказок Atmel уже даже в FAQ вынес. Пишут, что была проблема, когда при внезапном отключении питания нулевая ячейка не успевала записаться. Но ее давно уже пофиксили, ввели в чип мониторы напряжения или типа того.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

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

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

sadman41 пишет:

ее давно уже пофиксили

Это микрочип пофиксил, а Вы уверены, что то, что мы закупаем в Поднебесной имеет отношение к микрочип?

dizzel
Offline
Зарегистрирован: 21.03.2016

Спасибо за совет. Тоже попробую.

sadman41
Offline
Зарегистрирован: 19.10.2016

ЕвгенийП пишет:

sadman41 пишет:

ее давно уже пофиксили

Это микрочип пофиксил, а Вы уверены, что то, что мы закупаем в Поднебесной имеет отношение к микрочип?

Справки я не выдаю, рентгеном все чипы не просвечиваю. О чем прочитал - тем поделился.

Клапауций 089
Клапауций 089 аватар
Offline
Зарегистрирован: 14.01.2018

ЕвгенийП пишет:

sadman41 пишет:

ее давно уже пофиксили

Это микрочип пофиксил, а Вы уверены, что то, что мы закупаем в Поднебесной имеет отношение к микрочип?

я уверен - лично вам продают палёные контроллеры и палёную водку.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Клапауций 089 пишет:

палёную водку.

Ты ошибся, родной, он водку не покупает. Ему продают палёный боярышник.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

это мне всё паленое продають. 

dizzel
Offline
Зарегистрирован: 21.03.2016

Как и обещал привожу код ниже целиком:

#include <EEPROM.h>
#include <Adafruit_NeoPixel.h>

#define RND_PIN 5             //для рандома (5 для ATTiny85 1ая нога)
#define PHOTO_PIN 4           //фоторезистор (3 для ATTiny85 2ая нога)
#define NUM_LEDS 6            //кол-во светодиодов
#define DATA_PIN 2            //output pin (0 для ATTiny85 5ая нога) mega328 - 2
#define BTN_PIN 3             //input pin (4 для ATTiny85 3ья нога) mega328 - 3
#define BTN_DELAY 250         //задержка для дребезга
#define NUM_PATTERNS 14       //кол-во эффектов
#define PHOTO_MIN 20          //минимальный порог показания датчика освещенности
#define PHOTO_MAX 800         //максимальный порог показания датчика освещенности
#define BRIGHT_MIN 150        //минимальная яркость
#define BRIGHT_MAX 255        //максимальная яркость
#define PHOTO_LATENCY 10000   //период опроса датчика освещенности

//массивы
uint32_t colorset[] = {0xFF0000, 0x00FF00, 0x0000FF, 0xFFC000, 0xFF4000, 0xFF0C00, 0xFF0040,
                       0xFF7F00, 0x00FFFF, 0xFF00FF, 0xC0FF00, 0x40FF00, 0x00FFC0, 0x00FF40,
                       0xFF007F, 0x7FFF00, 0x7F00FF, 0xC000FF, 0x4000FF, 0x00C0FF, 0x0040FF,
                       0xFFFF00, 0x00FF7F, 0x007FFF};
uint32_t RGB[] =      {0,0,0,0,0,0};

//общие переменные
uint8_t   num = 0;
uint8_t   buttonState = 0;
uint8_t   direction = 1;
uint8_t   j = 1;
uint32_t  mark, lastCheckPhoto;
byte      pattern = 0;
int       addr = 0;

//ledJump переменные 
uint8_t   total_leds;
uint8_t   r;

//randomFader переменные
uint8_t   lastRND;
uint8_t   lastPix = 0; 
uint8_t   myPix = 0;
uint32_t  pastColor = 0;

//colorFader переменные
int8_t    direct1 = 1;
int8_t    direct2 = -direct1;
uint8_t   v = 0;
int16_t   color1 = 0;
int16_t   color2 = 0;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, DATA_PIN, NEO_GRB + NEO_KHZ800); 

void setup() {
  delay (1500);
  randomSeed(analogRead(RND_PIN));
  pinMode(BTN_PIN,INPUT);
  strip.begin();
  strip.show();
  delay (1500);
  if (EEPROM.read(addr) > NUM_PATTERNS || EEPROM.read(addr) < 0) 
    {
      EEPROM.write(addr,0);
    }
}

void loop() {
  if (direction == 1) { j++; } else { j--; }
  if (j > 254 || j < 1) {direction = -direction;}
  if (millis() - lastCheckPhoto > PHOTO_LATENCY) {
    uint16_t photo = constrain(analogRead(PHOTO_PIN), PHOTO_MIN, PHOTO_MAX);
    uint8_t bright = map(photo, PHOTO_MIN, PHOTO_MAX, BRIGHT_MIN, BRIGHT_MAX);
    strip.setBrightness(bright);
    lastCheckPhoto = millis();
  }
  startShow (EEPROM.read(addr));
}

void startShow (int show) {
  switch(show){
    case 0: fastColor(0,0,0); break;
    case 1: colorFader (1, 150, 10); break;
    case 2: colorFader (2, 150, 10); break;
    case 3: colorFader (3, 150, 10); break;
    case 4: if (num == 24) {num = 0;}
            ledJumpIn(100, 10000);
            ledJumpOut(100, 1000);
            num++;
            break;
    case 5: randomPixelFader (1500); break;
    case 6: randomStripFader(500); break;
    case 7: rainbowCycle(50); break;
    case 8: rainbow(50); break;
    case 9: fastColor(255,0,0); break;
    case 10: fastColor(255,255,0); break;
    case 11: fastColor(0,255,0); break;
    case 12: fastColor(0,255,255); break;
    case 13: fastColor(0,0,255); break;
    case 14: fastColor(255,0,255); break;
  }
}

void ledJumpIn (uint16_t wait, uint16_t interval_) {
  total_leds=NUM_LEDS;
  for (int i = 0; i < total_leds; i++) {
    strip.setPixelColor(i, colorset[num]);
    strip.show();
    if (i == total_leds-1) {
      i=-1;  
      --total_leds;
      if (total_leds == -1) { break;}
    }
    timer(wait);
    strip.setPixelColor(i, 0);
    strip.show();
  }
  timer(interval_);
}

void ledJumpOut(uint16_t wait, uint16_t interval_) {
  total_leds = NUM_LEDS; r = 1;
  for (int i = NUM_LEDS-1; i < total_leds+1; i++) {
    if (r == total_leds+1) {break;}
    strip.setPixelColor(i, colorset[num]);
    strip.show();
    if (i==total_leds) {
      ++r; 
      i -= r;
    }
    timer(wait);
    strip.setPixelColor(i, 0);
    strip.show();
  }
  timer(interval_);
}

void colorFader (int8_t colormode, uint16_t wait, uint16_t shift) {
  uint8_t red, green, blue;
  if (direct1 == 1) { v++; } else { v--; }
  color1 += direct1*shift; color1 = constrain (color1,0,255);
  color2 += direct2*shift; color2 = constrain (color2,0,255);
  switch (colormode) {
    case 1: red = color1; green = color2; blue = 0; break;
    case 2: red = 0; green = color1; blue = color2; break;
    case 3: red = color1; green = 0; blue = color2; break;
  }
  for (int pos = strip.numPixels()-1; pos > -1; pos--) {
    if (pos != 0) {
      strip.setPixelColor(pos, RGB[pos]);
      RGB[min(pos+1,strip.numPixels()-1)] = RGB[pos];
    } else if (pos == 0) {
      RGB[pos] = strip.Color(red, green, blue);
      strip.setPixelColor(pos, RGB[pos]);
      RGB[pos+1] = RGB[pos];
    }
  }
  strip.show();
  timer(wait);
  if (v == (255/shift) || v == 0) { direct1 = -direct1; direct2 = -direct2;}
}

void randomPixelFader(uint16_t wait) {
  uint32_t timer = 0;
  uint8_t colorPick[] = {0,0,0};
  uint8_t getRND1, getRND2;
  if (millis() - timer > wait) {
    if(myPix != lastPix) {
      getRND1 = (random(3));
      do {
        getRND2 = (random(3));
      } while (getRND1 == getRND2 || getRND2 == lastRND);
      colorPick[getRND1] = (random(255));
      colorPick[getRND2] = 255;
      fromColorToColor(myPix, 0, RGB[myPix], 10);
      RGB[myPix] = strip.Color(colorPick[0], colorPick[1], colorPick[2]);
      fromColorToColor(myPix, RGB[myPix], 0, 10);
      strip.show();
      timer=millis();
      lastPix=myPix;
      lastRND=getRND2;
    } else {
    myPix=random(0,strip.numPixels());}
  }
}

void randomStripFader(uint16_t wait) {
  uint8_t colorPick[] = {0,0,0};
  uint8_t getRND1, getRND2;
  getRND1 = (random(3));
    do {
      getRND2 = (random(3));
    } while (getRND1 == getRND2 || getRND2 == lastRND);
  colorPick[getRND1] = (random(255));
  colorPick[getRND2] = 255;
  uint32_t color = strip.Color(colorPick[0], colorPick[1], colorPick[2]);
  for(uint16_t d = 0; d < strip.numPixels(); d++) {
    fromColorToColor(d, color, pastColor, 2);
    timer(wait);
  }
  pastColor = color;
  lastRND = getRND2;
}

void rainbow(uint8_t wait) {
  for (uint16_t f = 0; f < strip.numPixels(); f++) {
    strip.setPixelColor(f, Wheel((f + j) & 255));}
  strip.show();
  timer (wait);
}

void rainbowCycle(uint8_t wait) {
  for (uint16_t g = 0; g < strip.numPixels(); g++) {
    strip.setPixelColor(g, Wheel(((g * 256 / strip.numPixels()) + j) & 255));}
  strip.show();
  timer(wait);
}

void fastColor (uint8_t red, uint8_t green, uint8_t blue) {
  for (uint16_t k = 0; k < strip.numPixels(); k++) {
    strip.setPixelColor(k, red, green, blue);
    strip.show();
    if(chkBtn(digitalRead(BTN_PIN))) { break; }
  }
}

void fromColorToColor(uint8_t pixel, uint32_t newColor, uint32_t oldColor, uint8_t wait) {
  int16_t new_c[3], old_c[3], diff[3], cur_c[3];
  for (uint8_t l = 0; l < 3; l++) {
    new_c[l] = (uint8_t)((newColor >> (16-(l*8))) & 0xff);
    old_c[l] = (uint8_t)((oldColor >> (16-(l*8))) & 0xff);
    cur_c[l] = old_c[l];
  }
  for (uint8_t q = 0; q < 255; q++) { 
    for (uint8_t w = 0; w < 3; w++) {
      if (cur_c[w] < new_c[w]) {diff[w] = 1;} else if (cur_c[w] > new_c[w]) {diff[w] = -1;} else {diff[w] = 0;}
      cur_c[w] += diff[w];
    }
    strip.setPixelColor(pixel,cur_c[0],cur_c[1],cur_c[2]);
    strip.show();
    timer(wait);
  }
}

void timer(uint16_t period) {
  uint32_t timer = 0;
  timer = millis();
  do {
    if(chkBtn(digitalRead(BTN_PIN))) { break; }
  } while (millis() - timer < period);
}

boolean chkBtn(int buttonState) {
  if (buttonState == HIGH && (millis() - mark) > BTN_DELAY) {
    j = 1;
    pastColor = 0;
    mark = millis();
    pattern = EEPROM.read(addr);
    pattern++;
    if (pattern > NUM_PATTERNS) {pattern = 0;}
    EEPROM.write(addr, pattern);
    return true;
  } 
  else { return false; }
}

uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

А вот по поводу фьюзов конфуз. Я вообще их не выставлял и как они должны быть выставлены не знаю. Если можно как-то выставить конкретный фьюз то как это сделать через тот же Ардуино ИДЕ например?

В Ардуино ИДЕ чтобы прошить ATtiny85 я выставляю настройки через меню следующим образом

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

И как Вы её прошиваете?

Давайте так, Вы не тяните кота за хвост, а расскажит епоностью.

1. Что за 85-ая? На какой плате? на самопальной или покупной? Если ли на плате кварц? Какой?

2. Как Вы её прошиваете? Командой "пршить через программатор" или у Вас там на плате FTDI имеется? Если через программатор, что какой?

Тогда я сомогу ответить про фьюзы и всё остальное. Потому как, если кварца нет, то 16МГц явно много. Должно быть 8 или 1 в зависимости от фьюзов. Ну и много всего - давайте информацию.

dizzel
Offline
Зарегистрирован: 21.03.2016

Извините, что не предоставил информацию заранее

Это ATTINY85-20SU SOIC8

Шью из Arduino IDE через Arduino NANO, который заранее прошил скетчем ArduinoISP из готовых примеров. Шью на обычной борде вот в таком виде только без светодиода с резистором

В готовом проекте кварц не использую

Для работы с Тини тянул библиотеки отсюда https://github.com/SpenceKonde/ATTinyCore

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Значит 16МГц - ТОЧНО мимо. Пробуйте 8, но чтобы гоаорить точно ... можете зайти в меню "Файл|настройки", Включить там подробный вывод загрузки и скопипастить сюда всё, что выдаётся во время загрузки?

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Я может че не знаю, но уже штук несколько программировал at85 там же просто выбирается в arduino ide нужный МК и жмется пункт записать загрузчик - ставиться нужная частота - нет? 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

И кстати attiny при 3 вольтах питания работает только при частоте 1 МГц 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Я не знаю, я ни разу не прошивал через ардуино.

Но точно я знаю, что

1. 16МГц (как стоит у ТС) без кварца невозможно
2. Если стоит 16МГц, а реально там 1 или 8, то всё, что связано со временем (millis, delay и т.п.) будет врать

Вот и пытаюсь узнать какие там у ТС фьюзы.

Штирлиц
Штирлиц аватар
Offline
Зарегистрирован: 13.06.2015

ЕвгенийП пишет:

1. 16МГц (как стоит у ТС) без кварца невозможно

ATtiny85 на частоте 16 МГц с использованием PLL должен работать нормально при напряжении питания  более 3,3В.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Штирлиц пишет:

ЕвгенийП пишет:

1. 16МГц (как стоит у ТС) без кварца невозможно

ATtiny85 на частоте 16 МГц с использованием PLL должен работать нормально при напряжении питания  более 3,3В.


Должен? Сами пробовали?

Штирлиц
Штирлиц аватар
Offline
Зарегистрирован: 13.06.2015

andycat пишет:
Штирлиц пишет:

ЕвгенийП пишет:

1. 16МГц (как стоит у ТС) без кварца невозможно

ATtiny85 на частоте 16 МГц с использованием PLL должен работать нормально при напряжении питания  более 3,3В.

Должен? Сами пробовали?

Нормально работает - интервалы соответствуют установленным.Работает от 5ти вольт. Что еще проверить ?Иде 1.8.5 , AttinyCore из ссылки ТС

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Штирлиц пишет:

andycat пишет:
Штирлиц пишет:

ЕвгенийП пишет:

1. 16МГц (как стоит у ТС) без кварца невозможно

ATtiny85 на частоте 16 МГц с использованием PLL должен работать нормально при напряжении питания  более 3,3В.

Должен? Сами пробовали?

Нормально работает - интервалы соответствуют установленным.Работает от 5ти вольт. Что еще проверить ?Иде 1.8.5 , AttinyCore из ссылки ТС

Я извиняюсь но вопрос был про 16 МГц и 3 вольта, а вы пишите что работает  при 5 вольт  . 

Впрочем не важно, пока сами на грабли не наступил это все теория. 

И вообще тема про eeprom - давайте придерживаться 

 

Штирлиц
Штирлиц аватар
Offline
Зарегистрирован: 13.06.2015

andycat пишет:

Я извиняюсь но вопрос был про 16 МГц и 3 вольта,

Где вопрос про 16Мгц   и 3 вольта?  Евгений спрашивал про возможность работы от внутреннего на 16Мгц. Вот я и ответил и проверил. А на 3,3 вольта если кому и надо - пусть проверяют.Хотя сейчас гляну...

Работает и на 3.3вольта. Но надо проверять на стабильность.

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Спасибо.