cancel
Showing results for 
Search instead for 
Did you mean: 

CAN receive interrupts and remap.

jamessteward
Associate II
Posted on February 12, 2009 at 01:00

CAN receive interrupts and remap.

8 REPLIES 8
jamessteward
Associate II
Posted on May 17, 2011 at 13:02

Hi All,

I've got 2 STM32-P103 Olimex boards with CAN connected. These have the CAN pins wired to port C pins 8 and 9, so I've remapped them, but can't seem to get a receive interrupt to occur, despite setting the filter mask to 0x00000000.

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO |

RCC_APB2Periph_GPIOA |

RCC_APB2Periph_GPIOB |

RCC_APB2Periph_GPIOC, ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN |

RCC_APB1Periph_USART2 |

RCC_APB1Periph_TIM2, ENABLE);

/* CAN register init */

CAN_DeInit();

CAN_StructInit(&CAN_InitStructure);

/* CAN filter init */

CAN_FilterInitStructure.CAN_FilterNumber = 0;

CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;

CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;

CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;

CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;

CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;

CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;

CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;

CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;

CAN_FilterInit(&CAN_FilterInitStructure);

/* 36 MHz / (1 + BS1 + BS2) = 3000000. */

prescaler = 3000000UL / baud;

/* CAN cell init */

CAN_InitStructure.CAN_TTCM = DISABLE;

CAN_InitStructure.CAN_ABOM = DISABLE;

CAN_InitStructure.CAN_AWUM = DISABLE;

CAN_InitStructure.CAN_NART = DISABLE;

CAN_InitStructure.CAN_RFLM = DISABLE;

CAN_InitStructure.CAN_TXFP = DISABLE;

CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;

CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;

CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;

CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;

CAN_InitStructure.CAN_Prescaler = prescaler;

CAN_Init(&CAN_InitStructure);

/* CAN FIFO0 message pending interrupt enable */

CAN_ITConfig(CAN_IT_FMP0, ENABLE);

/* Configure CAN pin: RX */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

GPIO_Init(GPIOB, &GPIO_InitStructure);

/* Configure CAN pin: TX */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOB, &GPIO_InitStructure);

/* Put CAN pins out on port B pins 8 and 9 */

GPIO_PinRemapConfig(GPIO_Remap1_CAN, ENABLE);

/* Enable the CAN RX Interrupt */

NVIC_InitStructure.NVIC_IRQChannel = CAN_RX1_IRQChannel;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

/* CAN RX1 ISR */

void CAN_RX1_IRQHandler(void)

{

u32 head, next_head;

SerialPutString(''can_recv isr RX1\r\n''); <<-- Never happens

head = can_fifo.head;

next_head = head + 1;

if (next_head == CAN_FIFO) {

next_head = 0;

}

if (next_head != can_fifo.tail) {

//read rx mailbox into can rx fifo

CanRxMsg *message_p;

message_p = &(can_fifo.fifo[head]);

bzero(message_p, sizeof(CanRxMsg));

CAN_Receive(CAN_FIFO0, message_p);

can_fifo.head = next_head;

} else {

//Just clear out the rx mailbox

CanRxMsg rejected;

CAN_Receive(CAN_FIFO0, &rejected);

}

}

The receive ISR never gets called, although I can see valid messages on the bus from the bus master sending a SYNC message regularly.

Anybody got a hint?

venus
Associate II
Posted on May 17, 2011 at 13:02

Hi,

Maybe the problems happened in reciving master.when you do CAN test,you should pay attention to CAN baudrate,ID betweend sending mailbox and receiving mail box.If you open IT,do not forget to delay,then close IT.

Hope this helps :D

Venus

jamessteward
Associate II
Posted on May 17, 2011 at 13:02

Hi Venus,

I don't quite understand what you are saying. The baud rate is the same at both ends. I have a LogicPort from Intronix on both CAN receive lines, so I can see that the Ack bit is set. The filters at each end are set to capture everything, if I understand the datasheet correct.

CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;

CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;

CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;

CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;

CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;

CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;

What do you mean by

Quote:

If you open IT,do not forget to delay,then close IT.

??

Regards,

James.

venus
Associate II
Posted on May 17, 2011 at 13:02

Hi James,

Sorry for my broken English.I meant that if you receive can message via CAN interrupt,do not forget to add time delay.

Here is my CAN receive code,it works ok.

Venus

[ This message was edited by: venus.tear on 11-02-2009 02:33 ]

sima
Associate II
Posted on May 17, 2011 at 13:02

You set FIFO 0:

CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;

But you use interrupt for FIFO 1?

void CAN_RX1_IRQHandler(void)

Change the interrupt to FIFO 0.

void USB_LP_CAN_RX0_IRQHandler(void)

[ This message was edited by: sima1 on 11-02-2009 13:06 ]

[ This message was edited by: sima1 on 11-02-2009 13:07 ]

jamessteward
Associate II
Posted on May 17, 2011 at 13:02

Thanks sima1. I wasn't sure about that. I didn't find any clear documentation. I had tried both interrupt handlers at one stage and still couldn't get any receive messages, probably because of some other bug. I'll try again today. I got side tracked yesterday ;)

Cheers,

James.

jamessteward
Associate II
Posted on May 17, 2011 at 13:02

Hi,

I'm still not getting any Rx interrupts.

The receiving end asserts the Ack bit.

The filter is set to allow all on FIFO0.

CAN_IT_FMP0 is enabled.

USB_LP_CAN_RX0_IRQChannel is enabled in the NVIC.

GPIOB, AFIO and CAN clocks are enabled.

CAN is remapped using Remap1, to pins 8 & 9 on port B.

void USB_LP_CAN_RX0_IRQHandler(void) {..} is never called.

Is there anything else?

jamessteward
Associate II
Posted on May 17, 2011 at 13:02

With a little nudge from ST technical support, I solved this mystery.

In the FWLib, in CAN_Init() there is a bit of code that looks like;

Code:

/* Wait the acknowledge */ <BR> <BR> for(WaitAck = 0x400; WaitAck > 0x0; WaitAck--) <BR> <BR> { <BR> <BR> } <BR> <BR> <BR> <BR> /* ...and check acknowledged */ <BR> <BR> if ((CAN->MSR & MSR_INAK) == MSR_INAK) <BR> <BR> { <BR> <BR> InitStatus = CANINITFAILED; <BR> <BR> } <BR> <BR>

However if GCC optimisation is turned on, the empty for loop is removed!! Hence the delay is gone, and the initialisation fails.

I made it look like this;

Code:

<BR> /* Wait the acknowledge */ <BR> <BR> for(WaitAck = 0x400; WaitAck > 0x0; WaitAck--) <BR> <BR> { <BR> <BR> if ((CAN->MSR & MSR_INAK) != MSR_INAK) { <BR> break; <BR> } <BR> <BR> } <BR> <BR> <BR> <BR> /* ...and check acknowledged */ <BR> <BR> if ((CAN->MSR & MSR_INAK) == MSR_INAK) <BR> <BR> { <BR> <BR> InitStatus = CANINITFAILED; <BR> <BR> } <BR>

Which seems to work ok with gcc -Os.

Cheers ST tech support and folks from the forum.

One thing, CAN_Init returns a u8. Failure is returned as 0. There are 2 points of failure. It would be more helpful to debug if the returned value was dfferent depending on the failure mode, etc. I.e. return a s8, and assign -1 to the first failure point, -2 to the next, and 0 or 1 to success.

Regards,

James.

[ This message was edited by: jamessteward on 12-02-2009 05:31 ]