This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Problem with my CAN_IRQHandler() receiving double messages

Hi,

The device is a Cortex M3 (1768, specifically).

When I send a CAN message to both port 1 and port 2 from a third node on the network, I see a double receipt of the CAN message.

A bit of characterizing showed me the following:
- if both ports are plugged into the network I get the double message
- can port 2 is being read twice (which was the target port for the message)
- I am seeing two interrupts being called, one for each port (which is understandable).

The only cure for this seems to be to clear the CMR bits on both CANs after reading in just one message.

It looks like this in the code snippet below: LPC_CAN2->CMR = BIT_TWO; /* Release receive buffer */ LPC_CAN1->CMR = BIT_TWO; /* Release receive buffer */

I would have thought that the correct algorithm would be:
- to disable interrupts at the start,
- handle what I need to,
- clear the interrupt bit,
- and re-enable interrupts

Using the IER register seems to be incorrect (LPC_CAN1->IER &= ~0x0001) as it also clears the interrupt so I never read the received contents.

Can anyone suggest an alternative?

Thanks,

--Erik

PS -

My CAN ISR
/******************************************************************************
* CAN interrupt handler
* * Message received if ICR bit 0 (receive Interrupt) is set
* Bit 0 is only set if CANxIER is also 1
* * Recvs:
* Return:
******************************************************************************/
void CAN_IRQHandler (void) {

/* Check CAN controller 2 -- "DOWNSTREAM" */ if (LPC_CAN2->ICR & 0x01) { /* CAN Controller #2 message is received */ // disable interrupts LPC_CAN1->IER &= ~0x0001; LPC_CAN2->IER &= ~0x0001;

canMetrics.rx2IsrCalled++; CAN_rdMsg (I_AM_A_DOWNSTREAM_CAN_PORT); /* Read the message */ LPC_CAN2->CMR = BIT_TWO; /* Release receive buffer */ LPC_CAN1->CMR = BIT_TWO; /* Release receive buffer */ }

/* Check CAN controller 1 -- "UPSTREAM" */ if (LPC_CAN1->ICR & 0x01) { /* CAN Controller #1 message is received */ // disable interrupts LPC_CAN1->IER &= ~0x0001; LPC_CAN2->IER &= ~0x0001;

canMetrics.rx1IsrCalled++; CAN_rdMsg (I_AM_AN_UPSTREAM_CAN_PORT); /* Read the message */ LPC_CAN1->CMR = BIT_TWO; /* Release receive buffer */ LPC_CAN2->CMR = BIT_TWO; /* Release receive buffer */ }

canMetrics.IRQHandlerCalled++;

// re-enable interrupts LPC_CAN1->IER |= 0x0001; LPC_CAN2->IER |= 0x0001;

}

Example CAN ISR from Keil
/*---------------------------------------------------------------------------- CAN interrupt handler *----------------------------------------------------------------------------*/
void CAN_IRQHandler (void) { volatile uint32_t icr;

/* check CAN controller 1 */ icr = LPC_CAN1->ICR; /* clear interrupts */

if (icr & (1 << 0)) { /* CAN Controller #1 meassage is received */ CAN_rdMsg (1, &CAN_RxMsg[0]); /* read the message */ LPC_CAN1->CMR = (1 << 2); /* Release receive buffer */

CAN_RxRdy[0] = 1; /* set receive flag */ }

if (icr & (1 << 1)) { /* CAN Controller #1 meassage is transmitted */ CAN_TxRdy[0] = 1; }

/* check CAN controller 2 */ icr = LPC_CAN2->ICR; /* clear interrupts */

if (icr & (1 << 0)) { /* CAN Controller #2 meassage is received */ CAN_rdMsg (2, &CAN_RxMsg[1]); /* read the message */ LPC_CAN2->CMR = (1 << 2); /* Release receive buffer */

CAN_RxRdy[1] = 1; /* set receive flag */ }

if (icr & (1 << 1)) { /* CAN Controller #2 meassage is transmitted */ CAN_TxRdy[1] = 1; }

}

Parents
  • Please read the instructions for how to post source code. It's clearly explained directly above the message input box.

    If you connect both ports to the same CAN bus, the message will obviously arrive to both ports. What configuration are you using that should make one port accept the message and the other port ignore it?

Reply
  • Please read the instructions for how to post source code. It's clearly explained directly above the message input box.

    If you connect both ports to the same CAN bus, the message will obviously arrive to both ports. What configuration are you using that should make one port accept the message and the other port ignore it?

Children
  • Sorry about the code formatting.

    What do you mean by configuration, exactly? The state of the CAN registers, the physical network, the acceptance filters?

    My goal is to be able to receive the same message simultaneously on both Port1 and Port2 and only read it once from Port2.

    Filtering is SW only right now and is performed after the IRQ(). I believe that putting in a HW filter will solve the problem (I simply haven't configured that yet), but perhaps there is a smarter way to do this within the interrupt itself.

    Any thoughts? Thank you.

  • My goal is to be able to receive the same message simultaneously on both Port1 and Port2 and only read it once from Port2.

    Sorry, but that just doesn't make sense. If you receive a message on port1, you really have to read it on port1, too. If you're never going to read it from port1, what could possibly be the point of receiving it there?

  • Sorry, I was unclear.

    I have my development board set up in such a way that both ports are connected to a third node on the network. Port 1 simulates the Master, Port 2 is the slave.

    I think I have the solution. It is not within the IRQ() but within the filtering. This ostensibly crazy configuration is for testing but not deployment.

    Thanks for your response, however.

  • Well of course you need to filter the received data. Your messages are not sent with any address telling them to ignore port 1. So port 1 must know to drop the packets. And that is done by filtering.

    I don't really see how you could have thought the message should know that it should ignore one of the ports connected to the cable. Or how port1 should know that port2 is concurrently receiving the same message.