AT91SAM7X CAN driver problems

Hi everyone,

I am currently busy writing a CAN driver for the Atmel SAM7X. My setup is as follows:

2 Evaluation boards: Olimex SAM7-EX256 Rev. a. One for transmitting messages and the other for receiving them.

Controller : ATMEL AT91SAM7X256

Used toolchain: YAGARTO

Used debugger: Open OCD + Olimex ARM USB OCD

My code is based on an example for the IAR compiler: AT91SAM7X256-BasicCAN-IAR430A-1_2. Right now, my objective is to simply send a CAN message from one board to the other.

My init code:

// Enable CAN PIOs

AT91F_CAN_CfgPIO();

// Enable CAN Clock

AT91F_CAN_CfgPMC();

// Enable CAN Transceiver

AT91F_PIOA_CfgPMC();

// Init CAN Interrupt Source Level

AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, // CAN base address

AT91C_ID_CAN, // CAN ID

AT91C_AIC_PRIOR_HIGHEST, // Max priority

AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, // Level sensitive

AT91F_CAN_Handler); // C Handler

AT91F_AIC_EnableIt(AT91C_BASE_AIC,AT91C_ID_CAN);

// Cfg CAN Baudrate to 1Mbit/s => BRP = 5

// We choose 8 Time Quanta (tCSC = 125ns): 8tCSC = tSYNC + tPRS + tPHS1 + tPHS2

// Cfg PHASE1 PHASE2 PROPAG and SYNC segment

// Delay of busdriver + delay of receiver circuit = 200ns

// Delay of bus line considered negligible = 0ns

// tPRS = 2*(200+0) = 400ns < 4tCSC => PROPAG = 3

// tSYNC = 1tCSC => 8tCSC = 1tCSC + 4tCSC + tPHS1 + tPHS2

// tPHS1 + tPHS2 = 3tCSC => Phase Segment 2 = Max(IPT=2TQ,Phase Segment 1) = 2TQ => PHASE2 = 2-1 = 1 => PHASE1 = 0

// tSJW = Min(4 TQ, Phase Segment 1) = 1TQ => SJW = 1-1 = 0

AT91F_CAN_CfgBaudrateReg(AT91C_BASE_CAN,0x00050301);

enableIRQ(); //enable interrupts

// Enable CAN and Wait for WakeUp Interrupt

AT91F_CAN_EnableIt(AT91C_BASE_CAN,AT91C_CAN_WAKEUP);

AT91F_CAN_CfgModeReg(AT91C_BASE_CAN,AT91C_CAN_CANEN);

status = (AT91F_CAN_GetStatus(AT91C_BASE_CAN)&ERROR_MASK)>>16; //error active flag set in can status register! Not OK!

// Wait for WAKEUP flag raising <=> 11-recessive-bit were scanned by the transceiver

while( (testCAN != AT91C_TEST_OK) ) //the wake-up flag is set as expected in the CAN interrupt handler

{

}

// Configure Mailboxes

CANInitMailboxes();

//End of init.

#ifdef SENDER

// Ask Transmission on Mailbox 0

AT91F_CAN_InitTransferRequest(AT91C_BASE_CAN,AT91C_CAN_MB0);

// Enable Transmission Mailbox 0 interrupt

AT91F_CAN_EnableIt(AT91C_BASE_CAN,AT91C_CAN_MB0);

#else

// Enable Reception on Mailbox 1

AT91F_CAN_InitTransferRequest(AT91C_BASE_CAN,AT91C_CAN_MB1);

// Enable Mailbox 1 interrupt

AT91F_CAN_EnableIt(AT91C_BASE_CAN,AT91C_CAN_MB1);

#endif

/*

At this point the receiver should be waiting for a message in mailbox 1. The sender should send 1 message via mailbox 0 to the receiver.

*/

The CAN interrupt handler:

void AT91F_CAN_Handler(void)

{

volatile unsigned int status;

status = AT91F_CAN_GetStatus(AT91C_BASE_CAN) & AT91F_CAN_GetInterruptMaskStatus(AT91C_BASE_CAN);

AT91F_CAN_DisableIt(AT91C_BASE_CAN,status);

if(status & AT91C_CAN_WAKEUP) { //the wake-up interrupt is triggered, so thats ok.

testCAN = AT91C_TEST_OK;

D_TRACE_SIMPLE(“=>CAN WAKEUP”,1,BLUE);

}

if(status & AT91C_CAN_MB0) {

D_TRACE_SIMPLE(“=>CAN MB0 Int”,1,BLUE); //this interrupt is not triggered, so message sending fails

}

if(status & AT91C_CAN_MB1) {

D_TRACE_SIMPLE(“=>CAN MB1 Int”,1,BLUE); //this interrupt is not triggered, so message reception fails

}

}

The CAN wake-up flag is set as expected and handled by the ISR. However, as soon as I enable the CAN controller by setting CANEN in the mode register, the error active flag gets set in the status register.

Anyone an idea as to why this happens? When the transmitter is not attached to the bus (but with the 120 ohms terminator installed…), it keeps on sending frames. I assume these are error frames. The error

codes I read from the status register are:

-first only error active

-then warning limit & error passive & ack error

-then warning limit & error passive

-warning limit & error passive & ack error again

-and so on

When I then attach the receiver to the bus I get:

-warning limit & error passive & ack error & bit error

-and then warning limit & error passive

After that the communication dies down completely. So I assume the error frame sent by the transmitter is at least acknowledged by the receiver??

When the receiver is not connected to the bus I just get error active. when I then attach it to the bus it gives a form error & error active (after which the communication dies down, as said before).

Is there anybody who can point me in the right direction perhaps? Because right now I don’t have a clue. Or perhaps someone has already written a driver and is willing to share some code? Some help is much

appreciated.

regards,

Harm

Almost forgot. THis is how I init my mailboxes:

void CANInitMailboxes(void)

{

// Init CAN Mailbox 0

//taskENTER_CRITICAL();

AT91F_InitMailboxRegisters(AT91C_BASE_CAN_MB0,

AT91C_CAN_MOT_TX | AT91C_CAN_PRIOR, // Mailbox Mode Reg

0x00000000, // Mailbox Acceptance Mask Reg

AT91C_CAN_MIDvA & (0x07<<18), // Mailbox ID Reg

0x11223344, // Mailbox Data Low Reg

0x01234567, // Mailbox Data High Reg

(AT91C_CAN_MDLC & (0x8<<16)) ); // Mailbox Control Reg

//taskEXIT_CRITICAL();

//taskENTER_CRITICAL();

// Init CANMailbox 1

AT91F_InitMailboxRegisters(AT91C_BASE_CAN_MB1,

AT91C_CAN_MOT_RX | AT91C_CAN_PRIOR, // Mailbox Mode Reg

AT91C_CAN_MIDvA | AT91C_CAN_MIDvB | AT91C_CAN_MIDE, // Mailbox Acceptance Mask Reg

AT91C_CAN_MIDvA & (0x07<<18), // Mailbox ID Reg

0x00000000, // Mailbox Data Low Reg

0x00000000, // Mailbox Data High Reg

0x00000000); // Mailbox Control Reg

//taskEXIT_CRITICAL();

}

Did you manage to find a CAN driver? I’d be interested to know if you did.

Hi,

It turned out to be a memory allocation problem. ISR stack too small… Simple as that. So the example code I mentioned does indeed work.