Merge pull request #13 from sittner/add-xmc4300-support

Add xmc4300 support, will add adoptions for XMC4800 later
pull/15/head
nakarlsson 2016-10-11 08:46:13 +02:00 committed by GitHub
commit 276c240ff4
16 changed files with 1677 additions and 0 deletions

View File

@ -0,0 +1,172 @@
TARGET = xmc4300-ecat-slave
DEVICE = XMC4300
VARIANT = F100x256
EC_SII = sii_eeprom.bin
XMC_LIB = ./XMC_Peripheral_Library
SOES_DIR = ../../soes
SRC = \
main.c \
objectlist.c \
soes.c \
$(SOES_DIR)/esc.c \
$(SOES_DIR)/esc_coe.c \
$(SOES_DIR)/esc_eep.c \
$(SOES_DIR)/hal/xmc4/esc_hw.c \
$(SOES_DIR)/hal/xmc4/esc_hw_eep.c \
$(XMC_LIB)/XMCLib/src/xmc_gpio.c \
$(XMC_LIB)/XMCLib/src/xmc4_gpio.c \
$(XMC_LIB)/XMCLib/src/xmc4_scu.c \
$(XMC_LIB)/XMCLib/src/xmc_ecat.c \
$(XMC_LIB)/XMCLib/src/xmc4_flash.c \
$(XMC_LIB)/XMCLib/src/xmc_fce.c \
$(XMC_LIB)/Newlib/syscalls.c \
$(XMC_LIB)/CMSIS/Infineon/XMC4300_series/Source/system_XMC4300.c \
ASRC = \
$(XMC_LIB)/CMSIS/Infineon/XMC4300_series/Source/GCC/startup_XMC4300.S \
BINS = \
$(EC_SII)\
LINKER_SCRIPT = $(XMC_LIB)/CMSIS/Infineon/XMC4300_series/Source/GCC/XMC4300x256.ld
# JLink options
JLINK_SPEED = 1000
JLINK_IFACE = swd
# Define all object files.
OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) $(BINS:.bin=.o)
# Define all listing files.
LST = $(ASRC:.S=.lst) $(SRC:.c=.lst)
# Define all dependency files.
DEP = $(ASRC:.S=.d) $(SRC:.c=.d)
CPPFLAGS = -D$(DEVICE)_$(VARIANT)
CPPFLAGS += -MMD -MP -MF $(@:.o=.d) -MT $(@)
CPPFLAGS += -I./$(XMC_LIB)/XMCLib/inc
CPPFLAGS += -I./$(XMC_LIB)/CMSIS/Include
CPPFLAGS += -I./$(XMC_LIB)/CMSIS/Infineon/$(DEVICE)_series/Include
CPPFLAGS += -I.
CPPFLAGS += -I$(SOES_DIR)
CPPFLAGS += -I$(SOES_DIR)/hal/xmc4
CPPFLAGS += -I$(SOES_DIR)/include/sys/gcc
ARCHFLAGS = -mfloat-abi=softfp -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mthumb
OBJFLAGS = -Wall -fmessage-length=0 -Wa,-adhlns=$(@:.o=.lst) $(ARCHFLAGS)
CFLAGS = $(CPPFLAGS) $(OBJFLAGS) -Os -ffunction-sections -fdata-sections -std=gnu99 -pipe
ASFLAGS = -x assembler-with-cpp $(CPPFLAGS) $(OBJFLAGS)
LDFLAGS = -T$(LINKER_SCRIPT) -nostartfiles -Xlinker --gc-sections
LDFLAGS += -specs=nano.specs -specs=nosys.specs
LDFLAGS += -Wl,-Map,$(TARGET).map
LDFLAGS += $(ARCHFLAGS)
# Define programs and commands.
SHELL = sh
REMOVE = rm -f
CC = arm-none-eabi-gcc
OBJCOPY = arm-none-eabi-objcopy
OBJDUMP = arm-none-eabi-objdump
SIZE = arm-none-eabi-size
JLINK = JLinkExe
# Define Messages
# English
MSG_SIZE = Size:
MSG_FLASH_FILE = Creating load file for Flash:
MSG_FLASH = Programming target flash memory:
MSG_FLASH_ERASE = Erasing target flash memory:
MSG_EXTENDED_LISTING = Creating Extended Listing:
MSG_LINKING = Linking:
MSG_COMPILING = Compiling:
MSG_ASSEMBLING = Assembling:
MSG_OBJCOPY = ObjCopy:
MSG_CLEANING = Cleaning project:
# Default target.
all: $(TARGET).hex size
# Compile: create object files from C source files.
%.o : %.c
@echo
@echo $(MSG_COMPILING) $<
$(CC) -c $(CFLAGS) -o $@ $<
# Assemble: create object files from assembler source files.
%.o : %.S
@echo
@echo $(MSG_ASSEMBLING) $<
$(CC) -c $(ASFLAGS) -o $@ $<
# ObjCopy: create object files from binary files.
%.o : %.bin
@echo
@echo $(MSG_OBJCOPY) $<
$(OBJCOPY) -I binary -O elf32-littlearm -B arm $< $@
# Link: create ELF output file from object files.
$(TARGET).elf: $(OBJ)
@echo
@echo $(MSG_LINKING) $@
$(CC) $(LDFLAGS) -o $@ $(OBJ)
# Create final output file from ELF output file.
$(TARGET).hex: $(TARGET).elf
@echo
@echo $(MSG_FLASH_FILE) $@
$(OBJCOPY) -O ihex $< $@
# Create extended listing file from ELF output file.
$(TARGET).lss: $(TARGET).elf
@echo
@echo $(MSG_EXTENDED_LISTING) $@
$(OBJDUMP) -h -S $(TARGET).elf > $(TARGET).lss
# Display size of file.
size: $(TARGET).elf
@echo
@echo $(MSG_SIZE)
$(SIZE) --format=berkeley $(TARGET).elf
@echo
# Flash the target device.
flash: $(TARGET).hex
@echo
@echo $(MSG_FLASH)
echo -e "device $(DEVICE)-$(VARIANT)\nspeed $(JLINK_SPEED)\nsi $(JLINK_IFACE)\nloadfile $(TARGET).hex\ng\nqc\n" | $(JLINK)
# Erase the target flash
erase:
@echo
@echo $(MSG_FLASH_ERASE)
echo -e "device $(DEVICE)-$(VARIANT)\nspeed $(JLINK_SPEED)\nsi $(JLINK_IFACE)\nerase\nqc\n" | $(JLINK)
# Target: clean project.
clean:
@echo
@echo $(MSG_CLEANING)
$(REMOVE) $(TARGET).map
$(REMOVE) $(TARGET).elf
$(REMOVE) $(TARGET).hex
$(REMOVE) $(TARGET).lss
$(REMOVE) $(OBJ)
$(REMOVE) $(LST)
$(REMOVE) $(DEP)
# Include the dependency files.
-include $(DEP)
# Listing of phony targets.
.PHONY: all clean size flash erase

View File

@ -0,0 +1,6 @@
Please download the XMC Peripheral Library here:
http://dave.infineon.com/Libraries/XMCLib/XMC_Peripheral_Library_v2.1.6p1.zip
and unzip the content to this folder.

View File

@ -0,0 +1,42 @@
<?xml version="1.0"?>
<EtherCATInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="EtherCATInfo.xsd" Version="1.2">
<Vendor>
<Id>#x1337</Id>
<Name>rt-labs AB</Name>
</Vendor>
<Descriptions>
<Groups>
<Group>
<Type>ATENSLAVE</Type>
<Name>ATO</Name>
</Group>
</Groups>
<Devices>
<Device Physics="YY">
<Type ProductCode="#x12783456" RevisionNo="#x00000001">ATO sample application</Type>
<Name><![CDATA[ATEN-ATO output slave]]></Name>
<GroupType>ATENSLAVE</GroupType>
<Fmmu>Outputs</Fmmu>
<Fmmu>Inputs</Fmmu>
<Sm DefaultSize="128" StartAddress="#x1000" ControlByte="#x26" Enable="1">MBoxOut</Sm>
<Sm DefaultSize="128" StartAddress="#x1080" ControlByte="#x22" Enable="1">MBoxIn</Sm>
<Sm StartAddress="#x1100" ControlByte="#x24" Enable="1">Outputs</Sm>
<Sm StartAddress="#x1180" ControlByte="#x20" Enable="1">Inputs</Sm>
<Mailbox DataLinkLayer="1">
<CoE SdoInfo="1" CompleteAccess="0" PdoUpload="1"/>
</Mailbox>
<Dc>
<OpMode>
<Name>DcOff</Name>
<Desc>DC unused</Desc>
<AssignActivate>#x0000</AssignActivate>
</OpMode>
</Dc>
<Eeprom>
<ByteSize>3968</ByteSize>
<ConfigData>050E0306102700</ConfigData>
</Eeprom>
</Device>
</Devices>
</Descriptions>
</EtherCATInfo>

View File

@ -0,0 +1,15 @@
#include <string.h>
#include "xmc_gpio.h"
#include "soes.h"
int main(void)
{
soes_init();
while(1) {
soes_task();
}
}

View File

@ -0,0 +1,170 @@
/*
* SOES Simple Open EtherCAT Slave
*
* Copyright (C) 2007-2013 Arthur Ketels
*
* SOES is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* SOES is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* As a special exception, if other files instantiate templates or use macros
* or inline functions from this file, or you compile this file and link it
* with other works to produce a work based on this file, this file does not
* by itself cause the resulting work to be covered by the GNU General Public
* License. However the source code for this file must still be made available
* in accordance with section (3) of the GNU General Public License.
*
* This exception does not invalidate any other reasons why a work based on
* this file might be covered by the GNU General Public License.
*
* The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual
* property of, and protected by Beckhoff Automation GmbH.
*/
/** \file
* \brief
* CoE Object Dictionary.
*
* Part of application, describe the slave and its process data.
*/
#include "esc_coe.h"
#include "utypes.h"
#include <stddef.h>
extern _Rbuffer Rb;
extern _Wbuffer Wb;
extern _Cbuffer Cb;
extern uint32_t encoder_scale;
extern uint32_t encoder_scale_mirror;
static const char acName1000[] = "Device Type";
static const char acName1008[] = "Manufacturer Device Name";
static const char acName1009[] = "Manufacturer Hardware Version";
static const char acName100A[] = "Manufacturer Software Version";
static const char acName1018[] = "Identity Object";
static const char acName1018_01[] = "Vendor ID";
static const char acName1018_02[] = "Product Code";
static const char acName1018_03[] = "Revision Number";
static const char acName1018_04[] = "Serial Number";
static const char acNameMO[] = "Mapped object";
static const char acName1600[] = "Receive PDO mapping";
static const char acName1A00[] = "Transmit PDO mapping";
static const char acName1C00[] = "Sync Manager Communication type";
static const char acName1C00_01[] = "Communications type SM0";
static const char acName1C00_02[] = "Communications type SM1";
static const char acName1C00_03[] = "Communications type SM2";
static const char acName1C00_04[] = "Communications type SM3";
static const char acName1C10[] = "Sync Manager 0 PDO Assignment";
static const char acName1C11[] = "Sync Manager 1 PDO Assignment";
static const char acName1C12[] = "Sync Manager 2 PDO Assignment";
static const char acName1C13[] = "Sync Manager 3 PDO Assignment";
static const char acNameNOE[] = "Number of entries";
static const char acName6000[] = "Digital Inputs";
static const char acName6000_01[] = "Button";
static const char acName6000_02[] = "Encoder";
static const char acName7000[] = "Digital outputs";
static const char acName7000_01[] = "LED";
static const char acName7100[] = "Parameters";
static const char acName7100_01[] = "Encoder scale";
static const char acName7100_02[] = "Encoder scale mirror";
static const char acName8001[] = "Slave commands";
static const char acName8001_01[] = "Reset counter";
static char ac1008_00[] = "SOES test application";
static char ac1009_00[] = "0.0.2";
static char ac100A_00[] = "0.9.3";
const _objd SDO1000[] =
{ {0x00, DTYPE_UNSIGNED32, 32, ATYPE_RO, &acName1000[0], 0x00000000, NULL} };
const _objd SDO1008[] =
{ {0x00, DTYPE_VISIBLE_STRING, sizeof (ac1008_00) << 3, ATYPE_RO, &acName1008[0], 0, &ac1008_00[0]}
};
const _objd SDO1009[] =
{ {0x00, DTYPE_VISIBLE_STRING, sizeof (ac1009_00) << 3, ATYPE_RO, &acName1009[0], 0, &ac1009_00[0]}
};
const _objd SDO100A[] =
{ {0x00, DTYPE_VISIBLE_STRING, sizeof (ac100A_00) << 3, ATYPE_RO, &acName100A[0], 0, &ac100A_00[0]}
};
const _objd SDO1018[] =
{ {0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acNameNOE[0], 0x04, NULL},
{0x01, DTYPE_UNSIGNED32, 32, ATYPE_RO, &acName1018_01[0], 0x00001337, NULL},
{0x02, DTYPE_UNSIGNED32, 32, ATYPE_RO, &acName1018_02[0], 0x12783456, NULL},
{0x03, DTYPE_UNSIGNED32, 32, ATYPE_RO, &acName1018_03[0], 0x00000001, NULL},
{0x04, DTYPE_UNSIGNED32, 32, ATYPE_RO, &acName1018_04[0], 0x00000000, NULL}
};
const _objd SDO1600[] =
{ {0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acNameNOE[0], 0x01, NULL},
{0x01, DTYPE_UNSIGNED32, 32, ATYPE_RO, &acNameMO[0], 0x70000108, NULL}
};
const _objd SDO1A00[] =
{ {0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acNameNOE[0], 0x02, NULL},
{0x01, DTYPE_UNSIGNED32, 32, ATYPE_RO, &acNameMO[0], 0x60000108, NULL},
{0x02, DTYPE_UNSIGNED32, 32, ATYPE_RO, &acNameMO[0], 0x60000220, NULL}
};
const _objd SDO1C00[] =
{ {0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acNameNOE[0], 0x04, NULL},
{0x01, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acName1C00_01[0], 0x01, NULL},
{0x02, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acName1C00_02[0], 0x02, NULL},
{0x03, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acName1C00_03[0], 0x03, NULL},
{0x04, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acName1C00_04[0], 0x04, NULL}
};
const _objd SDO1C10[] =
{ {0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acName1C10[0], 0x00, NULL}
};
const _objd SDO1C11[] =
{ {0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acName1C11[0], 0x00, NULL}
};
const _objd SDO1C12[] =
{ {0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acNameNOE[0], 0x01, NULL},
{0x01, DTYPE_UNSIGNED16, 16, ATYPE_RO, &acNameMO[0], 0x1600, NULL}
};
const _objd SDO1C13[] =
{ {0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acNameNOE[0], 0x01, NULL},
{0x01, DTYPE_UNSIGNED16, 16, ATYPE_RO, &acNameMO[0], 0x1A00, NULL}
};
const _objd SDO6000[] =
{ {0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acNameNOE[0], 0x02, NULL},
{0x01, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acName6000_01[0], 0, &(Rb.button)},
{0x02, DTYPE_UNSIGNED32, 32, ATYPE_RO, &acName6000_02[0], 0, &(Rb.encoder)}
};
const _objd SDO7000[] =
{ {0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acNameNOE[0], 0x01, NULL},
{0x01, DTYPE_UNSIGNED8, 8, ATYPE_RW, &acName7000_01[0], 0, &(Wb.LED)}
};
const _objd SDO7100[] =
{ {0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acNameNOE[0], 0x02, NULL},
{0x01, DTYPE_UNSIGNED32, 32, ATYPE_RW, &acName7100_01[0], 0, &(encoder_scale)},
{0x02, DTYPE_UNSIGNED32, 32, ATYPE_RO, &acName7100_02[0], 0, &(encoder_scale_mirror)}
};
const _objd SDO8001[] =
{ {0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, &acNameNOE[0], 0x01, NULL},
{0x01, DTYPE_UNSIGNED32, 32, ATYPE_RW, &acName8001_01[0], 0, &(Cb.reset_counter)},
};
const _objectlist SDOobjects[] =
{ {0x1000, OTYPE_VAR, 0, 0, &acName1000[0], &SDO1000[0]},
{0x1008, OTYPE_VAR, 0, 0, &acName1008[0], &SDO1008[0]},
{0x1009, OTYPE_VAR, 0, 0, &acName1009[0], &SDO1009[0]},
{0x100A, OTYPE_VAR, 0, 0, &acName100A[0], &SDO100A[0]},
{0x1018, OTYPE_RECORD, 4, 0, &acName1018[0], &SDO1018[0]},
{0x1600, OTYPE_RECORD, 0x01, 0, &acName1600[0], &SDO1600[0]},
{0x1A00, OTYPE_RECORD, 0x02, 0, &acName1A00[0], &SDO1A00[0]},
{0x1C00, OTYPE_ARRAY, 4, 0, &acName1C00[0], &SDO1C00[0]},
{0x1C10, OTYPE_ARRAY, 0, 0, &acName1C10[0], &SDO1C10[0]},
{0x1C11, OTYPE_ARRAY, 0, 0, &acName1C11[0], &SDO1C11[0]},
{0x1C12, OTYPE_ARRAY, 1, 0, &acName1C12[0], &SDO1C12[0]},
{0x1C13, OTYPE_ARRAY, 1, 0, &acName1C13[0], &SDO1C13[0]},
{0x6000, OTYPE_ARRAY, 0x02, 0, &acName6000[0], &SDO6000[0]},
{0x7000, OTYPE_ARRAY, 0x01, 0, &acName7000[0], &SDO7000[0]},
{0x7100, OTYPE_ARRAY, 0x02, 0, &acName7100[0], &SDO7100[0]},
{0x8001, OTYPE_ARRAY, 0x01, 0, &acName8001[0], &SDO8001[0]},
{0xffff, 0xff, 0xff, 0xff, NULL, NULL}
};

Binary file not shown.

View File

@ -0,0 +1,10 @@
#ifndef _sii_eeprom_h_
#define _sii_eeprom_h_
extern const uint8_t _binary_sii_eeprom_bin_start;
extern const uint8_t _binary_sii_eeprom_bin_end;
#define SII_EE_DEFLT (&_binary_sii_eeprom_bin_start)
#define SII_EE_DEFLT_SIZE (&_binary_sii_eeprom_bin_end - &_binary_sii_eeprom_bin_start)
#endif

View File

@ -0,0 +1,296 @@
/*
* SOES Simple Open EtherCAT Slave
*
* Copyright (C) 2007-2013 Arthur Ketels
*
* SOES is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* SOES is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* As a special exception, if other files instantiate templates or use macros
* or inline functions from this file, or you compile this file and link it
* with other works to produce a work based on this file, this file does not
* by itself cause the resulting work to be covered by the GNU General Public
* License. However the source code for this file must still be made available
* in accordance with section (3) of the GNU General Public License.
*
* This exception does not invalidate any other reasons why a work based on
* this file might be covered by the GNU General Public License.
*
* The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual
* property of, and protected by Beckhoff Automation GmbH.
*/
/** \file
* \brief
* The application.
*
* The application, the main loop that service EtherCAT.
*/
#include <stddef.h>
#include "esc.h"
#include "esc_coe.h"
#include "esc_eep.h"
#include "esc_hw_eep.h"
#include "utypes.h"
#include "soes.h"
#define WD_RESET 1000
#define DEFAULTTXPDOMAP 0x1a00
#define DEFAULTRXPDOMAP 0x1600
#define DEFAULTTXPDOITEMS 1
#define DEFAULTRXPDOITEMS 1
static const XMC_GPIO_CONFIG_t gpio_config_btn = {
.mode = XMC_GPIO_MODE_INPUT_INVERTED_PULL_UP,
.output_level = 0,
.output_strength = 0
};
static const XMC_GPIO_CONFIG_t gpio_config_led = {
.mode = XMC_GPIO_MODE_OUTPUT_PUSH_PULL,
.output_level = XMC_GPIO_OUTPUT_LEVEL_LOW,
.output_strength = XMC_GPIO_OUTPUT_STRENGTH_STRONG_SOFT_EDGE
};
uint32_t encoder_scale;
uint32_t encoder_scale_mirror;
volatile _ESCvar ESCvar;
_MBX MBX[MBXBUFFERS];
_MBXcontrol MBXcontrol[MBXBUFFERS];
uint8_t MBXrun=0;
uint16_t SM2_sml,SM3_sml;
_Rbuffer Rb;
_Wbuffer Wb;
_Cbuffer Cb;
_App App;
uint16_t TXPDOsize,RXPDOsize;
int wd_cnt = WD_RESET;
volatile uint8_t digoutput;
volatile uint8_t diginput;
uint16_t txpdomap = DEFAULTTXPDOMAP;
uint16_t rxpdomap = DEFAULTRXPDOMAP;
uint8_t txpdoitems = DEFAULTTXPDOITEMS;
uint8_t rxpdoitems = DEFAULTTXPDOITEMS;
/** Mandatory: Hook called from the slave stack SDO Download handler to act on
* user specified Index and Sub-index.
*
* @param[in] index = index of SDO download request to handle
* @param[in] sub-index = sub-index of SDO download request to handle
*/
void ESC_objecthandler (uint16_t index, uint8_t subindex)
{
switch (index)
{
case 0x1c12:
{
if (rxpdoitems > 1)
{
rxpdoitems = 1;
}
if ((rxpdomap != 0x1600) && (rxpdomap != 0x1601)
&& (rxpdomap != 0x0000))
{
rxpdomap = 0x1600;
}
RXPDOsize = SM2_sml = sizeRXPDO ();
break;
}
case 0x1c13:
{
if (txpdoitems > 1)
{
txpdoitems = 1;
}
if ((txpdomap != 0x1A00) && (txpdomap != 0x1A01)
&& (rxpdomap != 0x0000))
{
txpdomap = 0x1A00;
}
TXPDOsize = SM3_sml = sizeTXPDO ();
break;
}
case 0x7100:
{
switch (subindex)
{
case 0x01:
{
encoder_scale_mirror = encoder_scale;
break;
}
}
break;
}
case 0x8001:
{
switch (subindex)
{
case 0x01:
{
Cb.reset_counter = 0;
break;
}
}
break;
}
}
}
/** Mandatory: Hook called from the slave stack ESC_stopoutputs to act on state changes
* forcing us to stop outputs. Here we can set them to a safe state.
* set
*/
void APP_safeoutput (void)
{
DPRINT ("APP_safeoutput called\n");
Wb.LED = 0;
}
/** Mandatory: Write local process data to Sync Manager 3, Master Inputs.
*/
void TXPDO_update (void)
{
ESC_write (SM3_sma, &Rb.button, TXPDOsize);
}
/** Mandatory: Read Sync Manager 2 to local process data, Master Outputs.
*/
void RXPDO_update (void)
{
ESC_read (SM2_sma, &Wb.LED, RXPDOsize);
}
/** Mandatory: Function to update local I/O, call read ethercat outputs, call
* write ethercat inputs. Implement watch-dog counter to count-out if we have
* made state change affecting the App.state.
*/
void DIG_process (void)
{
if (wd_cnt)
{
wd_cnt--;
}
if (App.state & APPSTATE_OUTPUT)
{
/* SM2 trigger ? */
if (ESCvar.ALevent & ESCREG_ALEVENT_SM2)
{
ESCvar.ALevent &= ~ESCREG_ALEVENT_SM2;
RXPDO_update ();
wd_cnt = WD_RESET;
/* dummy output point */
if (Wb.LED) {
XMC_GPIO_SetOutputHigh(P_LED);
} else {
XMC_GPIO_SetOutputLow(P_LED);
}
}
if (!wd_cnt)
{
DPRINT("DIG_process watchdog tripped\n");
ESC_stopoutput ();
/* watchdog, invalid outputs */
ESC_ALerror (ALERR_WATCHDOG);
/* goto safe-op with error bit set */
ESC_ALstatus (ESCsafeop | ESCerror);
}
}
else
{
wd_cnt = WD_RESET;
}
if (App.state)
{
Rb.button = XMC_GPIO_GetInput(P_BTN);
Cb.reset_counter++;
Rb.encoder = ESCvar.Time;
TXPDO_update ();
}
}
/** SOES main loop. Start by initializing the stack software followed by
* the application loop for cyclic read the EtherCAT state and staus, update
* of I/O.
*/
void soes_init (void)
{
DPRINT ("SOES (Simple Open EtherCAT Slave)\n");
ESC_reset();
// configure I/O
XMC_GPIO_Init(P_BTN, &gpio_config_btn);
XMC_GPIO_Init(P_LED, &gpio_config_led);
TXPDOsize = SM3_sml = sizeTXPDO ();
RXPDOsize = SM2_sml = sizeRXPDO ();
/* Setup post config hooks */
static esc_cfg_t config =
{
.pre_state_change_hook = NULL,
.post_state_change_hook = NULL
};
ESC_config ((esc_cfg_t *)&config);
ESC_init (NULL);
/* wait until ESC is started up */
do {
ESC_read (ESCREG_DLSTATUS, (void *) &ESCvar.DLstatus,
sizeof (ESCvar.DLstatus));
ESCvar.DLstatus = etohs (ESCvar.DLstatus);
} while ((ESCvar.DLstatus & 0x0001) == 0);
/* reset ESC to init state */
ESC_ALstatus (ESCinit);
ESC_ALerror (ALERR_NONE);
ESC_stopmbx ();
ESC_stopinput ();
ESC_stopoutput ();
}
void soes_task (void)
{
/* On init restore PDO mappings to default size */
if((ESCvar.ALstatus & 0x0f) == ESCinit)
{
txpdomap = DEFAULTTXPDOMAP;
rxpdomap = DEFAULTRXPDOMAP;
txpdoitems = DEFAULTTXPDOITEMS;
rxpdoitems = DEFAULTTXPDOITEMS;
}
/* Read local time from ESC*/
ESC_read (ESCREG_LOCALTIME, (void *) &ESCvar.Time, sizeof (ESCvar.Time));
ESCvar.Time = etohl (ESCvar.Time);
/* Check the state machine */
ESC_state ();
/* If else to two separate execution paths
* If we're running BOOSTRAP
* - MailBox
* - FoE
* Else we're running normal execution
* - MailBox
* - CoE
*/
if (ESC_mbxprocess ())
{
ESC_coeprocess ();
ESC_xoeprocess ();
}
DIG_process ();
EEP_process ();
EEP_hw_process();
}

View File

@ -0,0 +1,14 @@
#ifndef _SOES_H_
#define _SOES_H_
#include <xmc_gpio.h>
#include <xmc_scu.h>
#define P_LED P4_1
#define P_BTN P3_4
extern void soes_init (void);
extern void soes_task (void);
#endif

View File

@ -0,0 +1,59 @@
/*
* SOES Simple Open EtherCAT Slave
*
* Copyright (C) 2007-2013 Arthur Ketels
*
* SOES is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* SOES is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* As a special exception, if other files instantiate templates or use macros
* or inline functions from this file, or you compile this file and link it
* with other works to produce a work based on this file, this file does not
* by itself cause the resulting work to be covered by the GNU General Public
* License. However the source code for this file must still be made available
* in accordance with section (3) of the GNU General Public License.
*
* This exception does not invalidate any other reasons why a work based on
* this file might be covered by the GNU General Public License.
*
* The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual
* property of, and protected by Beckhoff Automation GmbH.
*/
/** \file
* \brief
* Header file for Application types.
*
* Part of the application, host declarations of application types mapped against
* ServiceData Objects and ProcessData Objects.
*/
#ifndef __utypes_h__
#define __utypes_h__
#include <cc.h>
typedef struct
{
uint8_t state;
uint8_t button;
uint32_t encoder;
} _Rbuffer;
typedef struct
{
uint8_t LED;
} _Wbuffer;
typedef struct
{
uint32_t reset_counter;
} _Cbuffer;
#endif

View File

@ -7,6 +7,8 @@ add_library (soes
esc_coe.h
esc_foe.c
esc_foe.h
esc_eep.c
esc_eep.h
${HAL_SOURCES}
)
@ -17,4 +19,5 @@ install (FILES
esc.h
esc_coe.h
esc_foe.h
esc_eep.h
DESTINATION include)

105
soes/esc_eep.c 100644
View File

@ -0,0 +1,105 @@
/*
* SOES Simple Open EtherCAT Slave
*
* Copyright (C) 2010 ZBE Inc.
* Copyright (C) 2011-2013 Arthur Ketels.
* Copyright (C) 2012-2013 rt-labs.
*
* SOES is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* SOES is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* As a special exception, if other files instantiate templates or use macros
* or inline functions from this file, or you compile this file and link it
* with other works to produce a work based on this file, this file does not
* by itself cause the resulting work to be covered by the GNU General Public
* License. However the source code for this file must still be made available
* in accordance with section (3) of the GNU General Public License.
*
* This exception does not invalidate any other reasons why a work based on
* this file might be covered by the GNU General Public License.
*
* The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual
* property of, and protected by Beckhoff Automation GmbH.
*/
/** \file
* \brief
* ESI EEPROM emulator module.
*/
#include "cc.h"
#include "esc.h"
#include "esc_eep.h"
#include <string.h>
static uint8_t eep_buf[8];
/** EPP periodic task of ESC side EEPROM emulation.
*
*/
void EEP_process (void)
{
eep_stat_t stat;
/* check for eeprom event */
if ((ESCvar.ALevent & ESCREG_ALEVENT_EEP) == 0) {
return;
}
while (1) {
/* read eeprom status */
ESC_read (ESCREG_EECONTSTAT, &stat, sizeof (eep_stat_t));
stat.contstat.reg = etohs(stat.contstat.reg);
stat.addr = etohl(stat.addr);
/* check busy flag, exit if job finished */
if (!stat.contstat.bits.busy) {
return;
}
/* clear error bits */
stat.contstat.bits.csumErr = 0;
stat.contstat.bits.eeLoading = 0;
stat.contstat.bits.ackErr = 0;
stat.contstat.bits.wrErr = 0;
/* process commands */
switch (stat.contstat.bits.cmdReg) {
case EEP_CMD_IDLE:
break;
case EEP_CMD_READ:
case EEP_CMD_RELOAD:
/* handle read request */
if (EEP_read (stat.addr * sizeof(uint16_t), eep_buf, EEP_READ_SIZE) != 0) {
stat.contstat.bits.ackErr = 1;
} else {
ESC_write (ESCREG_EEDATA, eep_buf, EEP_READ_SIZE);
}
break;
case EEP_CMD_WRITE:
/* handle write request */
ESC_read (ESCREG_EEDATA, eep_buf, EEP_WRITE_SIZE);
if (EEP_write (stat.addr * sizeof(uint16_t), eep_buf, EEP_WRITE_SIZE) != 0) {
stat.contstat.bits.ackErr = 1;
}
break;
default:
stat.contstat.bits.ackErr = 1;
}
/* acknowledge command */
stat.contstat.reg = htoes(stat.contstat.reg);
ESC_write (ESCREG_EECONTSTAT, &stat.contstat.reg, sizeof(uint16_t));
}
}

88
soes/esc_eep.h 100644
View File

@ -0,0 +1,88 @@
/*
* SOES Simple Open EtherCAT Slave
*
* Copyright (C) 2010 ZBE Inc.
* Copyright (C) 2007-2013 Arthur Ketels
* Copyright (C) 2012-2013 rt-labs.
*
* SOES is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* SOES is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* As a special exception, if other files instantiate templates or use macros
* or inline functions from this file, or you compile this file and link it
* with other works to produce a work based on this file, this file does not
* by itself cause the resulting work to be covered by the GNU General Public
* License. However the source code for this file must still be made available
* in accordance with section (3) of the GNU General Public License.
*
* This exception does not invalidate any other reasons why a work based on
* this file might be covered by the GNU General Public License.
*
* The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual
* property of, and protected by Beckhoff Automation GmbH.
*/
/** \file
* \brief
* Headerfile for esc_eep.c
*/
#ifndef __esc_eep__
#define __esc_eep__
#include "cc.h"
/* EEPROM emulation related ESC registers */
#define ESCREG_EECONTSTAT 0x0502
#define ESCREG_EEDATA 0x0508
#define ESCREG_ALEVENT_EEP 0x0020
/* EEPROM commands */
#define EEP_CMD_IDLE 0x0
#define EEP_CMD_READ 0x1
#define EEP_CMD_WRITE 0x2
#define EEP_CMD_RELOAD 0x3
/* read/write size */
#define EEP_READ_SIZE 8
#define EEP_WRITE_SIZE 2
/* CONSTAT register content */
typedef struct CC_PACKED
{
union {
uint16_t reg;
struct {
uint8_t wrEnable:1;
uint8_t reserved:4;
uint8_t eeEmulated:1;
uint8_t eightByteRead:1;
uint8_t twoByteAddr:1;
uint8_t cmdReg:3;
uint8_t csumErr:1;
uint8_t eeLoading:1;
uint8_t ackErr:1;
uint8_t wrErr:1;
uint8_t busy:1;
} bits;
} contstat;
uint32_t addr;
} eep_stat_t;
/* periodic task */
void EEP_process (void);
/* From hardware file */
void EEP_init (void);
int8_t EEP_read (uint32_t addr, uint8_t *data, uint16_t size);
int8_t EEP_write (uint32_t addr, uint8_t *data, uint16_t size);
#endif

View File

@ -0,0 +1,235 @@
/*
* SOES Simple Open EtherCAT Slave
*
* File : esc_hw.c
* Version : 0.9.2
* Date : 22-02-2010
* Copyright (C) 2007-2013 Arthur Ketels
* Copyright (C) 2012-2013 rt-labs
*
* SOES is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* SOES is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* As a special exception, if other files instantiate templates or use macros
* or inline functions from this file, or you compile this file and link it
* with other works to produce a work based on this file, this file does not
* by itself cause the resulting work to be covered by the GNU General Public
* License. However the source code for this file must still be made available
* in accordance with section (3) of the GNU General Public License.
*
* This exception does not invalidate any other reasons why a work based on
* this file might be covered by the GNU General Public License.
*
* The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual
* property of, and protected by Beckhoff Automation GmbH.
*/
/** \file
* \brief
* ESC hardware layer functions.
*
* Function to read and write commands to the ESC. Used to read/write ESC
* registers and memory.
*/
#include "esc.h"
#include "esc_eep.h"
#include "xmc_gpio.h"
#include "xmc_ecat.h"
/* ESC to PHY interconnect setup */
#define ECAT_MDO P0_12
#define ECAT_MCLK P3_3
#define ECAT_CLK25 P1_13
#define ECAT_PHY_RESET P2_10
#define ECAT_LED_RUN P1_11
#define ECAT_LED_ERR P1_10
#define ECAT_P0_LINK_STATUS P1_15
#define ECAT_P0_LED_LINK_ACT P1_12
#define ECAT_P0_RXD3 P5_7
#define ECAT_P0_RXD2 P5_2
#define ECAT_P0_RXD1 P5_1
#define ECAT_P0_RXD0 P1_4
#define ECAT_P0_RX_DV P1_9
#define ECAT_P0_RX_CLK P1_1
#define ECAT_P0_RX_ERR P2_6
#define ECAT_P0_TXD3 P1_2
#define ECAT_P0_TXD2 P1_8
#define ECAT_P0_TXD1 P1_7
#define ECAT_P0_TXD0 P1_6
#define ECAT_P0_TX_EN P1_3
#define ECAT_P0_TX_CLK P1_0
#define ECAT_P1_LINK_STATUS P15_3
#define ECAT_P1_LED_LINK_ACT P0_11
#define ECAT_P1_RXD3 P14_14
#define ECAT_P1_RXD2 P14_13
#define ECAT_P1_RXD1 P14_12
#define ECAT_P1_RXD0 P14_7
#define ECAT_P1_RX_DV P14_15
#define ECAT_P1_RX_CLK P14_6
#define ECAT_P1_RX_ERR P15_2
#define ECAT_P1_TXD3 P0_3
#define ECAT_P1_TXD2 P0_2
#define ECAT_P1_TXD1 P3_2
#define ECAT_P1_TXD0 P3_1
#define ECAT_P1_TX_EN P3_0
#define ECAT_P1_TX_CLK P0_10
#define ESCADDR(x) (((uint8_t *) ECAT0_BASE) + x)
static const XMC_ECAT_PORT_CTRL_t port_control = {
.common = {
.mdio = XMC_ECAT_PORT_CTRL_MDIO_P0_12
},
.port0 = {
.rxd0 = XMC_ECAT_PORT0_CTRL_RXD0_P1_4,
.rxd1 = XMC_ECAT_PORT0_CTRL_RXD1_P5_1,
.rxd2 = XMC_ECAT_PORT0_CTRL_RXD2_P5_2,
.rxd3 = XMC_ECAT_PORT0_CTRL_RXD3_P5_7,
.rx_clk = XMC_ECAT_PORT0_CTRL_RX_CLK_P1_1,
.rx_dv = XMC_ECAT_PORT0_CTRL_RX_DV_P1_9,
.rx_err = XMC_ECAT_PORT0_CTRL_RX_ERR_P2_6,
.link = XMC_ECAT_PORT0_CTRL_LINK_P1_15,
.tx_clk = XMC_ECAT_PORT0_CTRL_TX_CLK_P1_0
},
.port1 = {
.rxd0 = XMC_ECAT_PORT1_CTRL_RXD0_P14_7,
.rxd1 = XMC_ECAT_PORT1_CTRL_RXD1_P14_12,
.rxd2 = XMC_ECAT_PORT1_CTRL_RXD2_P14_13,
.rxd3 = XMC_ECAT_PORT1_CTRL_RXD3_P14_14,
.rx_clk = XMC_ECAT_PORT1_CTRL_RX_CLK_P14_6,
.rx_dv = XMC_ECAT_PORT1_CTRL_RX_DV_P14_15,
.rx_err = XMC_ECAT_PORT1_CTRL_RX_ERR_P15_2,
.link = XMC_ECAT_PORT1_CTRL_LINK_P15_3,
.tx_clk = XMC_ECAT_PORT1_CTRL_TX_CLK_P0_10
}
};
static const XMC_GPIO_CONFIG_t gpio_config_input = {
.mode = XMC_GPIO_MODE_INPUT_TRISTATE,
.output_level = 0,
.output_strength = 0
};
static void init_input(XMC_GPIO_PORT_t *const port, const uint8_t pin)
{
XMC_GPIO_Init(port, pin, &gpio_config_input);
}
static void init_output(XMC_GPIO_PORT_t *const port, const uint8_t pin,
uint32_t function, XMC_GPIO_OUTPUT_STRENGTH_t strength)
{
XMC_GPIO_CONFIG_t config;
config.mode = (XMC_GPIO_MODE_t)((uint32_t)XMC_GPIO_MODE_OUTPUT_PUSH_PULL | function);
config.output_level = XMC_GPIO_OUTPUT_LEVEL_LOW;
config.output_strength = strength;
XMC_GPIO_Init(port, pin, &config);
}
#define init_output_sharp(pin, function) init_output(pin, function, XMC_GPIO_OUTPUT_STRENGTH_STRONG_SHARP_EDGE);
#define init_output_soft(pin, function) init_output(pin, function, XMC_GPIO_OUTPUT_STRENGTH_STRONG_SOFT_EDGE);
/** ESC read function used by the Slave stack.
*
* @param[in] address = address of ESC register to read
* @param[out] buf = pointer to buffer to read in
* @param[in] len = number of bytes to read
*/
void ESC_read (uint16_t address, void *buf, uint16_t len)
{
ESCvar.ALevent = etohs ((uint16_t)ECAT0->AL_EVENT_REQ);
memcpy (buf, ESCADDR(address), len);
}
/** ESC write function used by the Slave stack.
*
* @param[in] address = address of ESC register to write
* @param[out] buf = pointer to buffer to write from
* @param[in] len = number of bytes to write
*/
void ESC_write (uint16_t address, void *buf, uint16_t len)
{
ESCvar.ALevent = etohs ((uint16_t)ECAT0->AL_EVENT_REQ);
memcpy(ESCADDR(address), buf, len);
}
void ESC_reset (void)
{
/* disable ESC to force reset */
XMC_ECAT_Disable();
/* initialize EEPROM emulation */
EEP_init();
}
void ESC_init (const void * arg)
{
XMC_ECAT_CONFIG_t ecat_config;
/* configure inputs */
init_input(ECAT_P0_LINK_STATUS);
init_input(ECAT_P0_RXD3);
init_input(ECAT_P0_RXD2);
init_input(ECAT_P0_RXD1);
init_input(ECAT_P0_RXD0);
init_input(ECAT_P0_RX_DV);
init_input(ECAT_P0_RX_CLK);
init_input(ECAT_P0_RX_ERR);
init_input(ECAT_P0_TX_CLK);
init_input(ECAT_P1_LINK_STATUS);
init_input(ECAT_P1_RXD3);
init_input(ECAT_P1_RXD2);
init_input(ECAT_P1_RXD1);
init_input(ECAT_P1_RXD0);
init_input(ECAT_P1_RX_DV);
init_input(ECAT_P1_RX_CLK);
init_input(ECAT_P1_RX_ERR);
init_input(ECAT_P1_TX_CLK);
init_input(ECAT_MDO);
XMC_ECAT_SetPortControl(port_control);
/* read config from emulated EEPROM */
memset(&ecat_config, 0, sizeof(XMC_ECAT_CONFIG_t));
EEP_read (0, (uint8_t *) &ecat_config, sizeof(XMC_ECAT_CONFIG_t));
XMC_ECAT_Init(&ecat_config);
/* configure outputs */
init_output_sharp(ECAT_P0_TXD3, P1_2_AF_ECAT0_P0_TXD3);
init_output_sharp(ECAT_P0_TXD2, P1_8_AF_ECAT0_P0_TXD2);
init_output_sharp(ECAT_P0_TXD1, P1_7_AF_ECAT0_P0_TXD1);
init_output_sharp(ECAT_P0_TXD0, P1_6_AF_ECAT0_P0_TXD0);
init_output_sharp(ECAT_P0_TX_EN, P1_3_AF_ECAT0_P0_TX_ENA);
init_output_sharp(ECAT_P1_TXD3, P0_3_AF_ECAT0_P1_TXD3);
init_output_sharp(ECAT_P1_TXD2, P0_2_AF_ECAT0_P1_TXD2);
init_output_sharp(ECAT_P1_TXD1, P3_2_AF_ECAT0_P1_TXD1);
init_output_sharp(ECAT_P1_TXD0, P3_1_AF_ECAT0_P1_TXD0);
init_output_sharp(ECAT_P1_TX_EN, P3_0_AF_ECAT0_P1_TX_ENA);
init_output_sharp(ECAT_CLK25, P1_13_AF_ECAT0_PHY_CLK25);
init_output_sharp(ECAT_MCLK, P3_3_AF_ECAT0_MCLK);
init_output_soft(ECAT_P0_LED_LINK_ACT, P1_12_AF_ECAT0_P0_LED_LINK_ACT);
init_output_soft(ECAT_P1_LED_LINK_ACT, P0_11_AF_ECAT0_P1_LED_LINK_ACT);
init_output_soft(ECAT_LED_RUN, P1_11_AF_ECAT0_LED_RUN);
init_output_soft(ECAT_LED_ERR, P1_10_AF_ECAT0_LED_ERR);
XMC_GPIO_SetHardwareControl(ECAT_MDO, P0_12_HWCTRL_ECAT0_MDO);
init_output_soft(ECAT_PHY_RESET, P2_10_AF_ECAT0_PHY_RESET);
}

View File

@ -0,0 +1,369 @@
/*
* SOES Simple Open EtherCAT Slave
*
* File : esc_hw_eep.c
* Version : 1.0.0
* Date : 26-08-2016
* Copyright (C) 2016 Sascha Ittner
*
* SOES is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* SOES is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* As a special exception, if other files instantiate templates or use macros
* or inline functions from this file, or you compile this file and link it
* with other works to produce a work based on this file, this file does not
* by itself cause the resulting work to be covered by the GNU General Public
* License. However the source code for this file must still be made available
* in accordance with section (3) of the GNU General Public License.
*
* This exception does not invalidate any other reasons why a work based on
* this file might be covered by the GNU General Public License.
*
* The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual
* property of, and protected by Beckhoff Automation GmbH.
*/
/** \file
* \brief
* ESC hardware specific EEPROM emulation functions.
*/
#include "cc.h"
#include "esc.h"
#include "esc_hw_eep.h"
#include <string.h>
#include "sii_eeprom.h"
#if EEP_BYTES_PER_BLOCK > EEP_BYTES_PER_SECTOR
#error EEP_BYTES_PER_BLOCK needs to fit into EEP_BYTES_PER_SECTOR
#endif
static const XMC_FCE_t fce_config =
{
.kernel_ptr = EPP_FCE_CRC32,
.fce_cfg_update.config_refin = XMC_FCE_REFIN_RESET,
.fce_cfg_update.config_refout = XMC_FCE_REFOUT_RESET,
.fce_cfg_update.config_xsel = XMC_FCE_INVSEL_RESET,
.seedvalue = 0
};
static uint8_t eep_buf[EEP_EMU_BYTES];
static uint8_t eep_buf_dirty;
static uint32_t eep_last_write;
static uint8_t eep_write_req;
static eep_block_t *eep_curr_block;
static eep_block_t *eep_next_block;
static uint32_t *eep_write_src;
static uint32_t *eep_write_dst;
static uint32_t eep_write_page;
static eep_block_t eep_write_buf;
static void init_flash_data(void);
static void find_latest_block(eep_block_t *addr);
static eep_block_t *get_next_block(eep_block_t *block);
static eep_block_t *cleanup_unused_sect(eep_block_t *block);
static int32_t is_sector_empty(uint32_t *addr);
static uint32_t crc32(const uint8_t *data, uint32_t length);
#ifdef EEP_DEFAULT_BTN
static const XMC_GPIO_CONFIG_t gpio_config_btn = {
.mode = XMC_GPIO_MODE_INPUT_INVERTED_PULL_UP,
.output_level = 0,
.output_strength = 0
};
#define EEP_DEFAULT_BTN_INIT() XMC_GPIO_Init(EEP_DEFAULT_BTN, &gpio_config_btn)
#define EEP_DEFAULT_BTN_STATE() XMC_GPIO_GetInput(EEP_DEFAULT_BTN)
#else
#define EEP_DEFAULT_BTN_INIT() { }
#define EEP_DEFAULT_BTN_STATE() 0
#endif
#ifdef EEP_BUSY_LED
static const XMC_GPIO_CONFIG_t gpio_config_led = {
.mode = XMC_GPIO_MODE_OUTPUT_PUSH_PULL,
.output_level = XMC_GPIO_OUTPUT_LEVEL_LOW,
.output_strength = XMC_GPIO_OUTPUT_STRENGTH_STRONG_SOFT_EDGE
};
#define EEP_BUSY_LED_INIT() XMC_GPIO_Init(EEP_BUSY_LED, &gpio_config_led)
#define EEP_BUSY_LED_ON() XMC_GPIO_SetOutputHigh(EEP_BUSY_LED)
#define EEP_BUSY_LED_OFF() XMC_GPIO_SetOutputLow(EEP_BUSY_LED)
#else
#define EEP_BUSY_LED_INIT() { }
#define EEP_BUSY_LED_ON() { }
#define EEP_BUSY_LED_OFF() { }
#endif
/** Initialize EEPROM emulation (load default data, validate checksums, ...).
*
*/
void EEP_init (void)
{
/* initialize write buffer */
memset(&eep_write_buf, 0, EEP_BYTES_PER_BLOCK);
/* configure I/Os */
EEP_DEFAULT_BTN_INIT();
EEP_BUSY_LED_INIT();
/* Enable FCE module */
XMC_FCE_Enable();
/* Initialize the FCE Configuration */
XMC_FCE_Init(&fce_config);
/* try to find latest block in both sectors */
eep_curr_block = NULL;
if (!EEP_DEFAULT_BTN_STATE()) {
find_latest_block((eep_block_t *) EEP_SECTOR_A);
find_latest_block((eep_block_t *) EEP_SECTOR_B);
}
EEP_BUSY_LED_ON();
/* no valid block found -> initialize flash with default data */
if (eep_curr_block == NULL) {
init_flash_data();
}
/* cleanup unused block */
cleanup_unused_sect(eep_curr_block);
/* copy data from block to emu buffer */
memcpy(eep_buf, eep_curr_block->data, EEP_EMU_BYTES);
EEP_BUSY_LED_OFF();
/* initialize state variables */
eep_buf_dirty = 0;
eep_last_write = 0;
eep_write_req = 0;
eep_next_block = NULL;
}
/** EEPROM emulation controller side periodic task.
*
*/
void EEP_hw_process (void)
{
/* check for dirty buffer and set write */
if (eep_buf_dirty) {
int32_t idle_time = ((int32_t) ESCvar.Time) - ((int32_t) eep_last_write);
if (idle_time > EEP_IDLE_TIMEOUT) {
eep_buf_dirty = 0;
eep_write_req = 1;
}
}
/* check for write process */
if (eep_next_block != NULL) {
/* write flash page */
XMC_FLASH_ProgramPage(eep_write_dst, eep_write_src);
eep_write_src += XMC_FLASH_WORDS_PER_PAGE;
eep_write_dst += XMC_FLASH_WORDS_PER_PAGE;
/* update counter */
eep_write_page++;
/* check for finished job */
if (eep_write_page >= EEP_PAGES_PER_BLOCK) {
/* update block pointer and reset write state */
eep_curr_block = eep_next_block;
eep_next_block = NULL;
EEP_BUSY_LED_OFF();
}
return;
}
/* start write of new block */
if (eep_write_req) {
EEP_BUSY_LED_ON();
/* get next block */
eep_next_block = get_next_block(eep_curr_block);
/* copy data */
memcpy(eep_write_buf.data, eep_buf, EEP_EMU_BYTES);
/* setup header */
eep_write_buf.header.seq = eep_curr_block->header.seq + 1;
eep_write_buf.header.crc = crc32 (eep_write_buf.data, EEP_DATA_BYTES);
/* initialize write position */
eep_write_src = (uint32_t *) &eep_write_buf;
eep_write_dst = (uint32_t *) eep_next_block;
eep_write_page = 0;
/* reset write request */
eep_write_req = 0;
}
}
/** EEPROM read function
*
* @param[in] addr = EEPROM byte address
* @param[out] data = pointer to buffer of output data
* @param[in] count = number of bytes to read
* @return 0 on OK, 1 on error
*/
int8_t EEP_read (uint32_t addr, uint8_t *data, uint16_t count)
{
if (addr >= EEP_EMU_BYTES) {
return 1;
}
/* read data from ram buffer */
memcpy(data, eep_buf + addr, count);
return 0;
}
/** EEPROM write function
*
* @param[in] addr = EEPROM byte address
* @param[out] data = pointer to buffer of input data
* @param[in] count = number of bytes to write
* @return 0 on OK, 1 on error
*/
int8_t EEP_write (uint32_t addr, uint8_t *data, uint16_t count)
{
if (addr >= EEP_EMU_BYTES) {
return 1;
}
/* write data to ram buffer */
memcpy(eep_buf + addr, data, count);
/* mark buffer as dirty */
eep_buf_dirty = 1;
eep_write_req = 0;
eep_last_write = ESCvar.Time;
return 0;
}
static void init_flash_data(void)
{
uint32_t i;
const uint32_t *src;
uint32_t *dst;
/* erase both sectors */
XMC_FLASH_EraseSector(EEP_SECTOR_A);
XMC_FLASH_EraseSector(EEP_SECTOR_B);
/* copy default data to write buffer */
memcpy(eep_write_buf.data, SII_EE_DEFLT, (SII_EE_DEFLT_SIZE < EEP_EMU_BYTES) ? SII_EE_DEFLT_SIZE : EEP_EMU_BYTES);
/* setup header data */
eep_write_buf.header.seq = 0;
eep_write_buf.header.crc = crc32 (eep_write_buf.data, EEP_DATA_BYTES);
/* write pages */
src = (const uint32_t *) &eep_write_buf;
dst = EEP_SECTOR_A;
for (i = 0; i < EEP_PAGES_PER_BLOCK; i++) {
XMC_FLASH_ProgramPage(dst, src);
src += XMC_FLASH_WORDS_PER_PAGE;
dst += XMC_FLASH_WORDS_PER_PAGE;
}
/* set current block */
eep_curr_block = (eep_block_t *) EEP_SECTOR_A;
}
static void find_latest_block(eep_block_t *addr)
{
uint32_t blk, crc;
for (blk = 0; blk < EPP_BLOCKS_PER_SECT; blk++, addr++) {
/* check crc, skip invalid blocks */
crc = crc32 (addr->data, EEP_DATA_BYTES);
if (addr->header.crc != crc) {
continue;
}
/* check sequence number and update last pointer */
if (eep_curr_block == NULL || (addr->header.seq - eep_curr_block->header.seq) > 0) {
eep_curr_block = addr;
}
}
}
static eep_block_t *get_next_block(eep_block_t *block)
{
/* simple case: new block fits in current sector */
uint32_t sect_offset = ((uint32_t)block) & (EEP_BYTES_PER_SECTOR - 1);
if ((sect_offset + EEP_BYTES_PER_BLOCK) < EEP_BYTES_PER_SECTOR) {
return block + 1;
}
/* use other sector */
return cleanup_unused_sect(block);
}
static eep_block_t *cleanup_unused_sect(eep_block_t *block)
{
/* get other sector */
uint32_t *sect_addr = (uint32_t *) (((uint32_t)block) & ~(EEP_BYTES_PER_SECTOR - 1));
if (sect_addr == EEP_SECTOR_A) {
sect_addr = EEP_SECTOR_B;
} else {
sect_addr = EEP_SECTOR_A;
}
/* check if sector is empty, erase if not */
if (!is_sector_empty(sect_addr)) {
XMC_FLASH_EraseSector(sect_addr);
}
return (eep_block_t *) sect_addr;
}
static int32_t is_sector_empty(uint32_t *addr)
{
uint32_t i;
/* check for all bytes erased */
for (i=0; i<EEP_BYTES_PER_SECTOR; i+=sizeof(uint32_t), addr++) {
if (*addr != 0) {
return 0;
}
}
return 1;
}
static uint32_t crc32(const uint8_t *data, uint32_t length)
{
uint32_t crc;
XMC_FCE_InitializeSeedValue(&fce_config, 0xffffffff);
XMC_FCE_CalculateCRC32(&fce_config, (const uint32_t *) data, length & ~3L, &crc);
XMC_FCE_GetCRCResult(&fce_config, &crc);
return crc;
}

View File

@ -0,0 +1,93 @@
/*
* SOES Simple Open EtherCAT Slave
*
* File : esc_hw_eep.h
* Version : 1.0.0
* Date : 26-08-2016
* Copyright (C) 2016 Sascha Ittner
*
* SOES is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* SOES is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* As a special exception, if other files instantiate templates or use macros
* or inline functions from this file, or you compile this file and link it
* with other works to produce a work based on this file, this file does not
* by itself cause the resulting work to be covered by the GNU General Public
* License. However the source code for this file must still be made available
* in accordance with section (3) of the GNU General Public License.
*
* This exception does not invalidate any other reasons why a work based on
* this file might be covered by the GNU General Public License.
*
* The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual
* property of, and protected by Beckhoff Automation GmbH.
*/
/** \file
* \brief
* ESC hardware specifoc EEPROM emulation functions.
*/
#ifndef __esc_hw_eep__
#define __esc_hw_eep__
#include "cc.h"
#include "esc_eep.h"
#include "xmc_gpio.h"
#include "xmc_flash.h"
#include "xmc_fce.h"
/* if defined: reload default EEPROM content if pulled low */
#define EEP_DEFAULT_BTN P3_4
/* if defined: flash BUSY indicator */
#define EEP_BUSY_LED P4_0
/* used CRC32 kernel for checksum calculation */
#define EPP_FCE_CRC32 XMC_FCE_CRC32_0
/* idle timeout in ns before actual flash write will be issued */
#define EEP_IDLE_TIMEOUT 100000000
/* Packes per emulated EEPROM block*/
#define EEP_PAGES_PER_BLOCK 16
/* flash sector select */
#define EEP_BYTES_PER_SECTOR 0x04000
#define EEP_SECTOR_A XMC_FLASH_SECTOR_6
#define EEP_SECTOR_B XMC_FLASH_SECTOR_7
/* block header */
typedef struct CC_PACKED
{
int32_t seq;
uint32_t crc;
} eep_header_t;
/* calulate resulting sizes */
#define EEP_BYTES_PER_BLOCK (EEP_PAGES_PER_BLOCK * XMC_FLASH_BYTES_PER_PAGE)
#define EPP_BLOCKS_PER_SECT (EEP_BYTES_PER_SECTOR / EEP_BYTES_PER_BLOCK)
#define EEP_DATA_BYTES (EEP_BYTES_PER_BLOCK - sizeof(eep_header_t))
/* eeprom size increments in steps of 0x80 bytes */
#define EEP_EMU_BYTES (EEP_DATA_BYTES & ~0x7f)
/* block structure */
typedef struct CC_PACKED
{
eep_header_t header;
uint8_t data[EEP_DATA_BYTES];
} eep_block_t;
/* periodic task */
void EEP_hw_process (void);
#endif