历史上的今天
今天是: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)
史海拾趣
|
基于密码的访问控制系统应用在当今是非常普遍的,但人们对其提供的安全等级经常估计过高。通信传输速度和系统计算能力的提高使得系统受到恶意攻击或“密码扫描”的风险增加。在使用不安全的传送方式时,可能发生密码被盗取的现象。例如典型的通过电 ...… 查看全部问答> |
|
RELEASETYPE is not set. Using default settings. 今天编译CE5.0内核遇到这么个警告: RELEASETYPE is not set. Using default settings. 结果导致编译出错,而用同样的BSP在我同事的机子上却没事,所以我怀疑是PB出了问题,哪位大侠给指点一下… 查看全部问答> |
|
wince5.0 下 flash是 1G bytes 的,型号K9K8G08U0M 分号区后,我在存储管理器中看到,容量:960M,未分配的:896M,我只分到64M. 问题: 1、怎样我才能将未分配的容量加分出来呢? 2、OS是通过哪个函数分得64M的呢,FMD_ReadSector()?我驱 ...… 查看全部问答> |
|
创意盲文电话:接通的不仅仅是电话最近热播的中国移动最新广告,打动了无数人的情绪,就像安静水面掉入的一个小石块,激起层层涟漪,让我们的内心久久不能安静,这样的创意应当受到感谢的掌声。同样,这款创意盲文手机,也是一个巨大的创意,也许它 ...… 查看全部问答> |
|
我自己做了一块dsp28016的最小系统,测得电压、时钟信号都是正常的,用的仿真器是spectrum digital 510LC usb 每次连接报错是: Error connecting to the target: Error 0x80000200/-1135 Fatal Error during: OCS, Unrecoverable emulation ...… 查看全部问答> |




