本帖最后由 芯领域电子科技 于 2024-7-16 10:25 编辑
#申请原创# @小跑堂
1、MM32F3270简介
MM32F3270系列MCU使用高性能的ARM Cortex-M3为内核的32位微控制器,最高工作频率可达120MHz,内置高速存储器,256KB FLASH & 128KB SRAM,丰富的 I/O 端口和外设连接到外部总线。本产品包含多达3个12位的ADC、2个比较器、 2个16 位通用定时器、2个32 位通用定时器、2个16 位基本定时器和2个16位高级定时器。还包含标准的通信接口:2 个I2C接口、3个I2S接口、3个SPI 接口、1个USB OTG全速接口、1个CAN接口、1个SDIO接口和8个UART接口。
2、W5500简介
W5500是一款全硬件TCP/IP嵌入式以太网控制器,为嵌入式系统提供了更加简易的互联网连接方案。 W5500集成了TCP/IP协议栈,10/100M以太网数据链路层(MAC)及物理层(PHY),使得用户使用单芯片就能够在他们的应用中拓展网络连接。W5500内置的全硬件TCP/IP协议栈支持TCP,UDP,IPv4,ICMP,ARP,IGMP以及 PPPoE协议。W5500还内嵌了32K字节片上缓存以供以太网包处理。如果使用W5500,只需要一些简单的Socket编程就轻松能实现以太网应用。这将会比其他嵌入式以太网方案更加快捷、简便。
3、硬件原理图
我们直接购买了一块使用STM32F103C8T6作为主控MCU的W5500开发板。对于MM32F3270系列MCU支持LQFP48/64/100/144四种封装形式,与STM32F103系列在硬件上能够做到完全的PIN TO PIN兼容,所以我们将板载的STM32F103C8T6直接替换成MM32F3270G6P,原理图如下所示:
通过如上原理图获知,PC13控制LED发光二极管、PA0作为输入按键检测端口引脚、PA9/PA10作为UART串口功能,连接到了RS232芯片上,与DB9相连接、最后就是MM32F3273与W5500连接的部分了,使用PA2作为W5500的硬件复位控制引脚、使用PA3作为W5500的中断输入检测引脚、使用SPI1(PA4/PA5/PA6/PA7)与W5500的SPI通讯接口相连接,实现数据交互。
4、程序设计
4.1.下载MM32F3270系列MCU的官方库函数与例程:
https://www.mindmotion.com.cn/products/mm32mcu/performance_line/mm32f_performance/mm32f3270/
4.2.下载W5500官方的库函数与例程:
https://github.com/Wiznet/ioLibrary_Driver
4.3.初始化板载资源配置(KEY、LED、UART、SysTick等)
#define __PLATFORM_C
#include "platform.h"
volatile uint32_t SysTick_DelayTick = 0;
void PLATFORM_InitSysTick(void)
{
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
if (SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000))
{
while (1)
{
}
}
NVIC_SetPriority(SysTick_IRQn, 0x0);
}
void SysTick_DelayMS(uint32_t Tick)
{
SysTick_DelayTick = Tick;
while (SysTick_DelayTick)
{
}
}
void PLATFORM_InitConsole(uint32_t Baudrate)
{
GPIO_InitTypeDef GPIO_InitStruct;
UART_InitTypeDef UART_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2ENR_UART1, ENABLE);
UART_StructInit(&UART_InitStruct);
UART_InitStruct.BaudRate = Baudrate;
UART_InitStruct.WordLength = UART_WordLength_8b;
UART_InitStruct.StopBits = UART_StopBits_1;
UART_InitStruct.Parity = UART_Parity_No;
UART_InitStruct.HWFlowControl = UART_HWFlowControl_None;
UART_InitStruct.Mode = UART_Mode_Tx;
UART_Init(UART1, &UART_InitStruct);
UART_Cmd(UART1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_7);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
int fputc(int ch, FILE *f)
{
UART_SendData(UART1, (uint8_t)ch);
while (RESET == UART_GetFlagStatus(UART1, UART_FLAG_TXEPT))
{
}
return (ch);
}
void PLATFORM_InitKEY(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void PLATFORM_InitLED(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOC, ENABLE);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
}
void PLATFORM_PrintInfo(void)
{
RCC_ClocksTypeDef RCC_Clocks;
printf("\r\n");
printf("\r\nMCU : MM32F3273G6P");
printf("\r\n");
switch (RCC->CFGR & RCC_CFGR_SWS)
{
case 0x00:
printf("\r\nHSI used as system clock source");
break;
case 0x04:
printf("\r\nHSE used as system clock source");
break;
case 0x08:
if (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC)
{
printf("\r\nPLL (clocked by HSE) used as system clock source");
}
else
{
printf("\r\nPLL (clocked by HSI) used as system clock source");
}
break;
case 0x0C:
printf("\r\nLSI used as system clock source");
break;
default:
break;
}
RCC_GetClocksFreq(&RCC_Clocks);
printf("\r\n");
printf("\r\nSYSCLK Frequency : %7.3f MHz", (double)RCC_Clocks.SYSCLK_Frequency / (double)1000000.0);
printf("\r\nHCLK Frequency : %7.3f MHz", (double)RCC_Clocks.HCLK_Frequency / (double)1000000.0);
printf("\r\nPCLK1 Frequency : %7.3f MHz", (double)RCC_Clocks.PCLK1_Frequency / (double)1000000.0);
printf("\r\nPCLK2 Frequency : %7.3f MHz", (double)RCC_Clocks.PCLK2_Frequency / (double)1000000.0);
printf("\r\n");
}
void PLATFORM_Init(void)
{
PLATFORM_InitSysTick();
PLATFORM_InitConsole(115200);
PLATFORM_InitKEY();
PLATFORM_InitLED();
PLATFORM_PrintInfo();
}
4.4.初始化MM32F3273与W5500的控制IO(RST、INT)
对W5500硬件RST的控制,低电平的时候对W5500进行硬件复位,低电平需要持续500us以上;对于INT引脚,如果没有使用到,可以忽略不配置,如果使用到了,需要配置为EXTI,通过EXTI中断来及时的响应W5500的反馈,具体配置如下所示:
void W5500_InitGPIO(void)
{
EXTI_InitTypeDef EXTI_InitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
/* RST */
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
/* W5500 Hardware Reset */
GPIO_WriteBit(GPIOA, GPIO_Pin_2, Bit_RESET);
SysTick_DelayMS(5);
GPIO_WriteBit(GPIOA, GPIO_Pin_2, Bit_SET);
SysTick_DelayMS(5);
/* INT */
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStruct);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource3);
EXTI_StructInit(&EXTI_InitStruct);
EXTI_InitStruct.EXTI_Line = EXTI_Line3;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = EXTI3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
4.5.初始化MM32F3273与W5500之间的SPI通讯配置
void W5500_InitSPI1(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2ENR_SPI1, ENABLE);
SPI_StructInit(&SPI_InitStruct);
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_DataWidth = 8;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI1, &SPI_InitStruct);
SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Rx);
SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Tx);
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_5);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_5);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_5);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_5);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStruct);
SPI_Cmd(SPI1, ENABLE);
}
4.6.实现MM32F3273的SPI数据读写函数,并注册为W5500的接口函数
W5500的接口注册函数有如下几个:
void reg_wizchip_cris_cbfunc(void(*cris_en)(void), void(*cris_ex)(void));
void reg_wizchip_cs_cbfunc(void(*cs_sel)(void), void(*cs_desel)(void));
void reg_wizchip_bus_cbfunc(iodata_t (*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, iodata_t wb));
void reg_wizchip_spi_cbfunc(uint8_t (*spi_rb)(void), void (*spi_wb)(uint8_t wb));
void reg_wizchip_spiburst_cbfunc(void (*spi_rb)(uint8_t* pBuf, uint16_t len), void (*spi_wb)(uint8_t* pBuf, uint16_t len));
因为我们使用的是SPI接口与W5500进行通讯,所以可以仅实现SPI部分的注册函数即可,如下:
void reg_wizchip_cs_cbfunc(void(*cs_sel)(void), void(*cs_desel)(void));
void reg_wizchip_spi_cbfunc(uint8_t (*spi_rb)(void), void (*spi_wb)(uint8_t wb));
void reg_wizchip_spiburst_cbfunc(void (*spi_rb)(uint8_t* pBuf, uint16_t len), void (*spi_wb)(uint8_t* pBuf, uint16_t len));
其中reg_wizchip_cs_cbfunc函数是对SPI CS的操作,reg_wizchip_spi_cbfunc函数是注册单字节进行SPI读写操作,reg_wizchip_spiburst_cbfunc函数是注册多字节进行SPI读写操作,reg_wizchip_spi_cbfunc和reg_wizchip_spiburst_cbfunc只需要选其一进行进行函数注册即可。具体实现如下所示:
void W5500_SPI_CS_Select(void)
{
SPI_CSInternalSelected(SPI1, ENABLE);
}
void W5500_SPI_CS_Deselect(void)
{
SPI_CSInternalSelected(SPI1, DISABLE);
}
uint8_t W5500_SPI_ReadByte(void)
{
SPI_SendData(SPI1, 0x00);
while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT))
{
}
while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL))
{
}
return (SPI_ReceiveData(SPI1));
}
void W5500_SPI_WriteByte(uint8_t Data)
{
SPI_SendData(SPI1, Data);
while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT))
{
}
while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL))
{
}
SPI_ReceiveData(SPI1);
}
void W5500_SPI_ReadBurst(uint8_t *Buffer, uint16_t Length)
{
for (uint16_t i = 0; i < Length; i++)
{
SPI_SendData(SPI1, 0x00);
while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT))
{
}
while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL))
{
}
Buffer[i] = SPI_ReceiveData(SPI1);
}
}
void W5500_SPI_WriteBurst(uint8_t *Buffer, uint16_t Length)
{
for (uint16_t i = 0; i < Length; i++)
{
SPI_SendData(SPI1, Buffer[i]);
while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT))
{
}
while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL))
{
}
SPI_ReceiveData(SPI1);
}
}
4.7.对W5500进行初始化配置
#include "socket.h"
#include "wizchip_conf.h"
int main(void)
{
PLATFORM_Init();
W5500_InitGPIO();
W5500_InitSPI1();
reg_wizchip_cris_cbfunc(NULL, NULL);
reg_wizchip_cs_cbfunc(W5500_SPI_CS_Select, W5500_SPI_CS_Deselect);
reg_wizchip_spiburst_cbfunc(W5500_SPI_ReadBurst, W5500_SPI_WriteBurst);
printf("\r\nW5500 VERSIONR : 0x%02X", WIZCHIP_READ(VERSIONR));
if (ctlwizchip(CW_INIT_WIZCHIP, NULL) == -1)
{
printf("\r\nW5500 Initialized Fail.");
}
else
{
printf("\r\nW5500 Initialized Success.");
}
wiz_PhyConf PhyConf;
PhyConf.by = PHY_CONFBY_SW;
PhyConf.mode = PHY_MODE_MANUAL;
PhyConf.speed = PHY_SPEED_100;
PhyConf.duplex = PHY_DUPLEX_FULL;
ctlwizchip(CW_SET_PHYCONF, &PhyConf);
wiz_NetInfo NetInfo;
uint8_t mac[6] = {0x00, 0xf1, 0xbe, 0xc4, 0xa1, 0x05};
uint8_t ip[4] = {192, 168, 103, 136};
uint8_t sn[4] = {255, 255, 255, 0};
uint8_t gw[4] = {192, 168, 103, 1};
uint8_t dns[4] = {8, 8, 8, 8};
memcpy(NetInfo.mac, mac, sizeof(mac));
memcpy(NetInfo.ip, ip, sizeof(ip));
memcpy(NetInfo.sn, sn, sizeof(sn));
memcpy(NetInfo.gw, gw, sizeof(gw));
memcpy(NetInfo.dns, dns, sizeof(dns));
NetInfo.dhcp = NETINFO_STATIC;
ctlnetwork(CN_SET_NETINFO, &NetInfo);
wiz_NetInfo info;
ctlnetwork(CN_GET_NETINFO, &info);
printf("\r\n");
printf("W5500 Network Infomation :\r\n");
printf(" -mac : %d:%d:%d:%d:%d:%d\r\n", info.mac[0], info.mac[1], info.mac[2], info.mac[3], info.mac[4], info.mac[5]);
printf(" -ip : %d.%d.%d.%d\r\n", info.ip[0], info.ip[1], info.ip[2], info.ip[3]);
printf(" -sn : %d.%d.%d.%d\r\n", info.sn[0], info.sn[1], info.sn[2], info.sn[3]);
printf(" -gw : %d.%d.%d.%d\r\n", info.gw[0], info.gw[1], info.gw[2], info.gw[3]);
printf(" -dns : %d.%d.%d.%d\r\n", info.dns[0], info.dns[1], info.dns[2], info.dns[3]);
if (info.dhcp == NETINFO_DHCP)
{
printf(" -dhcp_mode : dhcp\r\n");
}
else
{
printf(" -dhcp_mode : static\r\n");
}
printf("\r\n");
while (1)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_13, GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0));
}
}
5、搭建环境
搭建硬件环境我们除了需要必备的W5500开发板之后,还需要准备一个网络交换机,以及3根网线;硬件连接示意图如下所示:
网络交换机的其中一个端口连接以太网、第二个接口连接W5500开发板,第三个接口连接PC电脑。
6、PING测试
打开串口监测软件,监控RS232输入的调试打印信息:
通过WIN+R快捷键,打开运行窗口,输入CMD进入终端,在窗口中输入ping 192.168.103.136并回车,查看PING的测试结果:
7、附件
原理图:
W5500开发板.PDF
(374.67 KB)
|
此文章已获得独家原创/原创奖标签,著作权归21ic所有,未经允许禁止转载。
打赏榜单
21小跑堂 打赏了 80.00 元 2024-07-30 理由:恭喜通过原创审核!期待您更多的原创作品~
21小跑堂 打赏了 80.00 元 2024-07-30 理由:恭喜通过原创审核!期待您更多的原创作品~
![](//uc2.21ic.com/avatar.php?uid=1777418&size=small) 共1人点赞
|
基于MM32F3273单片机,使用W5500以太网控制器,实现ping测试案例,硬件和软件资料详细,实现效果较佳。
hi 大佬 以后申请原创@21小跑堂 哦~