当前位置: 移动技术网 > 网络运营>网络>协议 > STM32H743 RL-TCP(一)基于RTX环境移植硬汉大哥例程(使用阿波罗开发板)

STM32H743 RL-TCP(一)基于RTX环境移植硬汉大哥例程(使用阿波罗开发板)

2020年08月12日  | 移动技术网网络运营  | 我要评论
STM32H743 RL-TCP(一)基于RTX环境移植硬汉大哥例程(使用阿波罗开发板)由于最近开始学习TCP/IP协议栈,从网上查询资料发现嵌入式端的主流协议栈包括lwip、RL-TCP等。在安富莱电子论坛上能找到lwip和RL-TCP的教程,综合来看,lwip用的人更多,但arm近来主推RL-TCP,在MDK5中使用较为方便,仅需要简单配置。最终本人选择了RL-TCP。硬汉大哥对RL-TCP有相关的教程,十分详细,但目前来说其教程都是基于安富莱v7开发板。由于手头只有阿波罗板,故需要对此进行适配,折

STM32H743 RL-TCP(一)基于RTX环境移植硬汉大哥例程(使用阿波罗开发板)

由于最近开始学习TCP/IP协议栈,从网上查询资料发现嵌入式端的主流协议栈包括lwip、RL-TCP等。在上能找到lwip和RL-TCP的教程,综合来看,lwip用的人更多,但arm近来主推RL-TCP,在MDK5中使用较为方便,仅需要简单配置。
最终本人选择了RL-TCP。硬汉大哥对RL-TCP有相关的教程,十分详细,但目前来说其教程都是基于安富莱v7开发板。由于手头只有阿波罗板,故需要对此进行适配,折腾了两天,遇到无数的坑,最终简单运行硬汉的demo,故以此文记录如何移植。

1、准备工作

1、硬件:正点原子阿波罗开发板,核心板型号为STM32H743IIT6、烧录器等
2、软件:MDK5.31(目前本人的环境,没尝试过其他版本)、来自硬汉大哥的工程
在这里插入图片描述
其余环境配置如下
在这里插入图片描述
软件包汇总下载地址

2、移植

打开工程目录文件,由于之前的步骤按照硬汉大哥的即可实现,此处省略,着眼于阿波罗开发板的适配。

2.1 修改网卡驱动

阿波罗板载PHY芯片型号为LAN8720A,但安富莱v7开发板为DM9161。并且根据阿波罗原理图可知,LAN8270A的复位引脚接在了IO扩展芯片PCF8574上,初始化时需要对PCF8574 的 D7 口写0复位。此处很容易犯错!!!!
同时,二者的引脚接法也有所不同。

首先,删除原有网卡DM9161驱动,将PHY_LAN8720.c 和 PHY_LAN8720.h添加进工程。这两个文件在。

随后添加复位部分文件,这里需要iic驱动PCF8574,故具有四个文件。pcf8574.c/ pcf8574.h/ myiic.c/ myiic.h

myiic.c(修改自原子的myiic.c)

#include "myiic.h"

//////////////////////////////////////////////////////////////////////////////////	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F429开发板
//IIC驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2016/1/13
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved									  
//////////////////////////////////////////////////////////////////////////////////

void delay_us(uint32_t nus)
{		
    for(int i; i<480*nus; i++)
    {
    }
//	采用此方式是为避免出现systick卡死情况
}
//IIC初始化
void IIC_Init(void)
{
    GPIO_InitTypeDef GPIO_Initure;
    
    __HAL_RCC_GPIOH_CLK_ENABLE();   //使能GPIOH时钟
    
    //PH4,5初始化设置
    GPIO_Initure.Pin=GPIO_PIN_4|GPIO_PIN_5;
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_FAST;     //快速
    HAL_GPIO_Init(GPIOH,&GPIO_Initure);
    
    IIC_SDA(1);
    IIC_SCL(1);  
	
}

//产生IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();     //sda线输出
	IIC_SDA(1);	  	  
	IIC_SCL(1);
	delay_us(4);
 	IIC_SDA(0);//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	IIC_SCL(0);//钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	IIC_SCL(0);
	IIC_SDA(0);//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	IIC_SCL(1); 
	IIC_SDA(1);//发送I2C总线结束信号
	delay_us(4);							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
uint8_t IIC_Wait_Ack(void)
{
	uint8_t ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	IIC_SDA(1);delay_us(1);	   
	IIC_SCL(1);delay_us(1);	 
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL(0);//时钟输出0 	   
	return 0;  
} 
//产生ACK应答
void IIC_Ack(void)
{
	IIC_SCL(0);
	SDA_OUT();
	IIC_SDA(0);
	delay_us(2);
	IIC_SCL(1);
	delay_us(2);
	IIC_SCL(0);
}
//不产生ACK应答		    
void IIC_NAck(void)
{
	IIC_SCL(0);
	SDA_OUT();
	IIC_SDA(1);
	delay_us(2);
	IIC_SCL(1);
	delay_us(2);
	IIC_SCL(0);
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(uint8_t txd)
{                        
    uint8_t t;   
	SDA_OUT(); 	    
    IIC_SCL(0);//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        IIC_SDA( (txd&0x80)>>7 );
        txd<<=1; 	  
		delay_us(2);   //对TEA5767这三个延时都是必须的
		IIC_SCL(1);
		delay_us(2); 
		IIC_SCL(0);	
		delay_us(2);
    }	 
} 	    
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
uint8_t IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        IIC_SCL(0); 
        delay_us(2);
		IIC_SCL(1);
        receive<<=1;
        if(READ_SDA)receive++;   
		delay_us(1); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}

myiic.h(修改自原子)

#ifndef _MYIIC_H
#define _MYIIC_H

#include "bsp.h"

//////////////////////////////////////////////////////////////////////////////////	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F429开发板
//IIC驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2016/1/13
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved									  
////////////////////////////////////////////////////////////////////////////////// 	
//IO方向设置
#define SDA_IN()  {GPIOH->MODER&=~(3<<(5*2));GPIOH->MODER|=0<<5*2;}	//PH5输入模式
#define SDA_OUT() {GPIOH->MODER&=~(3<<(5*2));GPIOH->MODER|=1<<5*2;} //PH5输出模式
//IO操作
#define IIC_SCL(a)   	if(a)	HAL_GPIO_WritePin(GPIOH,GPIO_PIN_4,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOH,GPIO_PIN_4,GPIO_PIN_RESET);//SCL
#define IIC_SDA(a)  	if(a)	HAL_GPIO_WritePin(GPIOH,GPIO_PIN_5,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOH,GPIO_PIN_5,GPIO_PIN_RESET);//SCL
#define READ_SDA  		HAL_GPIO_ReadPin(GPIOH,GPIO_PIN_5)

void delay_us(uint32_t nus);
//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口				 
void IIC_Start(void);				//发送IIC开始信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Send_Byte(uint8_t txd);			//IIC发送一个字节
uint8_t IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
uint8_t IIC_Wait_Ack(void); 				//IIC等待ACK信号
void IIC_Ack(void);					//IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号

void IIC_Write_One_Byte(uint8_t daddr,uint8_t addr,uint8_t data);
uint8_t IIC_Read_One_Byte(uint8_t daddr,uint8_t addr);	 


#endif



···

pcf8574.c
#include "pcf8574.h"

//////////////////////////////////////////////////////////////////////////////////	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F429开发板
//PCF8574驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2016/1/13
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved									  
////////////////////////////////////////////////////////////////////////////////// 	

//初始化PCF8574
uint8_t PCF8574_Init(void)
{
    uint8_t temp=0;
    GPIO_InitTypeDef GPIO_Initure;
    __HAL_RCC_GPIOB_CLK_ENABLE();           //使能GPIOB时钟
	
    GPIO_Initure.Pin=GPIO_PIN_12;           //PB12
    GPIO_Initure.Mode=GPIO_MODE_INPUT;      //输入
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);     //初始化
    IIC_Init();					            //IIC初始化 	
	//检查PCF8574是否在位
    IIC_Start();    	 	   
	IIC_Send_Byte(PCF8574_ADDR);            //写地址			   
	temp=IIC_Wait_Ack();		            //等待应答,通过判断是否有ACK应答,来判断PCF8574的状态
    IIC_Stop();					            //产生一个停止条件
    PCF8574_WriteOneByte(0XFF);	            //默认情况下所有IO输出高电平
    
    PCF8574_WriteBit(ETH_RESET_IO,0);
    HAL_Delay(100);
    
	return temp;
}

//读取PCF8574的8位IO值
//返回值:读到的数据
uint8_t PCF8574_ReadOneByte(void)
{				  
	uint8_t temp=0;		  	    																 
    IIC_Start();    	 	   
	IIC_Send_Byte(PCF8574_ADDR|0X01);   //进入接收模式			   
	IIC_Wait_Ack();	 
    temp=IIC_Read_Byte(0);		   
    IIC_Stop();							//产生一个停止条件	    
	return temp;
}
//向PCF8574写入8位IO值  
//DataToWrite:要写入的数据
void PCF8574_WriteOneByte(uint8_t DataToWrite)
{				   	  	    																 
    IIC_Start();  
    IIC_Send_Byte(PCF8574_ADDR|0X00);   //发送器件地址0X40,写数据 	 
	IIC_Wait_Ack();	    										  		   
	IIC_Send_Byte(DataToWrite);    	 	//发送字节							   
	IIC_Wait_Ack();      
    IIC_Stop();							//产生一个停止条件 
	HAL_Delay(10);	 
}

//设置PCF8574某个IO的高低电平
//bit:要设置的IO编号,0~7
//sta:IO的状态;0或1
void PCF8574_WriteBit(uint8_t bit,uint8_t sta)
{
    __IO uint8_t data;
    data=PCF8574_ReadOneByte(); //先读出原来的设置
    if(sta==0)data&=~(1<<bit);     
    else data|=1<<bit;
    PCF8574_WriteOneByte(data); //写入新的数据
}

//读取PCF8574的某个IO的值
//bit:要读取的IO编号,0~7
//返回值:此IO的值,0或1
uint8_t PCF8574_ReadBit(uint8_t bit)
{
    uint8_t data;
    data=PCF8574_ReadOneByte(); //先读取这个8位IO的值 
    if(data&(1<<bit))return 1;
    else return 0;   
}  
    

pcf8574.h
#ifndef __PCF8574_H
#define __PCF8574_H
#include "myiic.h"
//////////////////////////////////////////////////////////////////////////////////	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F429开发板
//PCF8574驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2016/1/13
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved									  
////////////////////////////////////////////////////////////////////////////////// 	

#define PCF8574_INT  PBin(12) //PCF8574 INT脚

#define PCF8574_ADDR 	0X40	//PCF8574地址(左移了一位)

//PCF8574各个IO的功能
#define BEEP_IO         0		//蜂鸣器控制引脚  	P0
#define AP_INT_IO       1   	//AP3216C中断引脚	P1
#define DCMI_PWDN_IO    2    	//DCMI的电源控制引脚	P2
#define USB_PWR_IO      3    	//USB电源控制引脚	P3
#define EX_IO      		4    	//扩展IO,自定义使用 	P4
#define MPU_INT_IO      5   	//MPU9250中断引脚	P5
#define RS485_RE_IO     6    	//RS485_RE引脚		P6
#define ETH_RESET_IO    7    	//以太网复位引脚		P7

uint8_t PCF8574_Init(void); 
uint8_t PCF8574_ReadOneByte(void); 
void PCF8574_WriteOneByte(uint8_t DataToWrite);
void PCF8574_WriteBit(uint8_t bit,uint8_t sta);
uint8_t PCF8574_ReadBit(uint8_t bit);
#endif



将此四个文件添加至工程,如下图所示
在这里插入图片描述

2.2 修改引脚约束

二者的引脚约束不同,需重新对应并修改。

2.2.1 网卡引脚

ETH_Init.c文件中,将函数HAL_ETH_MspInit修改为如下所示,注意几个引脚初始化位置的改动。

/*
*********************************************************************************************************
*	函 数 名: HAL_ETH_MspInit
*	功能说明: 以太网初始化调用的底层回调,用于初始化IO,时钟和中断
*	形    参: ---
*	返 回 值: 无
*********************************************************************************************************
*/
void HAL_ETH_MspInit(ETH_HandleTypeDef* heth)
{
	GPIO_InitTypeDef GPIO_InitStruct;

	/*
		PC1     ------> ETH_MDC
		PA1     ------> ETH_REF_CLK
		PA2     ------> ETH_MDIO
		PA7     ------> ETH_CRS_DV
		PC4     ------> ETH_RXD0
		PC5     ------> ETH_RXD1
		PB11    ------> ETH_TX_EN
		PG13    ------> ETH_TXD0
        PG14    ------> ETH_TXD1    
	*/
	if(heth->Instance==ETH)
	{
		/* 使能外设时钟 */
		__HAL_RCC_ETH1MAC_CLK_ENABLE();
		__HAL_RCC_ETH1TX_CLK_ENABLE();
		__HAL_RCC_ETH1RX_CLK_ENABLE();

		/* 使能时钟 */
		__HAL_RCC_GPIOA_CLK_ENABLE();
		__HAL_RCC_GPIOB_CLK_ENABLE();
		__HAL_RCC_GPIOC_CLK_ENABLE();
		__HAL_RCC_GPIOG_CLK_ENABLE();

		
		/* 配置PA1, PA2 , PA7 */
		GPIO_InitStruct.Pin =  GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull = GPIO_NOPULL ; 
		GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
		HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

		/* 配置PB11 */
		GPIO_InitStruct.Pin = GPIO_PIN_11;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

		/* 配置PC1, PC4和PC5 */
		GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; 
		HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);	

		/* 配置G13和PG14 */
		GPIO_InitStruct.Pin = GPIO_PIN_13 | GPIO_PIN_14;
		HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

		/* 设置中断优先级 */
		HAL_NVIC_SetPriority(ETH_IRQn, 3, 0);
		HAL_NVIC_EnableIRQ(ETH_IRQn);	
	}
}

2.2.2 其他冲突引脚

初始化时如果发生冲突,引脚将无法正常工作。此部分包含 按键(key) 串口3

2.2.2.1 KEY

打开bsp_key.c, 注意到按键的K3与iic引脚PH4冲突,需要修改成如下所示,注意,由于阿波罗板没有JOY摇杆,需要将其注释并修改按键数目。

#include "bsp.h"

#define HARD_KEY_NUM	    3	   						/* 实体按键个数 */
#define KEY_COUNT   	 	(HARD_KEY_NUM + 2)	/* 8个独立建 + 2个组合按键 */

/* 使能GPIO时钟 */
//#define ALL_KEY_GPIO_CLK_ENABLE() {	\
//		__HAL_RCC_GPIOB_CLK_ENABLE();	\
//		__HAL_RCC_GPIOC_CLK_ENABLE();	\
//		__HAL_RCC_GPIOG_CLK_ENABLE();	\
//		__HAL_RCC_GPIOH_CLK_ENABLE();	\
//		__HAL_RCC_GPIOI_CLK_ENABLE();	\
//	};
#define ALL_KEY_GPIO_CLK_ENABLE() {	\
		__HAL_RCC_GPIOC_CLK_ENABLE();	\
		__HAL_RCC_GPIOH_CLK_ENABLE();	\
	};


/* 依次定义GPIO */
typedef struct
{
	GPIO_TypeDef* gpio;
	uint16_t pin;
	uint8_t ActiveLevel;	/* 激活电平 */
}X_GPIO_T;

/* GPIO和PIN定义 */
static const X_GPIO_T s_gpio_list[HARD_KEY_NUM] = {
	{GPIOH, GPIO_PIN_3, 0},		/* K1 */
	{GPIOH, GPIO_PIN_2, 0},	    /* K2 */
	{GPIOC, GPIO_PIN_13, 0},    /* K3 */
//	{GPIOG, GPIO_PIN_2, 0},		/* JOY_U */	
//	{GPIOB, GPIO_PIN_0, 0},		/* JOY_D */
//	{GPIOG, GPIO_PIN_3, 0},		/* JOY_L */	
//	{GPIOG, GPIO_PIN_7, 0},		/* JOY_R */	
//	{GPIOI, GPIO_PIN_11, 0},	/* JOY_OK */
};

还有一个地方需要修改否则无法正常使用按键,就是在函数bsp_InitKeyVar中需要注释如下几行

	/* 摇杆上下左右,支持长按1秒后,自动连发 */
//	bsp_SetKeyParam(KID_JOY_U, 100, 6);
//	bsp_SetKeyParam(KID_JOY_D, 100, 6);
//	bsp_SetKeyParam(KID_JOY_L, 100, 6);
//	bsp_SetKeyParam(KID_JOY_R, 100, 6);

2.2.2.2 串口

此处串口默认打开USART3,与PB11冲突,需要将头文件 bsp_uart_fifo.h中的 宏定义UART3_FIFO_EN改为0

#define	UART3_FIFO_EN	0

3、添加网口复位代码

打开bsp.h,添加头文件引用#include "pcf8574.h"

打开bsp.c,找到函数bsp_Init,修改为

void bsp_Init(void)
{
	bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */       
	bsp_InitKey();    	/* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
	bsp_InitUart();		/* 初始化串口 */
    PCF8574_Init();
	bsp_InitExtIO();	/* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */	
	bsp_InitLed();    	/* 初始化LED */	
	bsp_InitTimer();  	/* 初始化滴答定时器 */
}

随后打开pcf8574.c
在函数PCF8574_Init末尾添加如下代码,将P7拉低

    PCF8574_WriteBit(ETH_RESET_IO,0);
    HAL_Delay(100);

4、测试

编译下载到板上,可以正常ping通。注意计算机网口如果没开DHCP服务器,需要将开发板设置为静态IP。具体参见
在这里插入图片描述

最终结果
在这里插入图片描述

致谢

十分感谢原子哥和硬汉哥对于嵌入式开发入门的帮助。

本文地址:https://blog.csdn.net/Onelasttime/article/details/107937124

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网