多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
我们打开裸机工程之后,就创建一个文件夹,命名为eth,并且在该文件夹下创建两个文件,分别为bsp\_eth.c与bsp\_eth.h文件,具体见图 3‑12。 ![](https://box.kancloud.cn/90719b903f0e747bc36ea9113f9aa02b_620x118.png) 图 3‑12创建bsp\_eth.c与bsp\_eth.h文件 然后再将bsp\_eth.c文件添加到工程分组中,具体见图 3‑13。 ![](https://box.kancloud.cn/5e8ae191ec0e4cbf554c50b34aace10c_312x231.png) 图 3‑13将bsp\_eth.c添加到工程中 然后我们就可以在bsp\_eth.c文件中进行初始化eth驱动了,暂时加入以下代码,具体见代码清单 3‑1。 ``` 1 /** 2 ****************************************************************************** 3 * @file main.c 4 * @author fire 5 * @version V1.0 6 * @date 2019-xx-xx 7 * @brief eth 8 ********************************************************************* 9 * @attention 10 * 11 * 实验平台:野火 STM32 F429 开发板 12 * 论坛 :http://www.firebbs.cn 13 * 淘宝 :http://firestm32.taobao.com 14 * 15 *********************************************************************** 16 */ 17 #include "./eth/bsp_eth.h" 18 #include "main.h" 19 20 21 #ifndef PRINT_DEBUG 22 #define PRINT_DEBUG 23 #endif 24 25 #ifndef PRINT_ERR 26 #define PRINT_ERR 27 #endif 28 29 /* Global Ethernet handle */ 30 ETH_HandleTypeDef heth; 31 32 #if defined ( __ICCARM__ ) /*!< IAR Compiler */ 33 #pragma data_alignment=4 34 #endif 35 __ALIGN_BEGIN ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB] __ALIGN_END; 36 /* Ethernet Rx MA Descriptor */ 37 38 #if defined ( __ICCARM__ ) /*!< IAR Compiler */ 39 #pragma data_alignment=4 40 #endif 41 __ALIGN_BEGIN ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB] __ALIGN_END; 42 /* Ethernet Tx DMA Descriptor */ 43 44 #if defined ( __ICCARM__ ) /*!< IAR Compiler */ 45 #pragma data_alignment=4 46 #endif 47 __ALIGN_BEGIN uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __ALIGN_END; 48 /* Ethernet Receive Buffer */ 49 50 #if defined ( __ICCARM__ ) /*!< IAR Compiler */ 51 #pragma data_alignment=4 52 #endif 53 __ALIGN_BEGIN uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __ALIGN_END; 54 /* Ethernet Transmit Buffer */ 55 56 57 void HAL_ETH_MspInit(ETH_HandleTypeDef* ethHandle) 58 { 59 GPIO_InitTypeDef GPIO_InitStruct; 60 if (ethHandle->Instance==ETH) 61 { 62 /* USER CODE BEGIN ETH_MspInit 0 */ 63 64 /* USER CODE END ETH_MspInit 0 */ 65 // /* Enable Peripheral clock */ 66 // __HAL_RCC_ETH_CLK_ENABLE(); 67 68 /**ETH GPIO Configuration 69 PC1 ------> ETH_MDC 70 PA1 ------> ETH_REF_CLK 71 PA2 ------> ETH_MDIO 72 PA7 ------> ETH_CRS_DV 73 PC4 ------> ETH_RXD0 74 PC5 ------> ETH_RXD1 75 PB11 ------> ETH_TX_EN 76 PG13 ------> ETH_TXD0 77 PG14 ------> ETH_TXD1 78 */ 79 GPIO_InitStruct.Pin = ETH_MDC_Pin|ETH_RXD0_Pin|ETH_RXD1_Pin; 80 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 81 GPIO_InitStruct.Pull = GPIO_NOPULL; 82 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 83 GPIO_InitStruct.Alternate = GPIO_AF11_ETH; 84 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); 85 86 GPIO_InitStruct.Pin = ETH_REF_CLK_Pin|ETH_MDIO_Pin|ETH_CRS_DV_Pin; 87 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 88 GPIO_InitStruct.Pull = GPIO_NOPULL; 89 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 90 GPIO_InitStruct.Alternate = GPIO_AF11_ETH; 91 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 92 93 GPIO_InitStruct.Pin = ETH_TX_EN_Pin; 94 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 95 GPIO_InitStruct.Pull = GPIO_NOPULL; 96 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 97 GPIO_InitStruct.Alternate = GPIO_AF11_ETH; 98 HAL_GPIO_Init(ETH_TX_EN_GPIO_Port, &GPIO_InitStruct); 99 100 GPIO_InitStruct.Pin = ETH_TXD0_Pin|ETH_TXD1_Pin; 101 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 102 GPIO_InitStruct.Pull = GPIO_NOPULL; 103 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 104 GPIO_InitStruct.Alternate = GPIO_AF11_ETH; 105 HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); 106 107 /* USER CODE BEGIN ETH_MspInit 1 */ 108 /* Enable the Ethernet global Interrupt */ 109 HAL_NVIC_SetPriority(ETH_IRQn, 6, 0); 110 HAL_NVIC_EnableIRQ(ETH_IRQn); 111 112 /* Enable ETHERNET clock */ 113 __HAL_RCC_ETH_CLK_ENABLE(); 114 /* USER CODE END ETH_MspInit 1 */ 115 } 116 } 117 118 static void Eth_Reset(void) 119 { 120 /* PHY RESET: PI1 */ 121 GPIO_InitTypeDef GPIO_InitStructure; 122 __HAL_RCC_GPIOI_CLK_ENABLE(); 123 124 GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; 125 GPIO_InitStructure.Pull = GPIO_PULLUP; 126 GPIO_InitStructure.Speed = GPIO_SPEED_FAST; 127 GPIO_InitStructure.Pin = GPIO_PIN_1; 128 HAL_GPIO_Init(GPIOI, &GPIO_InitStructure); 129 HAL_GPIO_WritePin(GPIOI, GPIO_PIN_1, GPIO_PIN_RESET); 130 HAL_Delay(5); 131 HAL_GPIO_WritePin(GPIOI, GPIO_PIN_1, GPIO_PIN_SET); 132 HAL_Delay(5); 133 } 134 135 void HAL_ETH_MspDeInit(ETH_HandleTypeDef* ethHandle) 136 { 137 if (ethHandle->Instance==ETH) 138 { 139 /* USER CODE BEGIN ETH_MspDeInit 0 */ 140 141 /* USER CODE END ETH_MspDeInit 0 */ 142 /* Peripheral clock disable */ 143 __HAL_RCC_ETH_CLK_DISABLE(); 144 145 /**ETH GPIO Configuration 146 PC1 ------> ETH_MDC 147 PA1 ------> ETH_REF_CLK 148 PA2 ------> ETH_MDIO 149 PA7 ------> ETH_CRS_DV 150 PC4 ------> ETH_RXD0 151 PC5 ------> ETH_RXD1 152 PB11 ------> ETH_TX_EN 153 PG13 ------> ETH_TXD0 154 PG14 ------> ETH_TXD1 155 */ 156 HAL_GPIO_DeInit(GPIOC, ETH_MDC_Pin|ETH_RXD0_Pin|ETH_RXD1_Pin); 157 158 HAL_GPIO_DeInit(GPIOA, ETH_REF_CLK_Pin|ETH_MDIO_Pin|ETH_CRS_DV_Pin); 159 160 HAL_GPIO_DeInit(ETH_TX_EN_GPIO_Port, ETH_TX_EN_Pin); 161 162 HAL_GPIO_DeInit(GPIOG, ETH_TXD0_Pin|ETH_TXD1_Pin); 163 164 /* USER CODE BEGIN ETH_MspDeInit 1 */ 165 166 /* USER CODE END ETH_MspDeInit 1 */ 167 } 168 } 169 170 HAL_StatusTypeDef Bsp_Eth_Init(void) 171 { 172 HAL_StatusTypeDef ret; 173 174 uint8_t MACAddr[6] ; 175 176 HAL_ETH_DeInit(&heth); 177 178 Eth_Reset(); 179 180 ETH->DMABMR |= ETH_DMABMR_SR; 181 182 /* Init ETH */ 183 MACAddr[0] = 0x02; 184 MACAddr[1] = 0x00; 185 MACAddr[2] = 0x00; 186 MACAddr[3] = 0x00; 187 MACAddr[4] = 0x00; 188 MACAddr[5] = 0x00; 189 heth.Instance = ETH; 190 heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE; 191 heth.Init.PhyAddress = LAN8720_PHY_ADDRESS; 192 heth.Init.MACAddr = &MACAddr[0]; 193 heth.Init.RxMode = ETH_RXPOLLING_MODE; // rx mode 194 heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE; 195 heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII; 196 heth.Init.Speed = ETH_SPEED_100M; //speed 197 heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX; 198 199 /* configure ethernet peripheral (GPIOs, clocks, MAC, DMA) */ 200 ret = HAL_ETH_Init(&heth); 201 if (ret == HAL_OK) 202 PRINT_DEBUG("eth hardware init sucess...\n"); 203 else 204 PRINT_DEBUG("eth hardware init faild...\n"); 205 206 /* Initialize Tx Descriptors list: Chain Mode */ 207 HAL_ETH_DMATxDescListInit(&heth, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB); 208 209 /* Initialize Rx Descriptors list: Chain Mode */ 210 HAL_ETH_DMARxDescListInit(&heth, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB); 211 /* Enable MAC and DMA transmission and reception */ 212 return ret; 213 } 214 215 216 void ETH_IRQHandler(void) 217 { 218 HAL_ETH_IRQHandler(&heth); 219 220 } 221 222 /** 223 * @brief Ethernet Rx Transfer completed callback 224 * @param heth: ETH handle 225 * @retval None 226 */ 227 228 void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth) 229 { 230 231 } 232 233 void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth) 234 { 235 ; 236 } 237 238 void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) 239 { 240 PRINT_ERR("eth err\n"); 241 } ``` STM32的HAL库使用一个数据结构对以太网进行描述,我们可以认为那是一个以太网的句柄,记录着以太网的注册基地址、连接状态、发送描述、接收描述等等,该数据结构是ETH\_HandleTypeDef,具体见代码清单 3‑2。在bsp\_eth.c我们需要定义一个用于描述以太网的数据结构heth,这样子我们就能通过heth对以太网进行初始化、收发数据等操作。 ``` 1 typedef struct 2 { 3 ETH_TypeDef *Instance; /*!< Register base address */ 4 5 ETH_InitTypeDef Init; /*!< Ethernet Init Configuration */ 6 7 uint32_t LinkStatus; /*!< Ethernet link status */ 8 9 ETH_DMADescTypeDef *RxDesc; /*!< Rx descriptor to Get */ 10 11 ETH_DMADescTypeDef *TxDesc; /*!< Tx descriptor to Set */ 12 13 ETH_DMARxFrameInfos RxFrameInfos; /*!< last Rx frame infos */ 14 15 __IO HAL_ETH_StateTypeDef State; /*!< ETH communication state */ 16 17 HAL_LockTypeDef Lock; /*!< ETH Lock */ 18 19 } ETH_HandleTypeDef; ``` 我们先看一下我们的Bsp\_Eth\_Init()函数,调用HAL库的HAL\_ETH\_DeInit(&heth)进行复位ETH 配置,该复位函数内部会调用我们bsp\_eth.c文件中的HAL\_ETH\_MspDeInit()函数,然后我们再对heth的参数进行初始化,如开启网络自适应功能,速度和工作模式无需配置、设置PHY的地址、设置MAC地址、设置接收网络数据的方式为中断方式、设置检查校验为硬件校验、设置以太网速度为100M等等,然后调用HAL库的HAL\_ETH\_Init()函数将以太网进行初始化,在初始化的时候,会调用HAL\_ETH\_MspInit()对以太网的接口进行初始化,所以,我们的bsp\_eth.c文件需要对HAL\_ETH\_MspInit()进行封装,根据我们的硬件接口(IO接口)进行初始化操作,再对以太网的收发数据描述列表,无需我们理会,这些HAL库已经帮我们处理好了,这样子,一个以太网接口基本就初始化完成,但是,收发数据的操作还需要我们自己写驱动,所以我们暂时还不可以使用它进行网络数据的收发操作,因为数据的收发需要配合LwIP,会在后面的章节中进行介绍。