STM32F107 以太网 + RL-TCPnet

介绍一下STM32F107以太网的配置和移植RL-TCPnet协议栈,官方所给的例程为lwip,这里介绍一下怎样使用RL-TCPnet。(需要包含stm32_eth.c和stm32_eth.h)

这里是描述符的定义,什么是描述符请看《STM32中文参考手册》以太网章节

/* 描述符数量和缓存大小定义 */
#define NUM_RX_BUF          4      //接收描述符数量和缓存数量
#define NUM_TX_BUF          2      //发送描述符数量和缓存数量
#define ETH_BUF_SIZE        1536   //每个缓存大小
	
/* 接收描述符和发送描述符结构体类型定义(含义请参考STM32中文参考手册) */
typedef struct {
  U32 volatile Stat;
  U32 Ctrl;
  U32 Addr;
  U32 Next;
} RX_Desc;

typedef struct {
  U32 volatile CtrlStat;
  U32 Size;
  U32 Addr;
  U32 Next;
} TX_Desc;

/* 当前使用的描述符序号 */
static U8 TxBufIndex;
static U8 RxBufIndex;

/* DMA描述符声明 */
static RX_Desc Rx_Desc[NUM_RX_BUF];
static TX_Desc Tx_Desc[NUM_TX_BUF];

/* 描述符所指向的内存 */
static U32 rx_buf[NUM_RX_BUF][ETH_BUF_SIZE>>2];
static U32 tx_buf[NUM_TX_BUF][ETH_BUF_SIZE>>2];

要使用RL-TCPnet协议栈需要为RL-TCPnet提供接口函数:
void init_ethernet (void);
void send_frame (OS_FRAME *frame);
void int_enable_eth (void);
void int_disable_eth (void);
以下为对应函数:

	//以太网硬件初始化(提供给RL-TCPnet的接口)
void init_ethernet (void) {
	
	NVIC_InitTypeDef   NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	ETH_InitTypeDef ETH_InitStructure;
	
	#define TIME_OUT	0x0003FFFFul
	uint32_t time = 0;
	
	/* 使能时钟  */
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ETH_MAC | RCC_AHBPeriph_ETH_MAC_Tx |
	                      RCC_AHBPeriph_ETH_MAC_Rx, ENABLE);
	/* 使能GPIO时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC |
	                       RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO,
						   ENABLE);
	
	/* 选择中断向量表 */
	NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
	 
	/* 使能以太网全局中断*/
	NVIC_InitStructure.NVIC_IRQChannel = ETH_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure); 
	
	/*
	以太网引脚配置
	当前使用RMII接口,无重映射
	需要使用MII接口请自行参照手册修改
	*/
	/* AF Output Push Pull:
	-ETH_RMII_MDIO: PA2
	-ETH_RMII_MDC: PC1
	-ETH_RMII_TX_EN: PB11
	-ETH_RMII_TXD0: PB12
	-ETH_RMII_TXD1: PB13
	*/
	
	/* Configure PA2 as alternate function push-pull */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	/* Configure PC1 as alternate function push-pull */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	
	/* Configure PB5, PB8, PB11, PB12 and PB13 as alternate function push-pull */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	/* Input:
	-ETH_RMII_REF_CLK: PA1
	-ETH_RMII_CRS_DV: PA7
	-ETH_RMII_RXD0: PC4
	-ETH_RMII_RXD1: PC5
	*/
	
	/* Configure PA1 and PA7 as input */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	/* Configure PC4 and PC5 as input */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
		
	/* 选择配置为MII或者RMII,当前为RMII*/
	GPIO_ETH_MediaInterfaceConfig(GPIO_ETH_MediaInterface_RMII);
	
	/* 重置以太网 */
	ETH_DeInit();
	ETH_SoftwareReset();
	
	/*等待重置完成*/
	while (ETH_GetSoftwareResetStatus() == SET);
	
	/* 以太网配置, 填充ETH_InitStructure结构体,最后调用 ETH_Init()配置以太网*/
	ETH_StructInit(Ð_InitStructure);
	
	/*------------------------   MAC   -----------------------------------*/
	ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable  ;
	ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;
	ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;
	ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;
	ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;
	ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;
	ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;
	ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;
	ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;
	#ifdef CHECKSUM_BY_HARDWARE
	ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable;
	#endif
	
	/*------------------------   DMA   -----------------------------------*/  
	ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable; 
	ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;         
	ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;     
	
	ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;       
	ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;   
	ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable;                                                          
	ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;      
	ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable;                
	ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;          
	ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;                                                                 
	ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;
	
	/*初始化以太网,第二个参数为PHY芯片地址*/
	ETH_Init(Ð_InitStructure, LAN9303_VPHY_ADDR);
	
	//接收描述符初始化		
	rx_descr_init();
	//发送描述符初始化
	tx_descr_init();
	
	/* 使能正常总中断和接收中断*/
	ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R, ENABLE);
	
	//使能发送和接收
	ETH->DMAOMR |= DOMR_ST | DOMR_SR;
	ETH->MACCR |= MCR_RE | MCR_TE;
	
	//配置MAC地址,否则只能收到广播数据
	ETH_MACAddressConfig(ETH_MAC_Address0, own_hw_adr);
}

//使能和禁止以太网中断
void int_enable_eth (void) {
	/* Ethernet Interrupt Enable function. */
	NVIC->ISER[1] = 1 << 29;
}
void int_disable_eth (void) {
	/* Ethernet Interrupt Disable function. */
	NVIC->ICER[1] = 1 << 29;
}

//发送一帧数据(提供给RL-TCPnet的接口函数)
void send_frame (OS_FRAME *frame) {
	U32 *sp,*dp;
	U32 i,j;
	
	j = TxBufIndex;
	/* 等待之前数据发送完 */
	while (Tx_Desc[j].CtrlStat & DMA_TX_OWN);
	
	sp =** (U32 *)&frame->data[0];
	dp = (U32 *)Tx_Desc[j].Addr;

	/* 拷贝需要发送的数据到发送描述符指定的内存 */
	for (i = (frame->length + 3) >> 2; i; i--) {
		*dp++ = *sp++;
	}

	//发送数据量
	Tx_Desc[j].Size = frame->length;
	//修改发送描述符属于DMA
	Tx_Desc[j].CtrlStat |= DMA_TX_OWN;
	
	/* 往DMATPDR中写数据开始DMA传输 */
	if((ETH->DMASR | DSR_TBUS) !*= 0)
	{
		ETH->DMASR = DSR_TBUS;
		ETH->DMATPDR = 0;
	}
	
	if (++j == NUM_TX_BUF) j = 0;
	TxBufIndex = j;
}

以上即为需要提供给RL-TCPnet的接口函数。

中断服务函数,用于接收以太网数据。

//以太网中断服务函数(用于接收以太网数据)
void ETH_IRQHandler (void) {
	/* Ethernet Controller Interrupt function. */
	OS_FRAME *frame;
	U32 i,RxLen;
	U32 *sp,*dp;
	
	i = RxBufIndex;
	do {
		/* Valid frame has been received. */*
		if (Rx_Desc[i].Stat & DMA_RX_ERROR_MASK) {
			goto rel;
		}
		if ((Rx_Desc[i].Stat & DMA_RX_SEG_MASK) != DMA_RX_SEG_MASK) {
			goto rel;
		}
		RxLen = ((Rx_Desc[i].Stat >> 16) & 0x3FFF) - 4;
		if (RxLen > ETH_MTU) {
			/* Packet too big, ignore it and free buffer. */
			goto rel;
		}
		/* Flag 0x80000000 to skip sys_error() call when out of memory. */
		frame = alloc_mem (RxLen | 0x80000000);
		/* if 'alloc_mem()' has failed, ignore this packet. */
		if (frame != NULL) {
			sp = (U32 *)(Rx_Desc[i].Addr & ~3);
			dp = (U32 *)&frame->data[0];
			for (RxLen = (RxLen + 3) >> 2; RxLen; RxLen--) {
				*dp++ = *sp++;
			}
			put_in_queue (frame);
		}
		/* Release this frame from ETH IO buffer. */
	rel:
		Rx_Desc[i].Stat = DMA_RX_OWN;
	
		if (++i == NUM_RX_BUF) i = 0;
	} 
	while ((Rx_Desc[i].Stat & DMA_RX_OWN) == 0);
	RxBufIndex = i;

	if (ETH->DMASR & INT_RBUIE) {
		/* Rx DMA suspended, resume DMA reception. */
		ETH->DMASR   = INT_RBUIE;
		ETH->DMARPDR = 0;
	}
	/* Clear the interrupt pending bits. */
	ETH->DMASR = INT_NISE | INT_RIE;
}

接收描述符初始化

//接收描述符初始化
static void rx_descr_init (void) {
	/* Initialize Receive DMA Descriptor array. */
	U32 i,next;
	
	RxBufIndex = 0;
	for (i = 0, next = 0; i < NUM_RX_BUF; i++) {
		if (++next == NUM_RX_BUF) next = 0;
		Rx_Desc[i].Stat = DMA_RX_OWN;
		Rx_Desc[i].Ctrl = DMA_RX_RCH | ETH_BUF_SIZE;
		Rx_Desc[i].Addr = (U32)&rx_buf[i];
		Rx_Desc[i].Next = (U32)&Rx_Desc[next];
	}
	//指向第一个描述符
	ETH->DMARDLAR = (U32)&Rx_Desc[0];
}

发送描述符初始化

//发送描述符初始化
static void tx_descr_init (void) {
	/* Initialize Transmit DMA Descriptor array. */
	U32 i,next;
	
	TxBufIndex = 0;
	for (i = 0, next = 0; i < NUM_TX_BUF; i++) {
		if (++next == NUM_TX_BUF) next = 0;
		Tx_Desc[i].CtrlStat = DMA_TX_TCH | DMA_TX_LS | DMA_TX_FS;
		Tx_Desc[i].Addr     = (U32)&tx_buf[i];
		Tx_Desc[i].Next     = (U32)&Tx_Desc[next];
	}
	//指向第一个描述符
	ETH->DMATDLAR = (U32)&Tx_Desc[0];
}

到此,在工程中加入RL-TCPnet库和配置文件即可使用RL-TCPnet,使用方法请参照RL-arm帮助文档。

你可能感兴趣的:(STM32,移植)