Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Работа с прерываниями в WinAVR
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
studert
Задаю благозвучное название прерывания
#define PacketReceiveComplete INT5_vect

Объявлена глобальная переменная, значение которой
uint64t_t DestMAC;

Обработчик прерывания, функция getDestMAC записывает в переменную DestMAC нужные данные
ISR(PacketReceiveComplete){
cli();
getDestMAC(&DestMAC);
sei();
}
int main(void){
...
printf("%lx",DestMAC);
}
Это не работает, печатает мусор,причем попытки изменить DestMAC main тоже неудачны, она не меняется. Что я делаю не так?
_dem
Код
#define PacketReceiveComplete INT5_vect

volatile uint64t_t DestMAC;

ISR(PacketReceiveComplete){
getDestMAC(&DestMAC);
}

int main(void){
...
printf("%lx",DestMAC);
}


ps. мое личное IMHO, использование int такого размера на 8-мибитнике для хранения MAC адреса - не лучшая идея.
Палыч
Цитата(studert @ Oct 17 2008, 14:07) *
Что я делаю не так?
Попробуйте так

int main(void){
uint64t_t temp;
...
cli();
temp= DestMAC;
sei();
printf("%lx",temp);
}
SasaVitebsk
volatile забыли. Иначе оптимизатор может выкинуть чтение перед выдачей.

Непонятно зачем cli в прерывании. Хотя смотря как вы вектор объявляли.
studert
Цитата(Палыч @ Oct 17 2008, 18:14) *
Попробуйте так

int main(void){
uint64t_t temp;
...
cli();
temp= DestMAC;
sei();
printf("%lx",temp);
}

Так тоже не работает, если при попытке отправить в порт DestMAC выводится мусор, то как присвоив мусор другой переменной от него избавиться? Где и как нужно объявлять глобальные переменные, чтобы они были доступны всем подпрограммам?
aesok
Цитата(studert @ Oct 17 2008, 15:07) *
Объявлена глобальная переменная, значение которой
uint64t_t DestMAC;


avr-libc-user-manual FAQ#1

Цитата(studert @ Oct 17 2008, 15:07) *
printf("%lx",DestMAC);


Уточните в avr-libc-user-manual поддерживает ли printf 64-битные типы.

Цитата(studert @ Oct 17 2008, 15:07) *
ISR(PacketReceiveComplete){
cli();
getDestMAC(&DestMAC);
sei();
}


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

Анатолий.
Палыч
Вы уверены, что функция printf выполняется после того, как в DestMAC будет что-то положено?
studert
Цитата(SasaVitebsk @ Oct 17 2008, 18:27) *
volatile забыли. Иначе оптимизатор может выкинуть чтение перед выдачей.

Непонятно зачем cli в прерывании. Хотя смотря как вы вектор объявляли.

Ну cli это я от незнания поставил, первый раз с прерываниями работаю в этом компиляторе, до этого на асме только использовал. Я правильно понял, что компилятор сам поставит cli/sei? А volatile что-то тоже не помог. Может есть у кого пример, в котором по внешнему прерыванию изменяется какая-нибудь переменная, которая потом выводится в main?
Палыч
Цитата(studert @ Oct 17 2008, 14:28) *
Так тоже не работает, если при попытке отправить в порт DestMAC выводится мусор, то как присвоив мусор другой переменной от него избавиться?
Переменная DestMAC занимает 8 байт. Чтобы 8-мибитному контроллеру переложить её значение из одной области памяти в другую (например, в стек при выполнении printf("%lx",DestMAC)) потребуется минимум 16 команд. Если при их выполнении произайдёт прерывание и изменится значение DestMAC, то получите значение: часть байтов - новые, часть - старые, т.е. что-то похожее на "мусор".
studert
Цитата(aesok @ Oct 17 2008, 18:33) *
avr-libc-user-manual FAQ#1
Уточните в avr-libc-user-manual поддерживает ли printf 64-битные типы.
Нельзя разрешать прерывания перед выходом из прерывания, они сами разрештся при выполнении инструкции RETI.

Анатолий.

Спасибо за ответ. Действительно принтф не поддерживает 64 бит.
Kernigan
Цитата(aesok @ Oct 17 2008, 14:33) *
Нельзя разрешать прерывания перед выходом из прерывания, они сами разрештся при выполнении инструкции RETI.

Можно конечно. Не запрещено.
mandrew
Цитата(studert @ Oct 17 2008, 15:07) *
Задаю благозвучное название прерывания
#define PacketReceiveComplete INT5_vect

Объявлена глобальная переменная, значение которой
uint64t_t DestMAC;

Обработчик прерывания, функция getDestMAC записывает в переменную DestMAC нужные данные
ISR(PacketReceiveComplete){
cli();
getDestMAC(&DestMAC);
sei();
}
int main(void){
...
printf("%lx",DestMAC);
}
Это не работает, печатает мусор,причем попытки изменить DestMAC main тоже неудачны, она не меняется. Что я делаю не так?


1) А просто printf у вас работает, если не использовать обработчиков прерываний по приему, по окончании передачи, по свободному регистру UDRn?
studert
Цитата(mandrew @ Oct 17 2008, 19:05) *
1) А просто printf у вас работает, если не использовать обработчиков прерываний по приему, по окончании передачи, по свободному регистру UDRn?

Принтф работает, выводит все как положено, если 64 битные данные не кормить.
MrYuran
Цитата(studert @ Oct 17 2008, 16:27) *
Принтф работает, выводит все как положено, если 64 битные данные не кормить.

Ну так может тогда вместо uint64 сделать char[8] и кормить как строку символов?

Не, погорячился. Тогда точно мусор будет.
Палыч
Никто не мешает разбить 64 бита на несколько ulong, uint или даже uchar (например, через union) и в printf использовать уже их. Тем более, что автору нужно шестнадцатиричное значение (не забыть, только, что выводить нужно с лидирующими нулями - поставить в формате соответствующие числа).
mdmitry
В каком виде надо MAC-адрес выводить? В зависимости от задачи и решение.
Можно сделать массив на 6 байт и в него записывать побайтно соответствующие значения и при необходимости побайтно выводить.

Есть проблемы с глобальной переменной: во время работы printf (функция очень медленная при выводе в порт) произошло прерывание и данные поменялись. Что выводим?

Необходимо задать значения по умолчанию (прерывания не было, а printf наступил).

P.S. Палыч чуть опередил.
_dem
Studert, а разве приведенный мною код у Вас не работает ?
aesok
Цитата(Kernigan @ Oct 17 2008, 16:04) *
Цитата
Нельзя разрешать прерывания перед выходом из прерывания, они сами разрештся при выполнении инструкции RETI


Можно конечно. Не запрещено.


1. Лишняя инструкция SEI, прерывания все равно будут разрешенны при выполнении инструкции RETI.

2. При разрешении прерывани до возвращения из обработчика создаються условия что следующиу обработчик(и) вызовутся когда в стеке еще находиться адрес возврата и возможно локальные переменные текущего обработчика, что приводит к повышенному и неэффективному использованию опреративной памяти.

3. Специфично для GCC. Если функции нужно место в стеке, то нужно модифицировать регистр указателя стека. Пролог и эпилог обработчика прерывиня генерируеться из предположения что прерывания отключены и в них не выполняеться временное отключение прерываний при модификации указателя стека. Разрешая прерывания до эпилога возникают условия что обработчик прерывания может быть вызван когда указатель стека модифицирован только частично (старший байт уже изменен младший еще нет), что может привести к критическим последствиям.

Анатолй.
demiurg_spb
Цитата(aesok @ Oct 17 2008, 21:20) *
Пролог и эпилог обработчика прерывиня генерируеться из предположения что прерывания отключены и в них не выполняеться временное отключение прерываний при модификации указателя стека.

На мой взляд такое предположение не совсем удачно. Компилятор ничего не должен предполагать - это прерогатива программиста.

Иногда просто необходимо разрешать прерывания внутри обработчика прерывания.
Выход видится такой:
Код
intX:
   прогол
   op1
   op2
   sei
   op3
   ....
   op333
   cli
   эпилог
   reti

Может есть другие, более изящные варианты?
Где в документации можно прочесть об этом нюансе?
aesok
Цитата(demiurg_spb @ Oct 17 2008, 22:51) *
Иногда просто необходимо разрешать прерывания внутри обработчика прерывания.
Выход видится такой:
Код
intX:
   прогол
   op1
   op2
   sei
   op3
   ....
   op333
   cli
   эпилог
   reti


Это будет работать до того момента, пока кто нибудь не напишет:
{
sei()
...
if(...)
return;
...
cli()
}

Цитата
Где в документации можно прочесть об этом нюансе?


http://gcc.gnu.org/onlinedocs/gcc-4.3.2/gc...tion-Attributes

Цитата
signal
Use this attribute on the AVR to indicate that the specified function is a signal handler. The compiler will generate function entry and exit sequences suitable for use in a signal handler when this attribute is present. Interrupts will be disabled inside the function.
ReAl
Цитата(demiurg_spb @ Oct 17 2008, 21:51) *
На мой взляд такое предположение не совсем удачно. Компилятор ничего не должен предполагать - это прерогатива программиста.
Если компилятор ничего не будет предполагать, он будет связан по рукам при оптимизации.
А прерогатива програмиста - управлять его предположениями.
Предполагает же он, что переменная не меняется, пока он сам её не поменяет? Предполагает. Пока программиcт не отобъёт эту предполагалку при помощи слова volatile.
С прерываниями - если нужно, чтобы данное прерывание всё выполнялось при разрешённых прерываниях, то
Код
ISR(INT0_vect,ISR_NOBLOCK)
{
}
и прерывания будут разрешены первой командой обработчика, потом будут если надо для модификаций указателя стека запрещаться на пару команд.

Цитата(demiurg_spb @ Oct 17 2008, 21:51) *
Иногда просто необходимо разрешать прерывания внутри обработчика прерывания.
Выход видится такой:
...
Может есть другие, более изящные варианты?
Где в документации можно прочесть об этом нюансе?
Если нужно разрешить на части обработчика, то других вариантов и нет. Чтобы не було проблем, обозначеннх aesok, надо глянуть <util/atomic.h>
Код
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>

volatile uint8_t a, b;

ISR(INT0_vect)
{
    ++a;
    NONATOMIC_BLOCK(NONATOMIC_FORCEOFF)
    { //+++ от сих
        PORTB |= 0x02;
        if( PINB & 0x01 ) return;  // а тут запретятся перед уходом на эпилог
        PORTB |= 0x04;        
    } //--- и до сих - прерывания разрешены
    ++b;
}


Это сделано на gcc-шном расширении C - атрибутах, приписывающих к переменным некие функции инициализации и очистки. По сути - конструкторы и деструкторы, выражаясь языком C++
Приведенный выше код эквивалентен С++ - ному
Код
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>

class noatomic_forceoff
{
public:
    noatomic_forceoff() { sei(); }
    ~noatomic_forceoff() { cli(); }
};

volatile uint8_t a, b;

ISR(INT0_vect)
{
    ++a;
    {
        noatomic_forceoff na;
        PORTB |= 0x02;
        if( PINB & 0x01 ) return;
        PORTB |= 0x04;        
    }
    ++b;
}
вплоть до сгенерированного компиляторами кода
avr-gcc -std=c99 -O2 -S -mmcu=atmega88
avr-g++ -O2 -S -mmcu=atmega88
CODE
__vector_1:
/* prologue: frame size=0 */
push __zero_reg__
push __tmp_reg__
in __tmp_reg__,__SREG__
push __tmp_reg__
clr __zero_reg__
push r24
/* prologue end (size=6) */
lds r24,a
subi r24,lo8(-(1))
sts a,r24
/* #APP */
sei
/* #NOAPP */
sbi 37-0x20,1
sbic 35-0x20,0
rjmp .L2
sbi 37-0x20,2
/* #APP */
cli
/* #NOAPP */
lds r24,b
subi r24,lo8(-(1))
sts b,r24
rjmp .L5
.L2:
/* #APP */
cli
/* #NOAPP */
.L5:
/* epilogue: frame size=0 */
pop r24
pop __tmp_reg__
out __SREG__,__tmp_reg__
pop __tmp_reg__
pop __zero_reg__
reti
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.