DM9000AE+STM32H7在rt-thread中的使用

概述

记录下DM9000AE在rt-thread上的使用

  1. FMC的配置

  2. rt-thread的网络设备驱动注册

硬件连接

  • 16bit总线

  • 挂在FMC_A0 地址0x6000_0000

FMC的配置

FMC是STM32H7的一个外设,通过FMC把DM9000当做一个SRAM来访问,只需要配置好FCM的时序就可以了。

DM9000时序描述

来看一下DM9000的数据手册上对时序的描述

从手册上来看DM9000的时序情况如下

访问方式数据建立时间地址建立时间
读取最小 10ns80ns (F0寄存器需要80ns)
写入最小 10ns40ns

FMC的时序配置

STM32H7的FMC外设,支持读写时序分离配置,也可以读写使用同一个时序配置,这里为了简单就直接使用一个,会牺牲效率, 性能优化可以在这里把读写分开,因为DM9000的读写速度明显不一样。

FMC的时钟配置,将地址建立时间大于80ns, 数据建立时间大于10ns

Timing.BusTurnAroundDuration = 2; // 片选信号,高脉宽

这个参数,实测影响的是片选信号的高电平,如果设置为0,则相当于片选一直有效

但是DM9000的SD口是地址和数据复用的,需要一定的切换时间,所以这个值需要设置,不然会发生异常。

这里设置为2,只是参考值,读者可以根据实际情况设置。

MPU配置(重要)

STM32H7有专用的内存保护单元,能够管理内存的访问权限。

这里FMC是挂在0x6000_0000的内存区域,为了能够正常访问外部的DM9000需要对该区域进行权限访问。

网络设备驱动注册

rt-thread的网络设备驱动的注册还是比较易懂的,我们需要实现的是操作硬件的接口即可。

这里重点关注这三个函数

  • rt_dm9000_init // DM9000的初始化

  • rt_dm9000_rx // DM9000读取网络数据包

  • rt_dm9000_tx // 发送网络数据包

实际上DM9000负责收发以太网帧, lwip负责协议处理。

dm9000的初始化没有什么特别的,按照初始化流程走,硬件、软件复位、校验ID、配置中断、使能等。

重点看看接收和发送

// DM9000
DM90000 INT-> rt_dm9000_isr-> eth_device_ready(&(dm9000_device.parent));-> return rt_mb_send(&eth_rx_thread_mb, (rt_uint32_t)dev);// 通过信号量通知接收线程-> eth_rx_thread_entry -> if (rt_mb_recv(&eth_rx_thread_mb, (rt_ubase_t *)&device, RT_WAITING_FOREVER) == RT_EOK)  // 等待信号量, DM9000中断触发while(1)    // 注意这里,循环读取,所以在eth_rx接口中,**读取一帧**就立即返回即可。{-> p = device->eth_rx(&(device->parent));                   // 注册驱动时指定的 读取DM9000的接口-> if( device->netif->input(p, device->netif) != ERR_OK )   // 提交给lwip协议栈}

DM9000的收发

DM9000有一个16KB的硬件FIFO, 默认配置下,前3KB用于发送,后13KB用于接收,这个大小可以通过配置相应的寄存器修改。

发送过程

  1. 数据放入发送FIFO

  2. 告诉DM9000数据总量

  3. 启动发送

  4. 可以轮询等待,也可以等中断通知

// 概要

rt_err_t rt_dm9000_tx( rt_device_t dev, struct pbuf* p)-> dm9000_io_write(DM9000_IMR, IMR_PAR); // 屏蔽中断,防止干扰-> DM9000_IO = DM9000_MWCMD;	// 写入操作while(1){-> word[word_index++] = ((u8_t*)q->payload)[pbuf_index++];-> DM9000_DATA = (word[1] << 8) | word[0]; // write two bytes to DM9000_DATA 每次2字节写入}-> dm9000_io_write(DM9000_TXPLL, p->tot_len & 0xff);-> dm9000_io_write(DM9000_TXPLH, (p->tot_len >> 8) & 0xff);-> dm9000_io_write(DM9000_TCR, TCR_TXREQ); // 使能bit0启动发送,发送完成后会自动清除-> dm9000_io_write(DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM | ISR_ROS | ISR_ROOS); // 恢复中断

接收过程

接收过程需要注意的地方多一点,主要是数据帧的组织和读取动作。

先来看看数据帧在FIFI中分布

  • 数据帧:4B的头+pyload+4B CRC

  • 多个数据帧连续排布

特别注意

  1. DM9000的FIFO是双字节对齐的

    当pyload为奇数时,会出现一下情况,在最后一个字节会多一字节,让下一帧对齐地址。

  2. DM9000触发中断后RX-FIFO可能会有多帧

    在rt-thread的网络驱动中,接收函数只需要构建一帧数据就好,在驱动线程中会一次性读取完,直到读取到空数据为止。
  3. DM9000的RX-FIFO每一帧都有4B的CRC

    协议栈不需要这4B 需要丢弃掉

    dummy_u16 = DM9000_DATA;
    dummy_u16 = DM9000_DATA;

ps: 源码放最后,感谢看完本篇的你!

源码

#ifndef __DRV_DM9000_H__
#define __DRV_DM9000_H__
​
// #define DM9000_IO_BASE      0x64000000  
// // #define DM9000_DATA_BASE    0x64000100  // FSMC_A7 -- CMD = 1
// #define DM9000_DATA_BASE    (0x64000000 + 0x00000002)  // FSMC_A7 -- CMD = 1
​
// #define DM9000_IO            (*((volatile rt_uint16_t *) DM9000_IO_BASE))    // CMD = 0
// #define DM9000_DATA      (*((volatile rt_uint16_t *) DM9000_DATA_BASE))  // CMD = 1
​#include "main.h"typedef __IO uint32_t  vu32;typedef __IO uint16_t vu16;typedef __IO uint8_t  vu8;
​typedef uint32_t  u32;typedef uint16_t u16;typedef uint8_t  u8;
//DM9000地址结构体
typedef struct
{vu16 REG;vu16 DATA;
}DM9000_TypeDef;
#define DM9000_BASE        ((u32)(0x60000000))
#define DM9000             ((DM9000_TypeDef *) DM9000_BASE)
​
#define DM9000_IO_BASE      (DM9000->REG)  
#define DM9000_DATA_BASE    (DM9000->DATA)  // FSMC_A0 -- CMD = 1
#define DM9000_IO           (DM9000->REG)    // CMD = 0
#define DM9000_DATA         (DM9000->DATA)  // CMD = 1
​
// #define DM9000_IO_BASE      0x64000000  
// #define DM9000_DATA_BASE    (0x64000000 + 0x2)  // FSMC_A0 -- CMD = 1
​
// #define DM9000_IO            (*((volatile rt_uint16_t *) DM9000_IO_BASE))    // CMD = 0
// #define DM9000_DATA      (*((volatile rt_uint16_t *) DM9000_DATA_BASE))  // CMD = 1
​
​
// #define DM9000_inb(r)        (*(volatile rt_uint8_t  *)r)
// #define DM9000_outb(r, d)    (*(volatile rt_uint8_t  *)r = d)
// #define DM9000_inw(r)        (*(volatile rt_uint16_t *)r)
// #define DM9000_outw(r, d)    (*(volatile rt_uint16_t *)r = d)
​
#define DM9000_ID           0x90000A46  /* DM9000 ID */
#define DM9000_PKT_MAX      1536        /* Received packet max size */
#define DM9000_PKT_RDY      0x01        /* Packet ready to receive */
​
#define DM9000_NCR          0x00
#define DM9000_NSR          0x01
#define DM9000_TCR          0x02
#define DM9000_TSR1         0x03
#define DM9000_TSR2         0x04
#define DM9000_RCR          0x05
#define DM9000_RSR          0x06
#define DM9000_ROCR         0x07
#define DM9000_BPTR         0x08
#define DM9000_FCTR         0x09
#define DM9000_FCR          0x0A
#define DM9000_EPCR         0x0B
#define DM9000_EPAR         0x0C
#define DM9000_EPDRL        0x0D
#define DM9000_EPDRH        0x0E
#define DM9000_WCR          0x0F
​
#define DM9000_PAR          0x10
#define DM9000_MAR          0x16
​
#define DM9000_GPCR         0x1e
#define DM9000_GPR          0x1f
#define DM9000_TRPAL        0x22
#define DM9000_TRPAH        0x23
#define DM9000_RWPAL        0x24
#define DM9000_RWPAH        0x25
​
#define DM9000_VIDL         0x28
#define DM9000_VIDH         0x29
#define DM9000_PIDL         0x2A
#define DM9000_PIDH         0x2B
​
#define DM9000_CHIPR        0x2C
#define DM9000_TCR2         0x2D
#define DM9000_OTCR         0x2E
#define DM9000_SMCR         0x2F
​
#define DM9000_ETCR         0x30    /* early transmit control/status register */
#define DM9000_CSCR         0x31    /* check sum control register */
#define DM9000_RCSSR        0x32    /* receive check sum status register */
​
#define DM9000_MRCMDX       0xF0
#define DM9000_MRCMD        0xF2
#define DM9000_MRRL         0xF4
#define DM9000_MRRH         0xF5
#define DM9000_MWCMDX       0xF6
#define DM9000_MWCMD        0xF8
#define DM9000_MWRL         0xFA
#define DM9000_MWRH         0xFB
#define DM9000_TXPLL        0xFC
#define DM9000_TXPLH        0xFD
#define DM9000_ISR          0xFE
#define DM9000_IMR          0xFF
​
#define CHIPR_DM9000A       0x19
#define CHIPR_DM9000B       0x1B
​
#define NCR_EXT_PHY         (1<<7)
#define NCR_WAKEEN          (1<<6)
#define NCR_FCOL            (1<<4)
#define NCR_FDX             (1<<3)
#define NCR_LBK             (3<<1)
#define NCR_RST             (1<<0)
​
#define NSR_SPEED           (1<<7)
#define NSR_LINKST          (1<<6)
#define NSR_WAKEST          (1<<5)
#define NSR_TX2END          (1<<3)
#define NSR_TX1END          (1<<2)
#define NSR_RXOV            (1<<1)
​
#define TCR_TJDIS           (1<<6)
#define TCR_EXCECM          (1<<5)
#define TCR_PAD_DIS2        (1<<4)
#define TCR_CRC_DIS2        (1<<3)
#define TCR_PAD_DIS1        (1<<2)
#define TCR_CRC_DIS1        (1<<1)
#define TCR_TXREQ           (1<<0)
​
#define TSR_TJTO            (1<<7)
#define TSR_LC              (1<<6)
#define TSR_NC              (1<<5)
#define TSR_LCOL            (1<<4)
#define TSR_COL             (1<<3)
#define TSR_EC              (1<<2)
​
#define RCR_WTDIS           (1<<6)
#define RCR_DIS_LONG        (1<<5)
#define RCR_DIS_CRC         (1<<4)
#define RCR_ALL             (1<<3)
#define RCR_RUNT            (1<<2)
#define RCR_PRMSC           (1<<1)
#define RCR_RXEN            (1<<0)
​
#define RSR_RF              (1<<7)
#define RSR_MF              (1<<6)
#define RSR_LCS             (1<<5)
#define RSR_RWTO            (1<<4)
#define RSR_PLE             (1<<3)
#define RSR_AE              (1<<2)
#define RSR_CE              (1<<1)
#define RSR_FOE             (1<<0)
​
#define FCTR_HWOT(ot)       (( ot & 0xf ) << 4 )
#define FCTR_LWOT(ot)       ( ot & 0xf )
​
#define IMR_PAR             (1<<7)
#define IMR_ROOM            (1<<3)
#define IMR_ROM             (1<<2)
#define IMR_PTM             (1<<1)
#define IMR_PRM             (1<<0)
​
#define ISR_ROOS            (1<<3)
#define ISR_ROS             (1<<2)
#define ISR_PTS             (1<<1)
#define ISR_PRS             (1<<0)
#define ISR_CLR_STATUS      (ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS)
​
#define EPCR_REEP           (1<<5)
#define EPCR_WEP            (1<<4)
#define EPCR_EPOS           (1<<3)
#define EPCR_ERPRR          (1<<2)
#define EPCR_ERPRW          (1<<1)
#define EPCR_ERRE           (1<<0)
​
#define GPCR_GEP_CNTL       (1<<0)
​
/* 原子例程 dm9000内部的phy寄存器 */
#define DM9000_PHY_BMCR     0X00
#define DM9000_PHY_BMSR     0X01
#define DM9000_PHY_PHYID1   0X02
#define DM9000_PHY_PHYID2   0X03
#define DM9000_PHY_ANAR     0X04
#define DM9000_PHY_ANLPAR   0X05
#define DM9000_PHY_ANER     0X06
#define DM9000_PHY_DSCR     0X10
#define DM9000_PHY_DSCSR    0X11
#define DM9000_PHY_10BTCSR  0X12
#define DM9000_PHY_PWDOR    0X13
#define DM9000_PHY_SCR      0X14
​
#ifdef __cplusplus
extern "C" {
#endif
​
int rt_hw_dm9000_init(void);
​
#ifdef __cplusplus
}
#endif
​
#endif // __DRV_DM9000_H__
#include "drv_dm9000.h"
​
#define DBG_TAG                        "dm9k"
#define DBG_LVL                        DBG_LOG
#include <rtdbg.h>
​
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
​
#include <netif/ethernetif.h>
​
#include "stm32h7xx_hal_sram.h"
​
// #define DM9000_DEBUG
#ifdef DM9000_DEBUG
#define DM9000_TRACE    rt_kprintf
#else
#define DM9000_TRACE(...)
#endif
​
/* dm9000 reset pin : GPIOD PIN7, LOW is RESET */
#define DM9000_RST_0        rt_pin_write(GET_PIN(A, 10), PIN_LOW)
#define DM9000_RST_1        rt_pin_write(GET_PIN(A, 10), PIN_HIGH)
​
#define MAX_ADDR_LEN        6       /* max length of hw address */
​
#define DM9000_PHY          0x40    /* PHY address 0x01 */
​
#define PIN_NRESET GET_PIN(A, 10) // 复位引脚
#define PIN_IRQ GET_PIN(A, 15)    // 例如:PA0 作为中断引脚
​
enum DM9000_PHY_mode
{DM9000_10MHD = 0, DM9000_100MHD = 1,DM9000_10MFD = 4, DM9000_100MFD = 5,DM9000_AUTO  = 8, DM9000_1M_HPNA = 0x10
};
​
enum DM9000_TYPE
{TYPE_DM9000E,TYPE_DM9000A,TYPE_DM9000B
};
​
struct rt_dm9000_eth
{/* inherit from ethernet device */struct eth_device parent;
​enum DM9000_TYPE type;enum DM9000_PHY_mode mode;
​rt_uint8_t packet_cnt;                /* packet I or II */rt_uint16_t queue_packet_len;          /* queued packet (packet II) */
​/* interface address info. */rt_uint8_t  dev_addr[MAX_ADDR_LEN];     /* hw address   */rt_uint8_t  init_complete;           /* init complete flag */
};
​
static struct rt_dm9000_eth dm9000_device;
static struct rt_semaphore sem_ack, sem_lock;
int dm_irq_cnt, dm_pkg_max;
​
// 这个一定要放在全局作用域下
//static SRAM_HandleTypeDef DM9000_Handler;           //DM9000句柄
​
/* --- */
​
static inline void dm9000_delay_ms(rt_uint32_t ms)
{rt_thread_mdelay(ms); return;
}
​
/* Read a byte from I/O port */
rt_inline rt_uint16_t dm9000_io_read(rt_uint16_t reg) {DM9000_IO = reg;return DM9000_DATA;
}
​
/* Write a byte to I/O port */
rt_inline void dm9000_io_write(rt_uint16_t reg, rt_uint16_t value) {DM9000_IO = reg;DM9000_DATA = value;
}
​
/* Get DeviceID of DM9000 */
static rt_uint32_t dm9000_get_device_id(void)
{rt_uint32_t value;value  = dm9000_io_read(DM9000_VIDL);value |= dm9000_io_read(DM9000_VIDH) << 8;value |= dm9000_io_read(DM9000_PIDL) << 16;value |= dm9000_io_read(DM9000_PIDH) << 24;return value;
}
​
/* Reset DM9000 */
static void dm9000_reset(void) {DM9000_TRACE("enter dm9000_reset\n");DM9000_RST_0; // set rst pin lowdm9000_delay_ms(10);
​DM9000_RST_1;dm9000_delay_ms(100);  // hardware rst over
​dm9000_io_write(DM9000_GPCR, 0x01);dm9000_io_write(DM9000_GPR, 0);dm9000_io_write(DM9000_NCR, (0x02 | NCR_RST)); // soft rst
​do{dm9000_delay_ms(25);}while(dm9000_io_read(DM9000_NCR) & 1); // wait for soft rst over
​dm9000_io_write(DM9000_NCR,0);dm9000_io_write(DM9000_NCR, (0x02 | NCR_RST)); // soft rst again
​do{dm9000_delay_ms(25);}while (dm9000_io_read(DM9000_NCR) & 1);
}
​
​
/* Read a word from phyxcer */
rt_inline rt_uint16_t dm9000_phy_read(rt_uint16_t reg) {rt_uint16_t val;
​/* Fill the phyxcer register into REG_0C */dm9000_io_write(DM9000_EPAR, DM9000_PHY | reg);dm9000_io_write(DM9000_EPCR, 0x0C); /* Issue phyxcer read command */
​dm9000_delay_ms(100);       /* Wait read complete */
​dm9000_io_write(DM9000_EPCR, 0x00); /* Clear phyxcer read command */val = (dm9000_io_read(DM9000_EPDRH) << 8) | dm9000_io_read(DM9000_EPDRL);
​return val;
}
​
/* Write a word to phyxcer */
rt_inline void dm9000_phy_write(rt_uint16_t reg, rt_uint16_t value)
{/* Fill the phyxcer register into REG_0C */dm9000_io_write(DM9000_EPAR, DM9000_PHY | reg);
​/* Fill the written data into REG_0D & REG_0E */dm9000_io_write(DM9000_EPDRL, (value & 0xFF));dm9000_io_write(DM9000_EPDRH, ((value >> 8) & 0xFF));dm9000_io_write(DM9000_EPCR, 0x0A); /* Issue phyxcer write command */
​dm9000_delay_ms(500);       /* Wait write complete */
​dm9000_io_write(DM9000_EPCR, 0x00); /* Clear phyxcer write command */
}
​
/* Set PHY operationg mode */
rt_inline void dm9000_phy_mode_set(rt_uint8_t mode)
{rt_uint16_t phy_BMCR, phy_ANAR;switch(mode){case DM9000_10MHD:phy_BMCR = 0X0000;phy_ANAR = 0X21;break;case DM9000_10MFD:phy_BMCR = 0X0100;phy_ANAR = 0X41;break;case DM9000_100MHD:phy_BMCR = 0X2000;phy_ANAR = 0X81;break;case DM9000_100MFD:phy_BMCR = 0X2100;phy_ANAR = 0X101;break;case DM9000_AUTO:phy_BMCR = 0X1000;phy_ANAR = 0X01E1;break;}
​dm9000_phy_write(DM9000_PHY_BMCR, phy_BMCR);dm9000_phy_write(DM9000_PHY_ANAR, phy_ANAR); /* Set PHY media mode */
​dm9000_io_write(DM9000_GPCR, 0x01); /* Let GPIO0 output */dm9000_io_write(DM9000_GPR, 0X00);  /* enable PHY */
}
​
/* interrupt service routine */
void rt_dm9000_isr(void *arg)
{rt_uint16_t int_status;rt_uint16_t last_io;
//    rt_uint32_t eint_pend;
​last_io = DM9000_IO;
​/* Disable all interrupts */dm9000_io_write(DM9000_IMR, IMR_PAR);
​/* Got DM9000 interrupt status */int_status = dm9000_io_read(DM9000_ISR);    /* Got ISR */dm9000_io_write(DM9000_ISR, int_status);    /* Clear ISR status */
​DM9000_TRACE("dm9000 isr: int status %04x\n", int_status);
​/* receive overflow */if (int_status & ISR_ROS){LOG_W("overflow, ISR:%02x", int_status);}
​if (int_status & ISR_ROOS){LOG_W("overflow counter overflow, ISR:%02x", int_status);}
​/* Received the coming packet */if (int_status & ISR_PRS){/* a frame has been received */eth_device_ready(&(dm9000_device.parent));dm_irq_cnt ++;}
​/* Transmit Interrupt check */if (int_status & ISR_PTS){/* clear int_status */dm9000_io_write(DM9000_ISR, ISR_PTS);
​/* transmit done */int tx_status = dm9000_io_read(DM9000_NSR); /* Got TX status */
​if (tx_status & (NSR_TX2END | NSR_TX1END)){dm9000_device.packet_cnt --;if (dm9000_device.packet_cnt > 0){DM9000_TRACE("dm9000 isr: tx second packet\n");
​/* transmit packet II *//* Set TX length to DM9000 */dm9000_io_write(DM9000_TXPLL, dm9000_device.queue_packet_len & 0xff);dm9000_io_write(DM9000_TXPLH, (dm9000_device.queue_packet_len >> 8) & 0xff);
​/* Issue TX polling command */dm9000_io_write(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */}
​/* One packet sent complete *//* clear tx isr */if (sem_ack.value != 0) {LOG_W("isr: trying to release sem_ack while its value > 0 / failed");} else {rt_sem_release(&sem_ack);}}}
​/* Re-enable interrupt mask */dm9000_io_write(DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM | ISR_ROS | ISR_ROOS);
​DM9000_IO = last_io;
}
​
static void dm9000_softrst_wait(rt_uint32_t ms)
{dm9000_io_write(DM9000_NCR, NCR_RST);do{rt_thread_mdelay(ms);} while (dm9000_io_read(DM9000_NCR) & 1); /* wait for soft rst over */
​/* initialize regs */
​/* GPIO0 on pre-activate PHY */dm9000_io_write(DM9000_GPR, 0x00);              /* REG_1F bit0 activate phyxcer */dm9000_io_write(DM9000_GPCR, GPCR_GEP_CNTL);    /* Let GPIO0 output */dm9000_io_write(DM9000_GPR, 0x00);               /* Enable PHY */
​/* Set PHY */dm9000_phy_mode_set(dm9000_device.mode);
​/* Program operating register */dm9000_io_write(DM9000_NCR, 0x0);   /* only intern phy supported by now */dm9000_io_write(DM9000_TCR, 0);     /* TX Polling clear */dm9000_io_write(DM9000_BPTR, 0x3f); /* Less 3Kb, 200us */dm9000_io_write(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));  /* Flow Control : High/Low Water */dm9000_io_write(DM9000_FCR, 0x0);   /* SH FIXME: This looks strange! Flow Control */dm9000_io_write(DM9000_SMCR, 0);    /* Special Mode */dm9000_io_write(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);  /* clear TX status */dm9000_io_write(DM9000_ISR, 0x0f);  /* Clear interrupt status */dm9000_io_write(DM9000_TCR2, 0x80); /* Switch LED to mode 1 */
​/* Activate DM9000 */dm9000_io_write(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN); /* RX enable */dm9000_io_write(DM9000_IMR, IMR_PAR);
}
​
/* RT-Thread Device Interface */
/* initialize the interface */
static rt_err_t rt_dm9000_init(rt_device_t dev)
{LOG_I("Driver dm9000 init / start");int i, oft, lnk;rt_uint32_t dm9000_id;
​/* RESET device */dm9000_reset();dm9000_delay_ms(100);
​/* identfy DM9000 */dm9000_id = dm9000_get_device_id();LOG_I("dm9000 id: 0x%x", dm9000_id);if (dm9000_id != DM9000_ID) {LOG_E("dm9000 id error");return -RT_ERROR;}
​/* set mac address */for (i = 0, oft = DM9000_PAR; i < 6; ++i, ++oft)dm9000_io_write(oft, dm9000_device.dev_addr[i]);/* set multicast address */for (i = 0, oft = DM9000_MAR; i < 8; ++i, ++oft)dm9000_io_write(oft, 0xff);
​dm9000_softrst_wait(25); /* init regs here */
​if (dm9000_device.mode == DM9000_AUTO){i = 0;while (!(dm9000_phy_read(1) & 0x20)){/* autonegation complete bit */rt_thread_delay( RT_TICK_PER_SECOND/10 );i++;if (i > 30 ) /* wait 3s */{LOG_E("could not establish link");return 0;}}}
​/* send a notify */eth_device_linkchange(&dm9000_device.parent, RT_TRUE);
​/* see what we've got */lnk = dm9000_phy_read(17) >> 12;switch (lnk){case 1:LOG_I("10M half duplex ");break;case 2:LOG_I("10M full duplex ");break;case 4:LOG_I("100M half duplex ");break;case 8:LOG_I("100M full duplex ");break;default:LOG_I("unknown: %d ", lnk);break;}
​/* Enable TX/RX interrupt mask */dm9000_io_write(DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM | ISR_ROS | ISR_ROOS);
​LOG_I("Driver dm9000 init / end");dm9000_device.init_complete = 1;return RT_EOK;
}
​
static rt_err_t rt_dm9000_open(rt_device_t dev, rt_uint16_t oflag)
{return RT_EOK;
}
​
static rt_err_t rt_dm9000_close(rt_device_t dev)
{/* RESET devie */dm9000_phy_write(0, 0x8000);    /* PHY RESET */dm9000_io_write(DM9000_GPR, 0x01);  /* Power-Down PHY */dm9000_io_write(DM9000_IMR, 0x80);  /* Disable all interrupt */dm9000_io_write(DM9000_RCR, 0x00);  /* Disable RX */
​return RT_EOK;
}
​
static rt_size_t rt_dm9000_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
{rt_set_errno(-RT_ENOSYS);return 0;
}
​
static rt_size_t rt_dm9000_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
{rt_set_errno(-RT_ENOSYS);return 0;
}
​
static rt_err_t rt_dm9000_control(rt_device_t dev, int cmd, void *args)
{switch (cmd){case NIOCTL_GADDR:/* get mac address */if (args) rt_memcpy(args, dm9000_device.dev_addr, 6);else return -RT_ERROR;break;
​default :break;}
​return RT_EOK;
}
​
/* ethernet device interface */
/* transmit packet. */
rt_err_t rt_dm9000_tx( rt_device_t dev, struct pbuf* p)
{
//    LOG_D("enter rt_dm9000_tx, p->tot_len: %d\n", p->tot_len);DM9000_TRACE("rt_dm9000_tx: %d\n", p->tot_len);
​/* lock DM9000 device */rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
​/* disable dm9000a interrupt */dm9000_io_write(DM9000_IMR, IMR_PAR);
​/* Move data to DM9000 TX RAM */// DM9000_outb(DM9000_IO_BASE, DM9000_MWCMD);DM9000_IO = DM9000_MWCMD;
​{/* q traverses through linked list of pbuf's* This list MUST consist of a single packet ONLY */struct pbuf *q;rt_uint16_t pbuf_index = 0;rt_uint8_t word[2], word_index = 0;
​q = p;/* Write data into dm9000a, two bytes at a time* Handling pbuf's with odd number of bytes correctly* No attempt to optimize for speed has been made */while (q){if (pbuf_index < q->len){word[word_index++] = ((u8_t*)q->payload)[pbuf_index++];if (word_index == 2){// DM9000_outw(DM9000_DATA_BASE, (word[1] << 8) | word[0]);DM9000_DATA = (word[1] << 8) | word[0]; // write two bytes to DM9000_DATAword_index = 0;}}else{q = q->next;pbuf_index = 0;}}/* One byte could still be unsent */if (word_index == 1){// DM9000_outw(DM9000_DATA_BASE, word[0]);DM9000_DATA = word[0]; // write one byte to DM9000_DATA}}
​
//    /* Set TX length to DM9000 */
//    dm9000_io_write(DM9000_TXPLL, p->tot_len & 0xff);
//    dm9000_io_write(DM9000_TXPLH, (p->tot_len >> 8) & 0xff);
//
//    /* Issue TX polling command */
//    dm9000_io_write(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
​if (dm9000_device.packet_cnt == 0){DM9000_TRACE("dm9000 tx: first packet\n");
​dm9000_device.packet_cnt ++;/* Set TX length to DM9000 */dm9000_io_write(DM9000_TXPLL, p->tot_len & 0xff);dm9000_io_write(DM9000_TXPLH, (p->tot_len >> 8) & 0xff);
​/* Issue TX polling command */dm9000_io_write(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */}else{DM9000_TRACE("dm9000 tx: second packet\n");
​dm9000_device.packet_cnt ++;dm9000_device.queue_packet_len = p->tot_len;}
​/* enable dm9000a all interrupt */dm9000_io_write(DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM | ISR_ROS | ISR_ROOS);
​/* unlock DM9000 device */rt_sem_release(&sem_lock);
​/* wait ack */rt_sem_take(&sem_ack, RT_WAITING_FOREVER);
​DM9000_TRACE("rt_dm9000_tx done\n");
​return RT_EOK;
}
​
/* reception packet. */
struct pbuf *rt_dm9000_rx(rt_device_t dev)
{struct pbuf* p;rt_uint32_t rx_ready; /* first rx byte */rt_uint16_t rx_status, rx_len;rt_uint16_t* data;rt_uint8_t dummy_u8;rt_uint16_t dummy_u16; // used for dummyrt_int32_t len;
​/* init p pointer */p = RT_NULL;
​/* lock DM9000 device */rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
​/* disable dm9000a interrupt */dm9000_io_write(DM9000_IMR, IMR_PAR);
​/* Check packet ready or not */// dm9000_io_read(DM9000_MRRH); // 读取这两个寄存器// dm9000_io_read(DM9000_MRRL);dm9000_io_read(DM9000_MRCMDX);              /* Dummy read */// rx_ready = DM9000_inb(DM9000_DATA_BASE);      /* Got most updated data */rx_ready = (u8)DM9000_DATA;      /* Got most updated data */if (rx_ready == 0x01){/* A packet ready now  & Get status/length */// DM9000_outb(DM9000_IO_BASE, DM9000_MRCMD);// rx_status = DM9000_inw(DM9000_DATA_BASE) & 0xff00;// rx_len = DM9000_inw(DM9000_DATA_BASE);
​DM9000_IO = DM9000_MRCMD;rx_status = DM9000_DATA & 0xff00;rx_len = DM9000_DATA;
​DM9000_TRACE("dm9000 rx: status %04x len %d\n", rx_status, rx_len);
​/* error handle */if ((rx_status & 0xbf00) || (rx_len < 0x40) || (rx_len > DM9000_PKT_MAX)){LOG_E("rx error: status %04x, rx_len: %d", rx_status, rx_len);
​if (rx_status & 0x100){LOG_E("rx fifo error");}if (rx_status & 0x200){LOG_E("rx crc error");}if (rx_status & 0x8000){LOG_E("rx length error");}if (rx_len > DM9000_PKT_MAX){LOG_E("rx length too big");}
​/* software-reset and re-init */dm9000_softrst_wait(25);
​/* it issues an error, release pbuf */if (p != RT_NULL)pbuf_free(p);p = RT_NULL;goto _rx_end;}
​/* allocate buffer */// p = pbuf_alloc(PBUF_LINK, rx_len, PBUF_RAM);rx_len -= 4; // remove 4B CRCp = pbuf_alloc(PBUF_RAW, rx_len, PBUF_POOL);if (p != RT_NULL){// RT_ASSERT(p->type == PBUF_RAM); /* set PBUF_RAM above */// if (p->type == PBUF_RAM) {/* p is one large chunk */
//                int i;
​// RT_ASSERT(p->next == RT_NULL);// RT_ASSERT(p->len == p->tot_len);
​data = (rt_uint16_t*)p->payload;len = p->len;
​while (len > 1) {// *data = DM9000_inw(DM9000_DATA_BASE);*data = DM9000_DATA;data++;len -= 2;}
​/* just read a byte, protect memory */if (len == 1) {// dummy_u8 = DM9000_inb(DM9000_DATA_BASE);dummy_u8 = (u8)DM9000_DATA;((rt_uint8_t*)p->payload)[p->len - 1] = dummy_u8;}
​dummy_u16 = DM9000_DATA;dummy_u16 = DM9000_DATA;
​// } else { /* p is not one large chunk *///     struct pbuf* q;//     rt_int32_t len;
​//     for (q = p; q != RT_NULL; q= q->next)//     {//         data = (rt_uint16_t*)q->payload;//         len = q->len;
​//         while (len > 0)//         {//             *data = DM9000_inw(DM9000_DATA_BASE);//             data ++;//             len -= 2;//         }//     }// }}else /* pbuf allocate failed */{LOG_E("dm9000 rx: no pbuf, rx_len:%d", rx_len);len = rx_len;
​/* no pbuf, discard data from DM9000 */while (len > 1){// dummy_u16 = DM9000_inw(DM9000_DATA_BASE); /* dummy read 2 bytes */dummy_u16 = DM9000_DATA; /* dummy read 2 bytes */len -= 2;}
​/* len == 1, if remaining 1 byte not read */if (len == 1){// dummy_u8 = DM9000_inb(DM9000_DATA_BASE); /* dummy read 1 byte */dummy_u8 = DM9000_DATA;}}}else if (rx_ready > 0x01) /* error, stop interface and wait to reset */{LOG_E("dm9000 rx: rx error, stop device rx_ready:%d", rx_ready);
​dm9000_io_write(DM9000_ISR, 0x80);  /* Stop INT request */dm9000_io_write(DM9000_ISR, 0x0F);  /* Clear ISR status */dm9000_io_write(DM9000_RCR, 0x00);  /* Stop Rx Function */
​dm9000_softrst_wait(5); /* software-reset and re-init */goto _rx_end;}/*else rx_ready == 0x00, no message should be read */
​
_rx_end:
​/* clear packet received latch status */dm9000_io_write(DM9000_ISR, ISR_PRS);
​/* restore receive interrupt */dm9000_io_write(DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM | ISR_ROS | ISR_ROOS);
​/* unlock DM9000 device */rt_sem_release(&sem_lock);
​return p;
}
​
static uint32_t FMC_Initialized = 0;
​
static void DM9000_GPIO_Init(void)
{/* USER CODE BEGIN FMC_MspInit 0 */
​__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOE_CLK_ENABLE();__HAL_RCC_GPIOF_CLK_ENABLE();/* USER CODE END FMC_MspInit 0 */GPIO_InitTypeDef GPIO_InitStruct = {0};if (FMC_Initialized){return;}FMC_Initialized = 1;
​/* Peripheral clock enable */__HAL_RCC_FMC_CLK_ENABLE();
​/** FMC GPIO ConfigurationPF0   ------> FMC_A0PE7   ------> FMC_D4PE8   ------> FMC_D5PE9   ------> FMC_D6PE10   ------> FMC_D7PE11   ------> FMC_D8PE12   ------> FMC_D9PE13   ------> FMC_D10PE14   ------> FMC_D11PE15   ------> FMC_D12PD8   ------> FMC_D13PD9   ------> FMC_D14PD10   ------> FMC_D15PD14   ------> FMC_D0PD15   ------> FMC_D1PC7   ------> FMC_NE1PD0   ------> FMC_D2PD1   ------> FMC_D3PD4   ------> FMC_NOEPD5   ------> FMC_NWE*//* GPIO_InitStruct */GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
​HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
​/* GPIO_InitStruct */GPIO_InitStruct.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
​HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
​/* GPIO_InitStruct */GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
​HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
​/* GPIO_InitStruct */GPIO_InitStruct.Pin = GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF9_FMC;
​HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
​/* USER CODE BEGIN FMC_MspInit 1 */
​/* USER CODE END FMC_MspInit 1 */
}
​
SRAM_HandleTypeDef hsram1;
​
/* FMC initialization function */
void DM9000_FMC_Config(void)
{/* USER CODE BEGIN FMC_Init 0 */
​/* USER CODE END FMC_Init 0 */
​FMC_NORSRAM_TimingTypeDef Timing = {0};
​/* USER CODE BEGIN FMC_Init 1 */DM9000_GPIO_Init();/* USER CODE END FMC_Init 1 */
​hsram1.Instance = FMC_NORSRAM_DEVICE;hsram1.Extended = FMC_NORSRAM_EXTENDED_DEVICE;/* hsram1.Init */hsram1.Init.NSBank              = FMC_NORSRAM_BANK1;hsram1.Init.DataAddressMux      = FMC_DATA_ADDRESS_MUX_DISABLE;hsram1.Init.MemoryType          = FMC_MEMORY_TYPE_SRAM;hsram1.Init.MemoryDataWidth     = FMC_NORSRAM_MEM_BUS_WIDTH_16; hsram1.Init.BurstAccessMode     = FMC_BURST_ACCESS_MODE_DISABLE;hsram1.Init.WaitSignalPolarity  = FMC_WAIT_SIGNAL_POLARITY_LOW;hsram1.Init.WaitSignalActive    = FMC_WAIT_TIMING_BEFORE_WS;hsram1.Init.WriteOperation      = FMC_WRITE_OPERATION_ENABLE;hsram1.Init.WaitSignal          = FMC_WAIT_SIGNAL_DISABLE;hsram1.Init.ExtendedMode        = FMC_EXTENDED_MODE_DISABLE;hsram1.Init.AsynchronousWait    = FMC_ASYNCHRONOUS_WAIT_DISABLE;hsram1.Init.WriteBurst          = FMC_WRITE_BURST_DISABLE;hsram1.Init.ContinuousClock     = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;hsram1.Init.WriteFifo           = FMC_WRITE_FIFO_DISABLE;hsram1.Init.PageSize            = FMC_PAGE_SIZE_NONE;
​
​// 使用的HCLK 120M = 8.3ns/* Timing */Timing.AddressSetupTime         = 10;       // DM9000手册建议地址建立时间为大于80ns F0寄存器Timing.AddressHoldTime          = 0;        // 模式A没用上Timing.DataSetupTime            = 2;        // DM9000手册建议数据建立时间为大于10ns  Timing.BusTurnAroundDuration    = 2;        // 片选信号,高脉宽Timing.CLKDivision              = 0;        // 模式A没用上Timing.DataLatency              = 0;        // 模式A没用上Timing.AccessMode               = FMC_ACCESS_MODE_A;if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK){Error_Handler();}
​/* USER CODE BEGIN FMC_Init 2 *///设置引脚为输入模式(下降沿触发)rt_pin_mode(PIN_IRQ, PIN_MODE_INPUT);rt_pin_attach_irq(PIN_IRQ, PIN_IRQ_MODE_FALLING, rt_dm9000_isr, RT_NULL);rt_pin_irq_enable(PIN_IRQ, PIN_IRQ_ENABLE);/* USER CODE END FMC_Init 2 */
}
​
// 获取DM9000的连接速度和双工模式
// 返回值:  0,100M半双工
//           1,100M全双工
//           2,10M半双工
//           3,10M全双工
//           0XFF,连接失败!
u8 DM9000_Get_SpeedAndDuplex(void)
{u8 temp;u8 i = 0;if (dm9000_device.mode == DM9000_AUTO) // 如果开启了自动协商模式一定要等待协商完成{while (!(dm9000_phy_read (0X01) & 0X0020)) // 等待自动协商完成{dm9000_delay_ms(10);i++;if (i > 100)return 0XFF; // 自动协商失败}}else // 自定义模式,一定要等待连接成功{while (!(dm9000_io_read(DM9000_NSR) & 0X40)) // 等待连接成功{dm9000_delay_ms(10);i++;if (i > 100)return 0XFF; // 连接失败}}temp = ((dm9000_io_read(DM9000_NSR) >> 6) & 0X02);  // 获取DM9000的连接速度temp |= ((dm9000_io_read(DM9000_NCR) >> 3) & 0X01); // 获取DM9000的双工状态return temp;
}
​
static void phy_linkchange()
{static rt_uint8_t phy_speed = 0;rt_uint8_t temp;
​temp = DM9000_Get_SpeedAndDuplex(); // 获取DM9000的连接速度和双工状态if (temp != 0XFF)                   // 连接成功,通过串口显示连接速度和双工状态{if(phy_speed != temp) // 如果连接状态发生变化{phy_speed = temp;LOG_D("DM9000 Speed:%dMbps,Duplex:%s duplex mode", (temp & 0x02) ? 10 : 100, (temp & 0x01) ? "Full" : "Half");eth_device_linkchange(&dm9000_device.parent, RT_TRUE);}else{return; // 没有变化,直接返回}}else{LOG_D("link down");phy_speed = 0;eth_device_linkchange(&dm9000_device.parent, RT_FALSE);}
}
​
void phy_state_check(void *arg)
{LOG_D("phy_state_check started");while(1){if (dm9000_device.init_complete == 1) phy_linkchange();rt_thread_mdelay(1000); // 每隔1秒检测一次PHY状态}
}
​
int rt_hw_dm9000_init(void) {/* stm32 hal lib dm9000 specific init */rt_uint32_t temp;DM9000_FMC_Config(); // FMC配置
​/* general dm9000 init */rt_sem_init(&sem_ack, "tx_ack", 0, RT_IPC_FLAG_FIFO);   // 同步信号量,初始为0,发送tx后等待中断释放信号量表示tx完成rt_sem_init(&sem_lock, "eth_lock", 1, RT_IPC_FLAG_FIFO); // 互斥信号量,初始为1,用于保护tx和rx过程不冲突dm9000_device.type  = TYPE_DM9000A;dm9000_device.mode  = DM9000_AUTO;dm9000_device.packet_cnt = 0;dm9000_device.queue_packet_len = 0;
​/** SRAM Tx/Rx pointer automatically return to start address,* Packet Transmitted, Packet Received*/// temp = *(volatile rt_uint16_t*)(0x1FFFF7E8);                //获取STM32的唯一ID的前24位作为MAC地址后三字节temp = HAL_GetUIDw0();dm9000_device.dev_addr[0] = 0x02;dm9000_device.dev_addr[1] = 0x00;dm9000_device.dev_addr[2] = 0x00;dm9000_device.dev_addr[3] = (temp >> 16) & 0xFF;    //低三字节用STM32的唯一IDdm9000_device.dev_addr[4] = (temp >> 8) & 0xFFF;dm9000_device.dev_addr[5] = temp  &0xFF;
​dm9000_device.parent.parent.init       = rt_dm9000_init;dm9000_device.parent.parent.open       = rt_dm9000_open;dm9000_device.parent.parent.close      = rt_dm9000_close;dm9000_device.parent.parent.read       = rt_dm9000_read;dm9000_device.parent.parent.write      = rt_dm9000_write;dm9000_device.parent.parent.control    = rt_dm9000_control;dm9000_device.parent.parent.user_data  = RT_NULL;
​dm9000_device.parent.eth_rx  = rt_dm9000_rx;dm9000_device.parent.eth_tx  = rt_dm9000_tx;eth_device_init(&(dm9000_device.parent), "e0");
​rt_thread_t tid;tid = rt_thread_create("phy", phy_state_check, RT_NULL, 512, RT_THREAD_PRIORITY_MAX - 2, 2);rt_thread_startup(tid);
​return RT_EOK;
}
​
INIT_DEVICE_EXPORT(rt_hw_dm9000_init);
​
void dm9000a(void)
{rt_kprintf("\n");rt_kprintf("NCR   (%02X): %02x\n", DM9000_NCR,   dm9000_io_read(DM9000_NCR));rt_kprintf("NSR   (%02X): %02x\n", DM9000_NSR,   dm9000_io_read(DM9000_NSR));rt_kprintf("TCR   (%02X): %02x\n", DM9000_TCR,   dm9000_io_read(DM9000_TCR));rt_kprintf("TSRI  (%02X): %02x\n", DM9000_TSR1,  dm9000_io_read(DM9000_TSR1));rt_kprintf("TSRII (%02X): %02x\n", DM9000_TSR2,  dm9000_io_read(DM9000_TSR2));rt_kprintf("RCR   (%02X): %02x\n", DM9000_RCR,   dm9000_io_read(DM9000_RCR));rt_kprintf("RSR   (%02X): %02x\n", DM9000_RSR,   dm9000_io_read(DM9000_RSR));rt_kprintf("ORCR  (%02X): %02x\n", DM9000_ROCR,  dm9000_io_read(DM9000_ROCR));rt_kprintf("CRR   (%02X): %02x\n", DM9000_CHIPR, dm9000_io_read(DM9000_CHIPR));rt_kprintf("CSCR  (%02X): %02x\n", DM9000_CSCR,  dm9000_io_read(DM9000_CSCR));rt_kprintf("RCSSR (%02X): %02x\n", DM9000_RCSSR, dm9000_io_read(DM9000_RCSSR));rt_kprintf("ISR   (%02X): %02x\n", DM9000_ISR,   dm9000_io_read(DM9000_ISR));rt_kprintf("IMR   (%02X): %02x\n", DM9000_IMR,   dm9000_io_read(DM9000_IMR));rt_kprintf("pin_G_6: %d\n", rt_pin_read(GET_PIN(G, 6)));rt_kprintf("\n");
}
​
#ifdef RT_USING_FINSH
#include <finsh.h>
MSH_CMD_EXPORT(dm9000a, dm9000a register dump);
#endif
​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/909909.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/909909.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TiDB 字符串行转列与 JSON 数据查询优化知识笔记

一、长字符串行转列方案 JSON_TABLE 方案&#xff08;TiDB 5.0 推荐&#xff09; 通过将逗号分隔字符串转为 JSON 数组后展开为行&#xff1a; sql SET str ‘a,b,c,d’; SELECT jt.val, jt.pos FROM JSON_TABLE( CONCAT(‘[’, REPLACE(str, ‘,’, ‘“,”’), ‘"]’…

1 Studying《Performance Analysis and Tuning on Modern CPUs》7-11

目录 Part2. Source Code Tuning For CPU 数据驱动优化 7 CPU Front-End Optimizations 7.1 Machine code layout //机器码布局 7.2 Basic Block 7.3 Basic block placement 7.4 Basic block alignment 7.5 Function splitting //函数拆分 7.6 Function groupin…

WinUI3入门6:子线程处理UI 窗口加载后执行 获取和设置控件尺寸 自动生成事件代码框架

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

中国招聘智能化白皮书:从 “人撑不住“ 到 “AI 破局“ 的底层逻辑革命——AI得贤招聘官第六代AI面试官

一场面试&#xff0c;牵动一家公司的人力系统。 当简历数量以千计堆叠、当HR通宵挑灯刷筛选、当面试质量与效率陷入两难&#xff0c;招聘不再只是流程问题&#xff0c;而成了“组织生存”的关键变量。 问题是&#xff1a;靠人&#xff0c;已经撑不住了。 企业招聘正步入前所…

防爆型激光测距传感器:危险环境中的安全守护者

在石油化工、煤矿开采、核电站等高危工业场景中&#xff0c;爆炸性气体与粉尘的存在让传统测量设备望而却步。而防爆型激光测距传感器的出现&#xff0c;犹如为这些领域注入了一剂“安全强心针”&#xff0c;以毫米级精度与防爆双重保障&#xff0c;重新定义了工业测量的安全边…

【AI编程】PC的一个提示词,生成网站首页,模型gpt4.1 、deepseekv3和claude3.7对比,你更喜欢哪个?

AI提示词&#xff1a; 角色 你是一位资深的前端工程师、设计师和插画师 设计风格 优雅的极简主义美学与功能的完美平衡; 清新柔和的渐变配色与品牌色系浑然一体; 恰到好处的留白设计; 轻盈通透的沉浸式体验; 信息层级通过微妙的阴影过渡与模块化卡片布局清晰呈现; 按钮添加…

跟着AI学习C# Day12

&#x1f4c5; Day 12&#xff1a;LINQ&#xff08;Language Integrated Query&#xff09;基础 ✅ 目标&#xff1a; 理解 LINQ 的基本概念和作用&#xff1b;掌握使用 LINQ 查询集合&#xff08;如 List<T>、Array&#xff09;&#xff1b;学会使用常用 LINQ 方法&am…

ubuntu网络管理五花八门netplan 、NetworkManager、systemd、networking是什么关系

文章目录 **1. Netplan&#xff08;网络配置抽象层&#xff09;****2. NetworkManager&#xff08;动态网络管理&#xff09;****3. systemd-networkd&#xff08;轻量级网络管理&#xff09;****4. networking&#xff08;传统的 ifupdown&#xff09;****5. 它们之间的关系**…

Python爬虫实战:研究Twisted框架相关技术

1. 引言 1.1 研究背景与意义 随着互联网信息的爆炸式增长,网络爬虫作为一种高效获取和收集网络信息的技术手段,在搜索引擎优化、市场调研、数据挖掘等领域有着广泛的应用。传统的同步爬虫在面对大量 URL 请求时,由于 I/O 操作的阻塞特性,效率低下,难以满足实际应用需求。…

内网运行控制四百来个海康威视硬件物联网定员管控软件(华为平板电脑版)

内网运行控制四百来个海康威视硬件物联网定员管控软件&#xff08;华为平板电脑版&#xff09; 从去年12月至今&#xff0c;自研一套在内网中的华为平板电脑上运行&#xff0c;控制四百来个海康威视硬件的物联网定员管控软件&#xff0c;开始上线投入运行。 运行环境为华为平板…

C++ 面向对象特性详解:继承机制

&#x1f680; C 面向对象特性详解&#xff1a;继承机制全解析——代码复用与扩展的核心&#xff08;含实战陷阱&#xff09; &#x1f4c5; 更新时间&#xff1a;2025年6月19日 &#x1f3f7;️ 标签&#xff1a;C | 继承 | OOP | 面向对象 | 代码复用 | C基础 文章目录 &…

学习日记-day33-6.19

知识点&#xff1a; 1.Spring课程概述 知识点 核心内容 重点 Spring框架概述 轻量级容器框架&#xff0c;封装复杂逻辑&#xff0c;需理解IOC、AOP等核心机制 容器框架 vs 普通框架、封装带来的理解门槛 学习难点 动态代理、反射、注解、IO操作、XML解析、容器&#xf…

网络编程中操作系统连接队列管理:Linux TCP队列深度解析

在现代网络编程中&#xff0c;操作系统内核扮演着至关重要的角色&#xff0c;负责管理网络通信的复杂细节&#xff0c;从而为应用程序提供抽象接口。对于服务器应用程序而言&#xff0c;高效处理大量传入连接请求是确保性能和可靠性的核心。操作系统通过维护专门的队列机制来管…

StableDiffusion实战-手机壁纸制作 第一篇:从零基础到生成艺术品的第一步!

大家好!欢迎来到《StableDiffusion实战-手机壁纸制作》系列的第一篇! 在这一篇文章里,我们将一起探索如何用StableDiffusion(SD)这款强大的工具,快速制作出炫酷的手机壁纸。 如果你对生成艺术、AI绘图感兴趣,那你一定不能错过! 你能做什么?你将做什么! 在之前的系…

运维——14.PowerShell 与Linux 、 macOS通用的命令

PowerShell 最初是 Windows 平台的&#xff0c;但现在已经有了 PowerShell Core&#xff0c;它是跨平台的&#xff0c;支持 Linux 和 macOS。在 PowerShell Core 中有一些Linux 和 macOS通用的命令。理清楚这些有助于学习多系统命令。 在 Linux/macOS 上使用 PowerShell 完成文…

C#的泛型和匿名类型

一、C#的泛型简介 泛型是一种允许你延迟编写类或方法中的数据类型规范&#xff0c;直到你在实际使用时才替换为具体的数据类型【简单的说&#xff1a;泛型就是允许我们编写能够适用于任何数据类型的代码&#xff0c;而无需为每种特定类型重写相同的代码】(T是类型参数&#xff…

日语面试ai助手推荐:高效备考并应对日语面试难题

在准备日语面试的路上&#xff0c;你是否时常感到力不从心&#xff1f;每到模拟面试环节&#xff0c;总怕自己答非所问、用语不地道&#xff0c;或是紧张到脑子一片空白。查找资料时&#xff0c;面对海量的日语问答、面试范本和专业术语&#xff0c;常常分不清轻重缓急&#xf…

【63 Pandas+Pyecharts | 泡泡玛特微博热搜评论数据分析可视化】

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据2.2 数据信息2.3 数据去重2.4 数据去空2.5 时间处理2.6 性别处理2.7 评论内容处理 &#x1f3f3;️‍&#x1f308; 3. Pyecharts数据可视化3.1 用户评论IP分…

python-最长无重复子数组

最长无重复子数组 描述代码实现 描述 给定一个长度为n的数组arr&#xff0c;返回arr的最长无重复元素子数组的长度&#xff0c;无重复指的是所有数字都不相同。 子数组是连续的&#xff0c;比如[1,3,5,7,9]的子数组有[1,3]&#xff0c;[3,5,7]等等&#xff0c;但是[1,3,7]不是…

探索 MySQL 缓存机制:提升数据库读取性能的有效策略

在现代应用中,数据库的读取性能是影响用户体验和系统响应速度的关键因素。当应用程序面临高并发读请求时,直接访问磁盘的开销会成为瓶颈。为了应对这一挑战,MySQL 引入了多种缓存机制,旨在减少磁盘 I/O,加快数据检索速度。 理解并合理利用这些缓存机制,是提升 MySQL 数据…