Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Еще раз про powerdown
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
smk
С чего возник вопрос. Есть прибор, который с периодичностью 1 с просыпается и контролирует два параметра с помощью АЦП. Приборчик должен быть автономный и долгоиграющий. Чтобы знать, что приборчик работает и батарейки не сдохли предусмотрена индикация каждые 10 с, т.е. каждый десятый раз просыпания. Теперь сам вопрос.

На http://www.gaw.ru/html.cgi/txt/doc/micros/avr/arh128/4.htm прочитал:
Выход из режима сна происходит при возникновении разрешенного прерывания. В этом случае, помимо времени старта микроконтроллер приостанавливается на 4 машинных цикла, выполняет процедуру обработки прерывания и продолжает выполнять команды следующие за SLEEP. Содержимое файла регистров и статического ОЗУ остается неизменным после выхода из режима сна. Если во время действия режима сна возникает условие сброса, то микроконтроллер пробуждается и исполняет код программы по вектору сброса.

Можно ли использовать регистр ОЗУ под счетчик к-ва "пробуждений" и как это сделать программно? Желательно уходить в power-down, а просыпаться по WDT. Использую С, WinAVR. Спасибо!
oran-be
Цитата(smk @ Apr 16 2008, 10:32) *
Можно ли использовать регистр ОЗУ под счетчик к-ва "пробуждений" и как это сделать программно? Желательно уходить в power-down, а просыпаться по WDT. Использую С, WinAVR. Спасибо!

Просыпание по WDT есть два варианта - использовать прерывание (мега48, 88, 168) или сброс по WDT.
Первый вариант типа возможен, но ввиду глюка прерывания от собаки работает не всегда. Если уходить в сброс, то необходимо счетчик засунуть в неинициализируемые данные. Если мне не изменяет память, в WinAVR необходимо объявить секцию с требуемыми атрибутами. (директива SECTION вроде). Тогда при сбросе эта секция перетираться не будет. Для инициализации первого включения после установки новых батарей необходимо будет добавить проверку на валидность значения этого счетчика - или CRC, или просто проинвертированное значение этого счетчика.
smk
Цитата
после установки новых батарей

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

Цитата
в WinAVR необходимо объявить секцию с требуемыми атрибутами.

Начинаю читать. Если кто-то знает как это делается - поделитесь опытом и (если можно) примером кода.

Я так понял речь об этгом?:
9.3.3 The .bss Section
Uninitialized global or static variables end up in the .bss section.

Как объявить такую переменную и как потом с ней обращаться?
Aleksandr Baranov
Цитата(smk @ Apr 17 2008, 12:35) *
В этой ситуации счет спокойно можно начинать с нуля. Суть в том, чтоб не утомлять пользователя частыми сигналами о работоспособности.
Начинаю читать. Если кто-то знает как это делается - поделитесь опытом и (если можно) примером кода.

Я так понял речь об этгом?:
9.3.3 The .bss Section
Uninitialized global or static variables end up in the .bss section.

Как объявить такую переменную и как потом с ней обращаться?




7.7.5 The .noinit Section
This sections is a part of the .bss section. What makes the
variables which are defined as such:
int foo __attribute__ ((section (".noinit")));
smk
Если я правильно понял, то так будет работать:

int my_variable __attribute__ ((section (".noinit"))); //объявляем глобальной
.
.
.

if (my_variable==10)
{
//показываем, что прибор работает
my_variable=0;
}


Все правильно?
Aleksandr Baranov
Цитата(smk @ Apr 17 2008, 15:54) *
Если я правильно понял, то так будет работать:

int my_variable __attribute__ ((section (".noinit"))); //объявляем глобальной
.
.
.

if (my_variable==10)
{
//показываем, что прибор работает
my_variable=0;
}
Все правильно?

Вот, что написано в мануале:

The .noinit Section
This sections is a part of the .bss section. What makes the .noinit section special is that variables which are defined as such:
int foo __attribute__ ((section (".noinit")));
will not be initialized to zero during startup as would normal .bss data.

Only uninitialized variables can be placed in the .noinit section. Thus, the following code will cause avr-gcc to issue an error:
int bar __attribute__ ((section (".noinit"))) = 0xaa;

It is possible to tell the linker explicitly where to place the .noinit section by adding -Wl,--section-start=.noinit=0x802000 to the avr-gcc command line at the linking stage. For example, suppose you wish to place the .noinit section at SRAM address 0x2000:

$ avr-gcc ... -Wl,--section-start=.noinit=0x802000 ...

Note:
Because of the Harvard architecture of the AVR devices, you must manually add 0x800000 to the address you pass to the linker as the start of the section. Otherwise, the linker thinks you want to put the .noinit section into the .text section instead of .data/.bss and will complain.
Baser
Цитата(smk @ Apr 17 2008, 19:35) *
Uninitialized global or static variables ...
Как объявить такую переменную и как потом с ней обращаться?

Как это в WinAVR не скажу, а в других компиляторах предельно просто. Есть расширение в виде ключевого слова.
В ИАР это: __no_init
В HiTech: persistent

Добавляется к любой переменной. Эта переменная попадает в секцию, которая не обнуляется после рестарта. Больше никаких отличий нет. Пример:

__no_init unsigned char Counter;

У меня в приборах с батарейным питанием половина переменных __no_init
Например регистры часов. Иначе любой случайный сброс - и время 00:00 smile.gif
smk
Цитата
Вот, что написано в мануале:

The .noinit Section
This sections is a part of the .bss section. What makes the .noinit section special is that variables which are defined as such:
int foo __attribute__ ((section (".noinit")));
will not be initialized to zero during startup as would normal .bss data.

Only uninitialized variables can be placed in the .noinit section. Thus, the following code will cause avr-gcc to issue an error:
int bar __attribute__ ((section (".noinit"))) = 0xaa;

It is possible to tell the linker explicitly where to place the .noinit section by adding -Wl,--section-start=.noinit=0x802000 to the avr-gcc command line at the linking stage. For example, suppose you wish to place the .noinit section at SRAM address 0x2000:

$ avr-gcc ... -Wl,--section-start=.noinit=0x802000 ...

Note:
Because of the Harvard architecture of the AVR devices, you must manually add 0x800000 to the address you pass to the linker as the start of the section. Otherwise, the linker thinks you want to put the .noinit section into the .text section instead of .data/.bss and will complain.


А как Вы сами это пользуете? Спасибо!

Вот это место не совсем понял:
Note: Because of the Harvard architecture of the AVR devices, you must manually add 0x800000 to the address you pass to the linker as the start of the section. Otherwise, the linker thinks you want to put the .noinit section into the .text section instead of .data/.bss and will complain.

Перевод: Примечание: Из-за Гарвардской архитектуры устройств AVR, вы должны вручную добавить 0x800000 по адресу, который вы передаете редактору связей как запуск секции. Иначе, редактор связей думает, что вы хотите поместить .noinit секцию в .text секцию вместо .data/.bss и будете жаловаться.
xelax
Цитата(smk @ Apr 17 2008, 23:54) *
Если я правильно понял, то так будет работать:

int my_variable __attribute__ ((section (".noinit"))); //объявляем глобальной

Все правильно?


Да правильно. Сам использую также:
uint8_t resetReason __attribute__ ((section (".noinit")));
Сохраняю там значение, если контроллер ресетнули программно. После ресета считываю то же значение, которое записал перед ресетом.
Спесиально эти секции в скрипте линкера не описываю, потому что WinAvr использует скрипты, где всё уже описанно.
После сборки проекта, можете сделать map карту проекта линкером и убедиться, что всё слинковалось куда надо.
wink.gif
smk
Цитата
Да правильно.

Спасибо! В студии работает как и было задумано. Интересно теперь как в железе будет...

И еще нужна консультация. Я правильно отправляю в power-down?

MCUCR=SLEEP_MODE_PWR_DOWN;
sleep_enable ();
sleep_mode ();

Спасибо!
xelax
Вы какую мегу юзаете?

В меге 1281, которую я использую есть регистр: SMCR – Sleep Mode Control Register. Вот его и пользую.
В даташите приведены кода всех энергосберегающих режимов.
В режим power down вхожу так:

Код
SMCR = (1 << SM1) | (1 << SE); // power-down
asm volatile ("sleep");


А MCUCR - MCU Control Register, что вы с помощью него хотите сделать?
smk
Цитата
Вы какую мегу юзаете?

tiny13

Цитата
А MCUCR - MCU Control Register, что вы с помощью него хотите сделать?

Там есть биты SE - sleep_enable; SM(1,0) - sleep_mode.

А Ваш пример явно мне интересен. Спасибо!
xelax
Цитата(smk @ Apr 18 2008, 12:47) *
Там есть биты SE - sleep_enable; SM(1,0) - sleep_mode.


smile.gif Тогда наверное правильно. Надо смотреть что представляют из себя макросы и функции:
SLEEP_MODE_PWR_DOWN
sleep_enable ()
sleep_mode ()
smk
Всем спасибо, все заработало в железе. Может кому пригодится - выкладываю что получилось:

#include <avr/sleep.h>
#include <avr/wdt.h>

#define num_wdt_reset 10

char my_variable __attribute__ ((section (".noinit")));

int main (void)
{
my_variable++;

if (my_variable==num_wdt_reset)
{
my_variable=0;
}

wdt_enable(WDTO_1S);
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_mode ();

while(1)
{
asm("nop");
}

return 0;
}
smk
Появился вот такой вопрос. При включении питания переменная my_variable будет иметь значение 0хFF, а при "просіпании" по сбросу от вочдог - последнее присвоенное значение? Цель вопроса - нужно надежно отличать старт при включении питания от старта по сбросу от вочдога. Кто как делает такое? Спасибо!
_Pasha
Цитата(smk @ May 18 2008, 18:37) *
Цель вопроса - нужно надежно отличать старт при включении питания от старта по сбросу от вочдога. Кто как делает такое? Спасибо!


Пример для меги8
Код
.org 0
rjmp start
...............
start:
        in r0,MCUCSR
        sbrc r0,PORF
        rjmp ColdBoot

; write hot boot code here
        rjmp Main

ColdBoot:
; write cold boot code here

Main:
; continue program execution
Сергей Борщ
Цитата(smk @ May 18 2008, 18:37) *
При включении питания переменная my_variable будет иметь значение 0хFF,
При включении питания ее значение не определено, т.е. может быть любым. Как указал _Pasha, надо определить факт включения по специально предназначенному для этого биту (PORF для меги8) и обнулить эту переменную.
smk
Цитата
Как указал _Pasha, надо определить факт включения по специально предназначенному для этого биту (PORF для меги8)

Спасибо.
Как я успел заметить - студия не симулирует регистр MCUSR (Tiny13)?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.