Приветствую. Пытаюсь перенести кусок кода не своего с ATmega128 на ATmega2560, и возникает проблема с записью из SRAM в EEPROM, а конкретно записывает одну переменную из семи, и дальше зависает. AVR Studio 4.18, оптимизация O3/Os
Код:
#define F_CPU 8000000UL // Я использую кристалл 8 МГц
/* Эта функция запускает процесс сохранение структуры конфигурации из sram в eeprom и немедленно возвращает управление,позволяя обработчику прерывания EEPROM продолжить работу по сохранению данных. */ uint8_t storeConfig(void) {
/* время выполнения этого прерывания может быть достаточно высоким в случае самой плохой ситуации, это должно быть обязательно исследовано! */ SIGNAL(SIG_EEPROM_READY) { uint8_t *pe, *ps; uint8_t ebyte;
pe = (uint8_t *)&config_ee + eeprom_store_idx; /* адрес данных в eeprom */ ps = (uint8_t *)&config + eeprom_store_idx; /* адрес данных в sram */ ebyte = eeprom_read_byte(pe);
/* перезаписывать данные в eeprom будем только если это необходимо */ /* сравним содержимое структур в sram и eeprom, выход из цикла осуществляем по первому найденному различию в данных */ while( (ebyte == *ps) && (eeprom_store_idx != (sizeof(struct config_t) - 1)) ) { eeprom_store_idx++; pe++; ps++; ebyte = eeprom_read_byte(pe); }
/* записываем новое значение в eeprom */ if (ebyte != *ps) eeprom_write_byte(pe, *ps);
/* если последняя запись в структуре не достигнута переходим к поиску следующего различия данных в sram и eeprom */ if (eeprom_store_idx == sizeof(struct config_t)-1) { /* запись закончена */ EECR &= ~_BV(EERIE); /* запретить прерывание от eeprom */ eeprom_store_busy = 0; /* сбросить флаг, eeprom занято*/ PORTB &= ~_BV(PB7); /* погасить светодиод */ } else { /* переходим к следующему различию */ eeprom_store_idx++; PORTB |= _BV(PB7); /* зажечь светодиод */ /* необходимо отметить, если светодиод горит более 5 сек следует снять питание с контроллера иначе возможно повреждение eeprom */ } }
int main(void){
DDRB |= _BV (PB7); //установить как выход LED PORTB &=~ _BV (PB7); //установить 0 LED
Для записи остальных переменных нужно шесть раз сбросить работу МК, нажатием на кнопку RESET. Предполагаю что обработчик прерывания SIG_EEPROM_READY не генерируется постоянно. Либо сбрасывается EERIE где-то. Что я делаю не так? Где может быть ошибка?
Я бы прогнал код в симуляторе студии и посмотрел, что к чему.
Обязательно учесть тот факт, что при выходе из прерывания, МК ОБЯЗАТЕЛЬНО исполняет одну следующую инструкцию программы (в данном случае функция main) и только потом снова входит в обработчик прерывания.
Ну и студию обновить до последней версии. Возможно, что что-то поменялось аппаратно у МК.
Да, программа зависала в функции storeConfig() потому что перезапускалась через main. Но в симуляции ни разу не сработало прерывание SIG_EEPROM_READY, хотя в реале один раз запускается. Вынес функцию storeConfig() из main в прерывание таймера
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
EEPE сбрасывается после записи, а если записи до этого не было?
Значит всё: сушим вёсла. Прерывания по готовности контроллера EEPROM не будет. В SPI та же проблема - флаг не встаёт, пока не запишешь в data регистр. Приходится писать, а только потом прерывание.
/* Эта функция запускает процесс сохранение структуры конфигурации из sram в eeprom и немедленно возвращает управление,позволяя обработчику прерывания TIMER0 продолжить работу по сохранению данных. */ uint8_t storeConfig(void) {
TCCR0B |= _BV(CS00); /* запустить таймер без предделителя */ TCNT0=240; /* за 16 тактов до переполнения */ return 0; }
/* время выполнения этого прерывания может быть достаточно высоким в случае самой плохой ситуации, это должно быть обязательно исследовано! */ ISR(TIMER0_OVF_vect) { uint8_t save_sreg=SREG; /* сохранить регистр состояния */ cli(); /* запретить прерывания */
uint8_t *pe, *ps; uint8_t ebyte;
pe = (uint8_t *)&config_ee + eeprom_store_idx; /* адрес данных в eeprom */ ps = (uint8_t *)&config + eeprom_store_idx; /* адрес данных в sram */ ebyte = eeprom_read_byte(pe);
/* перезаписывать данные в eeprom будем только если это необходимо */ /* сравним содержимое структур в sram и eeprom, выход из цикла осуществляем по первому найденному различию в данных */ while( (ebyte == *ps) && (eeprom_store_idx != (sizeof(struct config_t) - 1)) ) { eeprom_store_idx++; pe++; ps++; ebyte = eeprom_read_byte(pe); }
/* записываем новое значение в eeprom */ if (ebyte != *ps) eeprom_write_byte(pe, *ps);
/* если последняя запись в структуре не достигнута переходим к поиску следующего различия данных в sram и eeprom */ if (eeprom_store_idx == sizeof(struct config_t)-1) { /* запись закончена */ TCCR0B &= ~_BV(CS00); /* выключить таймер */ eeprom_store_busy = 0; /* сбросить флаг, eeprom занято*/ PORTB &= ~_BV(PB7); /* погасить светодиод */ } else { /* переходим к следующему различию */ eeprom_store_idx++; PORTB |= _BV(PB7); /* зажечь светодиод */ TCNT0=240; /* обновить регистр счёта */ /* необходимо отметить, если светодиод горит более 5 сек следует снять питание с контроллера иначе возможно повреждение eeprom */ } SREG=save_sreg; /* восстановить регистр состояния */ }
int main(void){
DDRB |= _BV (PB7); //установить как выход LED PORTB &=~ _BV (PB7); //установить 0 LED
Я бы в принципе пересмотрел концепцию (алгоритм) программы. Мы ж ведь так или иначе опрашиваем флаг занятости контроллера EEPROM (eeprom_store_busy). Так что мешает тогда всю работу делать в отдельной функции?
Весь алгоритм записи в память я завёл целиком в storeConfig(), проверку байт и саму запись объединил в цикл while. Вроде прокатило. Нужно будет проверить не словит ли глюка в процессе работы остальных прерываний. Вопрос в том как это работало в оригинальном устройстве? И почему оно вообще работало? Может компилятор не того, в оригинале вроде как через WinAVR компилили, но во всем коде из 25 файлов я только подправил названия регистров, и всё зафурычило как надо, кроме записи в епром.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 52
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения