Перейти к содержанию
    

Как сделать перезагрузку программно?

В многофайловой Си необходимо в одном из файлов по результатам выполнения функции выполнить перезагрузку контроллера AVR. Т.е. перейти по адресу 0h. Что-то сходу не могу разобраться как грамотно это сделать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Чтобы сделать перезагрузку полностью с внутренней периферией есть как минимум два пути:

1. дёрнуть в ноль свободным выводом ногу RESET;

2. запустить вотчдог на минимальное время и не сбрасывать его (зациклиться).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Чтобы сделать перезагрузку полностью с внутренней периферией есть как минимум два пути:

1. дёрнуть в ноль свободным выводом ногу RESET;

так делать нельзя...

По крайней мере Atmel на этот счет говорит четко, НИЗЯ!

2. запустить вотчдог на минимальное время и не сбрасывать его (зациклиться).

Это единственный способ работу которого гарантирует Atmel.

Единственно с минимальным временем нужно осторожнее, чтобы

случайно не оказаться в вечном ресете.

 

Есть правда еще один способ:

- запрещаем прерывания

- выключаем все запущенные модули

- сбрасываем флаги всех прерываний

- делаем jmp 0

Но это конечно длинный путь и легко чего-нить не предусмотреть...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

объявить указатель на функцию с адресом 0

 

вызвать ее

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

- делаем jmp 0

Можно пример? Ассемблерная вставка? Или у компилятора есть спец. средства для этого? Я нашел только: __indirect_jump_to 0x00

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

объявить указатель на функцию с адресом 0

вызвать ее

Насколько я знаю, это будет работать не во всех компиляторах.

(не для всех процессоров/моделей памяти/опций линкера по распределению памяти)

 

 

 

Ассемблерная вставка?
Например

Или у компилятора есть спец. средства для этого? Я нашел только: __indirect_jump_to 0x00
Indirect jump - это через регистр Z, вполне подойдет если он есть в IAR.

 

Вот пример, правда для WinAVR:

//-------------------------------------------------------------------
// Перезагрузка (рестарт с адреса 0)
//-------------------------------------------------------------------

void Reset()
{
  __asm__ __volatile__ ("cli");  // запретить прерывания
               // останавливаем всю переферию
  SysTimerStop();
  AdcStop();
  SpiStop();
  PwmStop();
  PortsReset();
  I2cStop();
               // переходим на адрес 0
  __asm__ __volatile__("ldi r30,0\n\t"\
                       "ldi r31,0\n\t"\
                       "ijmp");
}

в каждом xxxStop(); выключается соответствующий модуль и сбрасываются флаги прерываний

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно пример? Ассемблерная вставка? Или у компилятора есть спец. средства для этого? Я нашел только: __indirect_jump_to 0x00

http://electronix.ru/forum/index.php?showt...147&hl=goto

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно пример? Ассемблерная вставка? Или у компилятора есть спец. средства для этого? Я нашел только: __indirect_jump_to 0x00

В общем виде для Си:

void (*soft_reset)(void) = 0x00;
(*soft_reset)();

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Единственно с минимальным временем нужно осторожнее, чтобы

случайно не оказаться в вечном ресете.

Что значит в вечном ресете?

После перезагрузки вотчдог отключится! (если конечно фьюзы не стоят соотв.)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

так делать нельзя...

По крайней мере Atmel на этот счет говорит четко, НИЗЯ!

Ну разумеется не так буквально, как я написал.

Естественно нужно соблюсти требования по длительности сигнала RESET.

Один из таких способов - перестать сбрасывать внешний вотчдог.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

нормаль по собаке сделал.

дог по условию сбрасываю, а когда надо мк перезапустить, то нарушаю условие сброса. и все (немножко подождать) и мк рестартанет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В общем виде для Си:
void (*soft_reset)(void) = 0x00;
(*soft_reset)();

или soft_reset(); поскольку в С единственное легальное действие с указателем на функцию - это вызов функции. Конкретно для IAR есть еще одно решение:

extern void Reset();  // если С++ - extern "C" void Reset()
void Test
{

   Reset();
}
Project->Options->Linker->Extra Options -DReset=0x0000

Тот же ход для WinAVR:

extern void Reset();  // если С++ - extern "C" void Reset()
Project->Options->Linker->Add
-Wl,--defsym,Reset=0x0000
или в Makefile
LDFLAGS += -Wl,--defsym,Reset=0x0000

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что значит в вечном ресете?

После перезагрузки вотчдог отключится! (если конечно фьюзы не стоят соотв.)

Вы правы но лишь частично...

Во первых, как Вы правильно заметили (если конечно фьюзы не стоят соотв.)

Во вторых даже при отключенных соответствующих фузах в более новых

AVR Watchdog работает чуть-чуть иначе.

Вот кусочек даташита на Atmega48/88/168:

Note: If the Watchdog is accidentally enabled, for example by a runaway pointer or brown-out

condition, the device will be reset and the Watchdog Timer will stay enabled. If the code is not

set up to handle the Watchdog, this might lead to an eternal loop of time-out resets. To avoid this

situation, the application software should always clear the Watchdog System Reset Flag

(WDRF) and the WDE control bit in the initialisation routine, even if the Watchdog is not in use.

 

А вот тоже самое переведенное с английского на английский в руководстве

avr-libc для WinAVR:

Note that for newer devices (ATmega88 and newer, effectively any AVR that has the option

to also generate interrupts), the watchdog timer remains active even after a system

reset (except a power-on condition), using the fastest prescaler value (approximately

15 ms). It is therefore required to turn off the watchdog early during program startup,

the datasheet recommends a sequence like the following:

..........................

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Использую оба решения, но при использовании программного сброса легко упустить инициализацию портов. Например, оставить на выход сигналы программного I2C.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тот же ход для WinAVR:

extern void Reset();  // если С++ - extern "C" void Reset()
Project->Options->Linker->Add
-Wl,--defsym,Reset=0x0000
или в Makefile
LDFLAGS += -Wl,--defsym,Reset=0x0000

Сергей, а это проверенное решение для WinAVR ?

Оно одинаково работает на контроллерах с call/rcall и тех у которых только rcall ?

 

Дело в том что именно с WinAVR у меня была проблема на mega8 с вызовом

функции адрес которой назначен 0x0000.

В итоге и написал через asm вставки (см. выше).

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...