Hi Everybody,
I am currently working on a project, where I have to used EtherCAT communication. The main focus of the project isn't the communication, and microcontroller programming ins't my best skill.
I have a SPI ethercat controller from Beckhoff. Beckhoff also provided the code, but it is for a PIC24, and I want to migrate it in order to be able to use it in the F28069 controlstick.
Any help will be really apreaciated, and while I can understand most of the code, i have some problems. I read about all the registers, and I can follow each line, but PIC and c2000 are a little different when it comes to the configuration. any help will be really appreciated. especially with the configuration (what should I leave here, and what should I move in the "main.c" and initialize as I learned from the examples/tutorials).
I will post here the hardware related code and I will attach an archive with the entire project + part of the schematic.
[code]
/**
\defgroup el9800hw el9800hw.c: EL9800 hardware abstraction
\brief Hardware access implementation for EL9800 onboard PIC18/PIC24 connected via SPI to ESC\n
\brief Changes to version V5.0:
\brief V5.01 HW1: Invalid ESC access function was used
\brief Changes to version V4.40:
\brief V5.0 ESC4: Save SM disable/Enable. Operation may be pending due to frame handling.
\brief Changes to version V4.30:\n
\brief V4.40 : File renamed from spihw.c to el9800hw.c
\brief Changes to version V4.20:\n
\brief V4.30 ESM: if mailbox Syncmanger is disabled and bMbxRunning is true the SyncManger settings need to be revalidate
\brief V4.30 EL9800: EL9800_x hardware initialization is moved to el9800.c
\brief V4.30 SYNC: change synchronisation control function. Add usage of 0x1C32:12 [SM missed counter].
\brief Calculate bus cycle time (0x1C32:02 ; 0x1C33:02) CalcSMCycleTime()
\brief V4.30 PDO: rename PDO specific functions (COE_xxMapping -> PDO_xxMapping and COE_Application -> ECAT_Application)
\brief V4.30 ESC: change requested address in GetInterruptRegister() to prevent acknowledge events.
\brief (e.g. reading an SM config register acknowledge SM change event)
\brief GENERIC: renamed several variables to identify used SPI if multiple interfaces are available
\brief V4.20 MBX 1: Add Mailbox queue support
\brief V4.20 SPI 1: include SPI RxBuffer dummy read
\brief V4.20 DC 1: Add Sync0 Handling
\brief V4.20 PIC24: Add EL9800_4 (PIC24) required source code
\brief V4.08 ECAT 3: The AlStatusCode is changed as parameter of the function AL_ControlInd\n
\brief Changes to version V4.02:\n
\brief V4.03 SPI 1: In ISR_GetInterruptRegister the NOP-command should be used.\n
\brief Changes to version V4.01:\n
\brief V4.02 SPI 1: In HW_OutputMapping the variable u16OldTimer shall not be set,
\brief otherwise the watchdog might exceed too early.\n
\brief Changes to version V4.00:\n
\brief V4.01 SPI 1: DI and DO were changed (DI is now an input for the uC, DO is now an output for the uC)\n
\brief V4.01 SPI 2: The SPI has to operate with Late-Sample = FALSE on the Eva-Board\n
\brief Changes to version V3.20:\n
\brief V4.00 ECAT 1: The handling of the Sync Manager Parameter was included according to
\brief the EtherCAT Guidelines and Protocol Enhancements Specification\n
\brief V4.00 APPL 1: The watchdog checking should be done by a microcontroller
\brief timer because the watchdog trigger of the ESC will be reset too
\brief if only a part of the sync manager data is written\n
\brief V4.00 APPL 4: The EEPROM access through the ESC is added\n
\version 5.01
*/
//---------------------------------------------------------------------------------------
/**
\ingroup el9800hw
\file el9800hw.c
\brief Implementation.
*/
//---------------------------------------------------------------------------------------
/**
\addtogroup el9800hw
@{
*/
//---------------------------------------------------------------------------------------
/*--------------------------------------------------------------------------------------
------
------ Includes
------
--------------------------------------------------------------------------------------*/
#include "ecat_def.h"
#define _EL9800HW_ 1
#include "el9800hw.h"
#undef _EL9800HW_
#define _EL9800HW_ 0
/*Slave Stack Code Tool :(#if MAILBOX_SUPPORTED) lines 71 to 73 deleted*/
#include "ecatslv.h"
#include "ecatappl.h"
/** @} */
/*--------------------------------------------------------------------------------------
------
------ internal Types and Defines
------
--------------------------------------------------------------------------------------*/
typedef union
{
unsigned short Word;
unsigned char Byte[2];
} UBYTETOWORD;
typedef union
{
UINT8 Byte[2];
UINT16 Word;
}
UALEVENT;
/*-----------------------------------------------------------------------------------------
------
------ SPI defines/macros
------
-----------------------------------------------------------------------------------------*/
#define SPI1_SEL _LATB2
#define SPI1_IF _SPI1IF
#define SPI1_BUF SPI1BUF
#define SPI1_CON1 SPI1CON1
#define SPI1_STAT SPI1STAT
#define WAIT_SPI_IF while( !SPI1_IF );
#define SELECT_SPI {(SPI1_SEL) = (SPI_ACTIVE);}
#define DESELECT_SPI {(SPI1_SEL) = (SPI_DEACTIVE);}
#define INIT_SSPIF {(SPI1_IF)=0;}
#define SPI1_STAT_VALUE 0x8000
#define SPI1_CON1_VALUE 0x027E
#define SPI1_CON1_VALUE_16BIT 0x047E
#define SPI_DEACTIVE 1
#define SPI_ACTIVE 0
/*Slave Stack Code Tool :(#elif _PIC18) lines 121 to 145 deleted*/
/*-----------------------------------------------------------------------------------------
------
------ Global Interrupt setting
------
-----------------------------------------------------------------------------------------*/
#define DISABLE_GLOBAL_INT SET_CPU_IPL(4) //set CPU priority to level 4 (disable interrupt level 1 - 4)
#define ENABLE_GLOBAL_INT SET_CPU_IPL(0)
#define DISABLE_AL_EVENT_INT DISABLE_GLOBAL_INT
#define ENABLE_AL_EVENT_INT ENABLE_GLOBAL_INT
/*Slave Stack Code Tool :(#elif _PIC18) lines 160 to 167 deleted*/
/*-----------------------------------------------------------------------------------------
------
------ ESC Interrupt
------
-----------------------------------------------------------------------------------------*/
#define INIT_ESC_INT {(_INT1EP) = 1;(_INT1IP) = 1;} //_INT1EP = 1: negative edge ; _INT1IP = 1; //highest priority
#define ESC_INT_REQ (_INT1IF) //ESC Interrupt (INT1) state
#define INT_EL (_RD8) //ESC Interrupt input port
#define EscIsr (_INT1Interrupt) // primary interrupt vector name
#define ACK_ESC_INT {(ESC_INT_REQ)=0;}
/*Slave Stack Code Tool :(#elif _PIC18) lines 184 to 192 deleted*/
/*-----------------------------------------------------------------------------------------
------
------ SYNC0 Interrupt
------
-----------------------------------------------------------------------------------------*/
#define INIT_SYNC0_INT {(_INT3EP) = 1;(_INT3IP) = 1;}//_INT3EP = 1: negative edge ; _INT3IP = 1; //highest priority
#define SYNC0_INT_REQ (_INT3IF) //ESC Interrupt (INT1) state
#define INT_SYNC0 (_RD10) //ESC Interrupt input port
#define Sync0Isr (_INT3Interrupt) // primary interrupt vector name
#define DISABLE_SYNC0_INT {(_INT3IE)=0;}//disable interrupt source INT3
#define ENABLE_SYNC0_INT {(_INT3IE) = 1;} //enable interrupt source INT3
#define ACK_SYNC0_INT {(SYNC0_INT_REQ) = 0;}
#define SET_SYNC0_INT {(SYNC0_INT_REQ) = 1;}
#define SYNC0_INT_PORT_IS_ACTIVE {(INT_EL) == 0;}
/*-----------------------------------------------------------------------------------------
------
------ Hardware timer
------
-----------------------------------------------------------------------------------------*/
/*Slave Stack Code Tool :(#if ECAT_TIMER_INT) lines 224 to 242 deleted*/
#define INIT_ECAT_TIMER {(PR7) = 2000;/*set period*/ \
(T7CONbits.TCKPS) = 2;/*set prescaler to 1:8*/ \
(TMR7) = 0;/*clear timer register*/}
#define STOP_ECAT_TIMER {(T7CONbits.TON) = 0; /*disable timer*/}
#define START_ECAT_TIMER {(T7CONbits.TON) = 1; /*enable timer*/}
/*Slave Stack Code Tool :(#elif _PIC18) lines 254 to 268 deleted*/
/*-----------------------------------------------------------------------------------------
------
------ Configuration Bits
------
-----------------------------------------------------------------------------------------*/
/*Slave Stack Code Tool :(#if _PIC18) lines 275 to 279 deleted*/
_FGS(GCP_OFF);
_FOSCSEL(FNOSC_PRI & IESO_OFF);
_FOSC(FCKSM_CSECMD & OSCIOFNC_ON & POSCMD_HS);
_FWDT(FWDTEN_OFF);
_FPOR(FPWRT_PWR1);
/*Slave Stack Code Tool :(#if EXT_DEBUGER_INTERFACE) lines 285 to 287 deleted*/
_FICD(ICS_PGD3 & JTAGEN_OFF);
/*-----------------------------------------------------------------------------------------
------
------ LED defines
------
-----------------------------------------------------------------------------------------*/
// EtherCAT Status LEDs -> StateMachine
#define LED_ECATGREEN LATFbits.LATF1
#define LED_ECATRED LATFbits.LATF0
/*--------------------------------------------------------------------------------------
------
------ internal Variables
------
--------------------------------------------------------------------------------------*/
UALEVENT EscALEvent; //contains the content of the ALEvent register (0x220), this variable is updated on each Access to the Esc
UINT16 nAlEventMask; //current ALEventMask (content of register 0x204:0x205)
TSYNCMAN TmpSyncMan;
/*--------------------------------------------------------------------------------------
------
------ internal functions
------
--------------------------------------------------------------------------------------*/
/////////////////////////////////////////////////////////////////////////////////////////
/**
\brief The function operates a SPI access without addressing.
The first two bytes of an access to the EtherCAT ASIC always deliver the AL_Event register (0x220).
It will be saved in the global "EscALEvent"
*////////////////////////////////////////////////////////////////////////////////////////
static void GetInterruptRegister(void)
{
UINT8 EscMbxReadEcatCtrl;
DISABLE_AL_EVENT_INT;
/* select the SPI */
SELECT_SPI;
/* reset transmission flag */
SPI1_IF=0;
/* there have to be at least 15 ns after the SPI1_SEL signal was active (0) before
the transmission shall be started */
/* write to SPI1_BUF register starts the SPI access*/
SPI1_BUF = (UINT8) (0x0000 >> 5);
/* SPI is busy */
WAIT_SPI_IF
/* get first byte of AL Event register */
EscALEvent.Byte[0] = SPI1_BUF;
/* reset SPI interrupt flag */
SPI1_IF = 0;
/* write to SPI1_BUF register starts the SPI access
read the sm mailbox read ecatenable byte */
SPI1_BUF = (UINT8) (((0x0000 & 0x1F) << 3) | ESC_RD);
/* write to SPI1_BUF register starts the SPI access */
WAIT_SPI_IF
/* get first byte of AL Event register */
EscALEvent.Byte[1] = SPI1_BUF;
/* reset SPI interrupt flag */
SPI1_IF = 0;
/* if the SPI transmission rate is higher than 15 MBaud, the Busy detection shall be
done here */
/* write to SPI1_BUF register starts the SPI access
read the sm mailbox read ecatenable byte (last byte) */
SPI1_BUF = 0xFF;
/* write to SPI1_BUF register starts the SPI access */
WAIT_SPI_IF
/* get first byte of AL Event register */
EscMbxReadEcatCtrl = SPI1_BUF;
/* reset SPI interrupt flag */
SPI1_IF = 0;
/* there has to be at least 15 ns + CLK/2 after the transmission is finished
before the SPI1_SEL signal shall be 1 */
DESELECT_SPI;
ENABLE_AL_EVENT_INT;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\brief The function operates a SPI access without addressing.
Shall be implemented if interrupts are supported else this function is equal to "GetInterruptRegsiter()"
The first two bytes of an access to the EtherCAT ASIC always deliver the AL_Event register (0x220).
It will be saved in the global "EscALEvent"
*////////////////////////////////////////////////////////////////////////////////////////
/*Slave Stack Code Tool :(#if !INTERRUPTS_SUPPORTED) lines 394 to 396 deleted*/
static void ISR_GetInterruptRegister(void)
{
/* SPI should be deactivated to interrupt a possible transmission */
DESELECT_SPI;
/* select the SPI */
SELECT_SPI;
/* reset transmission flag */
SPI1_IF=0;
/* there have to be at least 15 ns after the SPI1_SEL signal was active (0) before
the transmission shall be started */
/* write to SPI1_BUF register starts the SPI access,
read the sm mailbox read ecatenable byte
(has to be synchronous to the al event flags) */
SPI1_BUF = 0;
/* SPI is busy */
WAIT_SPI_IF
/* get first byte of AL Event register */
EscALEvent.Byte[0] = SPI1_BUF;
/* reset SPI interrupt flag */
SPI1_IF = 0;
/* write to SPI1_BUF register starts the SPI access
send NOP command */
SPI1_BUF = 0;
/* write to SPI1_BUF register starts the SPI access */
WAIT_SPI_IF
/* get first byte of AL Event register */
EscALEvent.Byte[1] = SPI1_BUF;
/* reset SPI interrupt flag */
SPI1_IF = 0;
/* if the SPI transmission rate is higher than 15 MBaud, the Busy detection shall be
done here */
DESELECT_SPI;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param Address EtherCAT ASIC address ( upper limit is 0x1FFF ) for access.
\param Command ESC_WR performs a write access; ESC_RD performs a read access.
\brief The function addresses the EtherCAT ASIC via SPI for a following SPI access.
*////////////////////////////////////////////////////////////////////////////////////////
static void AddressingEsc( UINT16 Address, UINT8 Command )
{
UBYTETOWORD tmp;
VARVOLATILE UINT8 dummy;
tmp.Word = ( Address << 3 ) | Command;
/* select the SPI */
SELECT_SPI;
/* reset transmission flag */
SPI1_IF=0;
dummy = SPI1_BUF;
/* there have to be at least 15 ns after the SPI1_SEL signal was active (0) before
the transmission shall be started */
/* send the first address/command byte to the ESC */
SPI1_BUF = tmp.Byte[1];
/* wait until the transmission of the byte is finished */
WAIT_SPI_IF
/* get first byte of AL Event register */
EscALEvent.Byte[0] = SPI1_BUF;
/* reset transmission flag */
SPI1_IF=0;
dummy = SPI1_BUF;
/* send the second address/command byte to the ESC */
SPI1_BUF = tmp.Byte[0];
/* wait until the transmission of the byte is finished */
WAIT_SPI_IF
/* get second byte of AL Event register */
EscALEvent.Byte[1] = SPI1_BUF;
/* reset transmission flag */
SPI1_IF = 0;
/* if the SPI transmission rate is higher than 15 MBaud, the Busy detection shall be
done here */
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param Address EtherCAT ASIC address ( upper limit is 0x1FFF ) for access.
\param Command ESC_WR performs a write access; ESC_RD performs a read access.
\brief The function addresses the EtherCAT ASIC via SPI for a following SPI access.
Shall be implemented if interrupts are supported else this function is equal to "AddressingEsc()"
*////////////////////////////////////////////////////////////////////////////////////////
/*Slave Stack Code Tool :(#if !INTERRUPTS_SUPPORTED) lines 494 to 496 deleted*/
static void ISR_AddressingEsc( UINT16 Address, UINT8 Command )
{
VARVOLATILE UINT8 dummy;
UBYTETOWORD tmp;
tmp.Word = ( Address << 3 ) | Command;
/* select the SPI */
SELECT_SPI;
/* reset transmission flag */
SPI1_IF=0;
/* there have to be at least 15 ns after the SPI1_SEL signal was active (0) before
the transmission shall be started */
/* send the first address/command byte to the ESC */
SPI1_BUF = tmp.Byte[1];
/* wait until the transmission of the byte is finished */
WAIT_SPI_IF
dummy = SPI1_BUF;
/* reset transmission flag */
SPI1_IF=0;
/* send the second address/command byte to the ESC */
SPI1_BUF = tmp.Byte[0];
/* wait until the transmission of the byte is finished */
WAIT_SPI_IF
dummy = SPI1_BUF;
/* reset transmission flag */
SPI1_IF = 0;
/* if the SPI transmission rate is higher than 15 MBaud, the Busy detection shall be
done here */
}
/** @} */
/*--------------------------------------------------------------------------------------
------
------ exported hardware access functions
------
--------------------------------------------------------------------------------------*/
/////////////////////////////////////////////////////////////////////////////////////////
/**
\return 0 if initialization was successful
\brief This function intialize the Process Data Interface (PDI) and the host controller.
*////////////////////////////////////////////////////////////////////////////////////////
UINT8 HW_Init(void)
{
UINT16 intMask;
/*Slave Stack Code Tool :(#if _PIC18) lines 550 to 552 deleted*/
PORT_CFG;
//Setup analog input
AD1PCFGLbits.PCFG3 = 0x0; //set RB3 to analog input
AD1CON1 = 0x0404; // ASAM bit = 1 implies sampling ..
AD1CHS0= 0x0003; // Connect RB3/AN3 as CH0 input ..
AD1CSSL = 0;
AD1CON3 = 0x0002; // Sample time manual, Tad = internal 2 Tcy
AD1CON2 = 0;
AD1CON1bits.ADON = 1; // turn ADC ON
//configure clock
// Im Referenzdesign lauft das ganze mit 10Mhz extere Oszillatorclock.
// Fcy = (1/2) * ((10000000*32)/(2*2)) = 40 MIPS
// extern 10Mhz / 2 (PLLPRE) = 5Mhz
// 5 Mhz * 32 (PLLFBD) = 160Mhz (VCO)
// 160Mhz / 2 (PLLPOST) = 80Mhz (FCY) -> entspricht 40 MIPS
PLLFBD = 0x1E; // 30, da aber 0 == 2 entspricht dieser Wert 32
CLKDIVbits.PLLPOST = 0; // 0 entspricht 2, Fcy == 80 MHz The resultant device operating speed is 80/2 = 40 MIPS
CLKDIVbits.PLLPRE = 0; // CLKDIVbits.PRESCLR = 0; 0 entspricht 2
//unlock OSCCON-Register High
//set Primary Oscillator with PLL
__builtin_write_OSCCONH(0x03);
//unlock OSCCON-Register Low
//start clockswitching
__builtin_write_OSCCONL(0x01);
//wait for clockswitch and ready PLL
while(OSCCONbits.COSC != 3);
while(OSCCONbits.LOCK != 1);
/*Slave Stack Code Tool :(#elif _PIC18) lines 589 to 595 deleted*/
/* initialize the SPI registers for the ESC SPI */
SPI1_CON1 = SPI1_CON1_VALUE;
SPI1_STAT = SPI1_STAT_VALUE;
do
{
intMask = 0x93;
HW_EscWriteWord(intMask, ESC_AL_EVENTMASK_OFFSET);
intMask = 0;
HW_EscReadWord(intMask, ESC_AL_EVENTMASK_OFFSET);
} while (intMask != 0x93);
INIT_ESC_INT
HW_ResetALEventMask(0);
ENABLE_ESC_INT();
INIT_SYNC0_INT
ENABLE_SYNC0_INT;
INIT_ECAT_TIMER;
START_ECAT_TIMER;
/* enable all interrupts */
ENABLE_GLOBAL_INT;
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\brief This function shall be implemented if hardware resources need to be release
when the sample application stops
*////////////////////////////////////////////////////////////////////////////////////////
void HW_Release(void)
{
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\return first two Bytes of ALEvent register (0x220)
\brief This function gets the current content of ALEvent register
*////////////////////////////////////////////////////////////////////////////////////////
UINT16 HW_GetALEventRegister(void)
{
GetInterruptRegister();
return EscALEvent.Word;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\return first two Bytes of ALEvent register (0x220)
\brief The SPI PDI requires an extra ESC read access functions from interrupts service routines.
The behaviour is equal to "HW_GetALEventRegister()"
*////////////////////////////////////////////////////////////////////////////////////////
/*Slave Stack Code Tool :(#if _PIC18 && AL_EVENT_ENABLED) lines 663 to 667 deleted*/
UINT16 HW_GetALEventRegister_Isr(void)
{
ISR_GetInterruptRegister();
return EscALEvent.Word;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param intMask interrupt mask (disabled interrupt shall be zero)
\brief This function makes an logical and with the AL Event Mask register (0x204)
*////////////////////////////////////////////////////////////////////////////////////////
void HW_ResetALEventMask(UINT16 intMask)
{
UINT16 mask;
HW_EscReadWord(mask, ESC_AL_EVENTMASK_OFFSET);
/*Slave Stack Code Tool :(#if BIG_ENDIAN_FORMAT) lines 688 to 690 deleted*/
mask &= intMask;
DISABLE_AL_EVENT_INT;
/*Slave Stack Code Tool :(#if BIG_ENDIAN_FORMAT) lines 695 to 697 deleted*/
HW_EscWriteWord(mask, ESC_AL_EVENTMASK_OFFSET);
HW_EscReadWord(nAlEventMask, ESC_AL_EVENTMASK_OFFSET);
ENABLE_AL_EVENT_INT;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param intMask interrupt mask (enabled interrupt shall be one)
\brief This function makes an logical or with the AL Event Mask register (0x204)
*////////////////////////////////////////////////////////////////////////////////////////
void HW_SetALEventMask(UINT16 intMask)
{
UINT16 mask;
HW_EscReadWord(mask, ESC_AL_EVENTMASK_OFFSET);
/*Slave Stack Code Tool :(#if BIG_ENDIAN_FORMAT) lines 717 to 719 deleted*/
mask |= intMask;
DISABLE_AL_EVENT_INT;
/*Slave Stack Code Tool :(#if BIG_ENDIAN_FORMAT) lines 724 to 726 deleted*/
HW_EscWriteWord(mask, ESC_AL_EVENTMASK_OFFSET);
HW_EscReadWord(nAlEventMask, ESC_AL_EVENTMASK_OFFSET);
ENABLE_AL_EVENT_INT;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param RunLed desired EtherCAT Run led state
\param ErrLed desired EtherCAT Error led state
\brief This function updates the EtherCAT run and error led
*////////////////////////////////////////////////////////////////////////////////////////
void HW_SetLed(UINT8 RunLed,UINT8 ErrLed)
{
LED_ECATGREEN = RunLed;
LED_ECATRED = ErrLed;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param pData Pointer to a byte array which holds data to write or saves read data.
\param Address EtherCAT ASIC address ( upper limit is 0x1FFF ) for access.
\param Len Access size in Bytes.
\brief This function operates the SPI read access to the EtherCAT ASIC.
*////////////////////////////////////////////////////////////////////////////////////////
void HW_EscRead( MEM_ADDR *pData, UINT16 Address, UINT16 Len )
{
/* HBu 24.01.06: if the SPI will be read by an interrupt routine too the
mailbox reading may be interrupted but an interrupted
reading will remain in a SPI transmission fault that will
reset the internal Sync Manager status. Therefore the reading
will be divided in 1-byte reads with disabled interrupt */
UINT16 i = Len;
UINT8 *pTmpData = (UINT8 *)pData;
/* loop for all bytes to be read */
while ( i-- > 0 )
{
/* the reading of data from the ESC can be interrupted by the
AL Event ISR, in that case the address has to be reinitialized,
in that case the status flag will indicate an error because
the reading operation was interrupted without setting the last
sent byte to 0xFF */
DISABLE_AL_EVENT_INT;
AddressingEsc( Address, ESC_RD );
/* when reading the last byte the DI pin shall be 1 */
SPI1_BUF = 0xFF;
/* wait until transmission finished */
WAIT_SPI_IF
/* get data byte */
*pTmpData++ = SPI1_BUF;
/* enable the ESC interrupt to get the AL Event ISR the chance to interrupt,
if the next byte is the last the transmission shall not be interrupted,
otherwise a sync manager could unlock the buffer, because the last was
read internally */
ENABLE_AL_EVENT_INT;
/* there has to be at least 15 ns + CLK/2 after the transmission is finished
before the SPI1_SEL signal shall be 1 */
DESELECT_SPI;
/* next address */
Address++;
/* reset transmission flag */
SPI1_IF = 0;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param pData Pointer to a byte array which holds data to write or saves read data.
\param Address EtherCAT ASIC address ( upper limit is 0x1FFF ) for access.
\param Len Access size in Bytes.
\brief The SPI PDI requires an extra ESC read access functions from interrupts service routines.
The behaviour is equal to "HW_EscRead()"
*////////////////////////////////////////////////////////////////////////////////////////
/*Slave Stack Code Tool :(#if _PIC18 && AL_EVENT_ENABLED) lines 815 to 819 deleted*/
void HW_EscReadIsr( MEM_ADDR *pData, UINT16 Address, UINT16 Len )
{
UINT16 i = Len;
UINT8 data = 0;
UINT8 *pTmpData = (UINT8 *)pData;
/* send the address and command to the ESC */
ISR_AddressingEsc( Address, ESC_RD );
/* loop for all bytes to be read */
while ( i-- > 0 )
{
if ( i == 0 )
{
/* when reading the last byte the DI pin shall be 1 */
data = 0xFF;
}
/* reset transmission flag */
SPI1_IF = 0;
/* start transmission */
SPI1_BUF = data;
/* wait until transmission finished */
WAIT_SPI_IF
/* get data byte */
*pTmpData++ = SPI1_BUF;
}
/* reset transmission flag */
SPI1_IF = 0;
/* there has to be at least 15 ns + CLK/2 after the transmission is finished
before the SPI1_SEL signal shall be 1 */
DESELECT_SPI;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param pData Pointer to a byte array which holds data to write or saves write data.
\param Address EtherCAT ASIC address ( upper limit is 0x1FFF ) for access.
\param Len Access size in Bytes.
\brief This function operates the SPI write access to the EtherCAT ASIC.
*////////////////////////////////////////////////////////////////////////////////////////
void HW_EscWrite( MEM_ADDR *pData, UINT16 Address, UINT16 Len )
{
UINT16 i = Len;
VARVOLATILE UINT8 dummy;
UINT8 *pTmpData = (UINT8 *)pData;
/* loop for all bytes to be written */
while ( i-- > 0 )
{
/* the reading of data from the ESC can be interrupted by the
AL Event ISR, so every byte will be written separate */
DISABLE_AL_EVENT_INT;
/* HBu 24.01.06: wrong parameter ESC_RD */
AddressingEsc( Address, ESC_WR );
/* start transmission */
SPI1_BUF = *pTmpData++;
/* wait until transmission finished */
WAIT_SPI_IF
/* enable the ESC interrupt to get the AL Event ISR the chance to interrupt */
/* SPI1_BUF must be read, otherwise the module will not transfer the next received data from SPIxSR to SPIxRXB.*/
dummy = SPI1_BUF;
ENABLE_AL_EVENT_INT;
/* there has to be at least 15 ns + CLK/2 after the transmission is finished
before the SPI1_SEL signal shall be 1 */
DESELECT_SPI;
/* next address */
Address++;
/* reset transmission flag */
SPI1_IF = 0;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param pData Pointer to a byte array which holds data to write or saves write data.
\param Address EtherCAT ASIC address ( upper limit is 0x1FFF ) for access.
\param Len Access size in Bytes.
\brief The SPI PDI requires an extra ESC write access functions from interrupts service routines.
The behaviour is equal to "HW_EscWrite()"
*////////////////////////////////////////////////////////////////////////////////////////
/*Slave Stack Code Tool :(#if _PIC18 && AL_EVENT_ENABLED) lines 913 to 917 deleted*/
void HW_EscWriteIsr( MEM_ADDR *pData, UINT16 Address, UINT16 Len )
{
UINT16 i = Len;
VARVOLATILE UINT16 dummy;
UINT8 *pTmpData = (UINT8 *)pData;
/* send the address and command to the ESC */
ISR_AddressingEsc( Address, ESC_WR );
/* loop for all bytes to be written */
while ( i-- > 0 )
{
/* reset transmission flag */
SPI1_IF = 0;
/* start transmission */
SPI1_BUF = *pTmpData;
/* wait until transmission finished */
WAIT_SPI_IF
/* increment data pointer */
dummy = SPI1_BUF;
pTmpData++;
}
/* reset transmission flag */
SPI1_IF = 0;
/* there has to be at least 15 ns + CLK/2 after the transmission is finished
before the SPI1_SEL signal shall be 1 */
DESELECT_SPI;
}
/*Slave Stack Code Tool :(#if BOOTSTRAPMODE_SUPPORTED) lines 951 to 960 deleted*/
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param channel Sync Manager channel
\brief This function disables a Sync Manager channel
*////////////////////////////////////////////////////////////////////////////////////////
void HW_DisableSyncManChannel(UINT8 channel)
{
UINT16 Offset;
/*Slave Stack Code Tool :(#if ESC_32BIT_ACCESS) lines 971 to 983 deleted*/
//The register 0x806 is only readable from PDI => writing 0 is valid
UINT16 smStatus = SM_SETTING_PDI_DISABLE;
Offset = (ESC_SYNCMAN_ACTIVE_OFFSET + (SIZEOF_SM_REGISTER*channel));
HW_EscWriteWord(smStatus,Offset);
/*wait until SyncManager is disabled*/
do
{
HW_EscReadWord(smStatus, Offset);
}while(!(smStatus & SM_SETTING_PDI_DISABLE));
/*Slave Stack Code Tool :( #else) lines 995 to 1006 deleted*/
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param channel Sync Manager channel
\brief This function enables a Sync Manager channel
*////////////////////////////////////////////////////////////////////////////////////////
void HW_EnableSyncManChannel(UINT8 channel)
{
UINT16 Offset;
/*Slave Stack Code Tool :(#if ESC_32BIT_ACCESS) lines 1018 to 1030 deleted*/
//The register 0x806 is only readable from PDI => writing 0 is valid
UINT16 smStatus = 0x0000;
Offset = (ESC_SYNCMAN_ACTIVE_OFFSET + (SIZEOF_SM_REGISTER*channel));
HW_EscWriteWord(smStatus,Offset);
/*wait until SyncManager is enabled*/
do
{
HW_EscReadWord(smStatus,Offset);
}while((smStatus & SM_SETTING_PDI_DISABLE));
/*Slave Stack Code Tool :( #else) lines 1042 to 1055 deleted*/
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param channel requested Sync Manger channel information
\return Pointer to the SYNC Manager channel description
\brief This function is called to read the SYNC Manager channel descriptions of the
process data SYNC Managers.
*////////////////////////////////////////////////////////////////////////////////////////
TSYNCMAN ESCMEM * HW_GetSyncMan(UINT8 channel)
{
// get a temporary structure of the Sync Manager:
HW_EscRead( (MEM_ADDR *) &TmpSyncMan, ESC_SYNCMAN_REG_OFFSET + (channel * SYNCMAN_REG_SIZE), SYNCMAN_REG_SIZE );
/*Slave Stack Code Tool :(#if BIG_ENDIAN_FORMAT) lines 1072 to 1075 deleted*/
return &TmpSyncMan;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\brief Interrupt service routine for the PDI interrupt from the EtherCAT Slave Controller
*////////////////////////////////////////////////////////////////////////////////////////
/*Slave Stack Code Tool :(#if _PIC18) lines 1087 to 1094 deleted*/
void __attribute__ ((__interrupt__, no_auto_psv)) EscIsr(void)
{
PDI_Isr();
/* reset the interrupt flag */
ACK_ESC_INT;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\brief Interrupt service routine for the interrupts from SYNC0
*////////////////////////////////////////////////////////////////////////////////////////
void __attribute__((__interrupt__, no_auto_psv)) Sync0Isr(void)
{
Sync0_Isr();
/* reset the interrupt flag */
ACK_SYNC0_INT;
}
/*Slave Stack Code Tool :(#if _PIC24 && ECAT_TIMER_INT) lines 1121 to 1129 deleted*/
/** @} */
[/code]
Thank you for your help.
Please let me know if you need any details. 6708.Src.zip