目錄
一、生成協議棧及XML文件
?二、使用stm32CuboMX配置外設
?三、協議棧移植
? ? ? ? ?鑒于本人對EtherCAT的掌握程度十分有限,這篇文章僅作為我搭建基礎從站的過程記錄不做更多講解。本文內容主要為SPI模式的基礎搭建,更多深入的學習資料和細節,大家可以通過進一步的網上搜索來獲取。
軟件工具:XMLNotepad2007,SSC_V5.11,TwinCAT3,Keil5,STM32CubeMX
資源:lan9252-pic32-sdk_v1.1
一、生成協議棧及XML文件
? ? ? ? 我是使用的 SSC_V5.11 來自動生成協議棧與XML文件,期間使用到了LAN9252的官方SDK文件 lan9252-pic32-sdk_v1.1?版本,網站有許多資源可以自行下載。流程可參考官方的 AN1916 文件
1. 下載完SSC_V5.11后找到并打開SSC Tool程序。
?2.?點擊左上角 File -> New 彈出新建工程的選項卡,選擇左下角 Import? -> 選擇lan9252-pic-32_sdk_v1.1 文件夾下的 Microchip_LAN9252_SSC_Config.xml?導入官方的工程模板,一路確定完成導入。
?
?3. 選擇 Custom -> Microchip-SPI-GPIO -> OK 使用官方模板后,XML中的一些參數就不需要自己來修改了,非常的方便。
?4. 點擊OK后會提示讓你選取9252_HW.c文件,這個文件可以在lan9252-pic-32_sdk_v1.1/SSC/Common文件夾下找到。
?
?
????????完成之后是這樣的一個界面,可以按需自行更改項目信息,這里只是自己為了搭建從站進行測試,我這里先不做任何的修改。想了解里面每一項功能的可以閱讀下面這篇文章
EtherCAT Slave Stack Code Tool(SSC)使用筆記-CSDN博客文章瀏覽閱讀1w次,點贊87次,收藏190次。學習EtherCAT有幾個月了,準備做一個EtherCAT從站,摸爬滾打一路走來,遇到不少問題,這里僅作學習記錄使用。移植過的平臺 STM32F103,STM32F407,ari32F103。從站芯片LAN9252。EtherCAT Slave Stack Code Tool (SSC) V5.12(該軟件自動生成EtherCAT從站核心代碼。_slave stack code toolhttps://blog.csdn.net/efei123/article/details/136231104?fromshare=blogdetail&sharetype=blogdetail&sharerId=136231104&sharerefer=PC&sharesource=a1547998353&sharefrom=from_link
?5.使用Excel配置對象字典
? ? ? ? 通過選擇上方工具欄 Tool -> Application -> Create new 來創建Excel設置通信數據,第一次創建會先提示你保存項目,自己新建一個文件夾保存進去即可。
剛剛創建的Excel如下,0x6000~0x6FFF 定義輸入,0x7000~0x7FFF定義輸出(這里的輸入輸出是以主站的角度來看的),我們可以在對應位置添加自己的對象。
?按自己的需求簡單創建對象,d1用來測通訊,d2用來補位。
需要注意這里一定要四字節對齊!!!一定要四字節對齊!!!一定要四字節對齊!!!
因為我們后面移植協議棧時需要刪除 __packed 關鍵字,刪除之后會變成默認的四字節對齊,創建字典時如果沒有字節對齊會導致與從站通訊不上,編譯代碼時還不會報錯,到時候找問題你就找去吧,一找一個不吱聲別問我咋發現的T^T。
添加完后保存并退出,彈出的窗口點擊OK。
6.生成協議棧源碼
? ? ? ? 點擊左上角 Project -> Create new Slave Files -> 右下角Start -> OK ->Close 完成之后關閉SSC Tool工具就可以了。
?
?????????這時候打開剛剛工程的保存位置,看見如下四個文件說明成功了。其中 Src 里面保存的就是自動生成的協議棧代碼,不過是基于PIC32的,后面我們將把它慢慢修改成STM32的代碼。 .xml 文件后續我們需要通過 TwinCAT 燒寫進從站的EEPROM,想要閱讀可以使用 XMLNotepad 工具,網上有很多資源可以自己按需下載。
7. 官方給的SDK文件里有我們需要的SPI驅動,將驅動的.c .h文件復制到剛剛生成的Src文件夾內。
?二、使用stm32CuboMX配置外設
與LAN9252的SPI通訊需要以下幾個外設:
1. 一組4線標準SPI
2. 1ms定時器
3. 三個外部中斷 :主中斷 IRQ,兩個時鐘同步中斷 SYNC0、SYNC1
?時鐘樹:
1ms定時器:
?SPI配置:記得額外配置SPI_CS
外部中斷配置:下降沿觸發
?配置中斷優先級:IRQ與1ms定時中斷搶占優先級1,兩個時鐘同步中斷搶占優先級2
?
到此與LAN9252通訊需要的外設已經配置完成了,接下來可以配置其他自己所需的外設。
比如我在最一開始在字典的輸出部分加入的LED來測試通訊功能。
創建工程:
?打開剛剛創建的工程,將剛剛生成的Src文件夾中的內容全部添加到項目,熟悉之后可以按自己的喜好和習慣分組,我這邊直接全部放在了ECAT文件夾下了。
?三、協議棧移植
????????此時編譯會產生一大堆報錯,不要害怕,我們一點一點改掉就好了。接下來我會帶你們挨個的解決這些報錯,希望各位在抄答案前先能自己嘗試著慢慢修改,一定能有所收貨。
遇到的報錯及解決方案:
我們從第一個錯誤位置開始依次往下解決
..\EtherCAT\Src\9252_HW.c(190): warning: #223-D: function "INTDisableInterrupts" declared implicitlyDISABLE_AL_EVENT_INT;
通過全局搜索定位到當前文件的106行,通過宏明可以看出這是關閉全局變量的函數,將對應位置改為用stm32的方式實現,并添加對應頭文件。
#include "main.h"#define DISABLE_GLOBAL_INT __disable_irq()
#define ENABLE_GLOBAL_INT __enable_irq()
#define DISABLE_AL_EVENT_INT DISABLE_GLOBAL_INT
#define ENABLE_AL_EVENT_INT ENABLE_GLOBAL_INT
..\EtherCAT\Src\9252_HW.c(256): warning: #223-D: function "PMPWriteDWord" declared implicitlyPMPWriteDWord (0x54, data);
因為我們使用的是SPI通信,將被USE_SPI包含的252-261范圍內僅保留SPIWriteDord函數,并添加SPI驅動的頭文件。并對本文件內所有被#ifndef USE_SPI 過濾的代碼做同樣操作。
#include "SPIDriver.h" //添加頭文件//這只是部分修改后效果,未全部展示,文件內被 #ifndef USE_SPI 過濾的地方有很多,前后文都有,自己慢慢修改//IRQ enable,IRQ polarity, IRQ buffer type in Interrupt Configuration register.//Wrte 0x54 - 0x00000101data = 0x00000101;SPIWriteDWord (0x54, data);//Write in Interrupt Enable register -->//Write 0x5c - 0x00000001data = 0x00000001;SPIWriteDWord (0x5C, data);//Read Interrupt Status register//Read 0x58.SPIReadDWord(0x58);
往下劃注釋掉HW_SetLed()函數內的代碼,并刪除這之后的所有函數,那些是PIC32芯片的中斷服務程序我們不需要。
void HW_SetLed(UINT8 RunLed,UINT8 ErrLed)
{/* Here RunLed is not used. Because on chip supported RUN Led is available*/ // LED_ECATRED = ErrLed;
}
// 這個函數之下的所有內容刪除
..\EtherCAT\Src\9252_HW.c(295): error: #20: identifier "INTCONbits" is undefinedINIT_SYNC0_INT
追蹤到宏定義的位置,可以看出這是一個SYNC0的初始化函數,中斷初始化的代碼在使用Cubomx生成代碼時已經自動添加了,我們直接把宏后面的定義內容刪除,使其變成一個空的宏。
通過問題1和問題3不難發現9252_HW.c文件中的宏都是基于PIC32系列芯片來寫的,我們只需要全部將其修改為適配STM32即可。
將114~166行所有宏定義用HAL庫函數重寫,并刪除用不到的宏,全部修改完后如下所示:
#ifdef PIC32_HW
BOOL bEscInterrupt = 0;
BOOL bSync0Interrupt = 0;
BOOL bSync1Interrupt = 0;
BOOL bTimer5Interrupt = 0;
///
// Global Interrupt setting#define DISABLE_GLOBAL_INT __disable_irq()
#define ENABLE_GLOBAL_INT __enable_irq()
#define DISABLE_AL_EVENT_INT DISABLE_GLOBAL_INT
#define ENABLE_AL_EVENT_INT ENABLE_GLOBAL_INT///
// ESC Interrupt//0 - falling edge 1-
#define INIT_ESC_INT #define INT_EL HAL_GPIO_ReadPin(LAN9252_IRQ_GPIO_Port,LAN9252_IRQ_Pin) //ESC Interrupt input port#define ACK_ESC_INT __HAL_GPIO_EXTI_CLEAR_IT(LAN9252_IRQ_Pin)#define IS_ESC_INT_ACTIVE ((INT_EL) == 0) //0 - fro active low; 1 for hactive high
///
// SYNC0 Interrupt#ifndef RUN_FROM_SVB_FPGA#define INIT_SYNC0_INT #define INT_SYNC0 HAL_GPIO_ReadPin(LAN9252_SYNC0_GPIO_Port,LAN9252_SYNC0_Pin) //Sync1 Interrupt input port#define DISABLE_SYNC0_INT HAL_NVIC_DisableIRQ(LAN9252_SYNC0_EXTI_IRQn)//{(_INT1IE)=0;}//disable interrupt source INT1#define ENABLE_SYNC0_INT HAL_NVIC_EnableIRQ(LAN9252_SYNC0_EXTI_IRQn) //enable interrupt source INT1#define ACK_SYNC0_INT __HAL_GPIO_EXTI_CLEAR_IT(LAN9252_SYNC0_Pin)#define IS_SYNC0_INT_ACTIVE ((INT_SYNC0) == 0) //0 - fro active low; 1 for hactive high#define INIT_SYNC1_INT #define INT_SYNC1 HAL_GPIO_ReadPin(LAN9252_SYNC1_GPIO_Port,LAN9252_SYNC1_Pin) //Sync1 Interrupt input port#define DISABLE_SYNC1_INT HAL_NVIC_DisableIRQ(LAN9252_SYNC1_EXTI_IRQn)//disable interrupt source INT2#define ENABLE_SYNC1_INT HAL_NVIC_EnableIRQ(LAN9252_SYNC1_EXTI_IRQn) //enable interrupt source INT2#define ACK_SYNC1_INT __HAL_GPIO_EXTI_CLEAR_IT(LAN9252_SYNC1_Pin)#define IS_SYNC1_INT_ACTIVE ((INT_SYNC1) == 0) //0 - fro active low; 1 for hactive high
#else// Place-holder#endif///
// Hardware timer#define STOP_ECAT_TIMER HAL_TIM_Base_Stop_IT(&htim7)
#define INIT_ECAT_TIMER HAL_TIM_Base_Init(&htim7)#define START_ECAT_TIMER HAL_TIM_Base_Start_IT(&htim7)#endif // end of PIC32_HW
改完之后重新編譯會發現少了很多錯誤,接著一個一個改就好了。
..\EtherCAT\Src\ecatappl.c(250): warning: #223-D: function "HW_GetTimer" declared implicitlyStartTimerCnt = (UINT32) HW_GetTimer();
跟第一個問題同樣的方法,找到宏所在位置,發現是灰色的沒被編譯,可以選擇將限制條件#ifdef PIC32_HW 刪掉,也可以選擇改為#ifdef STM32F4(具體定義什么根據自己的芯片型號來,需要頭文件main.h)注釋掉兩個沒有的頭文件和 “ // Defines,types ”區域內的所有內容。
將#define ECAT_TIMER_INC_P_MS 后面的數值改為你配置1ms定時器時的計數重載器的值。
再根據宏名和給的注釋將152-166行附近的宏以同樣的方式用HAL庫函數實現。
修改后代碼如下:
//添加頭文件
#include "main.h"
#include "tim.h"
#include "spi.h"
#include "gpio.h"
#include "stm32f4xx_hal.h"///
// Hardware timer settings#define ECAT_TIMER_INC_P_MS 2000 /**< \brief 312 ticks per ms*////
// Interrupt and Timer Defines#ifndef DISABLE_ESC_INT#define DISABLE_ESC_INT() HAL_NVIC_DisableIRQ(LAN9252_SYNC0_EXTI_IRQn) /**< \brief Disable interrupt source INT1*/
#endif
#ifndef ENABLE_ESC_INT#define ENABLE_ESC_INT() HAL_NVIC_EnableIRQ(LAN9252_SYNC0_EXTI_IRQn) /**< \brief Enable interrupt source INT1*/
#endif//TODO
#ifndef HW_GetTimer#define HW_GetTimer() __HAL_TIM_GET_COUNTER(&htim7) /**< \brief Access to the hardware timer*/
#endif#ifndef HW_ClearTimer#define HW_ClearTimer() __HAL_TIM_SET_COUNTER(&htim7,0) /**< \brief Clear the hardware timer*/
#endif#endif
改完再重新編譯一下又少了很多錯誤,此時第一個錯誤應該是來自 SPIDriver.h 文件,接下來借此機會我們來直接修改SPI驅動使適配STM32。
在 SPIDriver.h 中修改如下內容:
刪除plib.h,并增加如下頭文件
#include "ecat_def.h"
#include "gpio.h"
#include "spi.h"
#include "main.h"
將宏CSLOW()與CSHIGH()修復為自己SPI的控制引腳
#define SPI_OFF HAL_GPIO_WritePin(SPI1_CS_GPIO_Port,SPI1_CS_Pin,GPIO_PIN_SET)#define SPI_ON HAL_GPIO_WritePin(SPI1_CS_GPIO_Port,SPI1_CS_Pin,GPIO_PIN_RESET)#define CSLOW() SPI_ON#define CSHIGH() SPI_OFF
?在 SPIDriver.c 中修改如下內容:
刪除Delay、SPIPut、SPIOpen三個函數。
修改SPIWrite與SPIRead函數,用HAL庫方式實現。
void SPIWrite(UINT8 data)
{HAL_SPI_Transmit(&hspi1,&data,1,2000);
}
UINT8 SPIRead()
{UINT8 data;HAL_SPI_Receive(&hspi1,&data,1,2000);return (data);
}
剩下的就是UINT32_VAL與UINT16_VAL類型未定義引起的問題,這兩個變量是PIC芯片內的庫文件包含的,我們添加一個 "GenericTypeDefs.h" 頭文件到工程并引用即可。
GenericTypeDefs.h
/*******************************************************************Generic Type Definitions********************************************************************FileName: GenericTypeDefs.hDependencies: NoneProcessor: PIC10, PIC12, PIC16, PIC18, PIC24, dsPIC, PIC32Compiler: MPLAB C Compilers for PIC18, PIC24, dsPIC, & PIC32Hi-Tech PICC PRO, Hi-Tech PICC18 PROCompany: Microchip Technology Inc.Software License AgreementThe software supplied herewith by Microchip Technology Incorporated(the "Company") is intended and supplied to you, the Company'scustomer, for use solely and exclusively with products manufacturedby the Company.The software is owned by the Company and/or its supplier, and isprotected under applicable copyright laws. All rights are reserved.Any use in violation of the foregoing restrictions may subject theuser to criminal sanctions under applicable laws, as well as tocivil liability for the breach of the terms and conditions of thislicense.THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES,WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITEDTO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR APARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL ORCONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.********************************************************************File Description:Change History:Rev Date Description1.1 09/11/06 Add base signed types1.2 02/28/07 Add QWORD, LONGLONG, QWORD_VAL1.3 02/06/08 Add def's for PIC321.4 08/08/08 Remove LSB/MSB Macros, adopted by Peripheral lib1.5 08/14/08 Simplify file headerDraft 2.0 07/13/09 Updated for new release of coding standards
*******************************************************************/#ifndef __GENERIC_TYPE_DEFS_H_
#define __GENERIC_TYPE_DEFS_H_#ifdef __cplusplus
extern "C"{
#endif/* Specify an extension for GCC based compilers */
#if defined(__GNUC__)
#define __EXTENSION __extension__
#else
#define __EXTENSION
#endif/* get compiler defined type definitions (NULL, size_t, etc) */
#include <stddef.h>
#include "ecat_def.h"//typedef enum _BOOL { FALSE = 0, TRUE } BOOL; /* Undefined size */
//typedef enum _BIT { CLEAR = 0, SET } BIT;#define PUBLIC /* Function attributes */
#define PROTECTED
#define PRIVATE static/* INT is processor specific in length may vary in size */
//typedef signed int INT;
//typedef signed char INT8;
//typedef signed short int INT16;
//typedef signed long int INT32;/* MPLAB C Compiler for PIC18 does not support 64-bit integers */
#if !defined(__18CXX)
__EXTENSION typedef signed long long INT64;
#endif/* UINT is processor specific in length may vary in size */
//typedef unsigned int UINT;
//typedef unsigned char UINT8;
//typedef unsigned short int UINT16;
/* 24-bit type only available on C18 */
#if defined(__18CXX)
typedef unsigned short long UINT24;
#endif
//typedef unsigned long int UINT32; /* other name for 32-bit integer */
/* MPLAB C Compiler for PIC18 does not support 64-bit integers */
#if !defined(__18CXX)
__EXTENSION typedef unsigned long long UINT64;
#endiftypedef union
{UINT8 Val;struct{__EXTENSION UINT8 b0:1;__EXTENSION UINT8 b1:1;__EXTENSION UINT8 b2:1;__EXTENSION UINT8 b3:1;__EXTENSION UINT8 b4:1;__EXTENSION UINT8 b5:1;__EXTENSION UINT8 b6:1;__EXTENSION UINT8 b7:1;} bits;
} UINT8_VAL, UINT8_BITS;typedef union
{UINT16 Val;UINT8 v[2];struct{UINT8 LB;UINT8 HB;} byte;struct{__EXTENSION UINT8 b0:1;__EXTENSION UINT8 b1:1;__EXTENSION UINT8 b2:1;__EXTENSION UINT8 b3:1;__EXTENSION UINT8 b4:1;__EXTENSION UINT8 b5:1;__EXTENSION UINT8 b6:1;__EXTENSION UINT8 b7:1;__EXTENSION UINT8 b8:1;__EXTENSION UINT8 b9:1;__EXTENSION UINT8 b10:1;__EXTENSION UINT8 b11:1;__EXTENSION UINT8 b12:1;__EXTENSION UINT8 b13:1;__EXTENSION UINT8 b14:1;__EXTENSION UINT8 b15:1;} bits;
} UINT16_VAL, UINT16_BITS;/* 24-bit type only available on C18 */
#if defined(__18CXX)
typedef union
{UINT24 Val;UINT8 v[3];struct{UINT8 LB;UINT8 HB;UINT8 UB;} byte;struct{__EXTENSION UINT8 b0:1;__EXTENSION UINT8 b1:1;__EXTENSION UINT8 b2:1;__EXTENSION UINT8 b3:1;__EXTENSION UINT8 b4:1;__EXTENSION UINT8 b5:1;__EXTENSION UINT8 b6:1;__EXTENSION UINT8 b7:1;__EXTENSION UINT8 b8:1;__EXTENSION UINT8 b9:1;__EXTENSION UINT8 b10:1;__EXTENSION UINT8 b11:1;__EXTENSION UINT8 b12:1;__EXTENSION UINT8 b13:1;__EXTENSION UINT8 b14:1;__EXTENSION UINT8 b15:1;__EXTENSION UINT8 b16:1;__EXTENSION UINT8 b17:1;__EXTENSION UINT8 b18:1;__EXTENSION UINT8 b19:1;__EXTENSION UINT8 b20:1;__EXTENSION UINT8 b21:1;__EXTENSION UINT8 b22:1;__EXTENSION UINT8 b23:1;} bits;
} UINT24_VAL, UINT24_BITS;
#endiftypedef union
{UINT32 Val;UINT16 w[2];UINT8 v[4];struct{UINT16 LW;UINT16 HW;} word;struct{UINT8 LB;UINT8 HB;UINT8 UB;UINT8 MB;} byte;struct{UINT16_VAL low;UINT16_VAL high;}wordUnion;struct{__EXTENSION UINT8 b0:1;__EXTENSION UINT8 b1:1;__EXTENSION UINT8 b2:1;__EXTENSION UINT8 b3:1;__EXTENSION UINT8 b4:1;__EXTENSION UINT8 b5:1;__EXTENSION UINT8 b6:1;__EXTENSION UINT8 b7:1;__EXTENSION UINT8 b8:1;__EXTENSION UINT8 b9:1;__EXTENSION UINT8 b10:1;__EXTENSION UINT8 b11:1;__EXTENSION UINT8 b12:1;__EXTENSION UINT8 b13:1;__EXTENSION UINT8 b14:1;__EXTENSION UINT8 b15:1;__EXTENSION UINT8 b16:1;__EXTENSION UINT8 b17:1;__EXTENSION UINT8 b18:1;__EXTENSION UINT8 b19:1;__EXTENSION UINT8 b20:1;__EXTENSION UINT8 b21:1;__EXTENSION UINT8 b22:1;__EXTENSION UINT8 b23:1;__EXTENSION UINT8 b24:1;__EXTENSION UINT8 b25:1;__EXTENSION UINT8 b26:1;__EXTENSION UINT8 b27:1;__EXTENSION UINT8 b28:1;__EXTENSION UINT8 b29:1;__EXTENSION UINT8 b30:1;__EXTENSION UINT8 b31:1;} bits;
} UINT32_VAL;/* MPLAB C Compiler for PIC18 does not support 64-bit integers */
#if !defined(__18CXX)
typedef union
{UINT64 Val;UINT32 d[2];UINT16 w[4];UINT8 v[8];struct{UINT32 LD;UINT32 HD;} dword;struct{UINT16 LW;UINT16 HW;UINT16 UW;UINT16 MW;} word;struct{__EXTENSION UINT8 b0:1;__EXTENSION UINT8 b1:1;__EXTENSION UINT8 b2:1;__EXTENSION UINT8 b3:1;__EXTENSION UINT8 b4:1;__EXTENSION UINT8 b5:1;__EXTENSION UINT8 b6:1;__EXTENSION UINT8 b7:1;__EXTENSION UINT8 b8:1;__EXTENSION UINT8 b9:1;__EXTENSION UINT8 b10:1;__EXTENSION UINT8 b11:1;__EXTENSION UINT8 b12:1;__EXTENSION UINT8 b13:1;__EXTENSION UINT8 b14:1;__EXTENSION UINT8 b15:1;__EXTENSION UINT8 b16:1;__EXTENSION UINT8 b17:1;__EXTENSION UINT8 b18:1;__EXTENSION UINT8 b19:1;__EXTENSION UINT8 b20:1;__EXTENSION UINT8 b21:1;__EXTENSION UINT8 b22:1;__EXTENSION UINT8 b23:1;__EXTENSION UINT8 b24:1;__EXTENSION UINT8 b25:1;__EXTENSION UINT8 b26:1;__EXTENSION UINT8 b27:1;__EXTENSION UINT8 b28:1;__EXTENSION UINT8 b29:1;__EXTENSION UINT8 b30:1;__EXTENSION UINT8 b31:1;__EXTENSION UINT8 b32:1;__EXTENSION UINT8 b33:1;__EXTENSION UINT8 b34:1;__EXTENSION UINT8 b35:1;__EXTENSION UINT8 b36:1;__EXTENSION UINT8 b37:1;__EXTENSION UINT8 b38:1;__EXTENSION UINT8 b39:1;__EXTENSION UINT8 b40:1;__EXTENSION UINT8 b41:1;__EXTENSION UINT8 b42:1;__EXTENSION UINT8 b43:1;__EXTENSION UINT8 b44:1;__EXTENSION UINT8 b45:1;__EXTENSION UINT8 b46:1;__EXTENSION UINT8 b47:1;__EXTENSION UINT8 b48:1;__EXTENSION UINT8 b49:1;__EXTENSION UINT8 b50:1;__EXTENSION UINT8 b51:1;__EXTENSION UINT8 b52:1;__EXTENSION UINT8 b53:1;__EXTENSION UINT8 b54:1;__EXTENSION UINT8 b55:1;__EXTENSION UINT8 b56:1;__EXTENSION UINT8 b57:1;__EXTENSION UINT8 b58:1;__EXTENSION UINT8 b59:1;__EXTENSION UINT8 b60:1;__EXTENSION UINT8 b61:1;__EXTENSION UINT8 b62:1;__EXTENSION UINT8 b63:1;} bits;
} UINT64_VAL;
#endif /* __18CXX *//***********************************************************************************//* Alternate definitions */
typedef void VOID;typedef char CHAR8;
typedef unsigned char UCHAR8;typedef unsigned char BYTE; /* 8-bit unsigned */
typedef unsigned short int WORD; /* 16-bit unsigned */
typedef unsigned long DWORD; /* 32-bit unsigned */
/* MPLAB C Compiler for PIC18 does not support 64-bit integers */
#if !defined(__18CXX)
__EXTENSION
typedef unsigned long long QWORD; /* 64-bit unsigned */
#endif /* __18CXX */
//typedef signed char CHAR; /* 8-bit signed */
typedef signed short int SHORT; /* 16-bit signed */
typedef signed long LONG; /* 32-bit signed */
/* MPLAB C Compiler for PIC18 does not support 64-bit integers */
#if !defined(__18CXX)
__EXTENSION
typedef signed long long LONGLONG; /* 64-bit signed */
#endif /* __18CXX */
typedef union
{BYTE Val;struct{__EXTENSION BYTE b0:1;__EXTENSION BYTE b1:1;__EXTENSION BYTE b2:1;__EXTENSION BYTE b3:1;__EXTENSION BYTE b4:1;__EXTENSION BYTE b5:1;__EXTENSION BYTE b6:1;__EXTENSION BYTE b7:1;} bits;
} BYTE_VAL, BYTE_BITS;typedef union
{WORD Val;BYTE v[2];struct{BYTE LB;BYTE HB;} byte;struct{__EXTENSION BYTE b0:1;__EXTENSION BYTE b1:1;__EXTENSION BYTE b2:1;__EXTENSION BYTE b3:1;__EXTENSION BYTE b4:1;__EXTENSION BYTE b5:1;__EXTENSION BYTE b6:1;__EXTENSION BYTE b7:1;__EXTENSION BYTE b8:1;__EXTENSION BYTE b9:1;__EXTENSION BYTE b10:1;__EXTENSION BYTE b11:1;__EXTENSION BYTE b12:1;__EXTENSION BYTE b13:1;__EXTENSION BYTE b14:1;__EXTENSION BYTE b15:1;} bits;
} WORD_VAL, WORD_BITS;typedef union
{DWORD Val;WORD w[2];BYTE v[4];struct{WORD LW;WORD HW;} word;struct{BYTE LB;BYTE HB;BYTE UB;BYTE MB;} byte;struct{WORD_VAL low;WORD_VAL high;}wordUnion;struct{__EXTENSION BYTE b0:1;__EXTENSION BYTE b1:1;__EXTENSION BYTE b2:1;__EXTENSION BYTE b3:1;__EXTENSION BYTE b4:1;__EXTENSION BYTE b5:1;__EXTENSION BYTE b6:1;__EXTENSION BYTE b7:1;__EXTENSION BYTE b8:1;__EXTENSION BYTE b9:1;__EXTENSION BYTE b10:1;__EXTENSION BYTE b11:1;__EXTENSION BYTE b12:1;__EXTENSION BYTE b13:1;__EXTENSION BYTE b14:1;__EXTENSION BYTE b15:1;__EXTENSION BYTE b16:1;__EXTENSION BYTE b17:1;__EXTENSION BYTE b18:1;__EXTENSION BYTE b19:1;__EXTENSION BYTE b20:1;__EXTENSION BYTE b21:1;__EXTENSION BYTE b22:1;__EXTENSION BYTE b23:1;__EXTENSION BYTE b24:1;__EXTENSION BYTE b25:1;__EXTENSION BYTE b26:1;__EXTENSION BYTE b27:1;__EXTENSION BYTE b28:1;__EXTENSION BYTE b29:1;__EXTENSION BYTE b30:1;__EXTENSION BYTE b31:1;} bits;
} DWORD_VAL;/* MPLAB C Compiler for PIC18 does not support 64-bit integers */
#if !defined(__18CXX)
typedef union
{QWORD Val;DWORD d[2];WORD w[4];BYTE v[8];struct{DWORD LD;DWORD HD;} dword;struct{WORD LW;WORD HW;WORD UW;WORD MW;} word;struct{__EXTENSION BYTE b0:1;__EXTENSION BYTE b1:1;__EXTENSION BYTE b2:1;__EXTENSION BYTE b3:1;__EXTENSION BYTE b4:1;__EXTENSION BYTE b5:1;__EXTENSION BYTE b6:1;__EXTENSION BYTE b7:1;__EXTENSION BYTE b8:1;__EXTENSION BYTE b9:1;__EXTENSION BYTE b10:1;__EXTENSION BYTE b11:1;__EXTENSION BYTE b12:1;__EXTENSION BYTE b13:1;__EXTENSION BYTE b14:1;__EXTENSION BYTE b15:1;__EXTENSION BYTE b16:1;__EXTENSION BYTE b17:1;__EXTENSION BYTE b18:1;__EXTENSION BYTE b19:1;__EXTENSION BYTE b20:1;__EXTENSION BYTE b21:1;__EXTENSION BYTE b22:1;__EXTENSION BYTE b23:1;__EXTENSION BYTE b24:1;__EXTENSION BYTE b25:1;__EXTENSION BYTE b26:1;__EXTENSION BYTE b27:1;__EXTENSION BYTE b28:1;__EXTENSION BYTE b29:1;__EXTENSION BYTE b30:1;__EXTENSION BYTE b31:1;__EXTENSION BYTE b32:1;__EXTENSION BYTE b33:1;__EXTENSION BYTE b34:1;__EXTENSION BYTE b35:1;__EXTENSION BYTE b36:1;__EXTENSION BYTE b37:1;__EXTENSION BYTE b38:1;__EXTENSION BYTE b39:1;__EXTENSION BYTE b40:1;__EXTENSION BYTE b41:1;__EXTENSION BYTE b42:1;__EXTENSION BYTE b43:1;__EXTENSION BYTE b44:1;__EXTENSION BYTE b45:1;__EXTENSION BYTE b46:1;__EXTENSION BYTE b47:1;__EXTENSION BYTE b48:1;__EXTENSION BYTE b49:1;__EXTENSION BYTE b50:1;__EXTENSION BYTE b51:1;__EXTENSION BYTE b52:1;__EXTENSION BYTE b53:1;__EXTENSION BYTE b54:1;__EXTENSION BYTE b55:1;__EXTENSION BYTE b56:1;__EXTENSION BYTE b57:1;__EXTENSION BYTE b58:1;__EXTENSION BYTE b59:1;__EXTENSION BYTE b60:1;__EXTENSION BYTE b61:1;__EXTENSION BYTE b62:1;__EXTENSION BYTE b63:1;} bits;
} QWORD_VAL;
#endif /* __18CXX */#undef __EXTENSION#ifdef __cplusplus}
#endif
#endif /* __GENERIC_TYPE_DEFS_H_ */
問題:
..\EtherCAT\Src\9252_HW.c(316): warning: #223-D: function "ConfigIntTimer5" declared implicitlyConfigIntTimer5(T5_INT_ON | T5_INT_PRIOR_3 );
沒有定義的函數,直接刪除。
問題:
..\EtherCAT\Inc\eoeappl.h(209): error: #1032: Definition of nested anonymous union in packed "struct <unnamed>" must be __packed} u; /**< \brief Data*/
這個錯誤是由 __packed 關鍵字引發的,我們直接使用Ctrl+F全局搜索關鍵字packed,追蹤到了ecat_def.h的742行和754行,將這兩個宏后面的映射語句刪掉,使其變成空的宏。
修改完這處錯誤不出意外的話再次編譯就不會報錯了,剩下的一些警告可以自己解決,當然,直接無視也沒什么問題。
接下來就是將協議棧暴露給我們的幾個函數在代碼相應的位置調用,以及編寫自己的業務邏輯。
?1.在 LAN9252_IRQ引腳對應的中斷服務程序中調用 PDI_Isr();我這里對應的是EXTI0
#include "applInterface.h" //添加頭文件void EXTI0_IRQHandler(void)
{/* USER CODE BEGIN EXTI0_IRQn 0 */PDI_Isr();/* USER CODE END EXTI0_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(LAN9252_IRQ_Pin);/* USER CODE BEGIN EXTI0_IRQn 1 *//* USER CODE END EXTI0_IRQn 1 */
}
2.在 LAN9252_SUNC0和LAN9252_SUNC1引腳對應的中斷服務程序中調用 Sync0_Isr() 和 Sync1_Isr()
/*** @brief This function handles EXTI line1 interrupt.*/
void EXTI1_IRQHandler(void)
{/* USER CODE BEGIN EXTI1_IRQn 0 */DISABLE_ESC_INT();Sync1_Isr();ENABLE_ESC_INT();/* USER CODE END EXTI1_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(LAN9252_SYNC1_Pin);/* USER CODE BEGIN EXTI1_IRQn 1 *//* USER CODE END EXTI1_IRQn 1 */
}/*** @brief This function handles EXTI line3 interrupt.*/
void EXTI3_IRQHandler(void)
{/* USER CODE BEGIN EXTI3_IRQn 0 */DISABLE_ESC_INT();Sync0_Isr();ENABLE_ESC_INT();/* USER CODE END EXTI3_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(LAN9252_SYNC0_Pin);/* USER CODE BEGIN EXTI3_IRQn 1 *//* USER CODE END EXTI3_IRQn 1 */
}
注意,設備上電后我們不可以直接調用HAL_NVIC_EnableIRQ函數將各種中斷使能,因為此時協議棧相關數據都沒初始化好,直接使能這些中斷將導致嚴重的邏輯問題。
因此我們需要回到gpio.c中,將CuboMX自動生成的使能語句注釋掉。
位置在MX_GPIO_Init()函數的結尾。/* EXTI interrupt init*/HAL_NVIC_SetPriority(EXTI0_IRQn, 1, 0);// HAL_NVIC_EnableIRQ(EXTI0_IRQn);HAL_NVIC_SetPriority(EXTI1_IRQn, 2, 0);// HAL_NVIC_EnableIRQ(EXTI1_IRQn);HAL_NVIC_SetPriority(EXTI3_IRQn, 2, 0);// HAL_NVIC_EnableIRQ(EXTI3_IRQn);
3. 在自己設置的1ms定時器的中斷服務函數中調用ECAT_CheckTimer()
void TIM7_IRQHandler(void)
{/* USER CODE BEGIN TIM7_IRQn 0 */ECAT_CheckTimer();/* USER CODE END TIM7_IRQn 0 */HAL_TIM_IRQHandler(&htim7);/* USER CODE BEGIN TIM7_IRQn 1 *//* USER CODE END TIM7_IRQn 1 */
}
4. 在主函數中添加頭文件 #include "applInterface.h" ,調用協議棧的初始化函數HW_Init()和MainInit(),并在while循環中調用MainLoop。
主函數中最好只放一個MainLoop函數,應用邏輯寫在APPL_Application函數中,需要注意不要在APPL_Application函數中進行耗時操作,如果耗時操作無法避免,可以另加操作系統,在其他線程中處理,否則會導致通信異常。
/* USER CODE BEGIN 2 */HW_Init();MainInit();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */MainLoop();}
5. 完成上述步驟剩下的就是在協議棧開放給我們的業務邏輯接口中編輯自己的業務邏輯。
如果你們一開始使用SSC生成協議棧時沒自己命名的話,接口可以在PIC32 EtherCAT Slave.c文件中找到。
需要自己寫的主要是下面三個函數:
//輸入數據映射,將需要發送的數據映射到pData指向的空間
void APPL_InputMapping(UINT16* pData) //輸出數據映射,將想要接收的數據從pData指向的空間取出
void APPL_OutputMapping(UINT16* pData) //應用邏輯
void APPL_Application(void)
下面是我的一段參考代碼,變量Value0x6000與Led0x7000是與自己當時在Excel中添加的字典是一一對應的,變量名可以在 PIC32 EtherCAT SlaveQbjects.h 文件中找到,以后如果需要修改對象字典只需要使用SSC重新生成協議棧文件將后,把工程原有的PIC32 EtherCAT SlaveQbjects.h 替換成新生成的,并重寫這三個函數即可。
/
/**
\param pData pointer to input process data\brief This function will copies the inputs from the local memory to the ESC memoryto the hardware
*
void APPL_InputMapping(UINT16* pData)
{pData[0] = Values0x6000.V1;pData[1] = Values0x6000.V2;
}
;
/
/**
\param pData pointer to output process data\brief This function will copies the outputs from the ESC memory to the local memoryto the hardware
*
void APPL_OutputMapping(UINT16* pData)
{Led0x7000.D1 = *pData;
}/
/**
\brief This function will called from the synchronisation ISR or from the mainloop if no synchronisation is supported
*
void APPL_Application(void)
{Values0x6000.V1 = 0x1234;Values0x6000.V2 = 0x5678;Led0x7000.D1 ? HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET) : HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET);}
至此我們的一個基于STM32和LAN9252的簡單從站就完成了,下面就是使用TwinCAT往EEPROM中燒寫XML文件并測試了。
四、測試
我這里使用的是 TwinCAT3 ,依然是自己找資源下載即可。
1.將 C:\TwinCAT\3.1\Config\Io\EtherCAT 路徑下的所有 .xml 文件刪除,并將SSC生成的XML文件拷貝過來。
?2.打開TwinCAT3新建一個EtherCAT工程,FILE -> New -> Project
?3. 先用一根網線將你的電路板與電腦連接起來,然后添加網卡驅動 TWNCAT -> Show Realtime EtherCAT Compatible Devices...
4. 掃描設備,一路確定,等待EEPROM燒寫完成
? ? ? ? ?
?下面這種狀態就表示通信成功了
?觀察是否輸出了自己期望的數據以及能否正常控制LED
?
到此就恭喜各位完成了STM32+LAN9252從站的搭建。?