Полная версия этой страницы:
atmega88pa
max_mart
Oct 8 2012, 09:06
всем привет,
Необходимо ресетить мегу. Как это можно реализовать через проограмму, принудительно по необходимости, например, при проверке одного флага, в определенный момент времени?
RabidRabbit
Oct 8 2012, 09:40
Соеденить какую-нибудь ногу GPIO с RESET, не?
kovigor
Oct 8 2012, 10:07
Цитата(max_mart @ Oct 8 2012, 12:06)

Необходимо ресетить мегу. Как это можно реализовать через проограмму, принудительно по необходимости, например, при проверке одного флага, в определенный момент времени?
Посредством WatchDog ...
DmitryM
Oct 8 2012, 10:12
Цитата(max_mart @ Oct 8 2012, 13:06)

Необходимо ресетить мегу. Как это можно реализовать через проограмму, принудительно по необходимости, например, при проверке одного флага, в определенный момент времени?
Завести Watchdog, и по необходимости "например, при проверке одного флага" уйти в бесконечный цикл.
Ззапретить прерывания, завести Watchdog на самую короткую продолжительность, и только после этого уйти в бесконечный цикл.
Например так:
Код
void Reset()
{
__disable_interrupt();
WDTCSR |= (1<<WDCE) | (1<<WDE);
WDTCSR = (1<<WDE); // 16 ms
for(;;);
}
(только это не для ATmega88pa писано).
demiurg_spb
Oct 8 2012, 11:44
Под avr-gcc для любых AVR.
Код
static inline void NORETURN mcu_reset(void) {wdt_enable(WDTO_15MS); cli(); for(;;);}
Пора бы уже эту фишку в avr-libc реализовать...
max_mart
Oct 8 2012, 11:50
спасибо огромное
prottoss
Oct 8 2012, 12:41
Цитата(max_mart @ Oct 8 2012, 15:06)

...принудительно по необходимости, например, при проверке одного флага, в определенный момент времени?
Цитата(RabidRabbit @ Oct 8 2012, 15:40)

Соеденить какую-нибудь ногу GPIO с RESET, не?
Лучший вариант, ибо это будет как раз в
определенный момент времени, а не после того как WDT сработает через
определенный момент времени после определенного момента времени.
Цитата(prottoss @ Oct 8 2012, 22:41)

Лучший вариант, ибо это будет как раз в определенный момент времени, а не после того как WDT сработает через определенный момент времени после определенного момента времени.
Ну, и здесь этот определенный момент также не очень-то определен, с учетом минимально допустимого времени сброса (2,5 мкс по даташиту), с учетом работы внутреннего счетчика задержки ресета, а также с учетом того, что при срабатывании ресета сигнал порта, вызывающего ресет, тоже сбрасывается.
prottoss
Oct 8 2012, 14:07
Цитата(V_G @ Oct 8 2012, 19:28)

Ну, и здесь...
Согласен, все в мире относительно

Просто в случае с WDT ко всем выше перечисленным задержкам прибавляется минимальное время реакции WDT.
max_mart
Oct 8 2012, 15:15
Ram и все регитсры сбрасываются или сохраняются значения, при сбросе от WDT?
prottoss
Oct 8 2012, 15:26
Цитата(max_mart @ Oct 8 2012, 21:15)

Ram и все регитсры сбрасываются или сохраняются значения, при сбросе от WDT?
Сброс по WDT работает так же как и сброс от внешнего RESET. Все регистры и порты ВВ принимают начальное значение описаное в даташите на МК. SRAM не изменится.
max_mart
Oct 8 2012, 15:57
т.е. значит флаги и некоторые переменные придется обнулять самому, поскольку я их в SRAM разместил
правильно я говорю?
И переменная сохранит свое значение до ресета?
prottoss
Oct 8 2012, 16:00
Цитата(max_mart @ Oct 8 2012, 21:57)

т.е. значит флаги и некоторые переменные придется обнулять самому, поскольку я их в SRAM разместил
правильно я говорю?
И переменная сохранит свое значение до ресета?
Ну да. А разве при инициализации программы у Вас флаги не устанавливаются в какое то дефолтное значение? Типа:
Код
unsigned int g_Flag_1 = 0x0000;
unsigned int g_Flag_2 = DEF_FLAG_A | DEF_FLAG_B;
void main(void)
{
...
}
_Артём_
Oct 8 2012, 16:02
Цитата(max_mart @ Oct 8 2012, 18:57)

т.е. значит флаги и некоторые переменные придется обнулять самому, поскольку я их в SRAM разместил
правильно я говорю?
А обычно вы их сами обнуляете? Или в стартапе они обнуляются?
Сброс по WDT аналогичен обычному, то есть всё пойдёт по тому же сценарию.
max_mart
Oct 8 2012, 16:30
Ну я обычно сразу в переменную 0х00 прописываю при ее инициализации.
Например:
volatile unsigned char example=0x00;
prottoss
Oct 8 2012, 16:34
Цитата(max_mart @ Oct 8 2012, 22:30)

Ну я обычно сразу в переменную 0х00 прописываю при ее инициализации
Вот Вы и ответили на свой вопрос - программа ведь после ресета стартует. Она все сделает, что Вы прописали в тексте программы.
_Артём_
Oct 8 2012, 16:47
Цитата(max_mart @ Oct 8 2012, 19:30)

volatile unsigned char example=0x00;
Совершенно излишне:
Код
volatile unsigned char example;
тот же результат даст.
max_mart
Oct 8 2012, 16:59
Артем
Т.е. вы хотите сказать, что она все время будит инициализироваться нулевой при самом первом запуске(по питанию)? А не может быть такого, что там может быть записан мусор, а у меня по этой переменной важное событие должно пройти, и тогда что? А мне необходимо, чтобы при самом первом запуске она именно нулевая была!
esaulenka
Oct 8 2012, 17:06
Во-первых, обнулять глобальные (не локальные!) переменные компилятор Си должен согласно спецификации.
А во-вторых, если переменная прямо такая важная, её изначально привести в нужное состояние можно и руками.
_Артём_
Oct 8 2012, 17:20
Цитата(max_mart @ Oct 8 2012, 19:59)

хотите сказать, что она все время будит инициализироваться нулевой при самом первом запуске(по питанию)?
При любом перезапуске так будет (они все через один вектор идут).
Цитата(max_mart @ Oct 8 2012, 19:59)

А не может быть такого, что там может быть записан мусор
Не может такого быть, если условия эксплуатации не нарушены.
max_mart
Oct 8 2012, 17:24
Кстати, а флаг WDRF регистра MCUSR, сохраняет свое значение 1, после сброса, что сброс был? По описанию он вроде только может быть сброшен вручную или по питанию.
В принципе контролировать WDRF будит достаточно)))
_Артём_
Oct 8 2012, 17:27
Цитата(max_mart @ Oct 8 2012, 20:24)

Кстати, а флаг WDRF регистра MCUSR, сохраняет свое значение 1, после сброса, что сброс был?
Естественно сохраняет.
Причём его надо обязательно сбрасывать, иначе не удасться установиь период WDT, отличный от минимального.
Цитата(prottoss @ Oct 8 2012, 18:26)

Сброс по WDT работает так же как и сброс от внешнего RESET.
За исключением того, что при этом взводится флаг WDRF в MCUSR, который держит в 1-ке бит WDE в WDTCSR (обратите внимание на
X вместо
0 в «состоянии после сброса» для WDE).
Т.е. после сброса по WDT этот самый WDT оказывается гарантированно разрешённым, а после сброса по RESET — ну, зависит от фьюза WDTON :-)
Т.е. мало просто использовать вызов вызов рекомендованных Reset()/mcu_reset(), надо добавить при старте очистку источников сброса в MCUSR и запрет WDT.
max_mart
Oct 8 2012, 17:43
ну значит сделаю тогда, так
if (!(MCUSR&0b00001000)) {...}
// проверяю флаг: если сброс вызван вотчдог, то ничего не делать, если питание на МК только поступило и флаг не установлен, то выполнить действие
MCUSR=0x00;
REAL
Т.е. Вы хотите сказать, что надо добавить еще сюда wdt_disable();?
И еще момент. Порты сбрасываются все как выхода в высокоомное состояние(состояние высокого импенданса)?
MCUSR = 0; сделать всегда, так как оставшийся от сброса по WDT бит (1 << WDRF) не даст ни запретить WDT, ни, как выше было сказано, изменить время (а уж оно-то по сбросу будет поставлено на минимальное).
После чего запретить либо сбросить WDT, в зависимости от того, используется ли он по прямому назначению.
Если WDT использовался только для сброса контроллера, то надо его запретить. Он разрешён после своей сработки и через 16 мс сработает опять.
max_mart
Oct 8 2012, 18:01
только для сброса контроллера. Сначала инициализирую МК,потом отключаю watchdog и сбрасываю флаг WDRF функцией WDT_Off(функцию взял прямо из даташита)
max_mart
Oct 8 2012, 19:36
Да и еще момент: Не может быть такого, что дапустим сразу при первом запуске МК(подачи питания) флаг WDRF установится в 1 или же он строго устанавливается только по срабатыванию ресета от вотчдог?
И порты сбрасываются все в состояние, как выхода в высокоомном состоянии(состояние высокого импенданса)?
_Артём_
Oct 8 2012, 20:13
Цитата(max_mart @ Oct 8 2012, 21:01)

Сначала инициализирую МК,потом отключаю watchdog и сбрасываю флаг WDRF функцией WDT_Off(функцию взял прямо из даташита)
Тоже как-то взял из даташита - но она в 4 такта не уложилась...
Цитата(max_mart @ Oct 8 2012, 22:36)

Да и еще момент: Не может быть такого, что дапустим сразу при первом запуске МК(подачи питания) флаг WDRF установится в 1 или же он строго устанавливается только по срабатыванию ресета от вотчдог?
Цитата
This bit is set if a Watchdog System Reset occurs. The bit is reset by a Power-on Reset, or by
writing a logic zero to the flag.
То есть если флаг установился (сбросом по wdt), то вернуть его в 0 может только запись 0 или Power-on Reset (но не BOD или Ext Reset).
Цитата(max_mart @ Oct 8 2012, 22:36)

И порты сбрасываются все в состояние, как выхода в высокоомном состоянии(состояние высокого импенданса)?
Да все в Z-state. Initial Value для DDRx и PORTx = 0.
max_mart
Oct 9 2012, 04:58
Артем,
Как тогда посоветуете правильно его отключить?
static inline void WDT_off(void)
{
wdt_reset();
/* Clear WDRF in MCUSR */
MCUSR &= ~(1<<WDRF);
/* Write logical one to WDCE and WDE */
/* Keep old prescaler setting to prevent unintentional time-out */
WDTCSR = 0b00011000;
/* Turn off WDT */
WDTCSR = 0x00;
}
Так?
И еще момент:
после сброса, я флаги все обнуляю и выключаю вотчдог. Но если мне он опять нужен , то перед включением я должен бит WDRF выставить в 1?
Либо он(WDRF) устанавливается автоматически при записи 1 в WDE?
_Артём_
Oct 9 2012, 14:56
Цитата(max_mart @ Oct 9 2012, 07:58)

Как тогда посоветуете правильно его отключить?
static inline void WDT_off(void)
{
wdt_reset();
/* Clear WDRF in MCUSR */
MCUSR &= ~(1<<WDRF);
/* Write logical one to WDCE and WDE */
/* Keep old prescaler setting to prevent unintentional time-out */
WDTCSR = 0b00011000;
/* Turn off WDT */
WDTCSR = 0x00;
}
Так?
Я делал примерно также, просто в однажды ИАР сгенерил код который перестал укладываться в 4 цикла.
Переделал так:
Код
void WDT_Prescaler_Change(unsigned char new_wdt_period);
int main() {
MCUSR = ~(1<<WDRF);
WDT_Prescaler_Change(6|(1<<WDE));
__watchdog_reset();
Код
WDT_Prescaler_Change:
; Turn off global interrupt
push r17
mov r17, r16
cli
; Reset Watchdog Timer
wdr
; Start timed sequence
lds r16, 0x60
ori r16, 0x18
sts 0x60, r16
; -- Got four cycles to set the new values from here -
; Set new prescaler(time-out) value = 64K cycles (~0.5 s)
sts 0x60, r17
; -- Finished setting new values, used 2 cycles -
; Turn on global interrupt
pop r17
ret
Цитата(max_mart @ Oct 9 2012, 07:58)

И еще момент:
после сброса, я флаги все обнуляю и выключаю вотчдог. Но если мне он опять нужен , то перед включением я должен бит WDRF выставить в 1?
Либо он(WDRF) устанавливается автоматически при записи 1 в WDE?
Цитата
This bit is set if a Watchdog System Reset occurs.
Вы не можете установить WDRF - он устанавливается аппаратно. Его нужно просто сбросить на старте записью в него единицы и больше о нём не вспоминать.
max_mart
Oct 9 2012, 16:35
Почему 1??? Когда в описании написано 0!
Цитата(max_mart @ Oct 9 2012, 20:30)

Почему 1??? Когда в описании написано 0!
"Вы не можете установить WDRF - он устанавливается аппаратно." - т.е. мне достаточно только прописать WDE, если мне необходим ресет и вотчдог включится
_Артём_
Oct 9 2012, 16:49
Цитата(max_mart @ Oct 9 2012, 19:35)

Почему 1??? Когда в описании написано 0!
Я ошибся - писать нужно 0.
Цитата(max_mart @ Oct 9 2012, 19:35)

т.е. мне достаточно только прописать WDE, если мне необходим ресет и вотчдог включится
да
Вариант без WDT
Код
__disable_interrupt();
((void (*)())0x0000)();
_Артём_
Oct 9 2012, 23:49
Цитата(abi @ Oct 10 2012, 01:08)

Вариант без WDT
Код
__disable_interrupt();
((void (*)())0x0000)();
Это не то же самое - процессор сброшен не будет и вся периферия останется в несброшенном состоянии.
Цитата(_Артём_ @ Oct 10 2012, 03:49)

Это не то же самое - процессор сброшен не будет и вся периферия останется в несброшенном состоянии.
Согласен, внутреннего системного сброса не произойдет. В зависимости от замысла принудительного программного сброса, системный сброс может и не понадобиться. В любом случае используемая периферия будет проинициализирована программой.
_Артём_
Oct 10 2012, 11:44
Цитата(abi @ Oct 10 2012, 05:40)

В любом случае используемая периферия будет проинициализирована программой.
Не в любом случае, а только есть этим озаботиться.
А иногда и
озабоченность озабачивание даже если этим озаботиться, то все равно разница с аппаратным сбросом будет, и существенная.
Например
Цитата(ATmega88PA doc)
• Bit 3 – TXENn: Transmitter Enable n
Writing this bit to one enables the USART Transmitter. The Transmitter will override normal port operation for the TxDn pin when enabled. The disabling of the Transmitter (writing TXENn to zero) will not become effective until ongoing and pending transmissions are completed, i.e., when the Transmit Shift Register and Transmit Buffer Register do not contain data to be transmitted. When disabled, the Transmitter will no longer override the TxDn port.
Т.е. даже если записать «сбросовое» значение 0x00 в UCSR0B, передатчик ещё будет передавать недопереданное. Куда-то в астрал, так как ножка отключится, но кто его знает, как там себя автоматы поведут, если до конца передачи опять проинициализировать USART либо даже не занулять UCSR0B а просто заново записать то, что нужно.
Как миниум, аккуратненько взведётся (вполне возможно не ожидаемый ещё программой) флаг TXC.
А нельзя по флагу сделать переход на самое начало программы /адрес 0000/и не задействовать WDT? Надо сбросить флажки всех прерываний и инициализировать указатель стека. Я похожее сделал, работает.
prottoss
Oct 11 2012, 16:55
Цитата(vgo1 @ Oct 11 2012, 22:40)

А нельзя по флагу сделать переход на самое начало программы /адрес 0000/и не задействовать WDT? Надо сбросить флажки всех прерываний и инициализировать указатель стека. Я похожее сделал, работает.
Тогда глобальные переменные инициализируются, а вот порты в дефолтное состояние не установятся. Стек, кстати, сам инициализируется, если на Си, конечно, пишите.
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.