EasyCAT LAB - EtherCAT master simple example
Dependencies: SOEM SPI_TFT_ILI9341 TFT_fonts
- This repository contains a simple example for the EasyCAT LAB , a complete educational and experimental EtherCAT® system, composed of one master and two slaves.
- The EasyCAT LAB is provided as a kit by AB&T Tecnologie Informatiche, to allow everybody to have an educational EtherCAT® system up and running in a matter of minutes.
- It uses the SOEM (Simple Open EtherCAT® Master) library by rt-labs, that has been ported in the ecosystem by AB&T Tecnologie Informatiche.
- The slaves are based on the EasyCAT SHIELD and the Arduino UNO.
Note
- This example uses two LAB 2 slaves.
Note
- In this example only two bytes of data are exchanged between the slaves and are also visualized on the TFT display.
main.cpp
- Committer:
- EasyCAT
- Date:
- 2021-05-07
- Revision:
- 1:385bdd2b4cd6
- Parent:
- 0:13be39911caf
- Child:
- 2:a0e017115fc5
File content as of revision 1:385bdd2b4cd6:
//******************************************************************************************** // * // This software is distributed as an example, "AS IS", in the hope that it could * // be useful, WITHOUT ANY WARRANTY of any kind, express or implied, included, but * // not limited, to the warranties of merchantability, fitness for a particular * // purpose, and non infringiment. In no event shall the authors be liable for any * // claim, damages or other liability, arising from, or in connection with this software. * // * //******************************************************************************************** // The AB&T EasyCAT LAB is a complete experimental EtherCAT® system, composed by // one master and two slaves. // The EasyCAT LAB software is provided free of charge and its pourpose is to allow // makers and educational institutes to experiment with the EtherCAT® protocol. // // The EasyCAT LAB is developed by "AB&T Tecnologie Informatiche" Via dell'About 2A Ivrea Italy. // www.bausano.net // www.easycatshield.com // // The EasyCAT LAB uses the SOEM library by rt:labs // https://rt-labs.com/products/soem-ethercat-master-stack/ // // EtherCAT® is a registered trademark and patented technology, licensed by Beckhoff Automation GmbH. // www.beckhoff.com // www.ethercat.org #define ETH_TXBUFNB 16 #define ETH_RXBUFNB 16 #include "mbed.h" #ifndef __align #define __align MBED_ALIGN #endif #include "config.h" #include "SPI_TFT_ILI9341.h" #include "Arial12x12.h" #include "Arial24x23.h" #include "Arial28x28.h" #include "font_big.h" #include "soem_start.h" #define CYCLE_TIME 1000 // master cycle time in uS // 1000 = 1mS #define SysMilliS() (uint32_t)Kernel::get_ms_count() UnbufferedSerial pc(USBTX,USBRX,115200); // set the debug serial line speed to 115200 //---- TFT with resistive touchscreen pins ------------------------------------- // the display used is the SeeedStudio 2.8 inch TFT v2.0 // http://wiki.seeedstudio.com/2.8inch_TFT_Touch_Shield_v2.0/ #define PIN_YP A3 // resistive touchscreen #define PIN_YM A1 // #define PIN_XM A2 // #define PIN_XP A0 // #define PIN_MOSI D11 // TFT display SPI #define PIN_MISO D12 // #define PIN_SCLK D13 // #define PIN_CS_TFT D5 // #define PIN_DC_TFT D6 // //---- visualization parameters ------------------------------------------------ #define BUTTONS_1_X 80 #define BUTTONS_1_Y 60 #define BUTTONS_2_X 80 #define BUTTONS_2_Y 180 #define BUTTONS_1_WIDTH 26 #define BUTTONS_1_R 3 #define BUTTONS_1_STEP 60 #define BUTTONS_2_WIDTH BUTTONS_1_WIDTH #define BUTTONS_2_R BUTTONS_1_R #define BUTTONS_2_STEP BUTTONS_1_STEP //---- local functions --------------------------------------------------------- void DrawBanner(); void DrawSlaveFixedParts(); void DrawButtons_1_Value(uint8_t Value); void DrawButtons_2_Value(uint8_t Value); void Application(); //---- global variables -------------------------------------------------------- bool FirstRound; //------------------------------------------------------------------------------ SPI_TFT_ILI9341 TFT(PIN_MOSI, PIN_MISO, PIN_SCLK, PIN_CS_TFT, NC, PIN_DC_TFT); Ticker SampleTicker; Thread thread; DigitalOut Test_1(D1); // debug test points DigitalOut Test_2(D2); // DigitalOut Test_3(D3); // DigitalOut Test_4(D4); // //------------------------------------------------------------------------------ uint8_t Buttons_1; uint8_t PrevButtons_1; uint8_t Segments_1; uint8_t PrevSegments_1; uint8_t Buttons_2; uint8_t PrevButtons_2; uint8_t Segments_2; uint8_t PrevSegments_2; //------------------------------------------------------------------------------ int ExpectWorkCounter; int WorkCounter; int WorkCounterSafe; bool NetworkError; bool NetworkErrorSafe; #define DATA_EXCHANGE_FLAG (1UL << 0) #define APPLICATION_FLAG (1UL << 1) EventFlags event_flags; Mutex IO_data; //---- data exchange thread ---------------------------------------------------- void ExchangeMaster() { while (true) { event_flags.wait_any(DATA_EXCHANGE_FLAG); // the thread waits for the synchronization flag //Test_1 = 1; IO_data.lock(); // Ethercat data exchange ec_send_processdata(); // WorkCounter = ec_receive_processdata(EC_TIMEOUTRET); if (WorkCounter != ExpectWorkCounter) NetworkError = true; else NetworkError = false; IO_data.unlock(); // event_flags.set(APPLICATION_FLAG); // synchronize the application //Test_1 = 0; } } //----- thicker generated sample time ------------------------------------------ void SampleIsr() // set the event that starts { // the data exchange event_flags.set(DATA_EXCHANGE_FLAG); // } // //****** initialization ******************************************************** int main() { int i; printf("Start \n"); Test_1 = 0; Test_2 = 0; Test_3 = 0; Test_4 = 0; TFT.background(Black); // init TFT TFT.cls(); // TFT.set_orientation(3); // DrawBanner(); NetworkError = false; if (ec_init(NULL)) // init SOEM { printf("ec_init succeeded.\n"); printf("Scanning the network\n"); TFT.cls(); TFT.set_font((unsigned char*) Arial12x12); TFT.foreground(Green); TFT.locate(0, 0); TFT.printf("Scanning the network\n"); if (network_scanning()) { if (network_configuration()) // check network configuration { ec_config_map(&IOmap); // map the I/O MapLocalStructures(); printf("\nSlaves mapped, state to SAFE_OP.\n"); // wait for all slaves to reach SAFE_OP state ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); printf("Request operational state for all slaves\n"); ec_slave[0].state = EC_STATE_OPERATIONAL; ec_send_processdata(); // send one valid process data to make outputs in slaves happy ExpectWorkCounter = ec_receive_processdata(EC_TIMEOUTRET); ec_writestate(0); // request OP state for all slaves // wait for all slaves to reach OP state ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE); if (ec_slave[0].state == EC_STATE_OPERATIONAL ) { printf("Operational state reached for all slaves.\n"); } else { printf("Not all slaves reached operational state.\n"); ec_readstate(); for(i = 1; i<=ec_slavecount ; i++) { if(ec_slave[i].state != EC_STATE_OPERATIONAL) { printf("Slave %d State=0x%04x StatusCode=0x%04x\n", i, ec_slave[i].state, ec_slave[i].ALstatuscode); } } TFT.foreground(Red); TFT.locate(0, 0); TFT.printf("Not all slaves reached operational state!"); while(1){} } DrawSlaveFixedParts(); thread.start(ExchangeMaster); thread.set_priority(osPriorityRealtime); SampleTicker.attach_us(&SampleIsr, CYCLE_TIME); Application(); } else { printf("Mismatch of network units!\n"); TFT.foreground(Red); TFT.locate(0, 0); TFT.printf("Mismatch of network units!"); while(1){} } } else { printf("No slaves found!\n"); TFT.foreground(Red); TFT.printf("No slaves found!"); while(1){} } } else { printf("Ethernet interface init failed!"); TFT.foreground(Red); TFT.locate(0, 0); TFT.printf("Ethernet interface init failed!"); while(1){} } } //****** user master application ********************************************** void Application() { while(1) { event_flags.wait_any(APPLICATION_FLAG); // the application waits for the synchronization flag //Test_2 = 1; IO_data.lock(); // copy the Ethercat data to a safe buffer memcpy(&IOmapSafe[0], &IOmap[0], IO_MAP_SIZE); // // if (NetworkError) // { // NetworkErrorSafe = NetworkError; // WorkCounterSafe = WorkCounter; // } // IO_data.unlock(); // if (NetworkErrorSafe) { TFT.rect(35,50, 285, 182, Red); TFT.fillrect(36,51, 284, 181, Black); TFT.foreground(Red); TFT.set_font((unsigned char*) Arial28x28); TFT.locate(58, 65); TFT.printf("Network error!"); printf("Network error!\n"); TFT.foreground(Magenta); TFT.set_font((unsigned char*) Arial12x12); TFT.locate(58, 106); if(WorkCounterSafe >= 0) { TFT.printf("Expected working counter %d", ExpectWorkCounter); TFT.locate(58, 118); TFT.printf("Actual working counter %d", WorkCounterSafe); printf("Expected working counter %d\n", ExpectWorkCounter); printf("Actual working counter %d\n", WorkCounterSafe); } else { TFT.printf("Timeout"); printf("Timeout\n"); } TFT.foreground(Green); TFT.locate(58, 142); TFT.printf("Please fix the error and"); TFT.locate(58, 154); TFT.printf("press the reset button"); printf("Please fix the error and press the reset button \n"); SampleTicker.detach(); // stop the sample interrupt while(1){} // and loop for ever } //----- slave LAB_2_1 data management ------ // Buttons_1 = in_LAB_2_1->Buttons; // read the buttons status from the slave // if (Buttons_1 != PrevButtons_1) // check if the buttons value has changed { // PrevButtons_1 = Buttons_1; // remember the current buttons value DrawButtons_1_Value(Buttons_1); // draw the current buttons value on the TFT } // // out_LAB_2_1->Segments = Buttons_2; // send to the slave the buttons status // from the slave LAB_2_2 //----- slave 2_2 data management ---------- // Buttons_2 = in_LAB_2_2->Buttons; // read the buttons status from the slave // if (Buttons_2 != PrevButtons_2) // check if the buttons value has changed { // PrevButtons_2 = Buttons_2; // remember the current buttons value DrawButtons_2_Value(Buttons_2); // draw the current buttons value on the TFT } // // out_LAB_2_2->Segments = Buttons_1; // send to the slave the buttons status // from the slave LAB_2_1 IO_data.lock(); // copy the IO data from the safe area memcpy(&IOmap[0], &IOmapSafe[0], IO_MAP_SIZE); // to the EtherCAT buffer IO_data.unlock(); // //Test_2 = 0; } } //****************************************************************************** //******* general functions **************************************************** //----- draw the fixed part of the slaves visualization ------------------------ void DrawSlaveFixedParts() { int i; TFT.cls(); // clear screen TFT.line(0, 120, 340, 120, Green); // draw the separation line for (i=0; i<3; i++) // draw the buttons fixed parts { // for the LAB_2_1 slave TFT.circle(BUTTONS_1_X+(i*BUTTONS_1_STEP), BUTTONS_1_Y, BUTTONS_1_R, Red); TFT.circle(BUTTONS_1_X+BUTTONS_1_WIDTH+(i*BUTTONS_1_STEP), BUTTONS_1_Y, BUTTONS_1_R, Red); // TFT.line(BUTTONS_1_X+(i*BUTTONS_1_STEP)-BUTTONS_1_R, BUTTONS_1_Y, BUTTONS_1_X+(i*BUTTONS_1_STEP)-BUTTONS_1_R-4, BUTTONS_1_Y, Red); TFT.line(BUTTONS_1_X+BUTTONS_1_WIDTH+(i*BUTTONS_1_STEP)+BUTTONS_1_R, BUTTONS_1_Y, BUTTONS_1_X+BUTTONS_1_WIDTH+(i*BUTTONS_1_STEP)+BUTTONS_1_R+4 , BUTTONS_1_Y, Red); } // // TFT.set_font((unsigned char*) Arial12x12); // TFT.locate(BUTTONS_1_X+12, BUTTONS_1_Y+20); // TFT.printf("LAB_2_1 Buttons"); // for (i=0; i<3; i++) // draw the buttons fixed parts { // for the LAB_2_2 slave TFT.circle(BUTTONS_2_X+(i*BUTTONS_2_STEP), BUTTONS_2_Y, BUTTONS_2_R, Red); TFT.circle(BUTTONS_2_X+BUTTONS_2_WIDTH+(i*BUTTONS_2_STEP), BUTTONS_2_Y, BUTTONS_2_R, Red); // TFT.line(BUTTONS_2_X+(i*BUTTONS_2_STEP)-BUTTONS_2_R, BUTTONS_2_Y, BUTTONS_2_X+(i*BUTTONS_2_STEP)-BUTTONS_2_R-4, BUTTONS_2_Y, Red); TFT.line(BUTTONS_2_X+BUTTONS_2_WIDTH+(i*BUTTONS_2_STEP)+BUTTONS_2_R, BUTTONS_2_Y, BUTTONS_2_X+BUTTONS_2_WIDTH+(i*BUTTONS_2_STEP)+BUTTONS_2_R+4 , BUTTONS_2_Y, Red); } // // TFT.set_font((unsigned char*) Arial12x12); // TFT.locate(BUTTONS_2_X+12, BUTTONS_2_Y+20); // TFT.printf("LAB_2_2 Buttons"); // DrawButtons_1_Value (Buttons_1); // draw the buttons status DrawButtons_2_Value (Buttons_2); // FirstRound = true; } //---- draw the starting banner ------------------------------------------------ void DrawBanner() { TFT.set_font((unsigned char*) Arial24x23); TFT.foreground(Red); TFT.locate(30, 30); TFT.printf("EasyCAT"); TFT.locate(30, 60); TFT.printf("SOEM MASTER"); TFT.foreground(Magenta); TFT.locate(30, 100); TFT.printf("simple example"); TFT.set_font((unsigned char*) Arial12x12); TFT.foreground(Green); TFT.locate(30, 150); TFT.printf("www.bausano.net"); TFT.foreground(Green); TFT.locate(30, 170); TFT.printf("www.easycatshield.com"); TFT.locate(30, 190); TFT.printf("https://openethercatsociety.github.io/"); } //---- slaves data visualization functions ------------------------------------- void DrawButtons_1_Value (uint8_t Value) // visualize on the TFT the { // slave LAB_2_1 buttons status uint8_t Slope; int i; for (i=0; i<3; i++) { if ((Value & 0x04) == 0x04) Slope = BUTTONS_1_R; else Slope = 16; TFT.fillrect(BUTTONS_1_X+(i*BUTTONS_1_STEP), BUTTONS_1_Y-16-1, BUTTONS_1_X+BUTTONS_1_WIDTH+(i*BUTTONS_1_STEP), BUTTONS_1_Y-BUTTONS_1_R-1, Black); TFT.line(BUTTONS_1_X+(i*BUTTONS_1_STEP), BUTTONS_1_Y-BUTTONS_1_R-1, BUTTONS_1_X+BUTTONS_1_WIDTH+(i*BUTTONS_1_STEP), BUTTONS_1_Y-Slope-1, Red); Value = Value << 1; } } void DrawButtons_2_Value (uint8_t Value) // visualize on the TFT the { // slave LAB_2_2 buttons status uint8_t Slope; int i; for (i=0; i<3; i++) { if ((Value & 0x04) == 0x04) Slope = BUTTONS_1_R; else Slope = 16; TFT.fillrect(BUTTONS_2_X+(i*BUTTONS_2_STEP), BUTTONS_2_Y-16-1, BUTTONS_2_X+BUTTONS_2_WIDTH+(i*BUTTONS_2_STEP), BUTTONS_2_Y-BUTTONS_2_R-1, Black); TFT.line(BUTTONS_2_X+(i*BUTTONS_2_STEP), BUTTONS_2_Y-BUTTONS_2_R-1, BUTTONS_2_X+BUTTONS_2_WIDTH+(i*BUTTONS_2_STEP), BUTTONS_2_Y-Slope-1, Red); Value = Value << 1; } }