STM32CUBEMX+STM32H750VB+LWIP+LAN8720A+FREERTOS TCP伺服器、UDP資料接收發送、網線熱插拔、IAR-8.32開發

STM32CUBEMX+STM32H750VB+LWIP+LAN8720A+FREERTOS TCP伺服器、UDP資料接收發送、網線熱插拔、IAR-8.32開發

  • STM32H750VB
    • 使用STM32CUBEMX生成工程
    • IAR+J-LINK除錯準備工作
    • CUBEMX生成的程式碼問題所在

STM32H750VB

這是一款比較新的Cortex-M7內核的MCU,因為專案原因,需要一款RAM大(1024KB),主頻高(480M)的晶片,我司的硬體工程師選擇了他。

使用STM32CUBEMX生成工程

需要注意的是為什麼不使用標準庫,而選用大多數嵌入式工程師不是很熟悉的STM32CUBEMX生成的HAL庫完全是因為找不到標準庫啊!啊!啊!,當然也有學習新開發工具的想法

我使用的是STM32CUBEMX_V5.6.1

1.首先選擇晶片(STM32H750VB

2.配置時鐘,選擇HSE(根據實際PCB選擇

3.配置HAL庫時鐘,選擇TIM1,因為需要上FreeRTOS系統,而系統的節拍器通常會選擇系統滴答定時器systick,所以我們這裡選擇TIM1作為庫定時器而不是systick。


4.使能Cache和MPU記憶體保護單元
因為H7結構體的特殊,LWIP網路需要使用的RAM要MPU保護,並且地址也是定死的0x30040000開始,和F4隨意定義不同
具體為何這麼設定得去看H750的使用者手冊

5.PHY晶片設定,PCB選用的是LAN8720A,雖然STM32CUBEMX選用的是LAN8742,但其實並沒有什麼很大的區別(即使區別不大,CUBEMX直接生成的程式也並不能讓你ping通網路,可能是晶片比較新,好多功能沒有得到實際驗證,具體如何修改,下面會進行詳細描述)。

6.FREERTOS系統設定,需要注意的也就衹有TOTAL_HEAP_SIZE,你需要根據實際需要設定大小,其他的就是用什麼使能什麼,譬如:使用訊號量的話就使能SEMAPHORE 等等。

7.LWIP設定,主要設定3個地方,注重注意的就是LWIP_NETIF_LINK_CALLBACK需要使能
通用設定很常規,這裡我不要DHCP,就除能設定成了靜態IP

使能了LINK_CALLBACK之後,就多了一個網線插拔時會進入的回呼函式,你就可以在裡面處理一些事情,不做也可以,他會自動deinit-ETH

PHY晶片選擇LAN8742A
8.隨意設定一個執行燈新增在TASK裡面,用來檢視程式執行狀態就結束可以生成程式了。

IAR+J-LINK除錯準備工作

因為STM32H750是一款很新的晶片,所以會出現,J-LINK和IAR中都沒有這款晶片的情況,這個時候就需要更新IDE和J-LIN了,我更新到了IAR8.32和J-LINK6.84。
這裡要吐槽的一點是IAR8.32真的是個垃圾,除錯的時候,只是把滑鼠放在變數名字上都會閃退,更別說在watch中看陣列了。

CUBEMX生成的程式碼問題所在

1.因為我task多,MX_LWIP_Init();這個LWIP初始化函式是在任務中,是開啟了系統任務排程之後才初始化的,就導致了PHY晶片初始化沒有完成的問題。

解決方法:
ethernetif.c中、

1
static void low_level_init(struct netif *netif)
1
2
3
4
5
6
7
8
9
10
11
12
13
/* USER CODE BEGIN PHY_PRE_CONFIG */
 
  HAL_GPIO_WritePin(GPIOC,GPIO_PIN_2,GPIO_PIN_RESET);
  HAL_Delay(50);
  HAL_GPIO_WritePin(GPIOC,GPIO_PIN_2,GPIO_PIN_SET);     //LAN8720A重定
 
/* USER CODE END PHY_PRE_CONFIG */
  /* Set PHY IO functions */
  LAN8742_RegisterBusIO(&LAN8742, &LAN8742_IOCtx);

  /* Initialize the LAN8742 ETH PHY */
  while(LAN8742_Init(&LAN8742) != LAN8742_STATUS_OK)    //需要寫一個while確保LAN8742_Init成功
        ;

新增一個重定功能和while等待初始化完成功能。

2.因為硬體上面沒有硬體上拉採用的自動協商,所以在軟體中也要完成自動協商,在初始化完成後新增

1
static void low_level_init(struct netif *netif)
1
2
3
/* USER CODE BEGIN PHY_POST_CONFIG */
LAN8742_StartAutoNego(&LAN8742);      //啟動自動協商
/* USER CODE END PHY_POST_CONFIG */

2.ETH_RX_BUFFER_SIZE的巨集定義是 1536UL
而生成程式碼

1
heth.Init.RxBuffLen = 1528;

需要改成

1
heth.Init.RxBuffLen = ETH_RX_BUFFER_SIZE;

3.清除高速Cache

1
static err_t low_level_output(struct netif *netif, struct pbuf *p)
1
2
3
4
5
6
7
  TxConfig.Length = framelen;
  TxConfig.TxBuffer = Txbuffer;

  SCB_CleanInvalidateDCache();        //清除Cache緩衝區
  HAL_ETH_Transmit(&heth, &TxConfig, ETH_DMA_TRANSMIT_TIMEOUT);
 
  return errval;
1
static struct pbuf * low_level_input(struct netif *netif)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  if (HAL_ETH_GetRxDataBuffer(&heth, &RxBuff) == HAL_OK)
  {<!-- -->
    SCB_CleanInvalidateDCache();        //清除Cache緩衝區
   
    HAL_ETH_GetRxDataLength(&heth, &framelength);
   
    /* Build Rx descriptor to be ready for next data reception */
    HAL_ETH_BuildRxDescriptors(&heth);
   
    SCB_InvalidateDCache_by_Addr((uint32_t *)Rx_Buff, (ETH_RX_DESC_CNT*ETH_RX_BUFFER_SIZE));
   
#if !defined(DUAL_CORE) || defined(CORE_CM7)
    /* Invalidate data cache for ETH Rx Buffers */
    SCB_InvalidateDCache_by_Addr((uint32_t *)RxBuff.buffer, framelength);
#endif

    custom_pbuf  = (struct pbuf_custom*)LWIP_MEMPOOL_ALLOC(RX_POOL);
    custom_pbuf->custom_free_function = pbuf_free_custom;

    p = pbuf_alloced_custom(PBUF_RAW, framelength, PBUF_REF, custom_pbuf, RxBuff.buffer, ETH_RX_BUFFER_SIZE);
  }

4.系統時鐘初始化完成後需要初始化SRAM3的時鐘

1
2
3
  /* USER CODE BEGIN SysInit */
  __HAL_RCC_D2SRAM3_CLK_ENABLE();       //啟動SRAM3的時鐘
  /* USER CODE END SysInit */

這樣就差不多了,我會把裡面的相關資源上傳

https://download.csdn.net/download/qq_37433166/15599386 J-LINK下載