Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как сделать перезагрузку программно?
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
ivainc1789
В многофайловой Си необходимо в одном из файлов по результатам выполнения функции выполнить перезагрузку контроллера AVR. Т.е. перейти по адресу 0h. Что-то сходу не могу разобраться как грамотно это сделать?
IgorKossak
Чтобы сделать перезагрузку полностью с внутренней периферией есть как минимум два пути:
1. дёрнуть в ноль свободным выводом ногу RESET;
2. запустить вотчдог на минимальное время и не сбрасывать его (зациклиться).
singlskv
Цитата(IgorKossak @ Jul 9 2007, 01:03) *
Чтобы сделать перезагрузку полностью с внутренней периферией есть как минимум два пути:
1. дёрнуть в ноль свободным выводом ногу RESET;

так делать нельзя...
По крайней мере Atmel на этот счет говорит четко, НИЗЯ!
Цитата
2. запустить вотчдог на минимальное время и не сбрасывать его (зациклиться).

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

Есть правда еще один способ:
- запрещаем прерывания
- выключаем все запущенные модули
- сбрасываем флаги всех прерываний
- делаем jmp 0
Но это конечно длинный путь и легко чего-нить не предусмотреть...
jorikdima
объявить указатель на функцию с адресом 0

вызвать ее
ivainc1789
Цитата(singlskv @ Jul 9 2007, 02:49) *
- делаем jmp 0

Можно пример? Ассемблерная вставка? Или у компилятора есть спец. средства для этого? Я нашел только: __indirect_jump_to 0x00
singlskv
Цитата(jorikdima @ Jul 9 2007, 08:43) *
объявить указатель на функцию с адресом 0
вызвать ее

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



Цитата(ivainc1789 @ Jul 9 2007, 09:08) *
Ассемблерная вставка?
Например
Цитата
Или у компилятора есть спец. средства для этого? Я нашел только: __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(); выключается соответствующий модуль и сбрасываются флаги прерываний
jorikdima
Цитата(ivainc1789 @ Jul 9 2007, 09:08) *
Можно пример? Ассемблерная вставка? Или у компилятора есть спец. средства для этого? Я нашел только: __indirect_jump_to 0x00

http://electronix.ru/forum/index.php?showt...147&hl=goto
spf
Цитата(ivainc1789 @ Jul 9 2007, 11:08) *
Можно пример? Ассемблерная вставка? Или у компилятора есть спец. средства для этого? Я нашел только: __indirect_jump_to 0x00

В общем виде для Си:
Код
void (*soft_reset)(void) = 0x00;
(*soft_reset)();
KRS
Цитата(singlskv @ Jul 9 2007, 02:49) *
Единственно с минимальным временем нужно осторожнее, чтобы
случайно не оказаться в вечном ресете.

Что значит в вечном ресете?
После перезагрузки вотчдог отключится! (если конечно фьюзы не стоят соотв.)
IgorKossak
Цитата(singlskv @ Jul 9 2007, 01:49) *
так делать нельзя...
По крайней мере Atmel на этот счет говорит четко, НИЗЯ!

Ну разумеется не так буквально, как я написал.
Естественно нужно соблюсти требования по длительности сигнала RESET.
Один из таких способов - перестать сбрасывать внешний вотчдог.
arttab
нормаль по собаке сделал.
дог по условию сбрасываю, а когда надо мк перезапустить, то нарушаю условие сброса. и все (немножко подождать) и мк рестартанет.
Сергей Борщ
Цитата(spf @ Jul 9 2007, 08:46) *
В общем виде для Си:
Код
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
singlskv
Цитата(KRS @ Jul 9 2007, 11:21) *
Что значит в вечном ресете?
После перезагрузки вотчдог отключится! (если конечно фьюзы не стоят соотв.)

Вы правы но лишь частично...
Во первых, как Вы правильно заметили (если конечно фьюзы не стоят соотв.)
Во вторых даже при отключенных соответствующих фузах в более новых
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:
..........................
Dog Pawlowa
Использую оба решения, но при использовании программного сброса легко упустить инициализацию портов. Например, оставить на выход сигналы программного I2C.
singlskv
Цитата(Сергей Борщ @ Jul 9 2007, 12:31) *
Тот же ход для 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 ничего по воле компилятора уже поменятся не может...
VladimirYU
[quote name='singlskv' date='Jul 9 2007, 02:49' post='270177']
так делать нельзя...
По крайней мере Atmel на этот счет говорит четко, НИЗЯ!

Можно по подобней, аппарвтный сброс еще никто не запрещал, ИМХО.
Сергей Борщ
Цитата(singlskv @ Jul 9 2007, 12:16) *
Сергей, а это проверенное решение для WinAVR ?
Оно одинаково работает на контроллерах с call/rcall и тех у которых только rcall ?
Оно проверено на вызове загрузчика, который живет по адресу 0x1800 и другой функции по другому адресу. Конкретно на адрес 0x0000 не переходил, но не вижу особой разницы - с точки зрения компилятора это вызов обычной функции, о расположении которой он ничего не знает и не должен знать. С точки зрения линкера адреса функций - обычные symbols, ему тоже все равно чему этот адрес равен конкретно. А опцией -Wl мы просто ему говорим "этот символ (метку) мы определили за тебя"
Цитата(singlskv @ Jul 9 2007, 12:16) *
В inderect jump ничего по воле компилятора уже поменятся не может...
Да, но оно требует загрузки R30:R31 и IJMP вместо обычного ®JMP.
singlskv
Цитата
Можно по подобней, аппарвтный сброс еще никто не запрещал, ИМХО.

Вот официальное мнение Atmel по этому вопросу:

Software Reset
Question
How can I reset my AVR through software?

Answer
If you want to perform a software reset of your AVR you should use the internal Watchdog. Simply enable it and let it time out. When the Watchdog triggers it resets the program counter back to 0, clears all the registers and performs all the other tasks. This operation gives the same result as pulling the RESET line low.

You should not try to:
- Use another pin of the AVR to pull the external RESET line. The pins of the AVR are tristated halfway through the minimum reset time, this releases the RESET line and hence nothing happens.
- Jump to program location 0. Jumping to program location 0 does not clear all the registers and hence you do not have a "clean" reset.



Цитата(Сергей Борщ @ Jul 9 2007, 14:12) *
Оно проверено на вызове загрузчика, который живет по адресу 0x1800 и другой функции по другому адресу. Конкретно на адрес 0x0000 не переходил, но не вижу особой разницы - с точки зрения компилятора это вызов обычной функции, о расположении которой он ничего не знает и не должен знать. С точки зрения линкера адреса функций - обычные symbols, ему тоже все равно чему этот адрес равен конкретно. А опцией -Wl мы просто ему говорим "этот символ (метку) мы определили за тебя

Вот в этом и вопрос знает или не знает ?
линкер должен знать smile.gif
Попробую найти/воспроизвести код с "неправильным" вызовом функции по адресу 0x0000,
а потом попробую Ваш вариант.
Цитата
"Да, но оно требует загрузки R30:R31 и IJMP вместо обычного ®JMP.

Ну вроде как в IAR для этого можно воспользоваться "__z" ?
Dog Pawlowa
Цитата(singlskv @ Jul 9 2007, 13:44) *
Вот официальное мнение Atmel по этому вопросу:
..
How can I reset my AVR through software?
...
You should not try to:
...
- Jump to program location 0. Jumping to program location 0 does not clear all the registers and hence you do not have a "clean" reset.[/i]

А оценить нужность "чистоты" регистров способен только один ATMEL, один раз для всех проектов, программист just "should not try"! biggrin.gif
VladimirYU
[quote name='singlskv' date='Jul 9 2007, 14:44' post='270332']
Вот официальное мнение Atmel по этому вопросу:

Software Reset
Question
How can I reset my AVR through software?

Answer
If you want to perform a software reset of your AVR you should use the internal Watchdog. Simply enable it and let it time out. When the Watchdog triggers it resets the program counter back to 0, clears all the registers and performs all the other tasks. This operation gives the same result as pulling the RESET line low.

You should not try to:
- Use another pin of the AVR to pull the external RESET line. The pins of the AVR are tristated halfway through the minimum reset time, this releases the RESET line and hence nothing happens.
- Jump to program location 0. Jumping to program location 0 does not clear all the registers and hence you do not have a "clean" reset.


Естественно, требования к аппаратному сбросу никто не отменял, поэтому ATMEL и не рекомендует "самострел". Ну о то что переход на 0х0000 это не эквивалент RESET ИМХО очевидно.
singlskv
Цитата(Dog Pawlowa @ Jul 9 2007, 15:56) *
А оценить нужность "чистоты" регистров способен только один ATMEL, один раз для всех проектов, программист just "should not try"! biggrin.gif

biggrin.gif biggrin.gif biggrin.gif
Ну дык Вы же сами намекнули
Цитата(Dog Pawlowa @ Jul 9 2007, 13:01) *
Использую оба решения, но при использовании программного сброса легко упустить инициализацию портов. Например, оставить на выход сигналы программного I2C.

почему они Вас боятся 08.gif
Dog Pawlowa
Цитата(singlskv @ Jul 9 2007, 16:50) *
почему они Вас боятся 08.gif

Я не люблю наступать на грабли, но даже ATMEL не отнимет мое право сделать ЭТО maniac.gif !
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.