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
英文地址,請注明出處:http://en.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 數據…