EasyCAT LAB - EtherCAT master very simple example

Dependencies:   SOEM

  • This repository contains a very basic example for the EasyCAT LAB , a complete educational and experimental EtherCAT® system, composed of one master and two slaves.

Note

  • This example uses two LAB 2 slaves.

Note

  • In this example, to keep things as simple as possible, only two bytes of data are exchanged between the slaves and the TFT display is not used .
Committer:
EasyCAT
Date:
Wed Oct 25 15:38:52 2023 +0000
Revision:
2:368e7d4d8171
Parent:
1:971b4897a4c5
Bug fix

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sulymarco 0:bc829777f1ea 1 //********************************************************************************************
sulymarco 0:bc829777f1ea 2 // *
sulymarco 0:bc829777f1ea 3 // This software is distributed as an example, "AS IS", in the hope that it could *
sulymarco 0:bc829777f1ea 4 // be useful, WITHOUT ANY WARRANTY of any kind, express or implied, included, but *
sulymarco 0:bc829777f1ea 5 // not limited, to the warranties of merchantability, fitness for a particular *
sulymarco 0:bc829777f1ea 6 // purpose, and non infringiment. In no event shall the authors be liable for any *
sulymarco 0:bc829777f1ea 7 // claim, damages or other liability, arising from, or in connection with this software. *
sulymarco 0:bc829777f1ea 8 // *
sulymarco 0:bc829777f1ea 9 //********************************************************************************************
sulymarco 0:bc829777f1ea 10
sulymarco 0:bc829777f1ea 11
sulymarco 0:bc829777f1ea 12 // The AB&T EasyCAT LAB is a complete experimental EtherCAT® system, composed by
sulymarco 0:bc829777f1ea 13 // one master and two slaves.
sulymarco 0:bc829777f1ea 14 // The EasyCAT LAB software is provided free of charge and its pourpose is to allow
sulymarco 0:bc829777f1ea 15 // makers and educational institutes to experiment with the EtherCAT® protocol.
sulymarco 0:bc829777f1ea 16 //
sulymarco 0:bc829777f1ea 17 // The EasyCAT LAB is developed by "AB&T Tecnologie Informatiche" Via dell'About 2A Ivrea Italy.
sulymarco 0:bc829777f1ea 18 // www.bausano.net
sulymarco 0:bc829777f1ea 19 // www.easycatshield.com
sulymarco 0:bc829777f1ea 20 //
sulymarco 0:bc829777f1ea 21 // The EasyCAT LAB uses the SOEM library by rt:labs
sulymarco 0:bc829777f1ea 22 // https://rt-labs.com/products/soem-ethercat-master-stack/
sulymarco 0:bc829777f1ea 23 //
sulymarco 0:bc829777f1ea 24 // EtherCAT® is a registered trademark and patented technology, licensed by Beckhoff Automation GmbH.
sulymarco 0:bc829777f1ea 25 // www.beckhoff.com
sulymarco 0:bc829777f1ea 26 // www.ethercat.org
sulymarco 0:bc829777f1ea 27
sulymarco 0:bc829777f1ea 28
sulymarco 0:bc829777f1ea 29 #define ETH_TXBUFNB 16
sulymarco 0:bc829777f1ea 30 #define ETH_RXBUFNB 16
sulymarco 0:bc829777f1ea 31
sulymarco 0:bc829777f1ea 32 #include "mbed.h"
sulymarco 0:bc829777f1ea 33
sulymarco 0:bc829777f1ea 34 #ifndef __align
sulymarco 0:bc829777f1ea 35 #define __align MBED_ALIGN
sulymarco 0:bc829777f1ea 36 #endif
sulymarco 0:bc829777f1ea 37
sulymarco 0:bc829777f1ea 38 #include "config.h"
sulymarco 0:bc829777f1ea 39 #include "soem_start.h"
sulymarco 0:bc829777f1ea 40
sulymarco 0:bc829777f1ea 41 #define CYCLE_TIME 1000 // master cycle time in uS
sulymarco 0:bc829777f1ea 42 // 1000 = 1mS
sulymarco 0:bc829777f1ea 43
sulymarco 0:bc829777f1ea 44
sulymarco 0:bc829777f1ea 45 #define SysMilliS() (uint32_t)Kernel::get_ms_count()
sulymarco 0:bc829777f1ea 46
EasyCAT 1:971b4897a4c5 47 UnbufferedSerial pc(USBTX,USBRX,115200); // set the debug serial line speed to 115200
sulymarco 0:bc829777f1ea 48
sulymarco 0:bc829777f1ea 49
sulymarco 0:bc829777f1ea 50
sulymarco 0:bc829777f1ea 51 //---- local functions ---------------------------------------------------------
sulymarco 0:bc829777f1ea 52
sulymarco 0:bc829777f1ea 53 void Application();
sulymarco 0:bc829777f1ea 54 void BlinkLedForever();
sulymarco 0:bc829777f1ea 55
sulymarco 0:bc829777f1ea 56 //------------------------------------------------------------------------------
sulymarco 0:bc829777f1ea 57
sulymarco 0:bc829777f1ea 58 Ticker SampleTicker;
sulymarco 0:bc829777f1ea 59 Thread thread;
sulymarco 0:bc829777f1ea 60
sulymarco 0:bc829777f1ea 61 DigitalOut Test_1(D1); // debug test points
sulymarco 0:bc829777f1ea 62 DigitalOut Test_2(D2); //
sulymarco 0:bc829777f1ea 63 DigitalOut Test_3(D3); //
sulymarco 0:bc829777f1ea 64 DigitalOut Test_4(D4); //
sulymarco 0:bc829777f1ea 65
sulymarco 0:bc829777f1ea 66 DigitalOut LED_RED(LED3);
sulymarco 0:bc829777f1ea 67
sulymarco 0:bc829777f1ea 68
sulymarco 0:bc829777f1ea 69 //------------------------------------------------------------------------------
sulymarco 0:bc829777f1ea 70
sulymarco 0:bc829777f1ea 71 int ExpectWorkCounter;
sulymarco 0:bc829777f1ea 72 int WorkCounter;
sulymarco 0:bc829777f1ea 73 int WorkCounterSafe;
sulymarco 0:bc829777f1ea 74 bool NetworkError;
sulymarco 0:bc829777f1ea 75 bool NetworkErrorSafe;
sulymarco 0:bc829777f1ea 76
sulymarco 0:bc829777f1ea 77 #define DATA_EXCHANGE_FLAG (1UL << 0)
sulymarco 0:bc829777f1ea 78 #define APPLICATION_FLAG (1UL << 1)
sulymarco 0:bc829777f1ea 79
sulymarco 0:bc829777f1ea 80 EventFlags event_flags;
sulymarco 0:bc829777f1ea 81
sulymarco 0:bc829777f1ea 82 Mutex IO_data;
sulymarco 0:bc829777f1ea 83
sulymarco 0:bc829777f1ea 84
sulymarco 0:bc829777f1ea 85 //---- data exchange thread ----------------------------------------------------
sulymarco 0:bc829777f1ea 86
sulymarco 0:bc829777f1ea 87 void ExchangeMaster()
sulymarco 0:bc829777f1ea 88 {
sulymarco 0:bc829777f1ea 89 while (true)
sulymarco 0:bc829777f1ea 90 {
sulymarco 0:bc829777f1ea 91 event_flags.wait_any(DATA_EXCHANGE_FLAG); // the thread waits for the synchronization flag
sulymarco 0:bc829777f1ea 92
sulymarco 0:bc829777f1ea 93 //Test_1 = 1;
sulymarco 0:bc829777f1ea 94
sulymarco 0:bc829777f1ea 95 IO_data.lock(); // Ethercat data exchange
sulymarco 0:bc829777f1ea 96 ec_send_processdata(); //
sulymarco 0:bc829777f1ea 97 WorkCounter = ec_receive_processdata(EC_TIMEOUTRET);
sulymarco 0:bc829777f1ea 98
sulymarco 0:bc829777f1ea 99 if (WorkCounter != ExpectWorkCounter)
sulymarco 0:bc829777f1ea 100 NetworkError = true;
sulymarco 0:bc829777f1ea 101 else
sulymarco 0:bc829777f1ea 102 NetworkError = false;
sulymarco 0:bc829777f1ea 103
sulymarco 0:bc829777f1ea 104 IO_data.unlock(); //
sulymarco 0:bc829777f1ea 105 event_flags.set(APPLICATION_FLAG); // synchronize the application
sulymarco 0:bc829777f1ea 106
sulymarco 0:bc829777f1ea 107 //Test_1 = 0;
sulymarco 0:bc829777f1ea 108 }
sulymarco 0:bc829777f1ea 109 }
sulymarco 0:bc829777f1ea 110
sulymarco 0:bc829777f1ea 111
sulymarco 0:bc829777f1ea 112 //----- thicker generated sample time ------------------------------------------
sulymarco 0:bc829777f1ea 113
sulymarco 0:bc829777f1ea 114 void SampleIsr() // set the event that starts
sulymarco 0:bc829777f1ea 115 { // the data exchange
sulymarco 0:bc829777f1ea 116 event_flags.set(DATA_EXCHANGE_FLAG); //
sulymarco 0:bc829777f1ea 117 } //
sulymarco 0:bc829777f1ea 118
sulymarco 0:bc829777f1ea 119
sulymarco 0:bc829777f1ea 120 //****** initialization ********************************************************
sulymarco 0:bc829777f1ea 121
sulymarco 0:bc829777f1ea 122 int main()
sulymarco 0:bc829777f1ea 123 {
sulymarco 0:bc829777f1ea 124 int i;
sulymarco 0:bc829777f1ea 125
sulymarco 0:bc829777f1ea 126 printf("Start \n");
sulymarco 0:bc829777f1ea 127
sulymarco 0:bc829777f1ea 128 Test_1 = 0;
sulymarco 0:bc829777f1ea 129 Test_2 = 0;
sulymarco 0:bc829777f1ea 130 Test_3 = 0;
sulymarco 0:bc829777f1ea 131 Test_4 = 0;
sulymarco 0:bc829777f1ea 132
sulymarco 0:bc829777f1ea 133 NetworkError = false;
sulymarco 0:bc829777f1ea 134
sulymarco 0:bc829777f1ea 135 if (ec_init(NULL)) // init SOEM
sulymarco 0:bc829777f1ea 136 {
sulymarco 0:bc829777f1ea 137 printf("ec_init succeeded.\n");
sulymarco 0:bc829777f1ea 138 printf("Scanning the network\n");
sulymarco 0:bc829777f1ea 139
sulymarco 0:bc829777f1ea 140 if (network_scanning())
sulymarco 0:bc829777f1ea 141 {
sulymarco 0:bc829777f1ea 142 if (network_configuration()) // check network configuration
sulymarco 0:bc829777f1ea 143 {
sulymarco 0:bc829777f1ea 144 ec_config_map(&IOmap); // map the I/O
sulymarco 0:bc829777f1ea 145 MapLocalStructures();
sulymarco 0:bc829777f1ea 146
sulymarco 0:bc829777f1ea 147 printf("\nSlaves mapped, state to SAFE_OP.\n");
sulymarco 0:bc829777f1ea 148 // wait for all slaves to reach SAFE_OP state
sulymarco 0:bc829777f1ea 149 ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE);
sulymarco 0:bc829777f1ea 150
sulymarco 0:bc829777f1ea 151 printf("Request operational state for all slaves\n");
sulymarco 0:bc829777f1ea 152 ec_slave[0].state = EC_STATE_OPERATIONAL;
sulymarco 0:bc829777f1ea 153
sulymarco 0:bc829777f1ea 154 ec_send_processdata(); // send one valid process data to make outputs in slaves happy
sulymarco 0:bc829777f1ea 155 ExpectWorkCounter = ec_receive_processdata(EC_TIMEOUTRET);
sulymarco 0:bc829777f1ea 156
sulymarco 0:bc829777f1ea 157 ec_writestate(0); // request OP state for all slaves
sulymarco 0:bc829777f1ea 158
sulymarco 0:bc829777f1ea 159 // wait for all slaves to reach OP state
sulymarco 0:bc829777f1ea 160 ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE);
sulymarco 0:bc829777f1ea 161 if (ec_slave[0].state == EC_STATE_OPERATIONAL )
sulymarco 0:bc829777f1ea 162 {
sulymarco 0:bc829777f1ea 163 printf("Operational state reached for all slaves.\n");
sulymarco 0:bc829777f1ea 164 }
sulymarco 0:bc829777f1ea 165 else
sulymarco 0:bc829777f1ea 166 {
sulymarco 0:bc829777f1ea 167 printf("Not all slaves reached operational state.\n");
sulymarco 0:bc829777f1ea 168 ec_readstate();
sulymarco 0:bc829777f1ea 169 for(i = 1; i<=ec_slavecount ; i++)
sulymarco 0:bc829777f1ea 170 {
sulymarco 0:bc829777f1ea 171 if(ec_slave[i].state != EC_STATE_OPERATIONAL)
sulymarco 0:bc829777f1ea 172 {
sulymarco 0:bc829777f1ea 173 printf("Slave %d State=0x%04x StatusCode=0x%04x\n",
sulymarco 0:bc829777f1ea 174 i, ec_slave[i].state, ec_slave[i].ALstatuscode);
sulymarco 0:bc829777f1ea 175 }
sulymarco 0:bc829777f1ea 176 }
sulymarco 0:bc829777f1ea 177
sulymarco 0:bc829777f1ea 178 printf("Not all slaves reached operational state!\n");
sulymarco 0:bc829777f1ea 179 void BlinkLedForever();
sulymarco 0:bc829777f1ea 180 }
sulymarco 0:bc829777f1ea 181
sulymarco 0:bc829777f1ea 182
sulymarco 0:bc829777f1ea 183 thread.start(ExchangeMaster);
sulymarco 0:bc829777f1ea 184 thread.set_priority(osPriorityRealtime);
sulymarco 0:bc829777f1ea 185
sulymarco 0:bc829777f1ea 186 SampleTicker.attach_us(&SampleIsr, CYCLE_TIME);
sulymarco 0:bc829777f1ea 187
sulymarco 0:bc829777f1ea 188 Application();
sulymarco 0:bc829777f1ea 189 }
sulymarco 0:bc829777f1ea 190
sulymarco 0:bc829777f1ea 191 else
sulymarco 0:bc829777f1ea 192 {
sulymarco 0:bc829777f1ea 193 printf("Mismatch of network units!\n");
sulymarco 0:bc829777f1ea 194 BlinkLedForever();
sulymarco 0:bc829777f1ea 195 }
sulymarco 0:bc829777f1ea 196 }
sulymarco 0:bc829777f1ea 197
sulymarco 0:bc829777f1ea 198 else
sulymarco 0:bc829777f1ea 199 {
sulymarco 0:bc829777f1ea 200 printf("No slaves found!\n");
sulymarco 0:bc829777f1ea 201 BlinkLedForever();
sulymarco 0:bc829777f1ea 202 }
sulymarco 0:bc829777f1ea 203 }
sulymarco 0:bc829777f1ea 204 else
sulymarco 0:bc829777f1ea 205 {
sulymarco 0:bc829777f1ea 206 printf("Ethernet interface init failed!");
sulymarco 0:bc829777f1ea 207 BlinkLedForever();
sulymarco 0:bc829777f1ea 208 }
sulymarco 0:bc829777f1ea 209 }
sulymarco 0:bc829777f1ea 210
sulymarco 0:bc829777f1ea 211
sulymarco 0:bc829777f1ea 212 //****** user master application **********************************************
sulymarco 0:bc829777f1ea 213
sulymarco 0:bc829777f1ea 214 void Application()
sulymarco 0:bc829777f1ea 215 {
sulymarco 0:bc829777f1ea 216
sulymarco 0:bc829777f1ea 217 while(1)
sulymarco 0:bc829777f1ea 218 {
sulymarco 0:bc829777f1ea 219 event_flags.wait_any(APPLICATION_FLAG); // the application waits for the synchronization flag
sulymarco 0:bc829777f1ea 220
sulymarco 0:bc829777f1ea 221 //Test_2 = 1;
sulymarco 0:bc829777f1ea 222
sulymarco 0:bc829777f1ea 223 IO_data.lock(); // copy the Ethercat data to a safe buffer
sulymarco 0:bc829777f1ea 224 memcpy(&IOmapSafe[0], &IOmap[0], IO_MAP_SIZE); //
sulymarco 0:bc829777f1ea 225 //
sulymarco 0:bc829777f1ea 226 if (NetworkError) //
sulymarco 0:bc829777f1ea 227 { //
sulymarco 0:bc829777f1ea 228 NetworkErrorSafe = NetworkError; //
sulymarco 0:bc829777f1ea 229 WorkCounterSafe = WorkCounter; //
sulymarco 0:bc829777f1ea 230 } //
sulymarco 0:bc829777f1ea 231 IO_data.unlock(); //
sulymarco 0:bc829777f1ea 232
sulymarco 0:bc829777f1ea 233 if (NetworkErrorSafe)
sulymarco 0:bc829777f1ea 234 {
sulymarco 0:bc829777f1ea 235 printf("Network error!\n");
sulymarco 0:bc829777f1ea 236
sulymarco 0:bc829777f1ea 237 if(WorkCounterSafe >= 0)
sulymarco 0:bc829777f1ea 238 {
sulymarco 0:bc829777f1ea 239 printf("Expected working counter %d\n", ExpectWorkCounter);
sulymarco 0:bc829777f1ea 240 printf("Actual working counter %d\n", WorkCounterSafe);
sulymarco 0:bc829777f1ea 241 }
sulymarco 0:bc829777f1ea 242 else
sulymarco 0:bc829777f1ea 243 {
sulymarco 0:bc829777f1ea 244 printf("Timeout\n");
sulymarco 0:bc829777f1ea 245 }
sulymarco 0:bc829777f1ea 246
sulymarco 0:bc829777f1ea 247 printf("Please fix the error and press the reset button \n");
sulymarco 0:bc829777f1ea 248
sulymarco 0:bc829777f1ea 249 SampleTicker.detach(); // stop the sample interrupt
sulymarco 0:bc829777f1ea 250 BlinkLedForever(); // and loop for ever
sulymarco 0:bc829777f1ea 251 }
sulymarco 0:bc829777f1ea 252
sulymarco 0:bc829777f1ea 253
sulymarco 0:bc829777f1ea 254 //----- slaves data management -----------
sulymarco 0:bc829777f1ea 255
sulymarco 0:bc829777f1ea 256
EasyCAT 2:368e7d4d8171 257 out_LAB_1->Segments = in_LAB_2->Buttons; // send to the slave LAB_2_1 the buttons status
sulymarco 0:bc829777f1ea 258 // from the slave LAB_2_2
sulymarco 0:bc829777f1ea 259
sulymarco 0:bc829777f1ea 260
EasyCAT 2:368e7d4d8171 261 out_LAB_2->Segments = in_LAB_1->Buttons; // send to the slave LAB_2_2 the buttons status
sulymarco 0:bc829777f1ea 262 // from the slave LAB_2_1
sulymarco 0:bc829777f1ea 263
sulymarco 0:bc829777f1ea 264
sulymarco 0:bc829777f1ea 265 //----------------------------------------
sulymarco 0:bc829777f1ea 266
sulymarco 0:bc829777f1ea 267
sulymarco 0:bc829777f1ea 268
sulymarco 0:bc829777f1ea 269 IO_data.lock(); // copy the IO data from the safe area
sulymarco 0:bc829777f1ea 270 memcpy(&IOmap[0], &IOmapSafe[0], IO_MAP_SIZE); // to the EtherCAT buffer
sulymarco 0:bc829777f1ea 271 IO_data.unlock(); //
sulymarco 0:bc829777f1ea 272
sulymarco 0:bc829777f1ea 273 //Test_2 = 0;
sulymarco 0:bc829777f1ea 274 }
sulymarco 0:bc829777f1ea 275 }
sulymarco 0:bc829777f1ea 276
sulymarco 0:bc829777f1ea 277 //******************************************************************************
sulymarco 0:bc829777f1ea 278
sulymarco 0:bc829777f1ea 279
sulymarco 0:bc829777f1ea 280 void BlinkLedForever() // blink the red led forever to signal
sulymarco 0:bc829777f1ea 281 // an unrecoverable error condition
sulymarco 0:bc829777f1ea 282
sulymarco 0:bc829777f1ea 283 // fix the error and press the reset button
sulymarco 0:bc829777f1ea 284 {
sulymarco 0:bc829777f1ea 285 while(1)
sulymarco 0:bc829777f1ea 286 {
sulymarco 0:bc829777f1ea 287 LED_RED = !LED_RED;
EasyCAT 1:971b4897a4c5 288 ThisThread::sleep_for(100ms);
sulymarco 0:bc829777f1ea 289 }
sulymarco 0:bc829777f1ea 290 }
sulymarco 0:bc829777f1ea 291
sulymarco 0:bc829777f1ea 292