G400 does not send messages

I haven’t finished with my previous G400 CAN issue, and ran in another one… In short: if there’s some traffic on the bus and I want to send a message, sometimes it is lost (about 5 in 1000). It is simply not sent, although sending function is called.

Here’s a source code that illustrates the problem. Comments inside the code.

public class Program {
        //It works as follows. LDR1 turns on/off continuous  broadcasting (~100 messages per second).
        //Clicking LDR0 sends 1000 messages and then stops.
        //I have two G400's, connected through CAN: a custom board and a G400HDR one. The code on both is
        //basically the same: I just change CAN message Id depending on board, so I could see which messages
        //comes from which board.

        //The experiment:
        //1. I reset both boards and attach debug output readers.
        //2. If I click LDR0 on both boards, all messages are sent and all of them are received.
        //3. I click LDR1 on both boards; this adds some traffic as both boards are then transmitting something all the time.
        //4. I click LDR0 (can be on one board), 1000 messages are sent, but very often, some messages are not actually sent to CAN. 
        //the sending board outputs "Sent 1000 messages, received xxx messages", and receiving board outputs "Sent xxx messages, received 967".


        static readonly InputPort buttonforBroadcasts = new InterruptPort((Cpu.Pin)(4), false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLow);
        static InputPort _buttonforSending = new InterruptPort((Cpu.Pin)(24), false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLow);
        static OutputPort led = new OutputPort((Cpu.Pin)(3 * 32 + 3), true); // led pd3      
        // static OutputPort led = new OutputPort((Cpu.Pin)(3 * 32 + 18), true); // led pd18     <--this is for my custom G400 board 


        static CAN.Message[] sendList;
        static CAN.Message[] receiveList;
        public static void Main() {

            //Create a message list of 1000 messages
            sendList = new CAN.Message[1000];
            for (int i = 0; i < sendList.Length; i++) {
                sendList[i] = new CAN.Message();
                sendList[i].ArbID = 100;
                sendList[i].DLC = 8;
                sendList[i].Data[1] = (byte)(i & 0xFF);
            }
            receiveList = new CAN.Message[1000];
            for (int i = 0; i < receiveList.Length; i++) {
                receiveList[i] = new CAN.Message();
            }

            //configuring CAN
            var brp = 6;
            var sjw = 1;
            var propag = 1;
            var phase1 = 7;
            var phase2 = 7;
            CAN can = new CAN(CAN.Channel.Channel_1, (uint)((brp << 16) + (sjw << 12) + (propag << 8) + (phase1 << 4) + (phase2 << 0)), 1000); //1Mbit

            // Subscribe to events
            can.DataReceivedEvent += new CANDataReceivedEventHandler(can_DataReceivedEvent);
            can.ErrorReceivedEvent += new CANErrorReceivedEventHandler(can_ErrorReceivedEvent);


            var isBroadcasting = false;
            buttonforBroadcasts.OnInterrupt += (data1, data2, data3) => {
                isBroadcasting = !isBroadcasting;

            };
            new Thread(() => {
                var y = 0;
                var messageToBroadcast = new CAN.Message() { DLC = 8, ArbID = 10 };
                messageToBroadcast.Data[0] = 1;
                var messagesToBroadcast = new CAN.Message[] { messageToBroadcast };
                while (true) {
                    if (isBroadcasting) {
                        //Adding some traffic to the bus
                        can.PostMessages(messagesToBroadcast, 0, 1);
                    }
                    Thread.Sleep(10);
                }
            }).Start();

            var isSending = false;
            _buttonforSending.OnInterrupt += (data1, data2, data3) => {
                isSending = true;

            };
            var sentCounter = 0;
            new Thread(() => {
                while (true) {
                    if (isSending) {
                        Debug.Print("Sending");
                        for (int i = 0; i < 1000; i++) {

                            //==== This is my manual send implementation — seems messages are not lost
                            //SendCanMessage(sendList[i].ArbID, sendList[i].Data);
                            //Thread.Sleep(1);
                            //=======================================================

                            //==== This is GHI implementation — messages are lost even with additional Thread.Sleep(1)
                            can.PostMessages(sendList, i, 1);
                            while (can.PostedMessagesSent == false) {
                                Thread.Sleep(1);
                            }
                            Thread.Sleep(1); //<-- if I remove this loss rate is higher
                            //=========================================================

                            sentCounter++;
                        }
                        isSending = false;
                    }

                    Thread.Sleep(10);
                }
            }).Start();

            Thread.Sleep(5000);

            while (true) {
                Debug.Print("Sent " + sentCounter + " messages, received " + receivedCounter);
                Thread.Sleep(1000);
            }
        }
        static int receivedCounter = 0;
        private static int totalReceived = 0;
        static Boolean error = false;
        static void can_DataReceivedEvent(CAN sender, CANDataReceivedEventArgs args) {
            // Blink LED every 50ms if r
            led.Write((totalReceived % 100 >= 50) && (error == false));
            var received = sender.GetMessages(receiveList, 0, receiveList.Length);
            totalReceived += received;
            for (int i = 0; i < received; i++) {
                //receivedCounter only counts messages that are sent from other board after pressing LDR0
                if (receiveList[i].ArbID > 99) receivedCounter++;
            }
            if (error == false && totalReceived % 1000 == 0) {
                Debug.Print("Still running " + totalReceived);
            }
        }

        static void can_ErrorReceivedEvent(CAN sender, CANErrorReceivedEventArgs args) {
            error = true;
            switch (args.Error) {
                case CAN.Error.Overrun:
                    Debug.Print("Overrun error. Message lost");
                    break;

                case CAN.Error.RXOver:
                    Debug.Print("RXOver error. Internal buffer is full. Message lost");
                    break;

                case CAN.Error.BusOff:
                    Debug.Print("BusOff error. Reset CAN controller.");
                    sender.Reset();
                    break;
            }
        }

        private static readonly Register Mailbox7ModeRegister = new Register(0xF80002E0);
        private static readonly Register Mailbox7StatusRegister = new Register(0xF80002F0);
        private static readonly Register Mailbox7IdRegister = new Register(0xF80002E8);
        private static readonly Register Mailbox7DataLowRegister = new Register(0xF80002F4);
        private static readonly Register Mailbox7DataHighRegister = new Register(0xF80002F8);
        private static readonly Register Mailbox7ControlRegister = new Register(0xF80002FC);
        private static readonly Register Mailbox7AcceptanceMaskRegister = new Register(0xF80002E4);

        public static void SendCanMessage(UInt32 id, byte[] data) {
            //Disabling M7
            Mailbox7ModeRegister.Write((0 << 24) | (0 << 16));
            //Writing ID
            Mailbox7IdRegister.Write((uint)((0 << 29) | (id << 18)));
            //Writing DLC?..
            //mailbox7ControlRegister.SetBits(7 << 16);
            //Writing data
            Mailbox7DataLowRegister.Write((uint)(data[0] + data[1] * 256 + data[2] * 256 * 256 + data[3] * 256 * 256 * 256));
            Mailbox7DataHighRegister.Write((uint)(data[4] + data[5] * 256 + data[6] * 256 * 256 + data[7] * 256 * 256 * 256));
            //Setting filter
            // Mailbox7AcceptanceMaskRegister.Write(0x1FFFFFFF);
            //Enabling M7
            Mailbox7ModeRegister.Write((3 << 24) | (1 << 16));
            //Sending M7
            Mailbox7ControlRegister.Write((1 << 23) | (8 << 16));
        }
    }
1 Like

@ Simon from Vilnius -

I think better if you add

while (can.PostedMessagesSent == false) {
                                Thread.Sleep(1);
                            }

right after PostMessages function. I am seeing there is one thread you are missing it.

And, as you are running with high traffic, better if there is no debug.print in can_DataReceivedEvent.

It is simply not sent, although sending function is called.

you can check on EMX or some CAN device, send function is called but it doesn’t mean the receiver will have the msg. You can post a message without receiver. I mean if there is something wrong inside, the msg will be ignored without any exception. We can add an exception there but it will be different with EMX or g120. That why check msg status is highly recommended after called post msg.

And in the current firmware, as I know, if there is a lot of message are coming, there is no place for sending, because ISR is called all the time

Ok, will try.

Hey it’s G400 — it certainly can handle a few debug prints :slight_smile: And in this situation, traffic is not high.

Huh? I’m far from high traffic. And if I use mailbox7 manually (I understand you use only mailbox0 and mailbox1), I have no problems. Or much less problems, don’t know that yet, because I did not loose any messages so far. So, something has to be wrong in ca.PostMessages() function…

@ Simon from Vilnius -

[quote]
Hey it’s G400 — it certainly can handle a few debug prints Smiley And in this situation, traffic is not high.[/quote]

if there are 1000 messages, I think you can not show all of them with receiveEvent in 1 second even that is g400 if you are debugging. With external power it may be.

No luck.

[quote=“Dat”]
@ Simon from Vilnius -

I understand that, but this is not the case now. So, can you reproduce the behaviour of lost messages?

@ Simon from Vilnius -

[quote]
I understand that, but this is not the case now. So, can you reproduce the behaviour of lost messages?[/quote]

using your code above and still g400 talks to G400?

I mean which way is easiest to reproduce?

And, using mailbox7 is your workaround now?

[quote=“Dat”]
@ Simon from Vilnius -

Yes, it’s G400 and G400. Check the comments in the code.

Just plug two G400HDR boards at it should be fine.

Yes, kind of. Appears to be working, but there may be some side-effects. I’m interfering with your firmware, after all.

@ Simon from Vilnius -

I will give it a try now, but please tell me if there is no thing like crash or firmware is gone randomly?

So boring if firmware is gone randomly again

Nope, no firmware corruption. Yet :slight_smile:

@ Simon from Vilnius -

Hello,

I see the issue but it looks like is not related to CAN.

On my site, boardcast msg is lost but sendlist works fine.
I wondered what is different between those object, and I find out the difference is the way to create them.

I still don’t know why ;D. It maybe a bug and happened with all NETMF devices.

Copy-paste exactly these and test it, please.

Edit: added counter to 2 threads

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHI.Premium.Hardware;

namespace g400_CANTestLostMessage
{
    public class Program
    {
        static readonly InputPort buttonforBroadcasts = new InterruptPort((Cpu.Pin)(4), false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLow);
        static InputPort _buttonforSending = new InterruptPort((Cpu.Pin)(24), false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLow);
        static OutputPort led = new OutputPort((Cpu.Pin)(3 * 32 + 3), true); // led pd3      
        // static OutputPort led = new OutputPort((Cpu.Pin)(3 * 32 + 18), true); // led pd18     <--this is for my custom G400 board


        static CAN.Message[] sendList;
        static CAN.Message[] receiveList;
        public static void Main() {

            //Create a message list of 1000 messages
            sendList = new CAN.Message[1000];
            for (int i = 0; i < sendList.Length; i++) {
                sendList[i] = new CAN.Message();
                sendList[i].ArbID = 100;
                sendList[i].DLC = 8;
                sendList[i].Data[1] = (byte)(i & 0xFF);
            }
            receiveList = new CAN.Message[1000];
            for (int i = 0; i < receiveList.Length; i++) {
                receiveList[i] = new CAN.Message();
            }

            //configuring CAN
            var brp = 6;
            var sjw = 1;
            var propag = 1;
            var phase1 = 7;
            var phase2 = 7;
            CAN can = new CAN(CAN.Channel.Channel_1, (uint)((brp << 16) + (sjw << 12) + (propag << 8) + (phase1 << 4) + (phase2 << 0)), 1000); //1Mbit

            // Subscribe to events
            can.DataReceivedEvent += new CANDataReceivedEventHandler(can_DataReceivedEvent);
            can.ErrorReceivedEvent += new CANErrorReceivedEventHandler(can_ErrorReceivedEvent);


            var isBroadcasting = false;
            buttonforBroadcasts.OnInterrupt += (data1, data2, data3) => {
                isBroadcasting = !isBroadcasting;

            };
          var sentCounter = 0;
            new Thread(() => {
                var y = 0;
                //var messageToBroadcast = new CAN.Message() { DLC = 8, ArbID = 10 };
                //messageToBroadcast.Data[0] = 1;
                var messagesToBroadcast = new CAN.Message[1];// { messageToBroadcast };
                for (int i = 0; i < messagesToBroadcast.Length; i++)
                {
                    messagesToBroadcast[i] = new CAN.Message();
                    messagesToBroadcast[i].ArbID = 100;
                    messagesToBroadcast[i].DLC = 8;
                    messagesToBroadcast[i].Data[1] = (byte)(i & 0xFF);
                }


                while (true) {
                    if (isBroadcasting) {
                        //Adding some traffic to the bus
                        can.PostMessages(messagesToBroadcast, 0, 1);
                        while (can.PostedMessagesSent == false)
                        {
                            Thread.Sleep(1);
                        }
                       sentCounter++;
                    }
                    Thread.Sleep(10);
                }
            }).Start();

            var isSending = false;
            _buttonforSending.OnInterrupt += (data1, data2, data3) => {
                isSending = true;

            };
           // var sentCounter = 0;
            new Thread(() => {
                while (true) {
                    if (isSending) {
                        Debug.Print("Sending");
                        for (int i = 0; i < 1000; i++) {

                            //==== This is my manual send implementation — seems messages are not lost
                            //SendCanMessage(sendList[i].ArbID, sendList[i].Data);
                            //Thread.Sleep(1);
                            //=======================================================

                            //==== This is GHI implementation — messages are lost even with additional Thread.Sleep(1)
                            can.PostMessages(sendList, i, 1);
                            while (can.PostedMessagesSent == false) {
                                Thread.Sleep(1);
                            }
                            Thread.Sleep(10); //<-- if I remove this loss rate is higher
                            //=========================================================

                            sentCounter++;
                        }
                        isSending = false;
                    }

                    Thread.Sleep(10);
                }
            }).Start();

            Thread.Sleep(5000);

            while (true) {
                Debug.Print("Sent " + sentCounter + " messages, received " + receivedCounter);
                Thread.Sleep(1000);
            }
        }
        static int receivedCounter = 0;
        private static int totalReceived = 0;
        static Boolean error = false;
        static void can_DataReceivedEvent(CAN sender, CANDataReceivedEventArgs args) {
            // Blink LED every 50ms if r
            led.Write((totalReceived % 100 >= 50) && (error == false));
            var received = sender.GetMessages(receiveList, 0, receiveList.Length);
            totalReceived += received;
            for (int i = 0; i < received; i++) {
                //receivedCounter only counts messages that are sent from other board after pressing LDR0
                if (receiveList[i].ArbID > 99) receivedCounter++;
            }
            if (error == false && totalReceived % 1000 == 0) {
                Debug.Print("Still running " + totalReceived);
            }
        }

        static void can_ErrorReceivedEvent(CAN sender, CANErrorReceivedEventArgs args) {
            error = true;
            switch (args.Error) {
                case CAN.Error.Overrun:
                    Debug.Print("Overrun error. Message lost");
                    break;

                case CAN.Error.RXOver:
                    Debug.Print("RXOver error. Internal buffer is full. Message lost");
                    break;

                case CAN.Error.BusOff:
                    Debug.Print("BusOff error. Reset CAN controller.");
                    sender.Reset();
                    break;
            }
        } 

    }
}

and you call

sentCounter++

only in sendlist, and counting only one thread. It may let you think the message is lost. it should be in both threads

No it should not. I only count sent and received messages with CanId=100. I don’t care about those with CanId=10 — they are just background traffic.

Will do tommorow.

After running for a few minutes, I get the following results:

Custom board: “Sent 20042 messages, received 19867”
G400HDR: “Sent 19910 messages, received 20020”

@ Simon from Vilnius -

we will check again!
Thank for your time to show step by step

Hi,

We are coming back with CAN. As I explained, on G400, G120, EMX, there is a check before sending a message. This is safe to avoid a free-crashing, hang or unexpected behavior with CAN.

Problem here is if there is not OK for sending, the message will be ignored without any exception.


This only tell you a message is sent, but it doesn't mean receiver got it.
So to check a message is really sent and receiver  got the message successfully, using

```cs

int sent = can.PostMessages(_sendList, i, 1);

will return how many message was sent. Go back your example, please replace your code

while (can.PostedMessagesSent == false)
                                {
                                    Thread.Sleep(1);
                                }
                                Thread.Sleep(1); //<-- if I remove this loss rate is higher
 sentCounter++;

by

int sent = 0;
                            while (sent == 0)
                            {
                                sent = can.PostMessages(_sendList, i, 1);
                                while (can.PostedMessagesSent == false)
                                {
                                    Thread.Sleep(1);
                                }
                                Thread.Sleep(1); //<-- if I remove this loss rate is higher
                            }
                            //=========================================================

                            sentCounter++;

It will work without any loss. I tested here 100.000 messages with loss is 0%.

Your code works because you send a message directly, without reading register status if it is OK to send or not. It is not safe so far.

Let me know if you have problem with CAN.

Actually if you remove sleep(1) (high traffic), there is no problem with PostMessages, but your code, it only send about 7000-9000 messages/10000 msg, loss is about 10%-30%. But I like your code, it is really simple to understand. I thought you can not send a message with simple code like that, but you got it. Add some reading status register then you don’t need PostMessage function anymore. :smiley: