Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
EasyCAT.cpp
00001 //******************************************************************************************** 00002 // * 00003 // AB&T Tecnologie Informatiche - Ivrea Italy * 00004 // http://www.bausano.net * 00005 // https://www.ethercat.org/en/products/791FFAA126AD43859920EA64384AD4FD.htm * 00006 // * 00007 //******************************************************************************************** 00008 // * 00009 // This software is distributed as an example, in the hope that it could be useful, * 00010 // WITHOUT ANY WARRANTY, even the implied warranty of FITNESS FOR A PARTICULAR PURPOSE * 00011 // * 00012 //******************************************************************************************** 00013 00014 00015 //----- EasyCAT library for mbed boards ----------------------------------------------------- 00016 //----- Derived from the AB&T EasyCAT Arduino shield library V 1.5 170912-------------------------- 00017 00018 //----- Tested with the STM32 NUCLEO-F767ZI board ------------------------------------------- 00019 00020 00021 00022 #include "mbed.h" 00023 #include "EasyCAT.h" 00024 00025 00026 DigitalOut * SpiCs; 00027 SPI Spi(D11, D12, D13); // declare MOSI MISO SCK 00028 00029 00030 #define SCS_Low_macro (*SpiCs = 0); // macro for set/reset SPI chip select 00031 #define SCS_High_macro (*SpiCs = 1); // 00032 00033 // macro for the SPI transfer 00034 inline static void SPI_TransferTx (unsigned char Data) 00035 { // 00036 Spi.write(Data); // 00037 }; // 00038 // 00039 inline static void SPI_TransferTxLast (unsigned char Data) 00040 { // 00041 Spi.write(Data); // 00042 }; // 00043 // 00044 inline static unsigned char SPI_TransferRx (unsigned char Data) 00045 { // 00046 return Spi.write(Data); // 00047 }; // 00048 00049 00050 00051 //---- constructors -------------------------------------------------------------------------------- 00052 00053 EasyCAT::EasyCAT() //------- default constructor ---------------------- 00054 { // 00055 Sync_ = ASYNC; // if no synchronization mode is declared 00056 // ASYNC is the default 00057 // 00058 SCS_ = (PinName)D9; // if no chip select is declared 00059 SpiCs = new DigitalOut(SCS_, 1); // pin D9 is the default 00060 } // 00061 00062 00063 EasyCAT::EasyCAT(PinName SCS) //------- SPI_CHIP_SELECT options ----------------- 00064 // 00065 // for EasyCAT board REV_A we can choose between: 00066 // D8, D9, D10 00067 // 00068 // for EasyCAT board REV_B we have three additional options: 00069 // A5, D6, D7 00070 { 00071 SCS_ = SCS; // initialize chip select 00072 SpiCs = new DigitalOut(SCS_, 1); // 00073 } // 00074 00075 00076 EasyCAT::EasyCAT(SyncMode Sync) //-------Synchronization options ---------------------- 00077 // 00078 // we can choose between: 00079 // ASYNC = free running i.e. no synchronization 00080 // between master and slave (default) 00081 // 00082 // DC_SYNC = interrupt is generated from the 00083 // Distributed clock unit 00084 // 00085 // SM_SYNC = interrupt is generated from the 00086 // Syncronizatiom manager 2 00087 { // 00088 Sync_ = Sync; // 00089 // 00090 SCS_ = (PinName)D9; // default chip select is pin 9 00091 SpiCs = new DigitalOut(SCS_, 1); // 00092 } // 00093 00094 00095 //-- Synchronization and chip select options ----- 00096 EasyCAT::EasyCAT(PinName SCS, SyncMode Sync) // 00097 // 00098 { // 00099 Sync_ = Sync; // 00100 // 00101 SCS_ = SCS; // initialize chip select 00102 SpiCs = new DigitalOut(SCS_, 1); // 00103 } // 00104 00105 00106 00107 //---- EasyCAT board initialization --------------------------------------------------------------- 00108 00109 00110 bool EasyCAT::Init() 00111 { 00112 #define Tout 1000 00113 00114 ULONG TempLong; 00115 unsigned short i; 00116 00117 Spi.frequency(14000000); // SPI speed 14MHz 00118 Spi.format(8,0); // 8 bit mode 0 00119 00120 wait_ms(100); 00121 00122 SPIWriteRegisterDirect (RESET_CTL, DIGITAL_RST); // LAN9252 reset 00123 00124 i = 0; // reset timeout 00125 do // wait for reset to complete 00126 { // 00127 i++; // 00128 TempLong.Long = SPIReadRegisterDirect (RESET_CTL, 4); // 00129 }while (((TempLong.Byte[0] & 0x01) != 0x00) && (i != Tout)); 00130 // 00131 if (i == Tout) // time out expired 00132 { // 00133 return false; // initialization failed 00134 } 00135 00136 i = 0; // reset timeout 00137 do // check the Byte Order Test Register 00138 { // 00139 i++; // 00140 TempLong.Long = SPIReadRegisterDirect (BYTE_TEST, 4); // 00141 }while ((TempLong.Long != 0x87654321) && (i != Tout)); // 00142 // 00143 if (i == Tout) // time out expired 00144 { // 00145 return false; // initialization failed 00146 } 00147 00148 i = 0; // reset timeout 00149 do // check the Ready flag 00150 { // 00151 i++; // 00152 TempLong.Long = SPIReadRegisterDirect (HW_CFG, 4); // 00153 }while (((TempLong.Byte[3] & READY) == 0) && (i != Tout));// 00154 // 00155 if (i == Tout) // time out expired 00156 { // 00157 return false; // initialization failed 00158 } 00159 00160 00161 00162 #ifdef BYTE_NUM 00163 printf ("STANDARD MODE\n"); 00164 #else 00165 printf ("CUSTOM MODE\n"); 00166 #endif 00167 00168 printf ("%u Byte Out\n",TOT_BYTE_NUM_OUT); 00169 printf ("%u Byte In\n",TOT_BYTE_NUM_IN); 00170 00171 printf ("Sync = "); 00172 00173 00174 if ((Sync_ == DC_SYNC) || (Sync_ == SM_SYNC)) //--- if requested, enable -------- 00175 { //--- interrupt generation -------- 00176 00177 if (Sync_ == DC_SYNC) 00178 { // enable interrupt from SYNC 0 00179 SPIWriteRegisterIndirect (0x00000004, AL_EVENT_MASK, 4); 00180 // in AL event mask register, and disable 00181 // other interrupt sources 00182 printf("DC_SYNC\n"); 00183 } 00184 00185 else 00186 { // enable interrupt from SM 0 event 00187 SPIWriteRegisterIndirect (0x00000100, AL_EVENT_MASK, 4); 00188 // in AL event mask register, and disable 00189 // other interrupt sources 00190 printf("SM_SYNC\n"); 00191 } 00192 00193 SPIWriteRegisterDirect (IRQ_CFG, 0x00000111); // set LAN9252 interrupt pin driver 00194 // as push-pull active high 00195 // (On the EasyCAT shield board the IRQ pin 00196 // is inverted by a mosfet, so Arduino 00197 // receives an active low signal) 00198 00199 SPIWriteRegisterDirect (INT_EN, 0x00000001); // enable LAN9252 interrupt 00200 } 00201 00202 else 00203 { 00204 printf("ASYNC\n"); 00205 } 00206 00207 00208 TempLong.Long = SPIReadRegisterDirect (ID_REV, 4); // read the chip identification 00209 printf ("Detected chip "); // and revision, and print it 00210 printf ("%x ", TempLong.Word[1]); // out on the serial line 00211 printf (" Rev "); // 00212 printf ("%u \n", TempLong.Word[0]); // 00213 00214 00215 /* 00216 printf ("%u \n", TOT_BYTE_NUM_OUT); 00217 printf ("%u \n", BYTE_NUM_OUT); 00218 printf ("%u \n", BYTE_NUM_ROUND_OUT); 00219 printf ("%u \n", LONG_NUM_OUT); 00220 00221 printf ("%u \n", SEC_BYTE_NUM_OUT); 00222 printf ("%u \n", SEC_BYTE_NUM_ROUND_OUT); 00223 printf ("%u \n\n", SEC_LONG_NUM_OUT); 00224 00225 printf ("%u \n", TOT_BYTE_NUM_IN); 00226 printf ("%u \n", BYTE_NUM_IN); 00227 printf ("%u \n", BYTE_NUM_ROUND_IN); 00228 printf ("%u \n", LONG_NUM_IN); 00229 00230 printf ("%u \n", SEC_BYTE_NUM_IN); 00231 printf ("%u \n", SEC_BYTE_NUM_ROUND_IN); 00232 printf ("%u \n", SEC_LONG_NUM_IN); 00233 */ 00234 00235 00236 //-------------------------------------------------------------------------------------------- 00237 00238 00239 return true; // initalization completed 00240 }; 00241 00242 00243 00244 00245 //---- EtherCAT task ------------------------------------------------------------------------------ 00246 00247 unsigned char EasyCAT::MainTask() // must be called cyclically by the application 00248 00249 { 00250 bool WatchDog = true; 00251 bool Operational = false; 00252 unsigned char i; 00253 ULONG TempLong; 00254 unsigned char Status; 00255 00256 00257 TempLong.Long = SPIReadRegisterIndirect (WDOG_STATUS, 1); // read watchdog status 00258 if ((TempLong.Byte[0] & 0x01) == 0x01) // 00259 WatchDog = false; // set/reset the corrisponding flag 00260 else // 00261 WatchDog = true; // 00262 00263 00264 TempLong.Long = SPIReadRegisterIndirect (AL_STATUS, 1); // read the EtherCAT State Machine status 00265 Status = TempLong.Byte[0] & 0x0F; // 00266 if (Status == ESM_OP) // to see if we are in operational state 00267 Operational = true; // 00268 else // set/reset the corrisponding flag 00269 Operational = false; // 00270 00271 00272 //--- process data transfert ---------- 00273 // 00274 if (WatchDog | !Operational) // if watchdog is active or we are 00275 { // not in operational state, reset 00276 for (i=0; i < TOT_BYTE_NUM_OUT ; i++) // the output buffer 00277 BufferOut.Byte[i] = 0; // 00278 00279 /* // debug 00280 if (!Operational) // 00281 printf("Not operational\n"); // 00282 if (WatchDog) // 00283 printf("WatchDog\n"); // 00284 */ // 00285 } 00286 00287 else 00288 { 00289 SPIReadProcRamFifo(); // otherwise transfer process data from 00290 } // the EtherCAT core to the output buffer 00291 00292 SPIWriteProcRamFifo(); // we always transfer process data from 00293 // the input buffer to the EtherCAT core 00294 00295 if (WatchDog) // return the status of the State Machine 00296 { // and of the watchdog 00297 Status |= 0x80; // 00298 } // 00299 return Status; // 00300 00301 } 00302 00303 00304 00305 //---- read a directly addressable registers ----------------------------------------------------- 00306 00307 unsigned long EasyCAT::SPIReadRegisterDirect (unsigned short Address, unsigned char Len) 00308 00309 // Address = register to read 00310 // Len = number of bytes to read (1,2,3,4) 00311 // 00312 // a long is returned but only the requested bytes 00313 // are meaningful, starting from LsByte 00314 { 00315 ULONG Result; 00316 UWORD Addr; 00317 Addr.Word = Address; 00318 unsigned char i; 00319 00320 SCS_Low_macro // SPI chip select enable 00321 00322 SPI_TransferTx(COMM_SPI_READ); // SPI read command 00323 SPI_TransferTx(Addr.Byte[1]); // address of the register 00324 SPI_TransferTxLast(Addr.Byte[0]); // to read, MsByte first 00325 00326 for (i=0; i<Len; i++) // read the requested number of bytes 00327 { // LsByte first 00328 Result.Byte[i] = SPI_TransferRx(DUMMY_BYTE); // 00329 } // 00330 00331 SCS_High_macro // SPI chip select disable 00332 00333 return Result.Long; // return the result 00334 } 00335 00336 00337 00338 00339 //---- write a directly addressable registers ---------------------------------------------------- 00340 00341 void EasyCAT::SPIWriteRegisterDirect (unsigned short Address, unsigned long DataOut) 00342 00343 // Address = register to write 00344 // DataOut = data to write 00345 { 00346 ULONG Data; 00347 UWORD Addr; 00348 Addr.Word = Address; 00349 Data.Long = DataOut; 00350 00351 SCS_Low_macro // SPI chip select enable 00352 00353 SPI_TransferTx(COMM_SPI_WRITE); // SPI write command 00354 SPI_TransferTx(Addr.Byte[1]); // address of the register 00355 SPI_TransferTx(Addr.Byte[0]); // to write MsByte first 00356 00357 SPI_TransferTx(Data.Byte[0]); // data to write 00358 SPI_TransferTx(Data.Byte[1]); // LsByte first 00359 SPI_TransferTx(Data.Byte[2]); // 00360 SPI_TransferTxLast(Data.Byte[3]); // 00361 00362 SCS_High_macro // SPI chip select enable 00363 } 00364 00365 00366 //---- read an undirectly addressable registers -------------------------------------------------- 00367 00368 unsigned long EasyCAT::SPIReadRegisterIndirect (unsigned short Address, unsigned char Len) 00369 00370 // Address = register to read 00371 // Len = number of bytes to read (1,2,3,4) 00372 // 00373 // a long is returned but only the requested bytes 00374 // are meaningful, starting from LsByte 00375 { 00376 ULONG TempLong; 00377 UWORD Addr; 00378 Addr.Word = Address; 00379 // compose the command 00380 // 00381 TempLong.Byte[0] = Addr.Byte[0]; // address of the register 00382 TempLong.Byte[1] = Addr.Byte[1]; // to read, LsByte first 00383 TempLong.Byte[2] = Len; // number of bytes to read 00384 TempLong.Byte[3] = ESC_READ; // ESC read 00385 00386 SPIWriteRegisterDirect (ECAT_CSR_CMD, TempLong.Long); // write the command 00387 00388 do 00389 { // wait for command execution 00390 TempLong.Long = SPIReadRegisterDirect(ECAT_CSR_CMD,4); // 00391 } // 00392 while(TempLong.Byte[3] & ECAT_CSR_BUSY); // 00393 00394 00395 TempLong.Long = SPIReadRegisterDirect(ECAT_CSR_DATA,Len); // read the requested register 00396 return TempLong.Long; // 00397 } 00398 00399 00400 //---- write an undirectly addressable registers ------------------------------------------------- 00401 00402 void EasyCAT::SPIWriteRegisterIndirect (unsigned long DataOut, unsigned short Address, unsigned char Len) 00403 00404 // Address = register to write 00405 // DataOut = data to write 00406 { 00407 ULONG TempLong; 00408 UWORD Addr; 00409 Addr.Word = Address; 00410 00411 00412 SPIWriteRegisterDirect (ECAT_CSR_DATA, DataOut); // write the data 00413 00414 // compose the command 00415 // 00416 TempLong.Byte[0] = Addr.Byte[0]; // address of the register 00417 TempLong.Byte[1] = Addr.Byte[1]; // to write, LsByte first 00418 TempLong.Byte[2] = Len; // number of bytes to write 00419 TempLong.Byte[3] = ESC_WRITE; // ESC write 00420 00421 SPIWriteRegisterDirect (ECAT_CSR_CMD, TempLong.Long); // write the command 00422 00423 do // wait for command execution 00424 { // 00425 TempLong.Long = SPIReadRegisterDirect (ECAT_CSR_CMD, 4); // 00426 } // 00427 while (TempLong.Byte[3] & ECAT_CSR_BUSY); // 00428 } 00429 00430 00431 //---- read from process ram fifo ---------------------------------------------------------------- 00432 00433 00434 void EasyCAT::SPIReadProcRamFifo() // read BYTE_NUM bytes from the output process ram, through the fifo 00435 // 00436 // these are the bytes received from the EtherCAT master and 00437 // that will be use by our application to write the outputs 00438 { 00439 ULONG TempLong; 00440 unsigned char i; 00441 00442 #if TOT_BYTE_NUM_OUT > 0 00443 00444 SPIWriteRegisterDirect (ECAT_PRAM_RD_CMD, PRAM_ABORT); // abort any possible pending transfer 00445 00446 00447 SPIWriteRegisterDirect (ECAT_PRAM_RD_ADDR_LEN, (0x00001000 | (((uint32_t)TOT_BYTE_NUM_OUT) << 16))); 00448 // the high word is the num of bytes 00449 // to read 0xTOT_BYTE_NUM_OUT---- 00450 // the low word is the output process 00451 // ram offset 0x----1000 00452 00453 SPIWriteRegisterDirect (ECAT_PRAM_RD_CMD, 0x80000000); // start command 00454 00455 00456 //------- one round is enough if we have ---- 00457 //------- to transfer up to 64 bytes -------- 00458 00459 do // wait for the data to be 00460 { // transferred from the output 00461 TempLong.Long = SPIReadRegisterDirect (ECAT_PRAM_RD_CMD,2); // process ram to the read fifo 00462 } // 00463 while (TempLong.Byte[1] != FST_LONG_NUM_OUT); // 00464 00465 SCS_Low_macro // enable SPI chip select 00466 00467 SPI_TransferTx(COMM_SPI_READ); // SPI read command 00468 SPI_TransferTx(0x00); // address of the read 00469 SPI_TransferTxLast(0x00); // fifo MsByte first 00470 00471 for (i=0; i< FST_BYTE_NUM_ROUND_OUT; i++) // transfer the data 00472 { // 00473 BufferOut.Byte[i] = SPI_TransferRx(DUMMY_BYTE); // 00474 } // 00475 00476 SCS_High_macro // disable SPI chip select 00477 #endif 00478 00479 00480 #if SEC_BYTE_NUM_OUT > 0 //-- if we have to transfer more then 64 bytes -- 00481 //-- we must do another round ------------------- 00482 //-- to transfer the remainig bytes ------------- 00483 00484 00485 do // wait for the data to be 00486 { // transferred from the output 00487 TempLong.Long = SPIReadRegisterDirect(ECAT_PRAM_RD_CMD,2);// process ram to the read fifo 00488 } // 00489 while (TempLong.Byte[1] != SEC_LONG_NUM_OUT); // 00490 00491 SCS_Low_macro // enable SPI chip select 00492 00493 SPI_TransferTx(COMM_SPI_READ); // SPI read command 00494 SPI_TransferTx(0x00); // address of the read 00495 SPI_TransferTxLast(0x00); // fifo MsByte first 00496 00497 for (i=0; i< (SEC_BYTE_NUM_ROUND_OUT); i++) // transfer loop for the remaining 00498 { // bytes 00499 BufferOut.Byte[i+64] = SPI_TransferRx(DUMMY_BYTE); // we transfer the second part of 00500 } // the buffer, so offset by 64 00501 00502 SCS_High_macro // SPI chip select disable 00503 #endif 00504 } 00505 00506 00507 //---- write to the process ram fifo -------------------------------------------------------------- 00508 00509 void EasyCAT::SPIWriteProcRamFifo() // write BYTE_NUM bytes to the input process ram, through the fifo 00510 // 00511 // these are the bytes that we have read from the inputs of our 00512 // application and that will be sent to the EtherCAT master 00513 { 00514 ULONG TempLong; 00515 unsigned char i; 00516 00517 00518 00519 #if TOT_BYTE_NUM_IN > 0 00520 00521 SPIWriteRegisterDirect (ECAT_PRAM_WR_CMD, PRAM_ABORT); // abort any possible pending transfer 00522 00523 00524 SPIWriteRegisterDirect (ECAT_PRAM_WR_ADDR_LEN, (0x00001200 | (((uint32_t)TOT_BYTE_NUM_IN) << 16))); 00525 // the high word is the num of bytes 00526 // to write 0xTOT_BYTE_NUM_IN---- 00527 // the low word is the input process 00528 // ram offset 0x----1200 00529 00530 SPIWriteRegisterDirect (ECAT_PRAM_WR_CMD, 0x80000000); // start command 00531 00532 00533 //------- one round is enough if we have ---- 00534 //------- to transfer up to 64 bytes -------- 00535 00536 do // check that the fifo has 00537 { // enough free space 00538 TempLong.Long = SPIReadRegisterDirect (ECAT_PRAM_WR_CMD,2); // 00539 } // 00540 while (TempLong.Byte[1] < FST_LONG_NUM_IN); // 00541 00542 SCS_Low_macro // enable SPI chip select 00543 00544 SPI_TransferTx(COMM_SPI_WRITE); // SPI write command 00545 SPI_TransferTx(0x00); // address of the write fifo 00546 SPI_TransferTx(0x20); // MsByte first 00547 00548 for (i=0; i< (FST_BYTE_NUM_ROUND_IN - 1 ); i++) // transfer the data 00549 { // 00550 SPI_TransferTx (BufferIn.Byte[i]); // 00551 } // 00552 // 00553 SPI_TransferTxLast (BufferIn.Byte[i]); // one last byte 00554 00555 SCS_High_macro // disable SPI chip select 00556 #endif 00557 00558 00559 #if SEC_BYTE_NUM_IN > 0 //-- if we have to transfer more then 64 bytes -- 00560 //-- we must do another round ------------------- 00561 //-- to transfer the remainig bytes ------------- 00562 00563 do // check that the fifo has 00564 { // enough free space 00565 TempLong.Long = SPIReadRegisterDirect(ECAT_PRAM_WR_CMD,2);// 00566 } // 00567 while (TempLong.Byte[1] < (SEC_LONG_NUM_IN)); // 00568 00569 SCS_Low_macro // enable SPI chip select 00570 00571 SPI_TransferTx(COMM_SPI_WRITE); // SPI write command 00572 SPI_TransferTx(0x00); // address of the write fifo 00573 SPI_TransferTx(0x20); // MsByte first 00574 00575 for (i=0; i< (SEC_BYTE_NUM_ROUND_IN - 1); i++) // transfer loop for the remaining 00576 { // bytes 00577 SPI_TransferTx (BufferIn.Byte[i+64]); // we transfer the second part of 00578 } // the buffer, so offset by 64 00579 // 00580 SPI_TransferTxLast (BufferIn.Byte[i+64]); // one last byte 00581 00582 SCS_High_macro // disable SPI chip select 00583 #endif 00584 }
Generated on Wed Jul 20 2022 19:41:42 by
