STM32F107 以太网 + RL-TCPnet

本文版权:成都至诚恒远物联网技术有限公司

网址: www.heryit.cn

联系电话:   028-87657875         13060063607

介绍一下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(&ETH_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(&ETH_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帮助文档。

时间: 2024-10-08 16:03:24

STM32F107 以太网 + RL-TCPnet的相关文章

浅谈单片机以太网接入方案

 单片机的种类繁多,从低端到高端,有以51单片机为代表的8位单片机和以ARM为代表的32位单片机,不同档次的单片机实现网络接口的方法不同.对于像ARM等高端处理器一般都可以运行嵌入式操作系统,例如嵌入式Linux.对于无操作系统要求的单片机如何实现网络接入,我下面将这些方案按TCP/IP协议栈的不同归结为两大类:第一类是传统的软件TCP/IP协议栈方案:第二类是最新的硬件TCP/IP协议栈方案.下面我就这两类方案的实现方式进行分析. 1. MAC+PHY方案 所谓的TCP/IP协议栈是一系列

STM32F107移植LWIP

STM32F107上移植LWIP2.0.3 因为最近需要在STM32F107上实现TCP/IP协议栈,所以网上查了一下,准备使用LWIP,虽然大多数用的是1.4.1版本但是官方说2系大版本修复了1.4.1的大量bug所以这里用的版本是2.0.3,其实移植上没有什么太大区别.STM32F107集成了以太网媒体接入控制器MAC(主要负责控制和连接物理层的物理介质),所以按四层分层模型组成来看底层物理层组成还缺少一个物理接口收发器(PHY).网上常见的应用于STM32上的PHY芯片有DP83848和L

以太网进化历程半景-从10Mbps到1Tbps

继Netfilter conntrack,Linux Bridge之后又是一个半景,依然如故,我不会在文中罗列技术规范和细节,仅仅是希望本文可以帮助人们理解以太网到底是什么,为什么如此成功. 0.动机,愿景以及声明 前端时间帮朋友解决一个编码问题,碰到了全双工这个概念,正好写了一个程序,实现了类似CDMA那种沃尔什编码,即从一个混合信号中分离中自己要的那部分,然而代码是好写的,往线缆上一放就全乱了,这是电学原理导致的.就这么说吧,请看下图: 请问P点的电压是多少?很简单的一个问题,是不是?是的.

【小梅哥FPGA进阶学习之旅】基于Altera FPGA 的DDR2+千兆以太网电路设计

DDR2电路设计 在高速大数据的应用中,高速大容量缓存是必不可少的硬件.当前在FPGA系统中使用较为广泛的高速大容量存储器有经典速度较低的单数据速率的SDRAM存储器,以及速度较高的双速率DDR.DDR2.DDR3型SDRAM存储器,DDR系列的存储器都需要FPGA芯片有对应的硬件电路结构支持.对于Altera Cyclone IV系列的FPGA,其最高支持到DDR2存储器(不支持DDR3存储器,到了Cyclone V系列的FPGA才支持DDR3存储器).芯航线AC6102开发板作为一个高速应用

用以太网通讯读写条码扫描头

把通讯封装成一个类“ 该程序的特点有优势: 传统写法当条码扫描头停机.异常断电.网络异常等,通讯终端后,程序无法正常恢复连接,丢失数据引发故障,我写的程序,无论扫描头断电还是产线重启,都能第一时间重启连接并通讯上,稳定性很好. 这个也是在一个朋友老程序不断出问题后,找我帮忙,我给重新写的,试用后效果很不过,非常好用,再也没有发生过问题. 如果您有硬件的通讯访问难点和项目,可以联系我解决,譬如 RS232 485 422 串口通讯.以太网接口的仪器仪表通讯.OPC Server自动化数据PLC访问

OpenAI Gym 入门与提高(一) Gym环境构建与最简单的RL agent

Openai gym是一个用于开发和比较RL算法的工具包,与其他的数值计算库兼容,如tensorflow或者theano库.现在主要支持的是python语言,以后将支持其他语言.gym文档在https://gym.openai.com/docs. Openai gym包含2部分: 1.gym开源库:包含一个测试问题集,每个问题成为环境(environment),可以用于自己的RL算法开发.这些环境有共享的接口,允许用户设计通用的算法.其包含了deep mind 使用的Atari游戏测试床. 2.

以太网

以太网:电磁辐射是可以通过发光的以太来传播一种网络低层协议 通常在OSI模型的物理层和数据链路层操作4.2.1以太网的标准和分类 4.2.2以太网的体系结构1.以太网体系结构2.协议数据单元PDU3.MAC帧格式 4.2.3以太网的特点:结构简单,技术成熟  成本低 4.2.4  10兆以太网 1.10Base52.100Base2.....局域网定义了网络的规模和范围以太网是一种协议 定义了网络中信息的传输方式 4.3快速以太网 4.3.1冲突直径的计算4.3.2  10兆以太网和快速以太网的

千兆以太网规范

千兆以太网规范 因为千兆以太网技术仍是目前一种最主流应用的以太网技术,所以关于这种以太网的规范还在不断推出,以满足不同应用环境需求,改进技术性能. 最 早在1998和1999年发布的IEEE 802.3z和IEEE 802.3ab标准中就包括1000Base-LX.1000Base-SX.1000Base-CX和1000Base-T(前三种统称为 1000Base-X子系列),如图5-12所示.其中前三个是由IEEE 802.3z标准规定的,而1000Base-T标准则是由IEEE 802.3a

【应用笔记】【AN003】VC++环境下基于以太网的4-20mA电流采集

简介 4-20mA电流环具有广泛的应用前景,在许多行业中都发挥着重要作用.本文主要介绍了以太网接口的4-20mA电流采集模块在VC++环境下进行温度采集,实现WINDOWS平台对数据的采集.分析及显示. 系统组成及工作原理 系统组成主要包括PT100铂电阻.SBWZ温度变送器.4-20mA电流采集模块(GM4008)以及上位机软件组成,如图1所示. PT100铂电阻温度传感器:利用铂金属阻值随温度的变化而变化的特性制成的一种温度传感器,主要用来测量温度的变化量. SBWZ温度变送器:一种现场安装