历史上的今天
返回首页

历史上的今天

今天是:2024年12月16日(星期一)

正在发生

2020年12月16日 | STM32F7xx —— LAN8720(FreeRTOS+LWIP)

2020-12-16 来源:eefocus

    STM32F767自带以太网模块,需要外接PHY芯片,完成以太网通信(MII/RMII接口)。LAN8720详细资料看手册。LWIP:1.4.1 FreeRTOS V8.2.3。


#define ETH_CHANNEL               ETH

#define ETH_PREEMPT_PRIO          ETHERNET_PRIORITY

#define ETH_CLK_ENABLE()          __HAL_RCC_ETH_CLK_ENABLE()

#define ETH_IRQ                   ETH_IRQn

#define ETH_IRQ_FUNC              ETH_IRQHandler

 

#define ETH_RESET_PORT            GPIOH

#define ETH_RESET_PIN             GPIO_PIN_11

#define ETH_RESET_CONFIG()        GPIOConfig(ETH_RESET_PORT, ETH_RESET_PIN, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL);

#define ETH_RESET_HIGH()          HAL_GPIO_WritePin(ETH_RESET_PORT, ETH_RESET_PIN, GPIO_PIN_SET)

#define ETH_RESET_LOW()           HAL_GPIO_WritePin(ETH_RESET_PORT, ETH_RESET_PIN, GPIO_PIN_RESET)

 

#define ETH_MDIO_PORT             GPIOA

#define ETH_MDIO_PIN              GPIO_PIN_2

#define ETH_MDIO_AF               GPIO_AF11_ETH

#define ETH_MDIO_CONFIG()         GPIOConfigExt(ETH_MDC_PORT, ETH_MDC_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, ETH_MDC_AF);

 

#define ETH_MDC_PORT              GPIOC

#define ETH_MDC_PIN               GPIO_PIN_1

#define ETH_MDC_AF                GPIO_AF11_ETH

#define ETH_MDC_CONFIG()          GPIOConfigExt(ETH_MDIO_PORT, ETH_MDIO_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, ETH_MDIO_AF);

 

#define ETH_RMII_REF_CLK_PORT     GPIOA

#define ETH_RMII_REF_CLK_PIN      GPIO_PIN_1

#define ETH_RMII_REF_CLK_AF       GPIO_AF11_ETH

#define ETH_RMII_REF_CLK_CONFIG() GPIOConfigExt(ETH_RMII_REF_CLK_PORT, ETH_RMII_REF_CLK_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, ETH_RMII_REF_CLK_AF);

 

#define ETH_RMII_CRS_DV_PORT      GPIOA

#define ETH_RMII_CRS_DV_PIN       GPIO_PIN_7

#define ETH_RMII_CRS_DV_AF        GPIO_AF11_ETH

#define ETH_RMII_CRS_DV_CONFIG()  GPIOConfigExt(ETH_RMII_CRS_DV_PORT, ETH_RMII_CRS_DV_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, ETH_RMII_CRS_DV_AF);

 

#define ETH_RMII_RXD0_PORT        GPIOC

#define ETH_RMII_RXD0_PIN         GPIO_PIN_4

#define ETH_RMII_RXD0_AF          GPIO_AF11_ETH

#define ETH_RMII_RXD0_CONFIG()    GPIOConfigExt(ETH_RMII_RXD0_PORT, ETH_RMII_RXD0_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, ETH_RMII_RXD0_AF);

 

#define ETH_RMII_RXD1_PORT        GPIOC

#define ETH_RMII_RXD1_PIN         GPIO_PIN_5

#define ETH_RMII_RXD1_AF          GPIO_AF11_ETH

#define ETH_RMII_RXD1_CONFIG()    GPIOConfigExt(ETH_RMII_RXD1_PORT, ETH_RMII_RXD1_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, ETH_RMII_RXD1_AF);

 

#define ETH_RMII_TXEN_PORT        GPIOB

#define ETH_RMII_TXEN_PIN         GPIO_PIN_11

#define ETH_RMII_TXEN_AF          GPIO_AF11_ETH

#define ETH_RMII_TXEN_CONFIG()    GPIOConfigExt(ETH_RMII_TXEN_PORT, ETH_RMII_TXEN_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, ETH_RMII_TXEN_AF);

 

#define ETH_RMII_TXD0_PORT        GPIOG

#define ETH_RMII_TXD0_PIN         GPIO_PIN_13

#define ETH_RMII_TXD0_AF          GPIO_AF11_ETH

#define ETH_RMII_TXD0_CONFIG()    GPIOConfigExt(ETH_RMII_TXD0_PORT, ETH_RMII_TXD0_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, ETH_RMII_TXD0_AF);

 

#define ETH_RMII_TXD1_PORT        GPIOG

#define ETH_RMII_TXD1_PIN         GPIO_PIN_14

#define ETH_RMII_TXD1_AF          GPIO_AF11_ETH

#define ETH_RMII_TXD1_CONFIG()    GPIOConfigExt(ETH_RMII_TXD1_PORT, ETH_RMII_TXD1_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, ETH_RMII_TXD1_AF);

lan8720_dev_t lan8720_dev;

 

static void lan8720_var_init(void)

{

  lan8720_dev.dma_rx = MemAlloc(SRAM_TYPE_DTCM, ETH_RXBUFNB * sizeof(ETH_DMADescTypeDef)); //申请内存

  lan8720_dev.dma_tx = MemAlloc(SRAM_TYPE_DTCM, ETH_TXBUFNB * sizeof(ETH_DMADescTypeDef)); //申请内存

  lan8720_dev.rx_buffer = MemAlloc(SRAM_TYPE_DTCM, ETH_RX_BUF_SIZE * ETH_RXBUFNB); //申请内存

  lan8720_dev.tx_buffer = MemAlloc(SRAM_TYPE_DTCM, ETH_TX_BUF_SIZE * ETH_TXBUFNB); //申请内存

}

 

static void lan8720_gpio_init(void)

{

  ETH_CLK_ENABLE();

 

  ETH_RESET_CONFIG();

  ETH_MDIO_CONFIG();

  ETH_MDC_CONFIG();

  ETH_RMII_REF_CLK_CONFIG();

  ETH_RMII_CRS_DV_CONFIG();

  ETH_RMII_RXD0_CONFIG();

  ETH_RMII_RXD1_CONFIG();

  ETH_RMII_TXEN_CONFIG();

  ETH_RMII_TXD0_CONFIG();

  ETH_RMII_TXD1_CONFIG();

}

 

static void lan8720_mode_init(void)

{

  uint8_t mac[6] = {0};

 

  ETH_RESET_CONFIG();

  ETH_RESET_HIGH();

  delay_ms(100);

  ETH_RESET_LOW();

  delay_ms(100);

 

  mac[0] = lwip_dev.mac[0];

  mac[1] = lwip_dev.mac[1];

  mac[2] = lwip_dev.mac[2];

  mac[3] = lwip_dev.mac[3];

  mac[4] = lwip_dev.mac[4];

  mac[5] = lwip_dev.mac[5];

 

  lan8720_dev.handle.Instance = ETH;

  lan8720_dev.handle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE; // 使能自协商模式

  lan8720_dev.handle.Init.Speed = ETH_SPEED_100M;                       // 速度100M,如果开启了自协商模式,此配置就无效

  lan8720_dev.handle.Init.DuplexMode = ETH_MODE_FULLDUPLEX;             // 全双工模式,如果开启了自协商模式,此配置就无效

  lan8720_dev.handle.Init.PhyAddress = LAN8720_PHY_ADDRESS;             // LAN8720地址

  lan8720_dev.handle.Init.MACAddr = mac;                                // MAC地址

  lan8720_dev.handle.Init.RxMode = ETH_RXINTERRUPT_MODE;                // 中断接收模式

  lan8720_dev.handle.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;      // 硬件帧校验

  lan8720_dev.handle.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;    // RMII接口

  HAL_ETH_Init(&lan8720_dev.handle);

}

 

static void lan8720_nvic_init(void)

{

  HAL_NVIC_SetPriority(ETH_IRQ, 3, 0); // 优先级必须小于configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY

  HAL_NVIC_EnableIRQ(ETH_IRQ);

}

 

uint32_t LAN8720ReadPHY(uint16_t reg)

{

  uint32_t regval;

 

  HAL_ETH_ReadPHYRegister(&lan8720_dev.handle, reg, ®val);

 

  return regval;

}

 

void LAN8720WritePHY(uint16_t reg, uint16_t value)

{

  uint32_t temp = value;

 

  HAL_ETH_ReadPHYRegister(&lan8720_dev.handle, reg, &temp);

}

 

static uint32_t lan8720_rx_size(ETH_DMADescTypeDef *dma_rx)

{

  uint32_t length = 0;

 

  if(((dma_rx->Status & ETH_DMARXDESC_OWN) == (uint32_t)RESET) &&

      ((dma_rx->Status & ETH_DMARXDESC_ES) == (uint32_t)RESET) &&

      ((dma_rx->Status & ETH_DMARXDESC_LS) != (uint32_t)RESET))

  {

    length = ((dma_rx->Status & ETH_DMARXDESC_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT);

  }

 

  return length;

}

 

void LAN8720Init(void)

{

  lan8720_var_init();

  lan8720_gpio_init();

  lan8720_mode_init();

  lan8720_nvic_init();

}

 

void ETH_IRQ_FUNC(void)

{

  while(lan8720_rx_size(lan8720_dev.handle.RxDesc))

  {

    LWIPCommProcess(); // 处理以太网数据,即将数据提交给LWIP

  }

  //清除中断标志位

  __HAL_ETH_DMA_CLEAR_IT(&lan8720_dev.handle, ETH_DMA_IT_R);

  __HAL_ETH_DMA_CLEAR_IT(&lan8720_dev.handle, ETH_DMA_IT_NIS);

}

sys_arch文件:


#ifndef _ARCH_SYS_ARCH_H_

#define _ARCH_SYS_ARCH_H_

 

#include "arch/cc.h"

#include "FreeRTOS.h"

#include "queue.h"

#include "semphr.h"

 

#define MAX_QUEUE_ENTRIES     20  // 每个消息邮箱的大小

 

// LWIP消息邮箱结构体

typedef struct

{

  QueueHandle_t xQueue;

} lwip_mbox;

 

typedef SemaphoreHandle_t sys_sem_t;   // LWIP使用的信号量

typedef lwip_mbox   sys_mbox_t;       // LWIP使用的消息邮箱,其实就是UCOS中的消息队列

typedef unsigned char  sys_thread_t;  // 线程ID,也就是任务优先级

 

#endif /* _ARCH_SYS_ARCH_H_ */

// 参照lwip_sys.h

 

static const uint32_t console_null;

 

// 创建一个消息邮箱

err_t sys_mbox_new(sys_mbox_t *mbox, int size)

{

  if(size > MAX_QUEUE_ENTRIES)

  {

    size = MAX_QUEUE_ENTRIES;

  }

  mbox->xQueue = xQueueCreate(size, sizeof(void *));

 

  if(mbox->xQueue != NULL)

  {

    return ERR_OK;

  }

  else

  {

    return ERR_MEM;

  }

}

 

// 释放并删除一个消息邮箱

void sys_mbox_free(sys_mbox_t *mbox)

{

  vQueueDelete(mbox->xQueue);

 

  mbox->xQueue = NULL;

}

 

// 向消息邮箱中发送一条消息(必须发送成功)

void sys_mbox_post(sys_mbox_t *mbox, void *msg)

{

  BaseType_t xHigherPriorityTaskWoken = pdFALSE;

 

  if(msg == NULL)

  {

    msg = (void*)&console_null;  //当msg为空时 msg等于pvNullPointer指向的值

  }

  if((SCB_ICSR_REG & 0xFF) == 0) //线程执行

  {

    while(xQueueSendToBack(mbox->xQueue, &msg, portMAX_DELAY) != pdPASS);//portMAX_DELAY,死等直到发送成功

  }

  else

  {

    while(xQueueSendToBackFromISR(mbox->xQueue, &msg, &xHigherPriorityTaskWoken) != pdPASS);

    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

  }

}

 

// 尝试向一个消息邮箱发送消息

// 此函数相对于sys_mbox_post函数只发送一次消息,发送失败后不会尝试第二次发送

err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)

{

  BaseType_t xHigherPriorityTaskWoken = pdFALSE;

  if(msg == NULL)

推荐阅读

史海拾趣

Chemi-Con公司的发展小趣事

在追求经济效益的同时,Chemi-Con公司也积极履行社会责任。公司注重环保和可持续发展,采用环保材料和生产工艺,减少对环境的影响。此外,Chemi-Con还积极参与社会公益事业,为社会的和谐发展做出贡献。这种负责任的态度不仅赢得了社会各界的认可,也为公司的长远发展注入了正能量。

这五个故事展示了Chemi-Con公司在电子行业中的发展历程和取得的成就。通过技术创新、品质管理、市场拓展、多元化发展和社会责任等方面的努力,Chemi-Con逐渐在电子行业中崭露头角,成为了铝电解电容器领域的佼佼者。

爱普特半导体(APTSEMI)公司的发展小趣事

爱普特半导体的产品因其卓越的性能和稳定的质量,赢得了众多大型企业的青睐。公司与小米、美的、阿里、LG等多家知名企业建立了战略合作关系。这些合作不仅为爱普特带来了稳定的订单和市场份额,还提升了公司的品牌影响力和行业地位。通过与这些企业的深度合作,爱普特不断吸收行业最新技术和管理经验,推动了自身技术水平和市场竞争力的提升。

EG & G Inc公司的发展小趣事

随着市场竞争的加剧,EG & G Inc公司意识到通过并购和整合来提升自身竞争力的重要性。公司先后收购了多家具有技术优势和市场潜力的企业,将其纳入自己的业务体系。这些并购不仅增强了公司的技术实力和市场地位,也为其未来的发展奠定了坚实的基础。

Foxboro I C T Inc公司的发展小趣事

随着电子技术的不断发展,EG & G Inc公司不断进行技术创新和产品升级。公司投入大量资源进行研发,成功推出了一系列具有竞争力的电子产品。其中,某款高精度测量仪器在市场上获得了广泛认可,成为了公司的明星产品。此外,公司还积极开拓新的应用领域,将电子技术应用于医疗、环保等多个领域,为公司带来了新的增长点。

Gulf Semiconductor公司的发展小趣事

EG & G Inc公司成立于20世纪早期,最初专注于电子设备的研发和生产。公司凭借其技术优势和创新能力,在电子行业中逐渐崭露头角。在成立初期,EG & G Inc就与多家知名企业和研究机构建立了合作关系,共同推动电子技术的发展和应用。这些合作关系不仅为公司带来了技术上的支持,也为其在市场上的扩张奠定了基础。

启珑(CHIPLON)公司的发展小趣事

EG & G Inc公司成立于20世纪早期,最初专注于电子设备的研发和生产。公司凭借其技术优势和创新能力,在电子行业中逐渐崭露头角。在成立初期,EG & G Inc就与多家知名企业和研究机构建立了合作关系,共同推动电子技术的发展和应用。这些合作关系不仅为公司带来了技术上的支持,也为其在市场上的扩张奠定了基础。

问答坊 | AI 解惑

PCB地与地的问题

一块PCB板子的地与接插件的地不通会怎样?怎样才会不通?各位大大99…

查看全部问答>

基于KEELOQ跳码技术的密码发生器设计

基于密码的访问控制系统应用在当今是非常普遍的,但人们对其提供的安全等级经常估计过高。通信传输速度和系统计算能力的提高使得系统受到恶意攻击或“密码扫描”的风险增加。在使用不安全的传送方式时,可能发生密码被盗取的现象。例如典型的通过电 ...…

查看全部问答>

求教:功耗问题

    我用的是飞思卡尔的射频芯片MC13213,需要完成的功能是:用MC13213的I2C接口接收数据,当从机有中断信号的时侯开始接收数据,接收到的数据不为0时才通过射频发送数据。    可是在功耗上出现了问题:不管有没有中断产生, ...…

查看全部问答>

添加记录问题

Imports System.Data.SqlServerCe Imports System.IO Public Class Form2     Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load        &nbs ...…

查看全部问答>

RELEASETYPE is not set. Using default settings.

今天编译CE5.0内核遇到这么个警告: RELEASETYPE is not set. Using default settings. 结果导致编译出错,而用同样的BSP在我同事的机子上却没事,所以我怀疑是PB出了问题,哪位大侠给指点一下…

查看全部问答>

AVR中怎么象51那样把不变的数据存到代码段?

最近 做东西需要很多数据的存储但是空间有限啊就是要把一些不变的制度数据存到其他的地方中去,以免占用太多的数据存储空间。。…

查看全部问答>

Nand Flash 分区只得到一半的容量?

wince5.0 下 flash是 1G bytes 的,型号K9K8G08U0M 分号区后,我在存储管理器中看到,容量:960M,未分配的:896M,我只分到64M. 问题: 1、怎样我才能将未分配的容量加分出来呢? 2、OS是通过哪个函数分得64M的呢,FMD_ReadSector()?我驱 ...…

查看全部问答>

创意盲文手机:接通的不仅仅是电话

创意盲文电话:接通的不仅仅是电话最近热播的中国移动最新广告,打动了无数人的情绪,就像安静水面掉入的一个小石块,激起层层涟漪,让我们的内心久久不能安静,这样的创意应当受到感谢的掌声。同样,这款创意盲文手机,也是一个巨大的创意,也许它 ...…

查看全部问答>

AT89C51控制M62429的程序谁有?

AT89C51控制M62429程序中的发送6位数据和发送5位数据子程序我不会作,谁能教教我?…

查看全部问答>

求助!ccs与目标板连接连接不上

我自己做了一块dsp28016的最小系统,测得电压、时钟信号都是正常的,用的仿真器是spectrum digital 510LC usb 每次连接报错是: Error connecting to the target: Error 0x80000200/-1135 Fatal Error during: OCS, Unrecoverable emulation ...…

查看全部问答>