Skip to main content
Just Matt
Associate III
January 28, 2014
Question

Receiving Can Messages. 70% of network traffic missing

  • January 28, 2014
  • 11 replies
  • 2636 views
Posted on January 28, 2014 at 20:18

Hi,

I'm using a STM32F407VGT mcu. Also with the latest DSP lib pack from ST. The network has 2 nodes, and I'm attempting to capture the traffic between the nodes. 500kbps 75% SP. 30% bus load. One node queries the other for some data, the responding node sends 145 CAN Messages over the network. (I am using a 3rd party tool to capture the traffic) My following code only picks up 31 of those messages, and its sporadic. It does always catch the first Message correctly. (Then it endlessly loops) Here is my code, I call this code right after a query is made to a node. Is this the right way to approach this situation? All feedback welcome :)

CanRxMsg rxMessage;
CanRxMsg rxMessageArray[144];
int
loopCount = 0;
int
receiveCount = 144;
while
(loopCount < receiveCount)
{
if
(CAN_MessagePending(CANx, CAN_FIFO0) > 0)
{ 
//Receive the Message
CAN_Receive(CANx, CAN_FIFO0, &rxMessage);
rxMessageArray[loopCount] = rxMessage;
loopCount++;
}
}

#can #can
This topic has been closed for replies.

11 replies

muhammaduzairafzal45
Associate III
January 29, 2014
Posted on January 29, 2014 at 07:17

Use CAN interrupt to capture packets. Polling is not a sufficient method if you do not want to miss data.

jpeacock2399
Associate III
January 29, 2014
Posted on January 29, 2014 at 15:59

How are your receive filters set up?  Are all messages directed to FIFO0?  You might try splitting message traffic between FIFO0 and FIFO1 when you set up the receive filters.

Are those 145 messages in a burst or do you have inhibit times to spread out the arrival? You may be flooding FIFO0, check for FIFO overflows.  Either you have to wait in the polling loop and do nothing else or switch to interrupt driven CAN.

  Jack Peacock
Just Matt
Just MattAuthor
Associate III
January 29, 2014
Posted on January 29, 2014 at 18:17

Jack and Afzal,

Thanks for your replies! I should have noted in my last post i'm new the STM platform (Hobbyist) The traffic originates from one node, on a single ArbId. I have a single filter setup directing everything to FIFO0. I'm not sure what you mean by splitting the traffic. Do you have an example or a reference I could look at? The 145 messages are sent in a burst (I cannot control the speed at which they are sent) I have switched to a interrupt driven setup. However, I'm still loosing messages :\ It may be in the way i'm storing the messages. I tried std::vector first then switched to plain ole array. Looking at the data, it seems that the first two messages are correct, then it skips like 30 of them. (See new code below)

extern 
''C''
void CAN
1
_RX
0
_IRQHandler(void)
{
CanRxMsg rxMessage;
CAN_Receive(CAN
1
, CAN_FIFO
0
, &rxMessage);
CanDriver::StuffCanMsg(rxMessage);
CAN_ClearITPendingBit(CAN
1
, CAN_IT_TME);
}
//std::vector<CanRxMsg> RxMessageArray;
CanRxMsg RxMessageArray [
145
];
int ArrayCounter = 
0
;
void CanDriver::StuffCanMsg(CanRxMsg RxMessage)
{ 
RxMessageArray[ArrayCounter++] = RxMessage;
if (ArrayCounter == 
50
) // So I can inspect what's in the array
{
DeconstructHandler(); // This just disables the handler. 
asm(
''nop''
);
}
}

Tesla DeLorean
Guru
January 29, 2014
Posted on January 29, 2014 at 19:52

I'm really not sure than spinning in a hard polling loop is any less effective than interrupts.

Splitting the traffic, I assume, means making it less bursty and increasing the inter-packet delays.

Thoughts, perhaps you can assign multiple FIFO mailboxes to the same filtering criterion, and thus handle back-to-back transfers. Figure you'd want at least TWO, to allow you the process the one in hand, and the one hot behind it on the wire.

Is there a DMA option for CAN that would allow you evacuate the FIFO sufficiently quickly so it wouldn't overflow?
Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Just Matt
Just MattAuthor
Associate III
January 30, 2014
Posted on January 30, 2014 at 02:26

Hi clive1, 

Thanks for the reply.

I cannot find any examples for DMA related to CAN. Nor can I find what channel or stream for the CAN DMA request mapping. (Pages 304 and 305 of the Reference Manual). Am I overlooking?

I'll give the multiple FIFO thing a try. (I'm not quiet sure how to implement it though)

Thanks!

-Matt
Just Matt
Just MattAuthor
Associate III
February 3, 2014
Posted on February 03, 2014 at 17:27

I still can't figure out this issue.

Does anyone else have any other debugging ideas? I have attached a logic analyzer to PD0 and PD1 of my MCU, I can verify that all the messages are at least making it that far.

If it helps, I'm offering a $100 bounty to whomever figures this out.

Cheers,

-Matt
frankmeyer9
Associate III
February 3, 2014
Posted on February 03, 2014 at 17:33

Does anyone else have any other debugging ideas? 

 

How about reducing your CAN network bitrate to a minimum,  and check how much of the traffic you still miss ?

If the picture changes, you seem to have a performance problem.

Just Matt
Just MattAuthor
Associate III
February 3, 2014
Posted on February 03, 2014 at 17:39

Unfortunately I cannot slow down the speed of the 3rd party module. 

I can probably build another module to send traffic. I'll give that a go and see.

-Matt

frankmeyer9
Associate III
February 4, 2014
Posted on February 04, 2014 at 09:10

Judging by some code you posted earlier, I suspect your concept, as implemented, is not workable. As I understood it, you disable the handler while parsing one message.

DeconstructHandler(); // This just disables the handler. 

I think you can't handle this CAN message in such a rigid synchronous manner. You lose CAN messages while you parse former messages.

My suggestion: add some GPIO toggle code to your CAN handler and parser, then take a scope to visualize you CAN traffic against the time spent in your handler code and parsing code.

carl2399
Associate III
February 5, 2014
Posted on February 05, 2014 at 07:24

I had a look at the data sheet for the STM32F10x family (which is at hand), although I don't believe the STM32F4xx is any sort of downgrade on that.

It has two receive FIFOs, each of which can store 3 complete packets!

Let's go worst case, and see what happens:

Speed: 1Mbps

Utilisation: 100%

Packet Length: 1 byte of data. (Anything less would be a bit useless).

The number of bits required to make a minimum packet is 55bits. So, you would expect to see a packet every 55 microseconds (~18000 packets per second). On the up-side, you have the full 55 microseconds to get this packet out of the FIFO. In the case of the F4 that's 55 microseconds at 168MHz or 9240 clocks. This is HEAPS to get the data out of the CAN peripheral and into a RAM based FIFO. I've done task switching on the F4 at 1M task switches per second! 

Your situation is more leisurely, being half the baud rate. Also I assume that their is more data per packet than just a single byte. Both these items will reduce the number of packets that require servicing.

While your CAN bus is only 30% utilised, I assume that what you meant to say is that 30% of the time it is 100% utilised and the other 70% is 0% utilised.

One thing worth checking for in your code (and also the STM32 library code) is that you're not accidentally resetting the FIFO every time you process a packet. For example: are you sending out some sort of ''ACK'' response that is resetting all the FIFO's as part of its process. It may be that the problem is not in any of the code you've shown us so far. Specifically check possible assignments to Bit 15 of the CANx->MCR register.

BTW I've never had issues with losing packets on a 1Mbps CAN bus, and I don't bother with using the filters.