欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

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

程序员文章站 2022-03-11 20:45:35
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(目前本人的环境,没尝试过其他版本)、来自硬汉大哥的工程移植模板
STM32H743 RL-TCP(一)基于RTX环境移植硬汉大哥例程(使用阿波罗开发板)
其余环境配置如下
STM32H743 RL-TCP(一)基于RTX环境移植硬汉大哥例程(使用阿波罗开发板)
软件包汇总下载地址
http://www.armbbs.cn/forum.php?mod=viewthread&tid=95609

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



将此四个文件添加至工程,如下图所示
STM32H743 RL-TCP(一)基于RTX环境移植硬汉大哥例程(使用阿波罗开发板)

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。具体参见安富莱_STM32-V7开发板_RL-TCPnet V7.X网络教程(V0.4).pdf
STM32H743 RL-TCP(一)基于RTX环境移植硬汉大哥例程(使用阿波罗开发板)

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

致谢

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

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