硬件平台:STM32F103 + AX58100
AX58100 提供两种过程数据接口 (PDI),Local Bus 接口和 SPI Slave 接口,可通过这些接口将 AX58100 连接到外部 MCU/以支持 EtherCAT 功能。
上一章内容写了SPI接口,本章对LocalBus接口进行介绍,和上章重复的部分就不在叙述。LocalBus为并行通讯方式,相对于SPI,通讯速率更高,最高可到100Mbit/s,适用于传输数量较大的情况。LocalBus支持8bit或16bit并行数据,与MCU的FSMC或FMC外设接口连接,本文以16bit数据传输、FSMC外设接口为例。
1、硬件连接
注意,AX58100的地址线LA0接地,LA1:13连接至MCU的ADR0:12。
2、MCU配置
2.1 时钟
2.2 FSMC
- 片选 NE1~NE4任意选择
- 内存类型:SRAM
- 地址位数,AX58100有14根地址线,此处填14 bits
- 数据位数:16bits
- 非同步模式
- 取消勾选Byte enable
- Extended mode设置为Disabled,FSMC自动使用模式A对SRAM进行操作,SRAM的读写操作速度基本相同,所以读写操作可以使用相同的时序参数,无需使用扩展模式单独设置读时序和写时序
- 时序,三个参数:地址建立时间、数据建立时间和总线翻转时间,需要结合芯片读写时序具体设置
2.2.1 FSMC控制SRAM的时序
模式A的读写时序,如下图。
该图表示一个存储器操作周期由地址建立周期(ADDSET)、数据建立周期(DATAST)以及2个HCLK周期组成。在地址建立周期中,地址线发出要访问的地址, 数据掩码信号线指示出要读取地址的高、低字节部分,片选信号使能存储器芯片;地址建立周期结束后读使能信号线发出读使能信号, 接着存储器通过数据信号线把目标数据传输给FSMC,FSMC把它交给内核。
写时序类似,区别是它的一个存储器操作周期仅由地址建立周期(ADDSET)和数据建立周期(DATAST)组成, 且在数据建立周期期间写使能信号线发出写信号,接着FSMC把数据通过数据线传输到存储器中。
2.2.2 localBus的时序要求
结合FSMC和localBus的时序要求,参数配置如下:
总线翻转时间:在NOR FLASH存储器中,地址线与数据线可以分时复用,总线转换周期就是指总线在这两种状态间切换需要的延时,防止冲突,控制其它存储器时这个参数无效,配置为0即可。
地址建立时间:
地址就绪至读使能的时间:TADR_BHE_setup (>0)
地址就绪至写使能的时间:TADR_BHE_DATA_setup(>6.5 ns) - TWR_active(>8.5 ns)
数据建立时间:
读使能至数据有效的时间:Tread(<300 ns) +TBUSY_to_DATA_valid(< -15 ns)
写使能至写使能结束的时间:TWR_active(>8.5 ns)
即 (ADDSET+1) > 0, 8.5ns < (DATAST+1) < 285ns ,FSMC的时钟周期是1/72Mhz = 13.9ns,所以设置ADDSET = 0,DATAST = 10即满足要求。
其他定时器和外部中断配置与上一章SPI接口一致。
3.软件接口
软件接口可以在ssc工具生成的mcihw.h/c(SSC->Hardware选项的MCI_HW置1)文件上修改。
mcihw.h
#ifndef _MCIHW_H_
#define _MCIHW_H_
/*-----------------------------------------------------------------------------------------
------
------ Includes
------
-----------------------------------------------------------------------------------------*/
#include "esc.h"
/*-----------------------------------------------------------------------------------------
------
------ Defines and Types
------
-----------------------------------------------------------------------------------------*/
#define ESC_PDI_BASEADDR ((UINT32)0x60000000) //Bank1_SRAMx_ADDR
/*---------------------------------------------
- hardware timer settings
-----------------------------------------------*/
/*---------------------------------------------
- Interrupt and Timer defines
-----------------------------------------------*/
#define HW_GetALEventRegister() (*(volatile UINT16 ESCMEM *)(ESC_PDI_BASEADDR+(ESC_AL_EVENT_OFFSET))) /**< \brief Returns the first 16Bit of the AL Event register (0x220)*/
#define HW_GetALEventRegister_Isr HW_GetALEventRegister /**< \brief Returns the first 16Bit of the AL Event register (0x220).<br>Called from ISRs.*/
#define HW_EscRead(pData,Address,Len) ESCMEMCPY((MEM_ADDR *)(pData), (UINT16 *)(ESC_PDI_BASEADDR+((Address))), (Len)) /**< \brief Generic ESC (register and DPRAM) read access.*/
#define HW_EscWrite(pData,Address,Len) ESCMEMCPY((UINT16 *)(ESC_PDI_BASEADDR+(Address)), (MEM_ADDR *)(pData), (Len)) /**< \brief Generic ESC (register and DPRAM) write access.*/
#define HW_EscReadIsr HW_EscRead /**< \brief Generic ESC (register and DPRAM) read access.<br>Called for ISRs.*/
#define HW_EscWriteIsr HW_EscWrite /**< \brief Generic ESC (register and DPRAM) write access.<br>Called for ISRs.*/
//#if ESC_32BIT_ACCESS
#define HW_EscReadDWord(DWordValue, Address) ((DWordValue) = (*(volatile UINT32 *)(ESC_PDI_BASEADDR+(Address)))) /**< \brief 32Bit ESC read access*/
#define HW_EscWriteDWord(DWordValue, Address) ((*(volatile UINT32 *)(ESC_PDI_BASEADDR+(Address))) = (UINT32)(DWordValue)) /**< \brief 32Bit ESC write access*/
#define HW_EscReadDWordIsr HW_EscReadDWord /**< \brief Interrupt specific 32Bit ESC read access*/
#define HW_EscWriteDWordIsr HW_EscWriteDWord /**< \brief Interrupt specific 32Bit ESC write access*/
//#elif ESC_16BIT_ACCESS
#define HW_EscReadWord(WordValue, Address) ((WordValue) = (*(volatile UINT16 *)(ESC_PDI_BASEADDR+(Address)))) /**< \brief 16Bit ESC read access*/
#define HW_EscWriteWord(WordValue, Address) ((*(volatile UINT16 *)(ESC_PDI_BASEADDR+(Address))) = (UINT16)(WordValue)) /**< \brief 16Bit ESC write access*/
#define HW_EscReadWordIsr HW_EscReadWord /**< \brief Interrupt specific 16Bit ESC read access*/
#define HW_EscWriteWordIsr HW_EscWriteWord /**< \brief Interrupt specific 16Bit ESC write access*/
//#else
// #define HW_EscReadByte(ByteValue,Address) ((ByteValue) = (*(volatile UINT8 *)(ESC_PDI_BASEADDR+(Address)))) /**< \brief 8Bit specific ESC (register and DPRAM) read access.*/
// #define HW_EscWriteByte(ByteValue, Address) ((*(volatile UINT8 *)(ESC_PDI_BASEADDR+(Address))) = (UINT8)(ByteValue)) /**< \brief 8Bit specific ESC (register and DPRAM) write access.*/
// #define HW_EscReadByteIsr HW_EscReadByte
// #define HW_EscWriteByteIsr HW_EscWriteByte
//#endif
#define HW_EscReadMbxMem(pData,Address,Len) ESCMBXMEMCPY((MEM_ADDR *)(pData), (UINT16 ESCMEM *)(ESC_PDI_BASEADDR+((Address))), (Len)) /**< \brief The mailbox data is stored in the local uC memory therefore the default read function is used.*/
#define HW_EscWriteMbxMem(pData,Address,Len) ESCMBXMEMCPY(((UINT16 ESCMEM *)(ESC_PDI_BASEADDR+((Address)))),(MEM_ADDR *)(pData), (Len)) /**< \brief The mailbox data is stored in the local uC memory therefore the default write function is used.*/
#endif //_MCIHW_H_
/* ECATCHANGE_START(V5.11) ECAT10*/
#if defined(_MCIHW_H_) && (_MCIHW_H_ == 1)
/* ECATCHANGE_END(V5.11) ECAT10*/
#define PROTO
#else
#define PROTO extern
#endif
/*-----------------------------------------------------------------------------------------
------
------ Global variables
------
-----------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------
------
------ Global functions
------
-----------------------------------------------------------------------------------------*/
PROTO UINT8 HW_Init(void);
PROTO void HW_Release(void);
#undef PROTO
/** @}*/
mcihw.c
/*--------------------------------------------------------------------------------------
------
------ Includes
------
--------------------------------------------------------------------------------------*/
#include "ecat_def.h"
#include "ecatslv.h"
#include "mcihw.h"
#include "ecatappl.h"
#include "gpio.h"
#include "tim.h"
/*--------------------------------------------------------------------------------------
------
------ internal Types and Defines
------
--------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------
------
------ SPI defines/macros
------
-----------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------
------
------ Global Interrupt setting
------
-----------------------------------------------------------------------------------------*/
#define ENABLE_GLOBAL_INT() __enable_irq()
#define DISABLE_GLOBAL_INT() __disable_irq()
#define ENABLE_AL_EVENT_INT ENABLE_GLOBAL_INT()
#define DISABLE_AL_EVENT_INT DISABLE_GLOBAL_INT()
/*-----------------------------------------------------------------------------------------
------
------ ESC Interrupt
------
-----------------------------------------------------------------------------------------*/
//PDI_Isr
#define ENABLE_ESC_INT() HAL_NVIC_EnableIRQ(EXTI0_IRQn)
#define DISABLE_ESC_INT() HAL_NVIC_DienableIRQ(EXTI0_IRQn)
/*-----------------------------------------------------------------------------------------
------
------ SYNC0 Interrupt
------
-----------------------------------------------------------------------------------------*/
//Sync0_Isr
#define ENABLE_SYNCO_INT() HAL_NVIC_EnableIRQ(EXTI9_5_IRQn)
#define DISABLE_SYNCO_INT() HAL_NVIC_DienableIRQ(EXTI9_5_IRQn)
//Sync1_Isr
#define ENABLE_SYNC1_INT() HAL_NVIC_EnableIRQ(EXTI4_IRQn)
#define DISABLE_SYNC1_INT() HAL_NVIC_DienableIRQ(EXTI4_IRQn)
/*-----------------------------------------------------------------------------------------
------
------ Hardware timer
------
-----------------------------------------------------------------------------------------*/
#define START_ECAT_TIMER() HAL_TIM_Base_Start_IT(&htim3)
#define STOP_ECAT_TIMER() HAL_TIM_Base_Stop_IT(&htim3)
#define HW_GetTimer() __HAL_TIM_GET_COUNTER(&htim3)
#define ECAT_TIMER_INC_P_MS 1000 //1ms定时器的计数值
/*-----------------------------------------------------------------------------------------
------
------ Configuration Bits
------
-----------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------
------
------ LED defines
------
-----------------------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------------------
------
------ internal Variables
------
----------------------------------------------------------------------------------
/*--------------------------------------------------------------------------------------
------
------ internal functions
------
--------------------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------------------
------
------ 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)
{
/*ECATCHANGE_START(V5.11) EL9800 2*/
UINT32 intMask;
/*ECATCHANGE_END(V5.11) EL9800 2*/
/* make sure it's localbus */
do
{
intMask = 0x00;
HW_EscReadByte(intMask, ESC_PDI_CONTROL_OFFSET);
} while (intMask != 0x08);
/*ECATCHANGE_START(V5.11) EL9800 2*/
do
{
intMask = 0x93;
HW_EscWriteDWord(intMask, ESC_AL_EVENTMASK_OFFSET);
intMask = 0;
HW_EscReadDWord(intMask, ESC_AL_EVENTMASK_OFFSET);
} while (intMask != 0x93);
intMask = 0x00;
HW_EscWriteDWord(intMask, ESC_AL_EVENTMASK_OFFSET);
/*ECATCHANGE_END(V5.11) EL9800 2*/
#if AL_EVENT_ENABLED
ENABLE_ESC_INT();
#endif
#if DC_SUPPORTED
ENABLE_SYNC0_INT();
ENABLE_SYNC1_INT();
#endif
#if ECAT_TIMER_INT
START_ECAT_TIMER();
#endif
#if INTERRUPTS_SUPPORTED
/* enable all interrupts */
ENABLE_GLOBAL_INT();
#endif
return 0;
}
/
/**
\brief This function shall be implemented if hardware resources need to be release
when the sample application stops
*
void HW_Release(void)
{
DISABLE_GLOBAL_INT();
}
/** @} */
其他内容与上一章SPI接口一致。