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.
Revision 0:7816b38c99cc, committed 2017-09-12
- Comitter:
- EasyCAT
- Date:
- Tue Sep 12 17:09:43 2017 +0000
- Child:
- 1:47eefd835111
- Child:
- 4:66867fae2256
- Commit message:
- first release
Changed in this revision
| EasyCAT.cpp | Show annotated file Show diff for this revision Revisions of this file |
| EasyCAT.h | Show annotated file Show diff for this revision Revisions of this file |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/EasyCAT.cpp Tue Sep 12 17:09:43 2017 +0000
@@ -0,0 +1,584 @@
+//********************************************************************************************
+// *
+// AB&T Tecnologie Informatiche - Ivrea Italy *
+// http://www.bausano.net *
+// https://www.ethercat.org/en/products/791FFAA126AD43859920EA64384AD4FD.htm *
+// *
+//********************************************************************************************
+// *
+// This software is distributed as an example, in the hope that it could be useful, *
+// WITHOUT ANY WARRANTY, even the implied warranty of FITNESS FOR A PARTICULAR PURPOSE *
+// *
+//********************************************************************************************
+
+
+//----- EasyCAT library for mbed boards -----------------------------------------------------
+//----- Derived from the AB&T EasyCAT Arduino shield library V 1.5 170912--------------------------
+
+//----- Tested with the STM32 NUCLEO-F767ZI board -------------------------------------------
+
+
+
+#include "mbed.h"
+#include "EasyCAT.h"
+
+
+DigitalOut * SpiCs;
+SPI Spi(D11, D12, D13); // declare MOSI MISO SCK
+
+
+#define SCS_Low_macro (*SpiCs = 0); // macro for set/reset SPI chip select
+#define SCS_High_macro (*SpiCs = 1); //
+
+ // macro for the SPI transfer
+inline static void SPI_TransferTx (unsigned char Data)
+{ //
+ Spi.write(Data); //
+}; //
+ //
+inline static void SPI_TransferTxLast (unsigned char Data)
+{ //
+ Spi.write(Data); //
+}; //
+ //
+inline static unsigned char SPI_TransferRx (unsigned char Data)
+{ //
+ return Spi.write(Data); //
+}; //
+
+
+
+//---- constructors --------------------------------------------------------------------------------
+
+EasyCAT::EasyCAT() //------- default constructor ----------------------
+{ //
+ Sync_ = ASYNC; // if no synchronization mode is declared
+ // ASYNC is the default
+ //
+ SCS_ = (PinName)D9; // if no chip select is declared
+ SpiCs = new DigitalOut(SCS_, 1); // pin D9 is the default
+} //
+
+
+EasyCAT::EasyCAT(PinName SCS) //------- SPI_CHIP_SELECT options -----------------
+ //
+ // for EasyCAT board REV_A we can choose between:
+ // D8, D9, D10
+ //
+ // for EasyCAT board REV_B we have three additional options:
+ // A5, D6, D7
+{
+ SCS_ = SCS; // initialize chip select
+ SpiCs = new DigitalOut(SCS_, 1); //
+} //
+
+
+EasyCAT::EasyCAT(SyncMode Sync) //-------Synchronization options ----------------------
+ //
+ // we can choose between:
+ // ASYNC = free running i.e. no synchronization
+ // between master and slave (default)
+ //
+ // DC_SYNC = interrupt is generated from the
+ // Distributed clock unit
+ //
+ // SM_SYNC = interrupt is generated from the
+ // Syncronizatiom manager 2
+{ //
+ Sync_ = Sync; //
+ //
+ SCS_ = (PinName)D9; // default chip select is pin 9
+ SpiCs = new DigitalOut(SCS_, 1); //
+} //
+
+
+ //-- Synchronization and chip select options -----
+EasyCAT::EasyCAT(PinName SCS, SyncMode Sync) //
+ //
+{ //
+ Sync_ = Sync; //
+ //
+ SCS_ = SCS; // initialize chip select
+ SpiCs = new DigitalOut(SCS_, 1); //
+} //
+
+
+
+//---- EasyCAT board initialization ---------------------------------------------------------------
+
+
+bool EasyCAT::Init()
+{
+ #define Tout 1000
+
+ ULONG TempLong;
+ unsigned short i;
+
+ Spi.frequency(14000000); // SPI speed 14MHz
+ Spi.format(8,0); // 8 bit mode 0
+
+ wait_ms(100);
+
+ SPIWriteRegisterDirect (RESET_CTL, DIGITAL_RST); // LAN9252 reset
+
+ i = 0; // reset timeout
+ do // wait for reset to complete
+ { //
+ i++; //
+ TempLong.Long = SPIReadRegisterDirect (RESET_CTL, 4); //
+ }while (((TempLong.Byte[0] & 0x01) != 0x00) && (i != Tout));
+ //
+ if (i == Tout) // time out expired
+ { //
+ return false; // initialization failed
+ }
+
+ i = 0; // reset timeout
+ do // check the Byte Order Test Register
+ { //
+ i++; //
+ TempLong.Long = SPIReadRegisterDirect (BYTE_TEST, 4); //
+ }while ((TempLong.Long != 0x87654321) && (i != Tout)); //
+ //
+ if (i == Tout) // time out expired
+ { //
+ return false; // initialization failed
+ }
+
+ i = 0; // reset timeout
+ do // check the Ready flag
+ { //
+ i++; //
+ TempLong.Long = SPIReadRegisterDirect (HW_CFG, 4); //
+ }while (((TempLong.Byte[3] & READY) == 0) && (i != Tout));//
+ //
+ if (i == Tout) // time out expired
+ { //
+ return false; // initialization failed
+ }
+
+
+
+#ifdef BYTE_NUM
+ printf ("STANDARD MODE\n");
+#else
+ printf ("CUSTOM MODE\n");
+#endif
+
+ printf ("%u Byte Out\n",TOT_BYTE_NUM_OUT);
+ printf ("%u Byte In\n",TOT_BYTE_NUM_IN);
+
+ printf ("Sync = ");
+
+
+ if ((Sync_ == DC_SYNC) || (Sync_ == SM_SYNC)) //--- if requested, enable --------
+ { //--- interrupt generation --------
+
+ if (Sync_ == DC_SYNC)
+ { // enable interrupt from SYNC 0
+ SPIWriteRegisterIndirect (0x00000004, AL_EVENT_MASK, 4);
+ // in AL event mask register, and disable
+ // other interrupt sources
+ printf("DC_SYNC\n");
+ }
+
+ else
+ { // enable interrupt from SM 0 event
+ SPIWriteRegisterIndirect (0x00000100, AL_EVENT_MASK, 4);
+ // in AL event mask register, and disable
+ // other interrupt sources
+ printf("SM_SYNC\n");
+ }
+
+ SPIWriteRegisterDirect (IRQ_CFG, 0x00000111); // set LAN9252 interrupt pin driver
+ // as push-pull active high
+ // (On the EasyCAT shield board the IRQ pin
+ // is inverted by a mosfet, so Arduino
+ // receives an active low signal)
+
+ SPIWriteRegisterDirect (INT_EN, 0x00000001); // enable LAN9252 interrupt
+ }
+
+ else
+ {
+ printf("ASYNC\n");
+ }
+
+
+ TempLong.Long = SPIReadRegisterDirect (ID_REV, 4); // read the chip identification
+ printf ("Detected chip "); // and revision, and print it
+ printf ("%x ", TempLong.Word[1]); // out on the serial line
+ printf (" Rev "); //
+ printf ("%u \n", TempLong.Word[0]); //
+
+
+ /*
+ printf ("%u \n", TOT_BYTE_NUM_OUT);
+ printf ("%u \n", BYTE_NUM_OUT);
+ printf ("%u \n", BYTE_NUM_ROUND_OUT);
+ printf ("%u \n", LONG_NUM_OUT);
+
+ printf ("%u \n", SEC_BYTE_NUM_OUT);
+ printf ("%u \n", SEC_BYTE_NUM_ROUND_OUT);
+ printf ("%u \n\n", SEC_LONG_NUM_OUT);
+
+ printf ("%u \n", TOT_BYTE_NUM_IN);
+ printf ("%u \n", BYTE_NUM_IN);
+ printf ("%u \n", BYTE_NUM_ROUND_IN);
+ printf ("%u \n", LONG_NUM_IN);
+
+ printf ("%u \n", SEC_BYTE_NUM_IN);
+ printf ("%u \n", SEC_BYTE_NUM_ROUND_IN);
+ printf ("%u \n", SEC_LONG_NUM_IN);
+*/
+
+
+//--------------------------------------------------------------------------------------------
+
+
+ return true; // initalization completed
+};
+
+
+
+
+//---- EtherCAT task ------------------------------------------------------------------------------
+
+unsigned char EasyCAT::MainTask() // must be called cyclically by the application
+
+{
+ bool WatchDog = true;
+ bool Operational = false;
+ unsigned char i;
+ ULONG TempLong;
+ unsigned char Status;
+
+
+ TempLong.Long = SPIReadRegisterIndirect (WDOG_STATUS, 1); // read watchdog status
+ if ((TempLong.Byte[0] & 0x01) == 0x01) //
+ WatchDog = false; // set/reset the corrisponding flag
+ else //
+ WatchDog = true; //
+
+
+ TempLong.Long = SPIReadRegisterIndirect (AL_STATUS, 1); // read the EtherCAT State Machine status
+ Status = TempLong.Byte[0] & 0x0F; //
+ if (Status == ESM_OP) // to see if we are in operational state
+ Operational = true; //
+ else // set/reset the corrisponding flag
+ Operational = false; //
+
+
+ //--- process data transfert ----------
+ //
+ if (WatchDog | !Operational) // if watchdog is active or we are
+ { // not in operational state, reset
+ for (i=0; i < TOT_BYTE_NUM_OUT ; i++) // the output buffer
+ BufferOut.Byte[i] = 0; //
+
+/* // debug
+ if (!Operational) //
+ printf("Not operational\n"); //
+ if (WatchDog) //
+ printf("WatchDog\n"); //
+*/ //
+ }
+
+ else
+ {
+ SPIReadProcRamFifo(); // otherwise transfer process data from
+ } // the EtherCAT core to the output buffer
+
+ SPIWriteProcRamFifo(); // we always transfer process data from
+ // the input buffer to the EtherCAT core
+
+ if (WatchDog) // return the status of the State Machine
+ { // and of the watchdog
+ Status |= 0x80; //
+ } //
+ return Status; //
+
+}
+
+
+
+//---- read a directly addressable registers -----------------------------------------------------
+
+unsigned long EasyCAT::SPIReadRegisterDirect (unsigned short Address, unsigned char Len)
+
+ // Address = register to read
+ // Len = number of bytes to read (1,2,3,4)
+ //
+ // a long is returned but only the requested bytes
+ // are meaningful, starting from LsByte
+{
+ ULONG Result;
+ UWORD Addr;
+ Addr.Word = Address;
+ unsigned char i;
+
+ SCS_Low_macro // SPI chip select enable
+
+ SPI_TransferTx(COMM_SPI_READ); // SPI read command
+ SPI_TransferTx(Addr.Byte[1]); // address of the register
+ SPI_TransferTxLast(Addr.Byte[0]); // to read, MsByte first
+
+ for (i=0; i<Len; i++) // read the requested number of bytes
+ { // LsByte first
+ Result.Byte[i] = SPI_TransferRx(DUMMY_BYTE); //
+ } //
+
+ SCS_High_macro // SPI chip select disable
+
+ return Result.Long; // return the result
+}
+
+
+
+
+//---- write a directly addressable registers ----------------------------------------------------
+
+void EasyCAT::SPIWriteRegisterDirect (unsigned short Address, unsigned long DataOut)
+
+ // Address = register to write
+ // DataOut = data to write
+{
+ ULONG Data;
+ UWORD Addr;
+ Addr.Word = Address;
+ Data.Long = DataOut;
+
+ SCS_Low_macro // SPI chip select enable
+
+ SPI_TransferTx(COMM_SPI_WRITE); // SPI write command
+ SPI_TransferTx(Addr.Byte[1]); // address of the register
+ SPI_TransferTx(Addr.Byte[0]); // to write MsByte first
+
+ SPI_TransferTx(Data.Byte[0]); // data to write
+ SPI_TransferTx(Data.Byte[1]); // LsByte first
+ SPI_TransferTx(Data.Byte[2]); //
+ SPI_TransferTxLast(Data.Byte[3]); //
+
+ SCS_High_macro // SPI chip select enable
+}
+
+
+//---- read an undirectly addressable registers --------------------------------------------------
+
+unsigned long EasyCAT::SPIReadRegisterIndirect (unsigned short Address, unsigned char Len)
+
+ // Address = register to read
+ // Len = number of bytes to read (1,2,3,4)
+ //
+ // a long is returned but only the requested bytes
+ // are meaningful, starting from LsByte
+{
+ ULONG TempLong;
+ UWORD Addr;
+ Addr.Word = Address;
+ // compose the command
+ //
+ TempLong.Byte[0] = Addr.Byte[0]; // address of the register
+ TempLong.Byte[1] = Addr.Byte[1]; // to read, LsByte first
+ TempLong.Byte[2] = Len; // number of bytes to read
+ TempLong.Byte[3] = ESC_READ; // ESC read
+
+ SPIWriteRegisterDirect (ECAT_CSR_CMD, TempLong.Long); // write the command
+
+ do
+ { // wait for command execution
+ TempLong.Long = SPIReadRegisterDirect(ECAT_CSR_CMD,4); //
+ } //
+ while(TempLong.Byte[3] & ECAT_CSR_BUSY); //
+
+
+ TempLong.Long = SPIReadRegisterDirect(ECAT_CSR_DATA,Len); // read the requested register
+ return TempLong.Long; //
+}
+
+
+//---- write an undirectly addressable registers -------------------------------------------------
+
+void EasyCAT::SPIWriteRegisterIndirect (unsigned long DataOut, unsigned short Address, unsigned char Len)
+
+ // Address = register to write
+ // DataOut = data to write
+{
+ ULONG TempLong;
+ UWORD Addr;
+ Addr.Word = Address;
+
+
+ SPIWriteRegisterDirect (ECAT_CSR_DATA, DataOut); // write the data
+
+ // compose the command
+ //
+ TempLong.Byte[0] = Addr.Byte[0]; // address of the register
+ TempLong.Byte[1] = Addr.Byte[1]; // to write, LsByte first
+ TempLong.Byte[2] = Len; // number of bytes to write
+ TempLong.Byte[3] = ESC_WRITE; // ESC write
+
+ SPIWriteRegisterDirect (ECAT_CSR_CMD, TempLong.Long); // write the command
+
+ do // wait for command execution
+ { //
+ TempLong.Long = SPIReadRegisterDirect (ECAT_CSR_CMD, 4); //
+ } //
+ while (TempLong.Byte[3] & ECAT_CSR_BUSY); //
+}
+
+
+//---- read from process ram fifo ----------------------------------------------------------------
+
+
+void EasyCAT::SPIReadProcRamFifo() // read BYTE_NUM bytes from the output process ram, through the fifo
+ //
+ // these are the bytes received from the EtherCAT master and
+ // that will be use by our application to write the outputs
+{
+ ULONG TempLong;
+ unsigned char i;
+
+ #if TOT_BYTE_NUM_OUT > 0
+
+ SPIWriteRegisterDirect (ECAT_PRAM_RD_CMD, PRAM_ABORT); // abort any possible pending transfer
+
+
+ SPIWriteRegisterDirect (ECAT_PRAM_RD_ADDR_LEN, (0x00001000 | (((uint32_t)TOT_BYTE_NUM_OUT) << 16)));
+ // the high word is the num of bytes
+ // to read 0xTOT_BYTE_NUM_OUT----
+ // the low word is the output process
+ // ram offset 0x----1000
+
+ SPIWriteRegisterDirect (ECAT_PRAM_RD_CMD, 0x80000000); // start command
+
+
+ //------- one round is enough if we have ----
+ //------- to transfer up to 64 bytes --------
+
+ do // wait for the data to be
+ { // transferred from the output
+ TempLong.Long = SPIReadRegisterDirect (ECAT_PRAM_RD_CMD,2); // process ram to the read fifo
+ } //
+ while (TempLong.Byte[1] != FST_LONG_NUM_OUT); //
+
+ SCS_Low_macro // enable SPI chip select
+
+ SPI_TransferTx(COMM_SPI_READ); // SPI read command
+ SPI_TransferTx(0x00); // address of the read
+ SPI_TransferTxLast(0x00); // fifo MsByte first
+
+ for (i=0; i< FST_BYTE_NUM_ROUND_OUT; i++) // transfer the data
+ { //
+ BufferOut.Byte[i] = SPI_TransferRx(DUMMY_BYTE); //
+ } //
+
+ SCS_High_macro // disable SPI chip select
+ #endif
+
+
+ #if SEC_BYTE_NUM_OUT > 0 //-- if we have to transfer more then 64 bytes --
+ //-- we must do another round -------------------
+ //-- to transfer the remainig bytes -------------
+
+
+ do // wait for the data to be
+ { // transferred from the output
+ TempLong.Long = SPIReadRegisterDirect(ECAT_PRAM_RD_CMD,2);// process ram to the read fifo
+ } //
+ while (TempLong.Byte[1] != SEC_LONG_NUM_OUT); //
+
+ SCS_Low_macro // enable SPI chip select
+
+ SPI_TransferTx(COMM_SPI_READ); // SPI read command
+ SPI_TransferTx(0x00); // address of the read
+ SPI_TransferTxLast(0x00); // fifo MsByte first
+
+ for (i=0; i< (SEC_BYTE_NUM_ROUND_OUT); i++) // transfer loop for the remaining
+ { // bytes
+ BufferOut.Byte[i+64] = SPI_TransferRx(DUMMY_BYTE); // we transfer the second part of
+ } // the buffer, so offset by 64
+
+ SCS_High_macro // SPI chip select disable
+ #endif
+}
+
+
+//---- write to the process ram fifo --------------------------------------------------------------
+
+void EasyCAT::SPIWriteProcRamFifo() // write BYTE_NUM bytes to the input process ram, through the fifo
+ //
+ // these are the bytes that we have read from the inputs of our
+ // application and that will be sent to the EtherCAT master
+{
+ ULONG TempLong;
+ unsigned char i;
+
+
+
+ #if TOT_BYTE_NUM_IN > 0
+
+ SPIWriteRegisterDirect (ECAT_PRAM_WR_CMD, PRAM_ABORT); // abort any possible pending transfer
+
+
+ SPIWriteRegisterDirect (ECAT_PRAM_WR_ADDR_LEN, (0x00001200 | (((uint32_t)TOT_BYTE_NUM_IN) << 16)));
+ // the high word is the num of bytes
+ // to write 0xTOT_BYTE_NUM_IN----
+ // the low word is the input process
+ // ram offset 0x----1200
+
+ SPIWriteRegisterDirect (ECAT_PRAM_WR_CMD, 0x80000000); // start command
+
+
+ //------- one round is enough if we have ----
+ //------- to transfer up to 64 bytes --------
+
+ do // check that the fifo has
+ { // enough free space
+ TempLong.Long = SPIReadRegisterDirect (ECAT_PRAM_WR_CMD,2); //
+ } //
+ while (TempLong.Byte[1] < FST_LONG_NUM_IN); //
+
+ SCS_Low_macro // enable SPI chip select
+
+ SPI_TransferTx(COMM_SPI_WRITE); // SPI write command
+ SPI_TransferTx(0x00); // address of the write fifo
+ SPI_TransferTx(0x20); // MsByte first
+
+ for (i=0; i< (FST_BYTE_NUM_ROUND_IN - 1 ); i++) // transfer the data
+ { //
+ SPI_TransferTx (BufferIn.Byte[i]); //
+ } //
+ //
+ SPI_TransferTxLast (BufferIn.Byte[i]); // one last byte
+
+ SCS_High_macro // disable SPI chip select
+ #endif
+
+
+ #if SEC_BYTE_NUM_IN > 0 //-- if we have to transfer more then 64 bytes --
+ //-- we must do another round -------------------
+ //-- to transfer the remainig bytes -------------
+
+ do // check that the fifo has
+ { // enough free space
+ TempLong.Long = SPIReadRegisterDirect(ECAT_PRAM_WR_CMD,2);//
+ } //
+ while (TempLong.Byte[1] < (SEC_LONG_NUM_IN)); //
+
+ SCS_Low_macro // enable SPI chip select
+
+ SPI_TransferTx(COMM_SPI_WRITE); // SPI write command
+ SPI_TransferTx(0x00); // address of the write fifo
+ SPI_TransferTx(0x20); // MsByte first
+
+ for (i=0; i< (SEC_BYTE_NUM_ROUND_IN - 1); i++) // transfer loop for the remaining
+ { // bytes
+ SPI_TransferTx (BufferIn.Byte[i+64]); // we transfer the second part of
+ } // the buffer, so offset by 64
+ //
+ SPI_TransferTxLast (BufferIn.Byte[i+64]); // one last byte
+
+ SCS_High_macro // disable SPI chip select
+ #endif
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/EasyCAT.h Tue Sep 12 17:09:43 2017 +0000
@@ -0,0 +1,424 @@
+//********************************************************************************************
+// *
+// AB&T Tecnologie Informatiche - Ivrea Italy *
+// http://www.bausano.net *
+// https://www.ethercat.org/en/products/791FFAA126AD43859920EA64384AD4FD.htm *
+// *
+//********************************************************************************************
+// *
+// This software is distributed as an example, in the hope that it could be useful, *
+// WITHOUT ANY WARRANTY, even the implied warranty of FITNESS FOR A PARTICULAR PURPOSE *
+// *
+//********************************************************************************************
+
+
+//----- EasyCAT library for mbed boards 170912 ----------------------------------------------
+//----- Derived from the AB&T EasyCAT Arduino shield library V 1.5 --------------------------
+
+//----- Tested with the STM32 NUCLEO-F767ZI board -------------------------------------------
+
+
+
+
+#ifndef EasyCAT_H
+#define EasyCAT_H
+
+
+
+
+//****** PDO configuration parameters ********************************************************
+
+// Here we can define how many I/O bytes our EasyCAT can exchange
+
+// We can use STANDARD MODE or CUSTOM MODE
+// !!! Warning: CUSTOM MODE is recommended only for advanced users !!!
+
+// In STANDARD MODE the EasyCAT exchanges a fixed number of bytes
+// in input and in output
+// The number of bytes in input are equal to the number of bytes in output
+// Valid values are 16, 32, 64, 128
+//
+// The configuration EEPROM on board of the EasyCAT must be
+// loaded with the corresponding bin file, provided by AB&T
+//
+// The EasyCAT is shipped configured for 32+32 bytes I.E. with
+// the "EasyCAT_32_32.bin" file loaded into the configuration EEPROM
+
+
+//-- BYTE_NUM ----------- Byte exchanged ------ Config EEPROM file
+
+//#define BYTE_NUM 16 // 16 + 16 EasyCAT_16_16.bin
+#define BYTE_NUM 32 // 32 + 32 EasyCAT_32_32.bin
+//#define BYTE_NUM 64 // 64 + 64 EasyCAT_64_64.bin
+//#define BYTE_NUM 128 // 128 + 128 EasyCAT_128_128.bin
+
+
+
+// In CUSTOM MODE, recommended only for advanced users, the EasyCAT exchanges
+// a configurable number of bytes, between 0 and 128, in input and in output
+// The number of bytes in input and in output can be different
+//
+// The configuration EEPROM on board of the EasyCAT must be
+// loaded with a suitable bin file, provided by the user
+// or with the "EasyCAT_configurable.bin" file provided by AB&T
+
+// Comment all the above BYTE_NUM #define for the STANDARD MODE
+// and define here the custom number of exchanged bytes
+
+ //----- CUSTOM_MODE example -------
+ //
+//#define CUST_BYTE_NUM_OUT 49 // total number of bytes in output
+//#define CUST_BYTE_NUM_IN 17 // total number of bytes in input
+
+// We can also customize names and data types for the PDOs
+// see the example in this file (look for tag "Custom data types example")
+
+//*************************************************************************************
+
+
+
+//-- the preprocessor calculates the parameters necessary to transfer out data ---
+
+ // define TOT_BYTE_NUM_OUT as the total
+ // number of byte you need to
+ // transfer in output (between 0 and 128)
+ // this must match your ESI XML
+
+#ifdef BYTE_NUM
+ #define TOT_BYTE_NUM_OUT BYTE_NUM // bytes in output
+#else
+ #define TOT_BYTE_NUM_OUT CUST_BYTE_NUM_OUT // any number between 0 and 128
+#endif
+
+
+#if ((TOT_BYTE_NUM_OUT & 0x03) != 0x00) // number of bytes in output
+ #define TOT_BYTE_NUM_ROUND_OUT ((TOT_BYTE_NUM_OUT | 0x03) + 1)
+#else // rounded to 4 (long)
+ #define TOT_BYTE_NUM_ROUND_OUT TOT_BYTE_NUM_OUT //
+#endif //
+
+#if TOT_BYTE_NUM_OUT > 64 // if we have more then 64 bytes
+ // we have to split the transfer in two
+
+ #define SEC_BYTE_NUM_OUT (TOT_BYTE_NUM_OUT - 64) // number of bytes of the second transfer
+
+ #if ((SEC_BYTE_NUM_OUT & 0x03) != 0x00) // number of bytes of the second transfer
+ #define SEC_BYTE_NUM_ROUND_OUT ((SEC_BYTE_NUM_OUT | 0x03) + 1)
+ #else // rounded to 4 (long)
+ #define SEC_BYTE_NUM_ROUND_OUT SEC_BYTE_NUM_OUT//
+ #endif //
+
+ #define SEC_LONG_NUM_OUT SEC_BYTE_NUM_ROUND_OUT/4// number of long of the second transfer
+
+ #define FST_BYTE_NUM_OUT 64 // number of bytes of the first transfer
+ #define FST_BYTE_NUM_ROUND_OUT 64 // number of bytes of the first transfer
+ // rounded to 4 (long)
+ #define FST_LONG_NUM_OUT 16 // number of long of the second transfer
+
+
+#else // if we have 64 bytes max we tranfert
+ // them in just one round
+
+ #define FST_BYTE_NUM_OUT TOT_BYTE_NUM_OUT // number of bytes of the first and only transfer
+
+ #if ((FST_BYTE_NUM_OUT & 0x03) != 0x00) // number of bytes of the first and only transfer
+ #define FST_BYTE_NUM_ROUND_OUT ((FST_BYTE_NUM_OUT | 0x03) + 1)
+ #else // rounded to 4 (long)
+ #define FST_BYTE_NUM_ROUND_OUT FST_BYTE_NUM_OUT
+ #endif
+
+ #define FST_LONG_NUM_OUT FST_BYTE_NUM_ROUND_OUT/4// number of long of the first and only transfer
+
+ #define SEC_BYTE_NUM_OUT 0 // we don't use the second round
+ #define SEC_BYTE_NUM_ROUND_OUT 0 //
+ #define SEC_LONG_NUM_OUT 0 //
+
+#endif
+
+
+//-- the preprocessor calculates the parameters necessary to transfer in data ---
+
+ // define TOT_BYTE_NUM_IN the total
+ // number of byte you need to
+ // transfer in input (between 0 and 128)
+
+#ifdef BYTE_NUM
+ #define TOT_BYTE_NUM_IN BYTE_NUM // bytes in input
+#else
+ #define TOT_BYTE_NUM_IN CUST_BYTE_NUM_IN // any number between 0 and 128
+#endif
+
+
+#if ((TOT_BYTE_NUM_IN & 0x03) != 0x00) // number of bytes in output
+ #define TOT_BYTE_NUM_ROUND_IN ((TOT_BYTE_NUM_IN | 0x03) + 1)
+#else // rounded to 4 (long)
+ #define TOT_BYTE_NUM_ROUND_IN TOT_BYTE_NUM_IN //
+#endif //
+
+#if TOT_BYTE_NUM_IN > 64 // if we have more then 64 bytes
+ // we have to split the transfer in two
+
+ #define SEC_BYTE_NUM_IN (TOT_BYTE_NUM_IN - 64) // number of bytes of the second transfer
+
+ #if ((SEC_BYTE_NUM_IN & 0x03) != 0x00) // number of bytes of the second transfer
+ #define SEC_BYTE_NUM_ROUND_IN ((SEC_BYTE_NUM_IN | 0x03) + 1)
+ #else // rounded to 4 (long)
+ #define SEC_BYTE_NUM_ROUND_IN SEC_BYTE_NUM_IN //
+ #endif //
+
+ #define SEC_LONG_NUM_IN SEC_BYTE_NUM_ROUND_IN/4 // number of long of the second transfer
+
+ #define FST_BYTE_NUM_IN 64 // number of bytes of the first transfer
+ #define FST_BYTE_NUM_ROUND_IN 64 // number of bytes of the first transfer
+ // rounded to 4 (long)
+ #define FST_LONG_NUM_IN 16 // number of long of the second transfer
+
+
+#else // if we have 64 bytes max we tranfert
+ // them in just one round
+
+ #define FST_BYTE_NUM_IN TOT_BYTE_NUM_IN // number of bytes of the first and only transfer
+
+ #if ((FST_BYTE_NUM_IN & 0x03) != 0x00) // number of bytes of the first and only transfer
+ #define FST_BYTE_NUM_ROUND_IN ((FST_BYTE_NUM_IN | 0x03) + 1)
+ #else // rounded to 4 (long)
+ #define FST_BYTE_NUM_ROUND_IN FST_BYTE_NUM_IN
+ #endif
+
+ #define FST_LONG_NUM_IN FST_BYTE_NUM_ROUND_IN/4 // number of long of the first and only transfer
+
+ #define SEC_BYTE_NUM_IN 0 // we don't use the second round
+ #define SEC_BYTE_NUM_ROUND_IN 0 //
+ #define SEC_LONG_NUM_IN 0 //
+
+#endif
+
+
+//---------------------------------------------------------------------------------
+
+//----------------- sanity check -------------------------------------------------------
+
+
+#ifdef BYTE_NUM // STANDARD MODE and CUSTOM MODE
+ // cannot be defined at the same time
+ #ifdef CUST_BYTE_NUM_OUT
+ #error "BYTE_NUM and CUST_BYTE_NUM_OUT cannot be defined at the same time !!!!"
+ #error "define them correctly in file EasyCAT.h"
+ #endif
+
+ #ifdef CUST_BYTE_NUM_IN
+ #error "BYTE_NUM and CUST_BYTE_NUM_IN cannot be defined at the same time !!!!"
+ #error "define them correctly in file EasyCAT.h"
+ #endif
+#endif
+
+#ifdef BYTE_NUM //--- for BYTE_NUM we accept only 16 32 64 128 --
+
+ #if ((BYTE_NUM !=16) && (BYTE_NUM !=32) && (BYTE_NUM !=64) && (BYTE_NUM !=128))
+ #error "BYTE_NUM must be 16, 32, 64 or 128 !!! define it correctly in file EasyCAT.h"
+ #endif
+
+#else
+ //--- CUST_BYTE_NUM_OUT and CUST_BYTE_NUM_IN --------
+ // must be max 128
+ #if (CUST_BYTE_NUM_OUT > 128)
+ #error "CUST_BYTE_NUM_OUT must be max 128 !!! define it correctly in file EasyCAT.h"
+ #endif
+
+ #if (CUST_BYTE_NUM_IN > 128)
+ #error "CUST_BYTE_NUM_IN must be max 128 !!! define it correctly in file EasyCAT.h"
+ #endif
+
+#endif
+
+
+//*************************************************************************************************
+
+
+
+
+//---- LAN9252 registers --------------------------------------------------------------------------
+
+ //---- access to EtherCAT registers -------------------
+
+#define ECAT_CSR_DATA 0x0300 // EtherCAT CSR Interface Data Register
+#define ECAT_CSR_CMD 0x0304 // EtherCAT CSR Interface Command Register
+
+
+ //---- access to EtherCAT process RAM -----------------
+
+#define ECAT_PRAM_RD_ADDR_LEN 0x0308 // EtherCAT Process RAM Read Address and Length Register
+#define ECAT_PRAM_RD_CMD 0x030C // EtherCAT Process RAM Read Command Register
+#define ECAT_PRAM_WR_ADDR_LEN 0x0310 // EtherCAT Process RAM Write Address and Length Register
+#define ECAT_PRAM_WR_CMD 0x0314 // EtherCAT Process RAM Write Command Register
+
+#define ECAT_PRAM_RD_DATA 0x0000 // EtherCAT Process RAM Read Data FIFO
+#define ECAT_PRAM_WR_DATA 0x0020 // EtherCAT Process RAM Write Data FIFO
+
+ //---- EtherCAT registers -----------------------------
+
+#define AL_STATUS 0x0130 // AL status
+#define WDOG_STATUS 0x0440 // watch dog status
+#define AL_EVENT_MASK 0x0204 // AL event interrupt mask
+
+ //---- LAN9252 registers ------------------------------
+
+#define HW_CFG 0x0074 // hardware configuration register
+#define BYTE_TEST 0x0064 // byte order test register
+#define RESET_CTL 0x01F8 // reset register
+#define ID_REV 0x0050 // chip ID and revision
+#define IRQ_CFG 0x0054 // interrupt configuration
+#define INT_EN 0x005C // interrupt enable
+
+
+//---- LAN9252 flags ------------------------------------------------------------------------------
+
+#define ECAT_CSR_BUSY 0x80
+
+#define PRAM_ABORT 0x40000000
+
+#define PRAM_BUSY 0x80
+
+#define PRAM_AVAIL 0x01
+
+#define READY 0x08
+
+#define DIGITAL_RST 0x00000001
+
+
+//---- EtherCAT flags -----------------------------------------------------------------------------
+
+ // EtherCAT state machine
+
+#define ESM_INIT 0x01 // init
+#define ESM_PREOP 0x02 // pre-operational
+#define ESM_BOOT 0x03 // bootstrap
+#define ESM_SAFEOP 0x04 // safe-operational
+#define ESM_OP 0x08 // operational
+
+
+//--- ESC commands --------------------------------------------------------------------------------
+
+#define ESC_WRITE 0x80
+#define ESC_READ 0xC0
+
+
+//---- SPI ----------------------------------------------------------------------------------------
+
+#define COMM_SPI_READ 0x03
+#define COMM_SPI_WRITE 0x02
+
+#define DUMMY_BYTE 0xFF
+
+
+
+//---- typedef ------------------------------------------------------------------------------------
+
+typedef union
+{
+ unsigned short Word;
+ unsigned char Byte[2];
+} UWORD;
+
+typedef union
+{
+ unsigned long Long;
+ unsigned short Word[2];
+ unsigned char Byte[4];
+} ULONG;
+
+
+typedef union //-- output buffer -----------------
+{ //
+ uint8_t Byte [TOT_BYTE_NUM_ROUND_OUT]; //
+
+ #if CUST_BYTE_NUM_OUT > 0 //----- Custom data types example -----
+/* //
+ struct // Here we can define our custom
+ { // data types and names for the outputs
+ //
+ uint8_t Control; // The total number of bytes declared
+ float PreZone1; // in this structure must be equal
+ float CommZone1; // to the value assigned to CUST_BYTE_NUM_OUT
+ float RampZone1; //
+ float PreZone2; // In this case 1+ 4+4+4+ 4+4+4+ 4+4+4+ 4+4+4 = 49
+ float CommZone2; //
+ float RampZone2; //
+ float PreZone3; //
+ float CommZone3; //
+ float RampZone3; //
+ float PreZone4; //
+ float CommZone4; //
+ float RampZone4; //
+ }Cust; //
+*/ //
+ #endif //
+
+} PROCBUFFER_OUT; //
+
+
+typedef union //-- input buffer ------------------
+{ //
+ uint8_t Byte [TOT_BYTE_NUM_ROUND_IN]; //
+
+ #if CUST_BYTE_NUM_IN > 0 //----- Custom data types example ------
+/* //
+ struct // Here we can define our custom
+ { // data types and names for the inputs
+ //
+ uint8_t Status; // The total number of bytes declared
+ float TempZone1; // in this structure must be equal
+ float TempZone2; // to the value assigned to CUST_BYTE_NUM_IN
+ float TempZone3; //
+ float TempZone4; // In this case 1+ 4+4+4+4 = 17
+ }Cust; //
+*/ //
+ #endif //
+
+} PROCBUFFER_IN; //
+
+
+typedef enum
+{
+ ASYNC,
+ DC_SYNC,
+ SM_SYNC
+}SyncMode;
+
+
+
+//-------------------------------------------------------------------------------------------------
+
+class EasyCAT
+{
+ public:
+ EasyCAT(); // default constructor
+ EasyCAT(PinName SCS);
+ EasyCAT(SyncMode Sync);
+ EasyCAT(PinName SCS, SyncMode Sync);
+
+
+ unsigned char MainTask(); // EtherCAT main task
+ // must be called cyclically by the application
+
+ bool Init(); // EasyCAT board initialization
+
+ PROCBUFFER_OUT BufferOut; // output process data buffer
+ PROCBUFFER_IN BufferIn; // input process data buffer
+
+
+ private:
+ void SPIWriteRegisterDirect (unsigned short Address, unsigned long DataOut);
+ unsigned long SPIReadRegisterDirect (unsigned short Address, unsigned char Len);
+
+ void SPIWriteRegisterIndirect (unsigned long DataOut, unsigned short Address, unsigned char Len);
+ unsigned long SPIReadRegisterIndirect (unsigned short Address, unsigned char Len);
+
+ void SPIReadProcRamFifo();
+ void SPIWriteProcRamFifo();
+
+ PinName SCS_;
+ SyncMode Sync_;
+};
+
+#endif