problem in can bus receive

Go To Last Post
14 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi,
I want to use CAN rx interrupt and I try to use the codes which are suggested here, I can get CAN data successfully when I send data by CAN card from my laptop, but when I connect ECU to my board, I didn't get anything. I checked the signal by the scope,whenever I connected ECU to my board, the level of signal peak destroyed, I tried to use different capacitor and schematic but non of them couldn't solve my problem. I attached the schematic of board and also my code. I would be grateful if someone could help me.

my code:

interrupt [CAN_IT] void can_isr(void) 
{ 
unsigned char save_canpage,i; 
save_canpage = CANPAGE; 
CANSTMOB = 0; 
CANPAGE = (1 << MOBNB1); Select MOb2. 

for(i=0;i<8;i++)
{
tx_buffer1[i] = CANMSG;
} 

tx_counter1=8; 
UDR1=tx_buffer[0];
CANPAGE = save_canpage; 
CANPAGE = (1 << MOBNB1); // Select MOb2. 

CANIDT1 = 0x00; 
CANIDT2 = 0x00;
CANIDT3 = 0x00; 
CANIDT4 = 0x00;   

CANIDM4 = 0x00;  
CANIDM3 = 0x00; 
CANIDM2 = 0x00; 
CANIDM1 = 0x00; 
 
CANCDMOB = (1 << CONMOB1) | (1 << DLC3); //Enable rx 
PORTB.7=1;
} 


void main(void) 
{
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif 
PORTB=0x00;
DDRB=0xFF;
//
// USART1 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART1 Receiver: Off
// USART1 Transmitter: On
// USART1 Mode: Asynchronous
// USART1 Baud Rate: 9600
UCSR1A=0x00;
UCSR1B=0x48;
UCSR1C=0x06;
UBRR1H=0x00;
UBRR1L=0x33;

can_init(); 
#asm("sei") 
can_rx(); 
UDR1=9;
while (1) 
 {
  
 }; 
}

void can_init(void) 
{ 
int i; 

#asm("cli") 

// CAN initialization: 
CANGCON=0;
CANGCON = (1<<SWRES); 
CANGIT=0;
for (i=0; i<15; i++) 
 { 
    CANPAGE = (i << 4); 
    
    CANCDMOB = 0x00;
    CANSTMOB = 0x00; 
 }    
 
CANBT1 = 0x00; // CAN baudrate: 500 kbit/s 
CANBT2 = 0x0C; 
CANBT3 = 0x37;

CANGIE = (1 << ENRX) | (1 << ENIT) | (1 << ENERR); 

CANIE2 = (1 << IEMOB2); 
CANIE1 = 0x00; 

//CANEN2 = (1<<ENMOB2);
//CANEN1=0;

CANGCON = (1 << ENASTB); // Enable CAN.

}

void can_rx(void) 
{ 
CANPAGE = (1 << MOBNB1); // Select MOb2. 

CANIDT1 = 0x00; 
CANIDT2 = 0x00;
CANIDT3 = 0x00; 
CANIDT4 = 0x00;   

CANIDM4 = 0x00;  
CANIDM3 = 0x00; 
CANIDM2 = 0x00; 
CANIDM1 = 0x00; 
 
CANCDMOB = (1 << CONMOB1) | (1 << DLC3); //Enable rx 
}

$ Fixed code tags - JS $

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You set and enable CANGIE.ENERR and your interrupt [CAN_IT] void can_isr() code blindly re-enabled the MOb Rx. Well, a CANSTMOB error flag does not disable the Rx MOb, so blindly re-enabling the Rx MOb (as in writing to an already busy MOb) when any CANSTMOB error is responded to is a big problem. You need to check for the CANSTMOB.RXOK flag before re-enabling the Rx MOb.

Since you are not doing anything with the CANSTMOB error flags interrupt I recommend you remove ENERR from the can_init() code to fix this problem, or at the very least rewrite your ISR code to be aware of and correctly respond to the RXOK flag.

Your PCA82C250 schematic is mostly (except the termination resistor value) from the data sheet Fig 3 Test circuit for dynamic characteristics:
http://www.nxp.com/documents/dat...

This is not the correct configuration to use this chip. In any case the capacitor on pin 3 Vcc is supposed to be 100 nf, not 100 pf. The other 100 pf and 30 pf capacitors should not be there for normal use. See the data sheet Fig 9 Application of the CAN transceiver. Since you selected high speed mode by grounding the RS pin it is recommended you use shielded CAN bus wiring (in your case this RS pin implementation is different from figure 9 in the data sheet).

There are fancier CAN bus setups using the SPLIT pin (your chip does not have this pin) or split termination, and caps connected to the CAN bus like Fig 9 Typical application for the TJA1040 with a 5V microcontroller and Fig 11 Optional circuitry at CANH and CANL (both from this application note):
http://www.nxp.com/documents/app...

Phillips (now NXP) "upgraded" the PCA82C250/251 to these chips: TJA1040 or TJA1050 back in 2001. It was called an upgrade notice, but it looked more like a replacement notice to me :wink: :
http://www.tw.nxp.com/documents/...
This upgrade document has additional application information.

Your AT90CAN chip needs to be 5 volt Vcc in your configuration.

You should learn to use CODE tags when posting source code in this forum.

Your interrupt [CAN_IT] code:

    CANPAGE = save_canpage;

is placed too soon in your code. This code:

    CANPAGE = (1 << MOBNB1); // Select MOb2.

that follows makes the save CANPAGE operation useless since it changes the CANPAGE value inside the ISR and does not restore the original CANPAGE value from before the when the ISR is exited. Move it to the end like this:

    PORTB.7=1;
    CANPAGE = save_canpage;
}

Your code:

    UDR1=tx_buffer[0];

looks very dangerous. First you never checked to see if the USART1 Tx buffer is already full or not. Then if you do check like you should, doing serial USART I/O inside an AVR interrupt is a very, very bad idea. A USART buffer ready wait can be really slow and these waits degrade the performance of the entire AVR interrupt system. Do your USART operations outside the ISR code. If you want diagnostics inside the ISR do something high speed like setting PORT pins for a LED display.

In the can_init() code you do not need these:

    #asm("cli")
    CANGCON=0;

The SWRES clears CANGCON and disables any possible CAN interrupts. Your code is secure against any CAN interrupts until after the ENASTB is set. It should not matter if other non-CAN interrupts are triggered while setting up the CAN module. BTW, your can_init() CANGIT=0; and CANIE1=0x00; are also already covered by the SWRES (see the data sheet register initial values).

I would work on correcting the above hardware and software problems first and try again after they are fixed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi Mike,
Thank you very much for your reply.
I checked my circuit and rewrite my code again, but unfortunately I couldn't get any data. although I can see signal in CAN H & CAN L pin,I couldn't receive any signal on my RX pin. it shows constant DC (around 5v).
I also checked mu code by AVR studio manually and it seems work correctly.
here I attached the schematic and my new code.
Thanks again for your guide.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sorry my code doesn't attach completely I send it again

Code:

/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.3 Standard
Automatic Program Generator
© Copyright 1998-2011 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 3/27/2012
Author : PerTic@n
Company : If You Like This Software,Buy It
Comments:

Chip type : AT90CAN128
Program type : Application
AVR Core Clock frequency: 8.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 1024
*****************************************************/

#include <90can128.h>

#ifndef RXB8
#define RXB8 1
#endif

#ifndef TXB8
#define TXB8 0
#endif

#ifndef UPE
#define UPE 2
#endif

#ifndef DOR
#define DOR 3
#endif

#ifndef FE
#define FE 4
#endif

#ifndef UDRE
#define UDRE 5
#endif

#ifndef RXC
#define RXC 7
#endif

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<DOR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

#define init 1
#define reset 2
#define receive 3
#define send 4
#define idle 5
#define data_saving 6

unsigned char can_state;

void can_mode(unsigned char r);
void can_init(void);
void can_receive(void);
void tx_send(void);
void can_reset(void);
void can_data(void);
// USART1 Transmitter buffer
#define TX_BUFFER_SIZE1 8
char tx_buffer1[TX_BUFFER_SIZE1];

#if TX_BUFFER_SIZE1 <= 256
unsigned char tx_wr_index1,tx_rd_index1,tx_counter1;
#else
unsigned int tx_wr_index1,tx_rd_index1,tx_counter1;
#endif

// USART1 Transmitter interrupt service routine
interrupt [USART1_TXC] void usart1_tx_isr(void)
{
if (tx_counter1)
{
--tx_counter1;
UDR1=tx_buffer1[tx_rd_index1++];
#if TX_BUFFER_SIZE1 != 256
if (tx_rd_index1 == TX_BUFFER_SIZE1) tx_rd_index1=0;
#endif
}
if(tx_counter1==1)
{
can_state=reset;
};
}

// Write a character to the USART1 Transmitter buffer
#pragma used+
void putchar1(char c)
{
while (tx_counter1 == TX_BUFFER_SIZE1);
#asm("cli")
if (tx_counter1 || ((UCSR1A & DATA_REGISTER_EMPTY)==0))
{
tx_buffer1[tx_wr_index1++]=c;
#if TX_BUFFER_SIZE1 != 256
if (tx_wr_index1 == TX_BUFFER_SIZE1) tx_wr_index1=0;
#endif
++tx_counter1;
}
else
UDR1=c;
#asm("sei")
}
#pragma used-

// CAN interrupt service routine
interrupt [CAN_IT] void can_isr(void)
{
CANSTMOB=0;
PORTB.7=1;

// Reset flags
CANGIT&= ~(1<<OVRTIM);
can_state=data_saving;
}

// Declare your global variables here

void main(void)
{

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Port B initialization
PORTB.7=0;
DDRB.7=1;

PORTD.7=0;
DDRD.7=1;

PORTD.6=0;
DDRD.6=1;

// USART1 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART1 Receiver: Off
// USART1 Transmitter: On
// USART1 Mode: Asynchronous
// USART1 Baud Rate: 9600
UCSR1A=0x00;
UCSR1B=0x48;
UCSR1C=0x06;
UBRR1H=0x00;
UBRR1L=0x33;

// Global enable interrupts
#asm("sei")
can_state=init;
while (1)
{
can_mode(can_state);

}
}

void can_mode(unsigned char r)
{
switch(r)
{
case init:
can_init();
break;

case reset:
can_reset();
break;

case receive:
can_receive();
break;

case send:
tx_send();
break;

case idle:
break;

case data_saving:
can_data();
break;
};
}

void can_init(void)
{

CANGCON=(1<<SWRES); // Reset the CAN controller

CANGSTA=0x00;

CANIE2=0x02; // Interrupts: MOb1: on
CANIE1=0x00;

CANHPMOB=(1 << HPMOB0);

CANGIE = (1 << ENIT) | (1 << ENRX);// CAN Interrupts:General intererupt, RX interrupt

//baud rate 500k
CANBT1=0x00;
CANBT2=0x0C;
CANBT3=0x37;

// CAN Timer Clock Period: 1.000 us
CANTCON=0x00;
can_state=reset;
}

void can_reset(void)
{
unsigned char ch;
unsigned char data;
//..... Reset all the MObs.........//
for (ch=0; ch<15; ch++)
{
CANPAGE=ch<<4;
CANSTMOB=0;
CANIDT1=0;
CANIDT2=0;
CANIDT3=0;
CANIDT4=0;
CANIDM1=0;
CANIDM2=0;
CANIDM3=0;
CANIDM4=0;
for (data=0; data<8; data++) CANMSG=0;
}
can_state=receive;
};

void can_receive(void)
{
CANPAGE=(1 << MOBNB0);

CANIDM4 = 0x00; // receive all
CANIDM3 = 0x00;
CANIDM2 = 0x00;
CANIDM1 = 0x00;

CANIDT4 = 0x00;
CANIDT3 = 0x00;
CANIDT2 = 0x00;
CANIDT1 = 0x00;
CANGCON=0x02;
CANCDMOB=(1 << CONMOB1) | (1 << DLC3); //enable rx
can_state=idle;
};

void tx_send(void)
{
UDR1=tx_buffer1[0];
tx_counter1=8;
can_state=reset;
};

void can_data(void)
{
unsigned char i;
for(i=0;i<8;i++)
{
tx_buffer1[i]=CANMSG;
};
can_state=send;
};

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You ignored the comment about using code tags when posting source code. Well, your source code does not really appear to have much indentation anyway. The code tags preserve the indentation in source code to hopefully make it more readable. Please clean up your source code formatting and use code tags when posting source code.

pari1363 wrote:
although I can see signal in CAN H & CAN L pin,I couldn't receive any signal on my RX pin. it shows constant DC (around 5v).
Well, there is not much I can do if your PCA82C250 RXD output pin is not changing states. First consider this:
PCA82C250 data sheet wrote:
Pin 8 (Rs) allows three different modes of operation to be selected: High-speed, Slope control and Standby.

If a HIGH level is applied to pin 8, the circuit enters a low-current Standby mode. In this mode, the transmitter is switched off and the receiver is switched to a low current. If dominant bits are detected (differential bus voltage >0.9 V), RXD will be switched to a LOW level. The microcontroller should react to this condition by switching the transceiver back to normal operation (via pin 8 ). Because the receiver is slow in Standby mode, the first message will be lost.

Now that you have the RS pin connected to the AVR CAN chip, are you controlling the RS pin correctly? For testing purposes just having the RS grounded like before would be a better way to start. You appear to be struggling with the CAN bus hardware design. For simple beginning use keep your CAN bus wiring short and use simple 120 ohm resistor termination, only at each end of the CAN bus. If you want a fancy EMC controlled CAN bus design, get some hardware engineering help on that after you get your program code working.
pari1363 wrote:
I also checked mu code by AVR studio manually and it seems work correctly.
If by checking manually you meant using the AVRstudio simulator, well this simulator does not support CAN at all. Your code does not work correctly anyway.

The CANGCON.SWRES resets the CAN hardware. Every CAN register description has a drawing of the register bits with Read/Write and Initial Value below each drawing.
1) The SWRES forces the initial value shown.
2) Only R/W bits may be successfully written to. R bits may not be written to.
3) Only the general registers have initial values.
4) None of the MOb registers have initial values.

For example in the can_init() code

    CANGSTA=0x00;

Well, the CANGSTA bits are read only and the SWRES already cleared all these bits during the CAN hardware reset. This code is meaningless and harmless, except it shows you are not paying attention to the data sheet and writing bad code or not understanding the CAN hardware registers at all. You have problems like this with CANHPMOB and ignoring the SWRES reset initial values with CANIE1 and CANTCON.

Next CANCDMOB is never initialized during the CAN initialization code. Well, looking at the data sheet CANCDMOB is a MOb register with no initial value. This means when you start the CAN module (set CANGCON.ENASTB) your CANCDMOB command bits have random garbage values in them. Your code needs to initialize all the CANCDMOB register bytes to zero values. Like this in can_reset():

for (ch=0; ch<15; ch++)
    {
        CANPAGE=ch<<4;
        CANCDMOB=0;
        CANSTMOB=0;
….

However, there is a problem since can_reset() is also called from main(). The CANCDMOB=0 will disable MOb 1 which is allowed, but you need to wait for CANEN.ENMOB1 to clear and for CANSTMOB to possibly be cleared by can_isr() after disabling a MOb (you are not doing this at all). Except now your CANPAGE assignment changes in can_reset() which will break any pending can_isr() interrupt (see MOb 1 below), so CANSTMOB may never clear, but your force it cleared in the can_reset() code. The can_reset() code totally breaks your program if you call it from main(). You need to rethink and rewrite this code. Your can_reset() code only works correctly (with the CANCDMOB=0 added) when it is part of can_init().

Take a moment to go through your code and check off all the CAN registers you use against the data sheet for read only bits and initialization values.

This:

    CANGCON=0x02;
-or-
    CANGCON=(1 << ENASTB);

is not even set until sometime after can_receive() is called. The CANGCON.ENASTB bit enables the entire CAN unit. So, your entire CAN module is not working at all until after you select a Rx operation. Try moving this to can_init():

....
    can_state=reset;
    CANGCON=(1 << ENASTB);
}

Enabling the CAN hardware is usually a one time event that is part of the CAN initialization. Even after you set ENASTB it still takes time for the AVR to synchronize with the existing CAN traffic, so this CAN enable is not instantaneous.

You only set CANPAGE to MOb 1 one single time, so the can_isr() code absolutely depends on this and your program code will only ever work with MOb 1. A normal can_isr() would save the CANPAGE value first thing, set the CANPAGE value for the interrupt processing as needed, then restore the original saved CANPAGE value before returning from the interrupt code. Since CANPAGE (which is a general register) must be set before accessing any MOb registers, normal can_isr() code must not change/corrupt the CANPAGE value when the CAN interrupt is triggered. Your code is very fragile and will completely break if you use additional MObs for anything at all, and your can_reset() code changes CANPAGE which breaks this fragile dependency when it is called from main(). The broken part is, a CANSTMOB interrupt could be pending during the can_reset(), then the change in CANPAGE makes it impossible for can_isr() to clear the interrupt flags in CANSTMOB for MOb 1. This means you exit can_isr() with CANSTMOB still set and the CAN interrupt still pending. Not a good thing to do. Your code has a very tricky/unlikely interrupt execution sequence time bomb waiting to explode if conditions ever go wrong after calling can_reset() from main().

In your schematic UC + CAN chip shows a RXD pin. This should be AVR pin 31 RXCAN. The AVR TXD pin should be pin 30 TXCAN. The AVR RXDn and TXDn pins are for the USARTs.

Until you figure out why the AVR RXCAN pin is not changing (RS pin held high in standby mode, incorrect EMC components on the CAN H and CAN L bus leads, or CAN bus CAN H and CAN L wired backwards, etc.?), there is no reason for your CAN to work at all. After the AVR RXCAN pin gets a CAN bus signal is when you may start debugging your program code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Mike

Thanks again for your reply.

I checked my hardware again and fortunately I could fix the problem. Now I have signal on my RX pin of MCP82C250 :D

I can see some code on the terminal, but I don't know are they true or not?

[If by checking manually you meant using the AVRstudio simulator, well this simulator does not support CAN at all. Your code does not work correctly anyway. ]

I installed at90can128_plugin and AVRstudio 4 and it shows me the flags set, but I'm not sure about it.

I tried to change my code as the way you suggested.
Could you please check them again?

code:
[/*****************************************************
Chip type : AT90CAN128
Program type : Application
AVR Core Clock frequency: 8.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 1024
*****************************************************/

#include <90can128.h>

#ifndef RXB8
#define RXB8 1
#endif

#ifndef TXB8
#define TXB8 0
#endif

#ifndef UPE
#define UPE 2
#endif

#ifndef DOR
#define DOR 3
#endif

#ifndef FE
#define FE 4
#endif

#ifndef UDRE
#define UDRE 5
#endif

#ifndef RXC
#define RXC 7
#endif

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<DOR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

#define init 1
#define receive 2
#define send 3
#define idle 4
#define data_saving 5

unsigned char can_state;

void can_mode(unsigned char r);
void can_init(void);
void can_receive(void);
void tx_send(void);
void can_data(void);
// USART1 Transmitter buffer
#define TX_BUFFER_SIZE1 8
char tx_buffer1[TX_BUFFER_SIZE1];

#if TX_BUFFER_SIZE1 <= 256
unsigned char tx_rd_index1,tx_counter1;
#else
unsigned int tx_wr_index1,tx_rd_index1,tx_counter1;
#endif

// USART1 Transmitter interrupt service routine
interrupt [USART1_TXC] void usart1_tx_isr(void)
{
if (tx_counter1)
{
--tx_counter1;
UDR1=tx_buffer1[tx_rd_index1++];
#if TX_BUFFER_SIZE1 != 256
if (tx_rd_index1 == TX_BUFFER_SIZE1) tx_rd_index1=0;
#endif
}
if(tx_counter1==1)
{
can_state=idle;
};
}

// CAN interrupt service routine
interrupt [CAN_IT] void can_isr(void)
{
unsigned char save_canpage;

save_canpage=CANPAGE;

CANSTMOB=0;
CANCDMOB=0;
PORTB.7=1;

// Reset flags
CANGIT&= ~(1<<OVRTIM);
CANPAGE=save_canpage;

CANIDM4 = 0x00; // receive all
CANIDM3 = 0x00;
CANIDM2 = 0x00;
CANIDM1 = 0x00;

CANIDT4 = 0x00;
CANIDT3 = 0x00;
CANIDT2 = 0x00;
CANIDT1 = 0x00;

//enable rx
CANCDMOB=(1 << CONMOB1) | (1 << DLC3);

can_state=data_saving;
}

// Declare your global variables here

void main(void)
{

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Port B initialization
PORTB.7=0;
DDRB.7=1;

//Rs pin of mcp82c2550
PORTD.7=0;
DDRD.7=1;

// USART1 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART1 Receiver: Off
// USART1 Transmitter: On
// USART1 Mode: Asynchronous
// USART1 Baud Rate: 9600
UCSR1A=0x00;
UCSR1B=0x48;
UCSR1C=0x06;
UBRR1H=0x00;
UBRR1L=0x33;

// Global enable interrupts
#asm("sei")
can_state=init;
while (1)
{
can_mode(can_state);

}
}

void can_mode(unsigned char r)
{
switch(r)
{
case init:
can_init();
break;

case receive:
can_receive();
break;

case send:
tx_send();
break;

case idle:
break;

case data_saving:
can_data();
break;
};
}

//........CAN_initialization..........//
void can_init(void)
{
unsigned char ch;
unsigned char data;

// Reset the CAN controller
CANGCON=(1<<SWRES);

//..... Reset all the MObs.........//
for (ch=0; ch<15; ch++)
{
CANPAGE = (ch << 4);

CANCDMOB = 0x00;
CANSTMOB = 0x00;
for (data=0; data<8; data++)
{
CANMSG=0;
}

}

// Interrupts: MOb1: on
CANIE2=(1 << IEMOB1);

// CAN Interrupts:General intererupt, RX interrupt
CANGIE = (1 << ENIT) | (1 << ENRX);

//baud rate 500k
CANBT1=0x00;
CANBT2=0x0C;
CANBT3=0x37;

CANGCON=0x02;
can_state=receive;
}

void can_receive(void)
{
CANPAGE=(1 << MOBNB0);

// receive all
CANIDM4 = 0x00;
CANIDM3 = 0x00;
CANIDM2 = 0x00;
CANIDM1 = 0x00;

CANIDT4 = 0x00;
CANIDT3 = 0x00;
CANIDT2 = 0x00;
CANIDT1 = 0x00;

//enable rx
CANCDMOB=(1 << CONMOB1) | (1 << DLC3);

can_state=idle;
};

void tx_send(void)
{
UDR1=tx_buffer1[0];
tx_counter1=8;
can_state=idle;
};

void can_data(void)
{
unsigned char i;
for(i=0;i<8;i++)
{
tx_buffer1[i]=CANMSG;
};
can_state=send;
};]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sorry I forgot to use tags. I sent them again

/*****************************************************
Chip type               : AT90CAN128
Program type            : Application
AVR Core Clock frequency: 8.000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 1024
*****************************************************/

#include <90can128.h>

#ifndef RXB8
#define RXB8 1
#endif

#ifndef TXB8
#define TXB8 0
#endif

#ifndef UPE
#define UPE 2
#endif

#ifndef DOR
#define DOR 3
#endif

#ifndef FE
#define FE 4
#endif

#ifndef UDRE
#define UDRE 5
#endif

#ifndef RXC
#define RXC 7
#endif

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<DOR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

#define init 1
#define receive 2
#define send 3
#define idle 4
#define data_saving 5

unsigned char can_state;

void can_mode(unsigned char r);
void can_init(void);
void can_receive(void);
void tx_send(void);
void can_data(void);
// USART1 Transmitter buffer
#define TX_BUFFER_SIZE1 8
char tx_buffer1[TX_BUFFER_SIZE1];

#if TX_BUFFER_SIZE1 <= 256
unsigned char tx_rd_index1,tx_counter1;
#else
unsigned int tx_wr_index1,tx_rd_index1,tx_counter1;
#endif

// USART1 Transmitter interrupt service routine
interrupt [USART1_TXC] void usart1_tx_isr(void)
{
if (tx_counter1)
   {
   --tx_counter1;
   UDR1=tx_buffer1[tx_rd_index1++];
#if TX_BUFFER_SIZE1 != 256
   if (tx_rd_index1 == TX_BUFFER_SIZE1) tx_rd_index1=0;
#endif
   }  
   if(tx_counter1==1)
   { 
   can_state=idle;
   };
}


// CAN interrupt service routine
interrupt [CAN_IT] void can_isr(void)
{
unsigned char save_canpage;

   save_canpage=CANPAGE;

   CANSTMOB=0;
   CANCDMOB=0;
   PORTB.7=1;

    // Reset flags
   CANGIT&= ~(1<<OVRTIM);
   CANPAGE=save_canpage;

   CANIDM4 = 0x00;   // receive all
   CANIDM3 = 0x00;
   CANIDM2 = 0x00;
   CANIDM1 = 0x00; 

   CANIDT4 = 0x00;    
   CANIDT3 = 0x00;
   CANIDT2 = 0x00;
   CANIDT1 = 0x00;  
   
   //enable rx         
   CANCDMOB=(1 << CONMOB1) | (1 << DLC3); 
   
   can_state=data_saving;
}

// Declare your global variables here

void main(void)
{

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif


// Port B initialization
PORTB.7=0;
DDRB.7=1;

//Rs pin of mcp82c2550
PORTD.7=0;
DDRD.7=1;


// USART1 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART1 Receiver: Off
// USART1 Transmitter: On
// USART1 Mode: Asynchronous
// USART1 Baud Rate: 9600
UCSR1A=0x00;
UCSR1B=0x48;
UCSR1C=0x06;
UBRR1H=0x00;
UBRR1L=0x33;


// Global enable interrupts
#asm("sei")
can_state=init;
while (1)
      {
      can_mode(can_state);

      }
}

void can_mode(unsigned char r)
{
 switch(r)
 {
 case init:
 can_init();
 break;
 
 
 case receive:
 can_receive();
 break;
 
 
 case send:
 tx_send();
 break;
 
 
 case idle:
 break; 
 
 
 case data_saving:
 can_data();
 break;
 };
}

//........CAN_initialization..........//
void can_init(void)
{
unsigned char ch; 
unsigned char data; 
    
    // Reset the CAN controller
    CANGCON=(1<<SWRES);
    
    //..... Reset all the MObs.........// 
    for (ch=0; ch<15; ch++)
     { 
        CANPAGE = (ch << 4); 
            
        CANCDMOB = 0x00;
        CANSTMOB = 0x00; 
        for (data=0; data<8; data++) 
        {
            CANMSG=0;
        }
            
     }  
      
    //  Interrupts: MOb1: on 
    CANIE2=(1 << IEMOB1);               
    
    // CAN Interrupts:General intererupt, RX interrupt
    CANGIE = (1 << ENIT) | (1 << ENRX);
    
    //baud rate 500k
    CANBT1=0x00;   
    CANBT2=0x0C;
    CANBT3=0x37;
    
    CANGCON=0x02; 
    can_state=receive;
}


void can_receive(void)
{
       CANPAGE=(1 << MOBNB0);

     
       // receive all
       CANIDM4 = 0x00;     
       CANIDM3 = 0x00;
       CANIDM2 = 0x00;
       CANIDM1 = 0x00; 

       CANIDT4 = 0x00;    
       CANIDT3 = 0x00;
       CANIDT2 = 0x00;
       CANIDT1 = 0x00; 
             
       //enable rx
       CANCDMOB=(1 << CONMOB1) | (1 << DLC3); 
       
       can_state=idle;
};


void tx_send(void)
{
UDR1=tx_buffer1[0];
tx_counter1=8;
can_state=idle;
};

void can_data(void)
{
 unsigned char i;
 for(i=0;i<8;i++)
 {
 tx_buffer1[i]=CANMSG;
 };
 can_state=send;
};
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for using the code tags.

pari1363 wrote:
I installed at90can128_plugin and AVRstudio 4 and it shows me the flags set, but I'm not sure about it.
All this plug-in does is things like display all the CANMSG values without having to set CANPAGE first to see each value. The plug-in works best with JTAG ICE debugging. Unfortunately, really important things like using CANCDMOB writes to set CANEN bits, setting CANCDMOB bits upon command completion, setting CANSIT bits, setting CANHPMOB values and such do not work at all with the software simulator :(. A Dragon is the least expensive current ATMEL JTAGICE.

This is a more typical structure to prevent CANPAGE being corrupted by the ISR:

interrupt [CAN_IT] void can_isr(void)
{
unsigned char save_canpage;

   save_canpage=CANPAGE;

   CANPAGE=(1 << MOBNB0);

   CANSTMOB=0;
   CANCDMOB=0;
   PORTB.7=1;

    // Reset flags
   CANGIT&= ~(1<<OVRTIM);

   CANIDM4 = 0x00;   // receive all
   CANIDM3 = 0x00;
   CANIDM2 = 0x00;
   CANIDM1 = 0x00;

   CANIDT4 = 0x00;
   CANIDT3 = 0x00;
   CANIDT2 = 0x00;
   CANIDT1 = 0x00;

// ** You should get any MOb data before the Rx re-enable below.
   //enable rx
   CANCDMOB=(1 << CONMOB1) | (1 << DLC3); // Re-enable the Rx MOb.

   can_state=data_saving;
   CANPAGE=save_canpage;
}

Notice that now nothing anywhere else outside the ISR will change the MOb 1 CANPAGE value in the ISR and the ISR will not corrupt any other code that sets CANPAGE outside the ISR. Since you removed can_reset() you could just not use save_canpage in the ISR, but this way makes the ISR code more robust for future changes in your code. Your ISR code is heavily simplified and will only work when using a single MOb (CANIE2.IEMOB1=1) for Rx only (CANGIE.ENIT=1 and CANGIE.ENRX=1). If you change these in the future you will need to rewrite the ISR code.

The Rx code needs to check and make sure the CAN MOb 1 is not already busy with a Rx:

void can_receive(void)
{
       if (CANEN2 & (1 << ENMOB1))  // Is MOb 1 busy and not ready?
           return (RX_BUSY_ERROR);
       CANPAGE=(1 << MOBNB0);
       if (CANSTMOB)                // Has the ISR finished with MOb 1?
           return (RX_BUSY_ERROR);
       ....

Then you need to create the RX_BUSY_ERROR definition and handle any error return. There are other ways of doing this. You just need to make sure you never write a new Rx command to MOb 1 if it is still busy with the last MOb 1 Rx command. The ISR Rx MOb 1 re-enable is already disabled because the ISR cannot be entered unless there was a MOb 1 CANSTMOB.RXOK=1 set by the CAN hardware. The RXOK disabled MOb 1, so no code is required to check for MOb 1 busy in the ISR.

The biggest problem is you re-enable MOb 1 Rx in the ISR before you extract any MOb data. When you re-enable the Rx MOb it makes whatever is stored in the MOb 1 registers vulnerable to automatic changes written by the CAN hardware (you will always absolutely have to beat the next CAN data Rx time or loose MOb 1 data). Try extracting CANMSG bytes in the ISR and placing it directly in your USART buffer before the ISR Rx MOb 1 re-enable. Also consider extracting all four CANIDT register values and the CANCDMOB register value in the ISR after the RXOK and saving these values to your larger USART buffer as well, before the Rx MOb 1 re-enable. Because you set CANIDM4.IDEMSK=0 you may Rx 11 bit or 29 bit format CAN identifiers. Because you set CANIDM4.RTRMSK=0 you may Rx data frames or remote frames. If you Rx a remote frame (CANIDT4.RTRTAG=1) there are no CANMSG bytes to save to the USART buffer because only data frames (CANIDT4.RTRTAG=0) have any valid CANMSG byte values. Maybe you meant to use this instead?

void can_receive(void)
    ….
    CANIDM4 = ((1 << RTRMSK) | (1 << IDEMSK));

The CANIDM4.IDEMSK=1 will force only 11 bit format identifiers to be received because CANCDMOB.IDE=0 when you enable your Rx MOb 1. The CANIDM4.RTRMSK=1 will force only CAN data frames (which have CANMSG bytes) to be received because CANIDT4.RTRTAG=0 when you enable your Rx MOb 1.

If you make this change and save the MOb information from inside the ISR to the USART buffer, obviously your "data_saving" state is obsolete and the ISR should end with the "send" state.

Because all your CANIDM.IDMSKn bits are set to zero you will receive any/all identifier values. So, if you do not recover this ID information from the MOb 1 registers, you will not have any idea where your CANMSG data bytes are from without any saved ID information. The RXOK fills in the CANIDT value with the actual ID the Tx CAN traffic sent.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Mike,

Thank you very much. you helped me learn a lot.
I changed my code as the way you said and I can see the data on my serial port.

I want to change my code in a way which let me to receive and transmit, but I faced with some problem. I received the data but the data is combined with some wrong data. how I can fix the problem?

my code:

/*****************************************************
Chip type               : AT90CAN128
Program type            : Application
AVR Core Clock frequency: 8.000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 1024
*****************************************************/

#include <90can128.h>

#ifndef RXB8
#define RXB8 1
#endif

#ifndef TXB8
#define TXB8 0
#endif

#ifndef UPE
#define UPE 2
#endif

#ifndef DOR
#define DOR 3
#endif

#ifndef FE
#define FE 4
#endif

#ifndef UDRE
#define UDRE 5
#endif

#ifndef RXC
#define RXC 7
#endif

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<DOR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

#define init 1
#define receive 2
#define send 3
#define idle 4
#define send_can 5

unsigned char can_state;

void can_mode(unsigned char r);
void can_init(void);
void can_receive(void);
void tx_send(void);
void can_send(void);
// USART1 Transmitter buffer
#define TX_BUFFER_SIZE1 8
char tx_buffer1[TX_BUFFER_SIZE1];

#if TX_BUFFER_SIZE1 <= 256
unsigned char tx_rd_index1,tx_counter1;
#else
unsigned int tx_wr_index1,tx_rd_index1,tx_counter1;
#endif

// USART1 Transmitter interrupt service routine
interrupt [USART1_TXC] void usart1_tx_isr(void)
{
if (tx_counter1)
   {
   --tx_counter1;
   UDR1=tx_buffer1[tx_rd_index1++];
#if TX_BUFFER_SIZE1 != 256
   if (tx_rd_index1 == TX_BUFFER_SIZE1) tx_rd_index1=0;
#endif
   }  
   if(tx_counter1==1)
   { 
   can_state=send_can;   //enable CAN send
   };
}


// CAN interrupt service routine
interrupt [CAN_IT] void can_isr(void)
{ 
unsigned char i;

  if (CANSTMOB & (1<<RXOK)) 
   {
    CANSTMOB=0;
    CANCDMOB=0;
    // Reset flags
    CANGIT&= ~(1<<OVRTIM);
    CANPAGE=(1 << MOBNB0);

       CANIDM4 = 0x00;     // receive EC4
       CANIDM3 = 0x00;
       CANIDM2 = 0xE0;
       CANIDM1 = 0xFF; 

       CANIDT4 = 0x00;    
       CANIDT3 = 0x00;
       CANIDT2 = 0x80;
       CANIDT1 = 0x7C;  
    
     
     for(i=0;i<8;i++)
     {
     tx_buffer1[i]=CANMSG;
     };
        
    CANCDMOB=(1 << CONMOB1) | (1 << DLC3); //enable rx
    can_state=send;      // send data to serial port
    PORTB.7=~PORTB.7;  
    };
     if (CANSTMOB & (1<<TXOK))
   {
    CANSTMOB=0;
    CANCDMOB=0;
    

    // Reset flags
    CANGIT&= ~(1<<OVRTIM);
    CANPAGE=(1 << MOBNB1);

       CANIDM4 = 0x00;     // receive EC5
       CANIDM3 = 0x00;
       CANIDM2 = 0xE0;
       CANIDM1 = 0xFF; 

       CANIDT4 = 0x00;    
       CANIDT3 = 0x00;
       CANIDT2 = 0xA0;
       CANIDT1 = 0x7C;  
    
       CANMSG=0X80;
       CANMSG=0X80;
       CANMSG=0X80;
       CANMSG=0X80;
       CANMSG=0X80;
       CANMSG=0X80;
       CANMSG=0X80;
       CANMSG=0X80;

        
    CANCDMOB=(1 << CONMOB0) | (1 << DLC3); //enable tx
    can_state=receive;         //enable CAN receive
    }; 
  
}

// Declare your global variables here

void main(void)
{

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif


// Port B initialization
PORTB.7=0;
DDRB.7=1;

//Rs pin of mcp82c2550
PORTD.7=0;
DDRD.7=1;


// USART1 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART1 Receiver: Off
// USART1 Transmitter: On
// USART1 Mode: Asynchronous
// USART1 Baud Rate: 9600
UCSR1A=0x00;
UCSR1B=0x48;
UCSR1C=0x06;
UBRR1H=0x00;
UBRR1L=0x33;


// Global enable interrupts
#asm("sei")
can_state=init;
while (1)
      {
      can_mode(can_state); 

      }
}

void can_mode(unsigned char r)
{
 switch(r)
 {
 case init:
 can_init();
 break;
 
 
 case receive:
 can_receive();
 break;
 
 
 case send:
 tx_send();
 break;
 
 
 case idle:
 break; 
 
 case send_can:
 can_send();
 break;
 
 
 };
}

//........CAN_initialization..........//
void can_init(void)
{
 unsigned char ch; 
 unsigned char data; 
 
    CANGCON=(1<<SWRES);// Reset the CAN controller

    //..... Reset all the MObs.........// 
    for (ch=0; ch<15; ch++)
     { 
        CANPAGE = (ch << 4); 
        
        CANCDMOB = 0x00;
        CANSTMOB = 0x00; 
        for (data=0; data<8; data++) 
        {
            CANMSG=0;
        }
        
     }   
     
    CANIE2=(1 << IEMOB1)|(1 << IEMOB2);               //  Interrupts: MOb1: on

    CANGIE = (1 << ENIT) | (1 << ENRX) | (1 << ENTX);// CAN Interrupts:General intererupt, RX interrupt
     
    //baud rate 500k
    CANBT1=0x00;   
    CANBT2=0x0C;
    CANBT3=0x37;
    
    CANGCON=0x02; 
    can_state=receive;
}


void can_receive(void)
{
       CANPAGE=(1 << MOBNB0);  //mob 1

     
       CANIDM4 = 0x00;     // receive 3E4
       CANIDM3 = 0x00;
       CANIDM2 = 0xE0;
       CANIDM1 = 0xFF; 

       CANIDT4 = 0x00;    
       CANIDT3 = 0x00;
       CANIDT2 = 0x80;
       CANIDT1 = 0x7C;              
       CANCDMOB=(1 << CONMOB1) | (1 << DLC3); //enable rx
       can_state=idle;
};

void can_send(void)
{
       CANPAGE=(1 << MOBNB1);    //mob2

     
       CANIDM4 = 0x00;     // receive 3E5
       CANIDM3 = 0x00;
       CANIDM2 = 0xE0;
       CANIDM1 = 0xFF; 

       CANIDT4 = 0x00;    
       CANIDT3 = 0x00;
       CANIDT2 = 0xA0;
       CANIDT1 = 0x7C;       
       
       CANCDMOB=(1 << CONMOB0) | (1 << DLC3); //enable Tx
       can_state=idle;
};

void tx_send(void)
{
UDR1=tx_buffer1[0];
tx_counter1=8;
can_state=idle;
};
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have a bit of syntax strangeness in your code. Search for:

};
- and replace all of them with -
}

Take a look at a C language reference manual for correct C syntax. Immediately try your corrected code first and see if anything changed.

pari1363 wrote:
I received the data but the data is combined with some wrong data. how I can fix the problem?
I do not understand what your problem is. I do not know what data is correct, what you meant by combined data or what data is wrong and most of all I have no idea what any of the data actually is :wink:. Is some of your data out of sequence (sent by the Tx CAN node, but displayed differently)? Is some of your data missing (like it was lost from the CAN Tx)? Is there any data that is not out of sequence or missing that just has unexplained values that were never sent by the CAN Tx node?

Consider your USART baud rate is only 9600 baud. This is one start bit, 8 data bits, one stop bit. This is 10 bits at 9600 baud, which takes about 1.041 ms per USART byte. A CAN data frame with 8 bits of data (1 data byte) is 55 CAN bits at 500 kbaud, which is .11 ms per CAN byte. So, to send a USART byte at 1.041 ms means a maximum frame rate CAN Rx byte could come in every .11 ms, which means the CAN might be up to 9.4 times faster than the USART. If you send more then one CAN byte in each data frame (up to 8 CAN bytes maximum), each additional CAN bite only takes a single CAN bit (the CAN overhead bits are the same for 1 to 8 CAN data bytes sent). This means sending more than one CAN data byte in each CAN frame makes CAN even faster then the USART.

At 500 kbps the CAN will take about .222 ms for 8 CAN data bytes in a single CAN data frame. The 9600 baud USART takes about 8.333 ms to send 8 bytes. This makes the 9600 baud USART about 37.5 times slower then the CAN (bad news for your USART debugging output).

If your CAN bus Rx data byte rate is capable of overrunning your USART byte Tx data rate, look at what happens. The USART is slowly (with respect to the CAN data rate) sending characters and the RXOK happens, the CAN ISR instantly replaces the tx_buffer1[i] data while the USART is still using it.

Think about what your USART data output will look like if the CAN using its interrupt just replaces tx_buffer1[i] data anytime it wants to with new CAN data. It is possible to completely corrupt your USART data. I would say it is more than possible and very likely this is what is happening.

With your AVR 8 MHz clock, UBRR = 0x0C and U2X1 = 1 you could get 76.8 k baud on USART1 (only a .2% error). See the data sheet Table 17-11. Examples of UBRRn Settings for Commonly Frequencies. This is about .13 ms per USART byte. Your USART is still slower than the CAN maximum data rate of .11 ms per CAN data byte, but it has a better chance of maybe keeping up with the CAN new data byte rate, than 9600 baud 1.041 ms per USART byte does.

The 76.8 kbps USART takes about 1.104 ms for 8 data bytes. The CAN is still capable of .222ms for 8 data bytes per CAN frame. Now your USART is only about 4.9 times slower than the CAN (allot better then 37.5 times slower at 9600 baud).

Keep in mind the CAN does not have to send at the maximum CAN data byte rate. The Tx CAN node could Tx data as slowly as it wants to. If your CAN Tx node is slow enough (even at 500 kbps) at sending new data bytes then you USART will be able to keep up without getting corruption.

Since all CAN nodes must all run at exactly the same CAN baud rate, if you are able to change the baud rate of all your CAN nodes to match, try testing at a much slower CAN baud rate and with a faster USART baud rate.

One way to look for corruption is when entering the CAN ISR code check can_state:

interrupt [CAN_IT] void can_isr(void)
{ 
unsigned char i;

  if (CANSTMOB & (1<<RXOK)) 
   {
    if (can_state == send_can) {
        // this ISR is about to corrupt data the USART is still sending
        // light up an error LED or some kind of fast error indicator
    }
....

This is for debugging only, but it will tell you if your CAN Rx data rate is overrunning your USART Tx data rate.

pari1363 wrote:
I want to change my code in a way which let me to receive and transmit, but I faced with some problem.
Since you have to rewrite your program code to do this, I would wait until after you take care of all the above stuff and know your CAN is working or not working the way it already is. Lets do this part later.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Immediately try your corrected code first and see if anything changed.

It won't. Semi-colon is just a statement terminator and you can use as many as you like:

#include 
;;;;;;;;;;;;;;;;;;

int main(void) {
  printf("hello");;;;;;;;;;;;;;;;;;
};;;;;;;;;;

is completely valid and will compile - the semi-colons (apart from the one that must follow printf()) have no effect.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I agree and understand your point, but is the OP testing yet another compiler to see if it works with totally unnecessary/unusual punctuator syntax or is the OP trying to get a program working? What you can get away with doing and what you should do is not always the same thing.

Turn the argument around and ask the OP why did you feel this syntax was needed and what did it do for you? I do not know what level of understanding the OP has. My first thought is the OP could be a beginner doing things without understanding any intent or lack of intent. Why not read a language reference and learn to write cleaner code or at least have a reason for what you do write?

*edit: the main point of immediately recompiling and testing is to look for editing/rewriting mistakes.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Mike,

I know the data which send bu ECU on CAN bus. Whenever I just enable receive interrupt what I received is completely true, but if I enable receive and transmit interrupt, the order of 8 data which are received by ISR changed and in some cases some wrong data comes between my data.

for exmple I send this data by CAN card from my Laptop CAN card: [1 2 3 4 5 6 7 8]

if I just enbale receive interrupt I received the data correctly, but in rx & tx isr enable I received this one: 1 0 1 7 2 3 4 8

The ECU send data on the CAN bus every 10 ms and I just want to receive the specific ID.

I try to modify my code again and send it back to you. Thanks again.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since you are only sending CAN Tx data at 10 ms intervals and your 9600 baud USART is taking about 8.333 ms, so you are not corrupting the tx_buffer1[i] data.

Your original code used to only enable one single MOb, so the interrupt code was able to start with:
if (CANSTMOB & (1<<RXOK))
and still work.

Now that you put two MObs into your program, consider that CANSTMOB requires setting CANPAGE first, or you will not know which CANSTMOB register you are accessing. Also, now that you have more than one MOb you must save CANPAGE when entering the CAN ISR and restore CANPAGE when exiting the CAN ISR (I fixed this). Your ISR comments about ID EC4 and EC5 were wrong. The IDs are 0x3E4 and 0x3E5 (I showed you another method to set these). You left RTRMSK=0 and IDEMSK=0 which allowed your Rx to receive Remote Frames (there are no CAN data bytes in Remote Frames) and 29 bit identifiers (I fixed this). The TXOK ISR was triggering infinite CAN Tx Data Frames, so I cleaned this up and removed the can_state= because the Tx ISR happens in its own unique time frame and has noting to do with the current CAN state (the ISR would abruptly change can_state on every TXOK). The Tx does not use CANIDM, but the reserved bits should be cleared. I moved your CANGIT clear to one single instance at the end of the ISR. Then in can_send() you sent a CAN Tx without setting up any CAN data at all which sends uninitialized garbage in the CAN Tx.

interrupt [CAN_IT] void can_isr(void)
{ 
unsigned char save_canpage,i;

  save_canpage = CANPAGE;

  CANPAGE=(1 << MOBNB0);    // MOb 1
  if (CANSTMOB & (1<<RXOK)) 
   {
     CANSTMOB=0;         // Clear the MOb 1 RXOK interrupt flag
     CANCDMOB=0;

     CANIDM4 = (1 << RTRMSK) | (1 << IDEMSK);
     CANIDM3 = 0x00;
     CANIDM2 = 0xE0;
     CANIDM1 = 0xFF;

//     CANIDT4 = 0x00;   // 0x7C80 is actually ID 0x3E4
//     CANIDT3 = 0x00;
//     CANIDT2 = 0x80;
//     CANIDT1 = 0x7C;
// Try this instead to avoid future confusion (this produces the same 0x7C80):
     CANIDT4 = (0 << RTRTAG);  // Data Frame
     CANIDT3 = 0x00;
     CANIDT2 = (unsigned char) (0x3E4 << 5);
     CANIDT1 = (unsigned char) (0x3E4 >> 3); // Set 11 bit format ID 0x3E4.

     for(i=0;i<8;i++)
     {
       tx_buffer1[i]=CANMSG;
     }

     CANCDMOB=(1 << CONMOB1) | (1 << DLC3); //enable rx
     can_state=send;      // send data to serial port
     PORTB.7=~PORTB.7;  
   }

   CANPAGE=(1 << MOBNB1);    // MOb 2
   if (CANSTMOB & (1<<TXOK))
   {
      CANSTMOB=0;         // Clear the MOb 2 TXOK interrupt flag
      CANCDMOB=0;
   }
   // Reset flags
   CANGIT &= ~(1<<OVRTIM);

   CANPAGE = save_canpage;
}

void can_send(void)
{
      CANPAGE=(1 << MOBNB1);    //mob2
     
      CANIDM4 = 0x00;     // Zero all reserved mask bits
      CANIDM3 = 0x00;     // CANIDM is not used for Tx
      CANIDM2 = 0x00;
      CANIDM1 = 0x00; 

//      CANIDT4 = 0x00;    // 0x7CA0 is actually ID 0x3E5
//      CANIDT3 = 0x00;
//      CANIDT2 = 0xA0;
//      CANIDT1 = 0x7C;  
// Try this instead to avoid future confusion (this produces the same 0x7CA0):
      CANIDT4 = (0 << RTRTAG);  // Data Frame
      CANIDT3 = 0x00;
      CANIDT2 = (unsigned char) (0x3E5 << 5);
      CANIDT1 = (unsigned char) (0x3E5 >> 3); // Set 11 bit format ID 0x3E5.

      CANMSG=0X80;
      CANMSG=0X80;
      CANMSG=0X80;
      CANMSG=0X80;
      CANMSG=0X80;
      CANMSG=0X80;
      CANMSG=0X80;
      CANMSG=0X80;
        
      CANCDMOB=(1 << CONMOB0) | (1 << DLC3); //enable tx
       can_state=idle;
}

Now the reason your program was not working with the Tx interrupt enabled is because CANPAGE was not first set to MOb 2, your TXOK test was failing and never clearing MOb 2 CANSTMOB.TXOK. Not clearing CANSTMOB.TXOK for MOb 2 caused your program to constantly re-enter the ISR over and over (the same MOb 2 TXOK interrupt flag was still set when you returned from the CAN ISR). The AVR allows running one non-interrupt instruction between repeated interrupt responses, so your program was only running one single non-interrupt AVR instruction between repeated CAN ISR re-entries (you run the complete ISR, then one single non-interrupt AVR instruction, then the complete ISR again, then the next single non-interrupt AVR instruction, then the complete ISR.... and so on). This slowed your program down so much you were totally blowing your 10 ms CAN Rx timing margins and totally corrupting your results and trying to lock yourself in an infinite CAN Tx loop did not help either (see below).

The next problem is when you detect a TXOK the first time meaning the first can_send() completed, you immediately re-enable the CAN Tx all over again. Well, the first CAN Tx that completes will cause a never ending series of ID 0x3E5 CAN Data Frames to Tx forever. In other words your very first CAN Tx starts an avalanche of never ending CAN Tx Data Frames :(. I do not know when you want to Tx on the CAN bus, but you cannot always automatically trigger another new Tx upon the completion of the last CAN Tx or you will consume the CAN bus in 100% never ending CAN Tx traffic. Maybe you want to send the CAN Tx after the USART output? Another CAN Tx will add .222ms to the 9600 baud USART 8.333 ms for about 8.555+ ms of your 10 ms budget. You will still make your timing margin but keep in mind it is getting tighter with only a 9600 baud USART.

*edit: I forgot to mention you need to fix CANIDM4 in can_receive().