Как загрузить данные из R2 в глобальную переменную с использованием asm?

osetroff
Offline
Зарегистрирован: 27.08.2014

Загрузчик сохраняет MCUSR в R2.

Пишу:

byte kmcusr;

__asm__ __volatile__ ("sts %0,r2":"=r"(kmcusr));

выдает ошибку "undefined reference to `r24'".

Пожалуйста, помогите правильно написать нутро asm.

 

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Функция вернёт текущее значение R2

uint8_t r2(){asm volatile ("mov r24, r2"  "\n\t" ); }

 

osetroff
Offline
Зарегистрирован: 27.08.2014
Благодарю!
Это тоже работает:

    register uint8_t tmp=0;      
    asm volatile ("mov %[TMP],r2":[TMP]"=&r"(tmp):);
    kmcusr=tmp;   

 

osetroff
Offline
Зарегистрирован: 27.08.2014

Только все равно, MCUSR что по кнопке reset на ARDUINO, что при срабатывании WATCHDOG одинаков:

B00001000 , т.е. установлен WDRF: Watchdog System Reset Flag.

А мне бы хотелось знать, перезапуск ARDUINO произошел по WATCHDOG или по другой причине.

 

P.S.При отключении питания MCUSR B00000100, т.е. BORF: Brown-out Reset Flag.

Других значений не смог получить.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

osetroff, да так и есть. Сам когда-то интересовался этим вопросом.  Нужно копать в исходнике, почему сохранённый регистр не соответствует первозданному. Что-то там автор намудрил, и похоже сам не заметил. Ведь на работу лоадера это никак не влияет :)

osetroff
Offline
Зарегистрирован: 27.08.2014

Да, пришлось переделать optiboot.

//========================
//address in ram to save wbyte if we are inside bootloader
//to know that watchdog event was happend inside bootloader, not in app
#define waddr 0x4f0
#define wbyte 0x55
//exit from bootloader -> go to app
static void startapp(){
    watchdogConfig(WATCHDOG_2S);
    asm volatile ("clr r30 \n"
                  "sts %[ADDR],r30 \n"
                  "clr r31 \n" 
                  "ijmp \n" ::[ADDR]""(waddr));
}
//===============================
int main(void) {
  register uint8_t ch = MCUSR;
  //save MCUSR for app:
  //==2 if was external reset
  //==4 if we get started or was low power
  //==8 if was watchdog interrupt inside app (not inside bootloader)
  GPIOR0=ch;
  watchdogConfig(WATCHDOG_500MS);
  MCUSR = 0;  
  asm volatile ("clr __zero_reg__");
#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__)
  SP=RAMEND;  // This is done by hardware reset
#endif
  //if not EXTRF goto app start
  if (!(ch & (_BV(EXTRF)))) {
    //test if we get watchdog reset when stay in bootloader
    register uint8_t tmp;      
    asm volatile ("lds %[TMP],%[ADDR]":[TMP]"=&r"(tmp):[ADDR]""(waddr));
    //we was inside bootloader -> clear WDRF
    if (tmp==wbyte) {GPIOR0=ch&(~_BV(WDRF))|_BV(EXTRF);}
    startapp();
  }
  //set that we inside bootloader
  asm volatile ("ldi r24,%[WBT]\n" 
                "sts %[ADDR],r24"::[ADDR]""(waddr),[WBT]""(wbyte));

Сохраняю в RAM признак того, что я в bootloader.

Поэтому, когда внутри bootloader происходит reset по watchdog, я очищаю этот признак для программы.

У меня теперь в программе GPIOR0:

2 при внешнем reset;

4 при включении и потере питания;

8 при срабатывании watchdog внутри программы.

Может кто поможет передать код в репозиторий optiboot?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

osetroff, по хорошему нужно написать автору оптибута. Его же эта тема тоже беспокоила, раз он в дистрибутив включил файлик test_reset.ino Собссно этот тест его и не работает как положено.   Но это нужно сносно на инглише объясняться.

osetroff
Offline
Зарегистрирован: 27.08.2014

Запостил на github issue #197, может добавят в оффициальную сборку.