0

Communication FEZ Domino sur le bus CAN en microframework

Carte de test du bus CAN

Premier pas dans la communication entre la carte d’asservissement et la carte mère du robot 2011, la communication sur le bus CAN (cf article sur le fonctionnement de la propulsion 2011).

Pour assurer cette bonne communication, la première étape était de réussir à faire communiquer deux cartes du même type entre elles. Possédant deux exemplaires de notre carte mère, nous cherchions à envoyer et recevoir des messages entre ces 2 cartes pour valider la bonne communication sur le port CAN.

Adapteur SOIC / DIP

Adapteur SOIC / DIP

La carte FEZ Domino comporte un controleur CAN mais pas de transceiver. Il faut donc adjoindre un transceiver CAN pour permettre à la carte de communiquer sur le bus. Nous avons commencé par tester la gamme des transceivers TI VP230. Il nous a été impossible  de trouver ce transceiver en mode DIP et avons donc été obligés de nous tourner vers un packaging SOIC souder sur un adaptateur DIP/SOIC. Le grand intérêt de la gamme TI VP230 est de fonctionner en logique 3.3V ce qui correspond à la logique de la FEZ Domino

Devant notre incapacité à souder proprement nos composants SOIC sans les endommager (4 échecs à notre actif et donc autant d’adapteurs à acheter), nous nous sommes tournés vers une autre gamme de transceiver les fameux MCP2551. Ils ont l’avantage d’être plus largement utilisés (et donc mieux documentés) ainsi que trouvable chez des distributeurs français (Farnell ou Radiospares par exemple) en packaging DIP. Ce transceiver bien que fonctionnant en logique 5V, s’interface sans le moindre souci avec la FEZ Domino pour deux raisons. Tout d’abord les inputs de la Fez Domino sont 5V tolerant c’est à dire que bien qu’alimenté en 3.3V l’USBizi Chipset sur lequel se base la carte est tout à fait capable des recevoir des signaux jusqu’à 5V en provenance du transceiver. De plus,  le transcevier detecte le 3.3V comme un état haut.

PCan-USB Peak-system

PCan-USB Peak-system

Pour tester les packet envoyés, nous avons raccordé à la sortie du transceiver (sans oublier la résistance de 60 Ohms) un port subD-9 pour connecter notre PCAN-USB de Peak-System. L’intéret du PCAN est de pouvoir vérifier en temps réel sur un ordinateur les messages envoyés sur le réseau CAN. Après vérification que les packets sont bien envoyés nous testons la communication inverse en envoyant les packets depuis l’interface du PCAN-USB. Il ne reste plus ensuite qu’a monter en miroir un deuxième transceiver sur la carte de test  pour relier une deuxième carte Domino.

Voici la photo ci-dessous de la carte de test finale avec au dessous les deux connexions pour les cartes Domino. En haut la sortie subD-9 pour branchement du PCAN-USB, au milieu la résistance de 60 Ohms (en théorie deux résistances de 120Ohms à chaque extrémité du réseau). Enfin quelques leds de test pour vérifier la bonne alimentation du tout.

Carte de test du bus CAN

Lors de nos tests nous utilisons une première carte Domino pour envoyer un message CAN lors de l’appui sur un bouton ainsi qu’une deuxième Domino pour recevoir le packet et afficher son contenu sur un petit afficheur LCD. Vous pouvez retrouver l’intégralité du code source pour les 2 cartes Domino sur notre Codeplex dans cette release.

POC Bus CAN

POC Bus CAN

Un petit extrait du code en C# :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
using System;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;

namespace MLRobotic.SISSA.TestCAN
{
public class Program
{

static GHIElectronics.NETMF.FEZ.FEZ_Components.SerialLCD serial;
static CAN canChannel;
private static OutputPort led;

public static void Main()
{

// Init CAN at 250kbps
uint BRP = 18;
uint T1 = 14;
uint T2 = 2;
uint Sync = 1;
uint BTR = ((T2 - 1) << 20) | (((T1 - Sync) - 1) << 16) | ((BRP - 1) << 0);

//Open CAN Channel
canChannel = new CAN(CAN.Channel.Channel_1,BTR);

//Uncomment one of the following line depending if you want to use the receiving or the sending program

// Uncomment the folowing line to use the receiving program
//ReceiveDataFromCAN();

//Uncomment the folowing line to use the sending program
//SendDataToCAN();
}

/// <summary>
/// Chack for Data on the CAN bus and print it on the serial LCD
/// </summary>
private static void ReceiveDataFromCAN()
{
//Define the serial LCD pinout, clear the screen, then place the LCD cursor to the first position
serial = new FEZ_Components.SerialLCD(FEZ_Pin.Digital.Di2);
serial.ClearScreen();
serial.CursorHome();

byte curseurPosition = 0;

// Create a CAN Message table to receive the data
CAN.Message[] messages = new CAN.Message[1];
messages[0] = new CAN.Message();

while (true)
{
// watch for can massage inside the queue then receive the first message
if (canChannel.GetRxQueueCount() > 0 && canChannel.GetMessages(messages) > 0)
{
// Set the cursor at the good position
serial.SetCursor(0, curseurPosition);
foreach (CAN.Message msg in messages)
{
//decode data of the CAN Message
foreach (byte byt in msg.data)
{
if (byt == byte.MaxValue)
{
//Clear the screen
serial.ClearScreen();
curseurPosition = 0;
serial.CursorHome();
}
else if (byt == byte.MinValue)
{
break;
}
else
{
curseurPosition++;
// write the message on the LCD
serial.PutC((char)byt);
}
}
}
}
}
}

/// <summary>
/// Send one string each time the Domino button is pressed, blink the led each time a message is sent
///
/// </summary>
private static void SendDataToCAN()
{

//Button used to send data
InputPort bouton = new InputPort((Cpu.Pin)GHIElectronics.NETMF.Hardware.USBizi.Pin.IO0, false, Port.ResistorMode.PullUp);

//Some dummy data
string[] lstString = new string[] { "Test", "Hippo", "Poney", "Renard", "Hipp", "Rien" };
int currentStr = 0;

//led use to chack when data is sent
led = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, false);

while (true)
{
if (!bouton.Read())
{
// increment index
currentStr = (currentStr + 1) % lstString.Length;

Send(lstString[currentStr]);

//blink the led after the sending
led.Write(true);
Thread.Sleep(150);
led.Write(false);

// wait for the button to be pull of
while (!bouton.Read())
Thread.Sleep(50);
}
}
}

private static CAN.Message msgOut = new CAN.Message();
private static CAN.Message[] lstMsg = new CAN.Message[] { msgOut };

/// <summary>
/// create the CAN message, check the Tx queue, then send the message
/// </summary>
/// <param name="DatatoSend"></param>
private static void Send(string DatatoSend)
{
//Create message header
msgOut.DLC = 8;
msgOut.ArbID = 0xAB;
msgOut.isEID = false;
msgOut.isRTR = false;

//Create data
int curIndex = 1;
msgOut.data[0] = byte.MaxValue;
foreach (char car in DatatoSend)
{
msgOut.data[curIndex] = (byte)car;
curIndex++;
if (curIndex == msgOut.data.Length)
{
// send data
canChannel.PostMessages(lstMsg);

curIndex = 0;
}
}

// send the last packet
if (curIndex > 0)
{
for (int j = curIndex; j < msgOut.data.Length; j++)
msgOut.data[j] = byte.MinValue;

//make the led blinking until the TxBuffer is available,
while (!canChannel.IsTxBufferAvailable())
{

led.Write(true);
Thread.Sleep(50);
led.Write(false);
Thread.Sleep(50);
}

// send the message
canChannel.PostMessages(lstMsg);

curIndex = 0;
}

}
}
}