文章目录
- 目的
- 基础说明
- 关键配置
- 关键代码
- 示例链接
- 总结
目的
以太网是比较常用到的功能,STM32系列单片机使用CubeMX配置使用以太网功能比非常方便。不过对于H7系列来说需要使能 DCache 才能启用LwIP,启用Cache后又会带来一些需要特别注意的事情。这篇文章将对相关内容进行介绍。
基础说明
STM32单片机以太网基础的配置启用等内容可以参考我之前的文章:
《STM32单片机示例:ETH_DP83848_DHCP_NonOS_Poll_F407》
目前虽然在CubeMX中需要配置 DCache 才能启用LwIP,但是配置生成的代码里直接注释掉主函数头部的 SCB_EnableDCache();
,以太网和LwIP也能正常工作,如果没有特别要求的话完全可以这样就直接用。
如果要使用 DCache 的话就需要特别注意DMA和CPU读写同一片内存数据不同步的问题了。
一种简单的解决方案是在 low_level_output
中使用 SCB_CleanDCache...
将Cache中数据更新到SRAM;在 low_level_input
中将使用 SCB_InvalidateDCache...
将SRAM中数据加载到Cache。
当然只要合理设置MPU,也可以不用清Cache和无效化Cache操作,比如官方例程的设置:
https://github.com/stm32-hotspot/STM32H7-LwIP-Examples
需要注意的是上面官方例程中虽然都是H7系列的,但是根据内存大小的不同,内存分布设置也是不同的,可以通过全局搜索 ETH_CODE
关键词来查看各个项目中相关的改动。
上面官方例程都是使用了 FreeRTOS ,下面将不使用操作系统的情况进行演示。
关键配置
时钟:
Cache和MPU:
以太网:
LwIP:
堆栈:
关键代码
main.c
中一些手动添加的代码:
#include "main.h"
#include "lwip.h"UART_HandleTypeDef huart6;/* With GCC, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch) // 实现__io_putchar函数
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */PUTCHAR_PROTOTYPE
{HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xFFFF); // for printf()return ch;
}int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_LWIP_Init(); // 初始化网络功能MX_USART6_UART_Init();while (1){MX_LWIP_Process(); // 处理网络相关事务static uint32_t previous = 0;if((HAL_GetTick() - previous)>=1000){previous = HAL_GetTick();extern struct netif gnetif; // 网卡对象,在lwip.c文件中定义// 打印时间和IP地址printf("%ld - loop: ip addr %s\n", HAL_GetTick(), ip4addr_ntoa(netif_ip_addr4(&gnetif)));}}
}
lwip.c
中一些手动添加的代码:
/*** @brief Notify the User about the network interface config status* @param netif: the network interface*/
static void ethernet_link_status_updated(struct netif *netif)
{if (netif_is_up(netif)){printf("%ld - link status callback: netif_is_up!\n", HAL_GetTick());}else /* netif is down */{printf("%ld - link status callback: netif_is_down!\n", HAL_GetTick());}
}
STM32H743ZITX_FLASH.ld
中一些手动添加的代码:
...} >RAM_D1/* ETH_CODE: add placement of DMA descriptors and RX buffers */.lwip_sec (NOLOAD) :{. = ABSOLUTE(0x30040000);*(.RxDecripSection) . = ABSOLUTE(0x30040060);*(.TxDecripSection). = ABSOLUTE(0x30040200);*(.Rx_PoolSection) } >RAM_D2/* Remove information from the standard libraries *//DISCARD/ :...
ethernetif.c
中一些手动添加的代码:
/* USER CODE BEGIN 2 */
/* ETH_CODE: placement of RX_POOL* Please note this was tested only for GCC compiler.* Additional code needed in linkerscript for GCC.** Also this buffer can be placed in D1 SRAM* if there is not sufficient space in D2.* This can be case of STM32H72x/H73x devices.* However the 32-byte alignment should be forced.* Below is example of placement into BSS section** . = ALIGN(32);* *(.Rx_PoolSection)* . = ALIGN(4);* _ebss = .;* __bss_end__ = _ebss;* } >RAM_D1*/
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma location = 0x30040200
extern u8_t memp_memory_RX_POOL_base[];#elif defined ( __CC_ARM ) /* MDK ARM Compiler */
__attribute__((at(0x30040200)) extern u8_t memp_memory_RX_POOL_base[];#elif defined ( __GNUC__ ) /* GNU Compiler */
__attribute__((section(".Rx_PoolSection"))) extern u8_t memp_memory_RX_POOL_base[];#endif
/* USER CODE END 2 */
上面的修改可能会在有些编译环境下保存,可以 lwipopts.h
中一些手动添加的代码:
/* USER CODE BEGIN 1 /
#undef LWIP_PROVIDE_ERRNO
#define LWIP_ERRNO_STDINCLUDE
/ USER CODE END 1 */
示例链接
仓库地址: https://github.com/NaisuXu/STM32_MCU_Examples
本文中的示例位于仓库中 ETH_LAN8742_DHCP_NonOS_Poll_H743
。
总结
通过上面的配置和改动就网络部分就可以正常使用了。之后网络应用的开发同样还是参考官方例程和文档:
《UM1713 使用 LwIP TCP/IP 栈,在 STM32Cube 上开发应用》