Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проблема с прерыванием CAN Rx
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Simok
Ребята, бъюсь с этим уже неделю, просто достало.

Установил прерывание на входящие пакеты по CAN.

-------------------------------

CODE
// CAN interrupt service routine
interrupt [CAN_IT] void can_isr(void)
{
// Place your code here

CANGIE = 0;

if((CANSIT2 & 1)!=0) // MOB0 сработал?
{

// for(i=0;i<8;i++) data[i]=CANMSG; // Прочитать сообщение целиком

can_in=1;
}


toggleLED1_on(); delay_ms(50); toggleLED1_off(); // Визуальный тест
}

-----------------------------------------

В теле основной программы в while вставил

CODE
/****************************************************************/
/* CAN initialization */
/****************************************************************/

void can_init (unsigned char BT_1,unsigned char BT_2,unsigned char BT_3)
{
unsigned char i=0;
unsigned char j=0;
//reset CAN interface
CANGCON |= (1<<SWRES);

//reset all MObs
for (i=0; i<15; i++)
{
CANPAGE = (i<<4); //select MOb
CANCDMOB = 0; //disable MOb
CANSTMOB = 0; //clear status
CANIDT1 = 0; //clear ID
CANIDT2 = 0;
CANIDT3 = 0;
CANIDT4 = 0;
CANIDM1 = 0; //clear mask
CANIDM2 = 0;
CANIDM3 = 0;
CANIDM4 = 0;
for (j=0; j<8; j++)
CANMSG = 0; //clear data
}

// set CAN -> baudrate
// bit timing -> datasheet 264 (check table)
// 250Kbps 8MHz cpu-clk
CANBT1 = BT_1; // 0x00;
CANBT2 = BT_2; // 0x0C;
CANBT3 = BT_3; // 0x60;

//start CAN interface
//CANGCON = (1<<ENASTB);

// clear CAN interrupt registers
CANGIE = 0xA0; // none interrupts
CANIE1 = 0; // none interrupts on MObs
CANIE2 = 0x03;
CANEN2 = 0x03; // 0x03 = 2 mail // 0x01 = 1 mail
CANSIT1 = 0;
CANSIT2 = 0;

//start CAN interface
CANGCON = (1<<ENASTB);

//wait until module ready
while (!(CANGSTA & (1<<ENFG)));
}

--------------------------------------------

CODE
void my_can_rx_unlim_time_11 (unsigned long my_id, unsigned char MyIDfiltr_4, unsigned char MyIDfiltr_3,
unsigned char MyIDfiltr_2, unsigned char MyIDfiltr_1){

unsigned char i;
CANHPMOB=0;

//select MOb0
CANPAGE = 0x00; //select MOb0

//clear MOb flags
//CANSTMOB = 0;

my_id *= 2; // умножение на 2
CANIDT1 = (unsigned char) (my_id>>4);
CANIDT2 = (unsigned char) (my_id<<4);

// set mask in order to receive only the message with the ID
CANIDM4 = MyIDfiltr_4; //
CANIDM3 = MyIDfiltr_3; //
CANIDM2 = MyIDfiltr_2; //
CANIDM1 = MyIDfiltr_1; //
// enable extended ID
//CANIDM4 |= (1<<IDEMSK);


// enable reception and
CANCDMOB=(1<<CONMOB1) | (0<<IDE);

// wait until reception is complete
// while(!(CANSTMOB&(1<<RXOK)));

// reset flag
// CANSTMOB &= ~(1<<RXOK);


va=CANIDT1;
vb=CANIDT2;

return;
}

// Поехали..

main{

while(1){

// № 1 ################################################################################
#######################

// Здесь принимаем только один единственный ID 0x321.
my_can_rx_unlim_time_11(0x321,248,255,255,255);

// Если сработало прерывание CAN Rx
if((CANSTMOB&(1<<RXOK))){

// wait until reception is complete
//while(!(CANSTMOB&(1<<RXOK)));

// reset flag
CANSTMOB &= ~(1<<RXOK);

}

can_in=0; // Снимаем флаг прерывания.
CANGIE = 0xA0; // Разрешаем прерывание CAN Rx.
}


//################################################################################
#########################

}

}

-------------------------------------------------------

Вот это все работает, но если я функции while последовательно вставлю еще одну проверку на другой пакет:

CODE
// № 2 ################################################################################
#######################

// Здесь принимаем только один единственный ID 0x325.
my_can_rx_unlim_time_11(0x325,248,255,255,255);

// Если сработало прерывание CAN Rx
if((CANSTMOB&(1<<RXOK))){

// wait until reception is complete
//while(!(CANSTMOB&(1<<RXOK)));

// reset flag
CANSTMOB &= ~(1<<RXOK);

}

can_in=0; // Снимаем флаг прерывания.
CANGIE = 0xA0; // Разрешаем прерывание CAN Rx.
}


//################################################################################
#########################


То прерывание срабатывает только на этот последний ID Под номером 2, а код под номером 1 не срабатывает на прерывание. Я уже запарился, не могу проверить (выловить) разный ID.
Simok
Вторую тему создал по CAN. Неужели никто не работает с этой шиной?? Ни одного ответа. Или нормальные герои не ходят в раздел для начинающих, хотя я бы не назвал себя начинающим, но структура форума такова, что в другом разделе не дает создать тему новенькому на форуме.
zltigo
Цитата(Simok @ Feb 2 2009, 17:30) *
Вторую тему создал по CAN. Неужели никто не работает с этой шиной??


Работают, работают! Только ведь Вы же не про "шину" спрашиваете а про то, что у Вас какой-то код не работает. Причем для неназванного чипа, но похоже, что CAN-AVR которую по нынешним временам использовать нет никакого смысла ввиду убогого функционала и неадекватной стоимости оставшейся с прошлого века. 

Потерпите, кто-нибудь возможно и потянется.
Simok
Цитата(zltigo @ Feb 2 2009, 21:30) *
Работают, работают! Только ведь Вы же не про "шину" спрашиваете а про то, что у Вас какой-то код не работает. Причем для неназванного чипа, но похоже, что CAN-AVR которую по нынешним временам использовать нет никакого смысла ввиду убогого функционала и неадекватной стоимости оставшейся с прошлого века. 

Потерпите, кто-нибудь возможно и потянется.


Понял, спасибо. Да, действительно, чип не указал. Камень у меня AT90CAN128. По поводу проблемы немного поясню короче и потолковее исходя из последних опытов. Проблема в прерывании CAN на входящие пакеты. Если в цикл while я вставляю функцию на получение только определенного ID, то все прекрасно работает, правда приходится прерывание останавливать при его возникновении и снова запускать, иначе всегда висит в прерывании, если оно сработало. Но если я вставлю подряд две функции и каждой назначен маской уникальный ID, то срабатывает прерывание исключительно на последнюю функцию. Результат, не могу использовать прерывание для нескольких разных ID (их нельзя указать одной маской).

Потом непонятно, почему прерывание не срабатывает само по себе, не вставляя функцию Rx в цикл. Хотя например прерывание от ноги (кнопки) срабатывает как и положено, само по внешнему сигналу, и для него нет необходимости вставлять код функции в тело Main, хватает кода и в самом прерывании. Почему не так в CAN прерывании, мне не понятно. По логике, оно должно было срабатывать при поступлении нужного сообщения само, а нет, надо делать запрос на получение в теле программы. Еще загвоздка в том, что если в само прерывание вставить функцию отправки или получения сообщения, то оно зависает через несколько пакетов, что тоже обламывает. Правда есть еще таймер от CAN, может оно решает подобные проблемы??
Simok
Камень AT90CAN128

Получаю по CAN сообщения с одним ID, остальные по маске не проходят. А мне нужно параллельно знать, поступают ли другие сообщения в сети в принципе. Как в таком случае узнать, что на линии еще есть другие сообщения?
andreyasm
Вы используете только MOB0, а их 15 штук, и для каждого полный набор регистров.
Где выбор MOB? перед чтением д.б. CANPAGE=new_MOb;
Обязательно в прерывании:
BYTE oldMob=CANPAGE; //запомнить
...
CANPAGE=oldMob; //востановить

После срабатывания прерывания нужно снова настраивать MOb на прием и уберите delay_ms(50) - в прерывании это ПРОТИВОЗАКОННО! . cool.gif
SasaVitebsk
Цитата(zltigo @ Feb 2 2009, 22:30) *
Работают, работают! Только ведь Вы же не про "шину" спрашиваете а про то, что у Вас какой-то код не работает. Причем для неназванного чипа, но похоже, что CAN-AVR которую по нынешним временам использовать нет никакого смысла ввиду убогого функционала и неадекватной стоимости оставшейся с прошлого века. 

Ну функционал не убогий. Тут вы погарячились. smile.gif
Наоборот функционал очень прекрасный, по сравнению например с пиками. smile.gif По сравнению с LPC - очень мало чем уступает.

А вот цена действительно несоответствующая сегодняшним реалиям.
Simok
Цитата(andreyasm @ Mar 1 2009, 15:14) *
Вы используете только MOB0, а их 15 штук, и для каждого полный набор регистров.
Где выбор MOB? перед чтением д.б. CANPAGE=new_MOb;
Обязательно в прерывании:
BYTE oldMob=CANPAGE; //запомнить
...
CANPAGE=oldMob; //востановить

После срабатывания прерывания нужно снова настраивать MOb на прием и уберите delay_ms(50) - в прерывании это ПРОТИВОЗАКОННО! . cool.gif


Прерывание настроено на два ящика, но я не пойму, как выловить это прерывание... Я пробовал и MOB0 и MOB1.. Я просто не въеду в эти ящики и прерывания. Если прерывание например на ногу порта, то оно и срабатывает независимо от хода программы, когда на ноге есть уровень. А здесь никаких действий. Вот что меня волнует. Прерывание срабатывает конечно, но только если его подтолкнуть, т.е. в коде программы надо вставлять функцию чтения ящиков, а это напрягает, если программа например находится в ожидании действий пользователя, то приходиться туда же повторно вставлять функцию чтения ящиков в While и break по условию. Если прерывание идет по MOB0, то прерывание должно срабатывать, т.е. должен исполняться код внутри прерывания, а этого не происходит. Непривычно как то, другие прерывания срабатывают, как положено, а это что за прерывание, если так и так нужно его "подталкивать", и это не зависимо от выбора ящика, а если еще и проводить проверку на получение, то пока не придет хотя бы один пакет, программа дальше работать не будет. Пришлось все пока реализовать засчет собственных конструкции, но хотелось бы компактнее и без лишних переменных. Читаешь описание протокола CAN, все настолько просто и ясно, начинаешь реализовывать и получашь не то, что думаешь. Все это касабельно прерывания, без него все просто и ясно.
KRS
Все работает как написано в даташите и прогнозируемо!
Я обрабатываю прерывания примерно так:
1. Считываю регистр CANGSTA проверяю там нужные флаги ( в основсном BUS OFF)
2. Считываю регистр CANHPMOB если он меньше чем 0xF0, то обрабатываю событие в MAILBOX
Если был принят пакет, очищаю MAILBOX и запускаю заново таким образом:
CANSTMOB=0;
CANCDMOB=0x90; // используются 29 битные ID
Strateg
Я работаю с CAN очень плотно, но использую связку SJA1000 + m8515. И к тому-же пишу только на ассемблере.
Если тебе поможет, то могу сбросить исходник ( на asm-e ) , как у меня организована фильтрация по ID
KRS
Цитата(Strateg @ Mar 10 2009, 23:57) *
Я работаю с CAN очень плотно, но использую связку SJA1000 + m8515.

SJA1000 тут точно не поможет, там все совсем по другому устроено.
Хорошая эта штука SJA1000, один из первых и до сих пор используется много, диагностика полная есть, глюков нет. Только места много занимает и 5 вольтовый. Всетки в новых разработках актуальнее и гораздо дешевле STM32 поставить, чем SJA1000 + m8515
Simok
Цитата(Strateg @ Mar 10 2009, 23:57) *
Если тебе поможет, то могу сбросить исходник ( на asm-e ) , как у меня организована фильтрация по ID


Был бы признателен, может этот пинок направит меня в нужное русло.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.