一直以来都想搞个寄存器配置版本的ETH,最近时间充裕,花了近2周,昨天终于实现了以太网的连接,上图
4 u' r- f- F! ]
" T" [) P# [6 W. Q9 D3 U0 U, K; H* ~; y# ]. g$ U, C: S3 F
& r5 G! a5 h+ \; x" B
Q# |: \2 x F
这是打印结果8 e1 C$ b; c5 Q$ D3 l
下面详细说明一下; {8 ]3 n; m7 t8 |/ M; v3 q, y% p" H3 J
首先实现lan8742的驱动
9 U: P* l; H3 y1 Q6 C6 p( D6 i( }- /* Ethernet pins configuration ************************************************/4 R# }7 P# H, q( |1 K" b
- /* D/ X4 X: _2 z" T9 v" i9 h
- RMII_REF_CLK ----------------------> PA1
' y* S' M9 Q" T - RMII_MDIO -------------------------> PA2& u8 b- C: K' t! l5 B% S. K
- RMII_MDC --------------------------> PC1
) y/ i# G; K' J2 n5 Q( B# \ - RMII_MII_CRS_DV -------------------> PA7
8 a, N. l" L& `) d6 H% }: B& y) E - RMII_MII_RXD0 ---------------------> PC41 u6 ~- y1 e3 j& S. i$ L" _; r
- RMII_MII_RXD1 ---------------------> PC5
4 S5 O) A' }, L$ K K3 I8 m - RMII_MII_RXER ---------------------> PG2/PD5$ u$ a, G. H3 v$ i! u
- RMII_MII_TX_EN --------------------> PG11+ P2 U- V K5 g5 j* U2 [; V
- RMII_MII_TXD0 ---------------------> PG13
. K6 m9 U" Q- j9 g& d4 L - RMII_MII_TXD1 ---------------------> PG14
4 M5 x( D* X( d$ z7 L - */6 O3 o" P% r) s# D8 X. T( Y
- *(uint32_t *)0x40023830 |= 0x45; //使能PORTA\C\G时钟 0x4d,ACDG. q5 z$ ^+ b* | N ]
- *(uint32_t *)0x40023830 |= 0xf000000; //使能ETH,TX,RX,MAC时钟
% |+ }4 D! x/ c8 q - GPIO_Set(GPIOA,PIN1|PIN2|PIN7,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_NONE); //PB3,PB4设置
% L) D, D1 K" G - GPIO_AF_Set(GPIOA,1,11); //PA1,AF11
( b- M/ P ]% _, m - GPIO_AF_Set(GPIOA,2,11); //PA2,AF11+ n2 {/ U: }& a4 k* `4 K
- GPIO_AF_Set(GPIOA,7,11); //PA7,AF116 H; R5 P j7 w# [5 M0 ^
- GPIO_Set(GPIOC,PIN1|PIN4|PIN5,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_NONE); //PB3,PB4设置
9 o: _( ^7 N6 t1 E6 C( F8 Y# |( b - GPIO_AF_Set(GPIOC,1,11); //PC1,AF119 G# |/ {& _ h" H2 O. q
- GPIO_AF_Set(GPIOC,4,11); //PC4,AF11
7 @( z: e5 h% ~- s - GPIO_AF_Set(GPIOC,5,11); //PC5,AF11
$ N" q& Y" D/ I - GPIO_Set(GPIOD,PIN5,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_NONE); //PB3,PB4设置( y& A/ d# F1 ]4 Q1 V
- GPIO_AF_Set(GPIOD,5,11); //PD5,AF11
3 I& `( {, ?8 ^ - GPIO_Set(GPIOG,PIN2|PIN11|PIN13|PIN14,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_NONE); //PB3,PB4设置5 a$ L: K8 ~- `# X
- GPIO_AF_Set(GPIOG,2,11); //PG2,AF11( n9 r. s; J2 x5 q
- GPIO_AF_Set(GPIOG,11,11); //PG11,AF11! \/ D! f7 v3 E8 T- J P
- GPIO_AF_Set(GPIOG,13,11); //PG13,AF11
5 Z1 p l0 P2 K$ d( F$ T8 |& `/ W - GPIO_AF_Set(GPIOG,14,11); //PG14,AF11" p0 s& C" K$ U o
: y; }2 x( G3 D: L$ }- MY_NVIC_Init(0,0,ETH_IRQn,2); //配置ETH中的分组
复制代码 然后实现LAN8742寄存器的配置' l+ u' Q; g: m1 J! |. N
- *(uint32_t *)0x40023830 |= 0x400000;
; G) N0 U. o2 R* u3 A" ]8 m3 q* r - RCC->AHB1RSTR |= 0x02000000;$ D% W4 _' F7 }9 A+ a3 m
- /* Enable SYSCFG Clock */
+ G+ S. q0 h1 e+ x0 c - *(uint32_t *)0x40023844 |= 0x4000;& J( i4 ~( z4 s/ v9 t
- SYSCFG->PMC &= ~(SYSCFG_PMC_MII_RMII_SEL);. {6 h* h6 O5 D1 b) G3 Z2 Y
- SYSCFG->PMC |= 0x800000;//RMII! A8 t7 b* s# q# b: T
- RCC->AHB1RSTR &= ~ 0x02000000;+ E# T/ T5 | F/ ^0 [
- ETH->DMABMR |= 0x1; //software reset7 H3 K4 l' B. z* S
- while (ETH->DMABMR & ETH_DMABMR_SR);
$ W+ Q" k+ K6 y2 O8 e9 f6 x2 B) F
! A- @- }6 f) ^9 B2 [- /* Write to ETHERNET MAC MIIAR: Configure the ETHERNET CSR Clock Range */
; ^* @: B3 ~! w. i8 P) Y' V+ D - ETH->MACMIIAR = (uint32_t)(1<<4);
- y8 ]2 V, E9 ~9 V0 B1 G1 ]$ Y - write_PHY(PHY_BCR, PHY_RESET);3 i! D: c$ A5 |+ n) g R3 N
- /* 等待复位完成 */) S$ @4 E' @, r; N2 J
- for (tout = 0; tout < 0x10000; tout++)" g7 h5 n' w: n, h2 V: o3 _
- {* ?9 F% U8 D$ u0 A+ G% R
- read_PHY (PHY_BSR,®v);
I* l: i) Z" Y0 X - if (!(regv & PHY_LINKED_STATUS))1 V& W+ U# G6 P
- {
E3 z+ c$ O. n" ?! k- ?0 x: ` - /* 复位完成 */
% z2 Y/ ]0 @3 D: v- |$ f" d+ q - printf("2. Reset Complete\r\n");
+ }# [+ Y" j. X( p, y) i# F1 V( T - break;" V) t# F# l& x1 V/ L
- }
2 J/ G" z# q9 l) Y1 L* q - }
0 |# b2 G( G, l7 _- g - write_PHY(PHY_BCR, PHY_AUTONEGOTIATION);
9 A: \) k0 ~3 }0 i, ` - for (tout = 0; tout < 0x10000; tout++)5 {# l, V! p) ?$ V6 {( c
- {! r! g' Z0 [# l; f
- read_PHY (PHY_BSR,®v);
1 |/ P n& ?7 n: p1 N - if (!(regv & PHY_AUTONEGO_COMPLETE))
+ \4 z' V' d7 e6 m& Z0 v% E) G - {% u6 Z4 q7 E! G- ~- C5 e+ Y) I5 ?
- /* 复位完成 */# R9 o' C% u- c" z: o0 k
- printf("3. Auto-Negotiation Complete\r\n");
' p0 l4 W4 k' M A+ ?% E; }9 P ]% ~ - break;" [4 u2 @% l0 n( M
- }
, D" Z# }) x- M; e$ }3 O - }
' a" c- T( K! b$ h! @5 } - for (tout = 0; tout < 0x1000; tout++);
* r# H" G% y8 [) }2 p - read_PHY (PHY_SR,®v);
+ o w% a6 m7 w' q# M/ h) @0 }+ `9 X - printf("%x\r\n",regv);
/ K! m8 j p# h4 N - /* Configure the MAC with the Duplex Mode fixed by the auto-negotiation process */5 a, o' o1 v8 Z- y6 j
- if((regv & PHY_DUPLEX_STATUS) != (uint32_t)RESET); |7 ?9 j. }9 _: g
- {
: z- B: ], F, j - /* Set Ethernet duplex mode to Full-duplex following the auto-negotiation */
' y2 b" B& `8 f/ _* [- }2 j; \ - printf("4. Full-duplex connection\r\n");
* b- k% {& ~1 X - phyreg |= ETH_MODE_FULLDUPLEX;
8 S) G. t3 r+ A8 ] - }4 p5 P4 a6 C5 V) X- g
- else
) D, |- Y4 l( U - {
: W. u% \! Y% X1 ~1 L) v - /* Set Ethernet duplex mode to Half-duplex following the auto-negotiation */- m! t- U( \# Q2 A
- printf("4. half-duplex connection\r\n");
9 @$ x( {3 ^9 c8 E - phyreg |= ETH_MODE_HALFDUPLEX; 4 x0 H' L0 C k+ D
- }! J: M* S& |" ~ m6 ?( B6 y% X+ R) O
- if((regv & PHY_SPEED_STATUS) != (uint32_t)RESET)' T5 m I; W! Q3 L; D. e
- {
! U6 b: e3 d9 N/ O( }# [ - /* Set Ethernet duplex mode to Full-duplex following the auto-negotiation */5 o/ o% Y0 V' r5 j+ z$ L
- printf("5. 10Mbps Mode\r\n"); " }+ e* t# R0 r& _" }; G
- phyreg |= ETH_SPEED_10M;2 e4 l s+ r7 w( ]
- }( G8 D4 g9 D; R( m V* y m5 A. b2 L
- else) ~0 e/ {- |) Y: y; S0 j! ^
- { i ]% P' D: o* J$ ]
- /* Set Ethernet duplex mode to Half-duplex following the auto-negotiation */
: c& K' l. h& }9 K! c/ s# S - printf("5. 100Mbps Mode\r\n"); . s1 a0 P7 O. L4 j" U
- phyreg |= ETH_SPEED_100M;
6 r& S# m( D- J2 a9 `8 p - }) f$ U f2 x7 R ~% O9 g
3 p, A# _, ]% b& h; q- r- /* Config MAC and DMA */
% m4 f9 e% d6 T$ Y2 E - ETH_MACDMAConfig(heth, phyreg);
复制代码 下面是实现读写的函数
2 q6 ^+ v6 N! ~- void write_PHY (uint32_t PhyReg, uint16_t RegValue)1 W9 J# D. d/ B2 E
- {3 Y0 h( Y+ W/ E. a
- uint32_t tout;( O8 f2 F+ _7 U+ U4 {; R. o% t( M
- uint32_t tmpreg = 0;( k6 O: c5 w: Y, t9 G
- 1 [$ K9 R0 ]- ~$ l* E% A
- ETH->MACMIIDR = (uint16_t)RegValue;* q6 A. I% T/ G
- 7 }2 l! f* U2 ] K! h
- 5 a8 Q0 ~1 a2 b- s# ?, `* l6 }
- /* Get the ETHERNET MACMIIAR value */
# _. R3 p; S/ ?2 b5 k* \ - tmpreg = ETH->MACMIIAR;3 D" F' U- ?' B% T( h3 g
-
& z' y$ `) o0 i% m' c - /* Keep only the CSR Clock Range CR[2:0] bits value */
3 a6 J; _; q) n" \, N0 p - tmpreg &= ~ETH_MACMIIAR_CR_MASK;
; V! O1 N; N& | -
! D; ^, D8 n v1 `% x - /* Prepare the MII register address value */
1 N% C2 r) W" X4 A! Q0 ] - tmpreg |=(((uint32_t)(LAN8742A_PHY_ADDRESS << 11)) & ETH_MACMIIAR_PA); /* Set the PHY device address */
! |8 z+ H+ k- j4 e0 h: Q- A - tmpreg |=(((uint32_t)PhyReg<<6) & ETH_MACMIIAR_MR); /* Set the PHY register address */
3 [* m: n4 R, q" m% s - tmpreg |= ETH_MACMIIAR_MW; /* Set the write mode */* x+ [! Y- ]' g& u
- tmpreg |= ETH_MACMIIAR_MB; /* Set the MII Busy bit */
; m5 u/ O# _& |; b5 Q- Y! } -
: ~5 ~0 W1 W: o" _8 x' s* I - /* Write the result value into the MII Address register */
& G f% L3 J, a, e3 J - ETH->MACMIIAR = tmpreg;8 _& c9 X( [0 o; z
- /* 等待操作完成,即等待MMAR_MB位被清零 */+ ~: R% F( Y6 N
- tout = 0;
5 m% u0 T t$ Q - for (tout = 0; tout < MII_WR_TOUT; tout++)
0 H! X! b" a2 H: ?& Q - {
( v6 r5 h) a* E3 @, M: b4 a - if ((ETH->MACMIIAR & ETH_MACMIIAR_MB) == 0)
8 S! s' ~7 N8 p7 v - {
2 J. H) a: L e Z' g2 K3 c6 G! [7 z - break;
& V! Z. F$ v0 ~8 K8 c8 X0 \ - }
: h {( J6 {, `8 s/ ] - }
8 v' Y' o/ S/ E3 k! V& H9 q. ~) N - }
/ O% o+ ?, P/ i/ Z: W7 Y! [ - ( ?' L/ L8 m4 c$ ]2 j* F) N: {5 s. v; Y
- void read_PHY (uint32_t PhyReg,uint32_t *RegValue)
6 C" S6 l% T y0 N$ U) i2 T7 k/ @ - {
8 x" l3 m+ d4 t5 B) u1 a. w - uint32_t tout;# g7 N1 {7 r" q( u' p" R* p9 d m
- uint32_t tmpreg = 0; 5 N8 a& p/ C/ @& I: E
- 1 I4 r2 K: o0 S3 N
- tmpreg = ETH->MACMIIAR;
2 m1 {+ [: s5 j1 C p0 K -
|- J0 l9 \# y1 e+ k9 Q. M8 W - /* Keep only the CSR Clock Range CR[2:0] bits value */
& ^, u- s/ _+ u4 |3 Z - tmpreg &= ~ETH_MACMIIAR_CR_MASK;
8 I- u6 O! N% c- A -
7 Q( y6 N8 L3 r) o, P& O' Q' w - /* Prepare the MII address register value *// K5 _ w [$ W* g1 o. a" a
- tmpreg |=(((uint32_t)(LAN8742A_PHY_ADDRESS << 11)) & ETH_MACMIIAR_PA); /* Set the PHY device address */( V' i. C# E7 S, U% R0 a. B1 L
- tmpreg |=(((uint32_t)PhyReg<<6) & ETH_MACMIIAR_MR); /* Set the PHY register address */
3 }) X* P4 V5 p4 {" G - tmpreg &= ~ETH_MACMIIAR_MW; /* Set the read mode */5 l% A! ? d0 z6 x9 H
- tmpreg |= ETH_MACMIIAR_MB; /* Set the MII Busy bit */, o/ J+ T. c0 I5 s v$ Z$ j
-
7 _5 c) W3 Z# D7 O- W) A - /* Write the result value into the MII Address register */
! [, J, a, h! l! _2 ]+ d - ETH->MACMIIAR = tmpreg;
+ r; H& {% ^6 V - 7 a- g# b Z+ u" Z7 d+ g. F
- /* 等待操作完成,即等待MMAR_MB位被清零 */# R7 @# G0 E$ J( g
- tout = 0;* Z! Z) ?) z* A n! f: O5 p
- for (tout = 0; tout < MII_RD_TOUT; tout++)
4 L7 y4 {- }1 n1 l) ]! K! x - {
' F4 V: [4 t5 s/ |- L [ - if ((ETH->MACMIIAR & ETH_MACMIIAR_MB) == 0) + B+ Q# Z( i+ ?8 [* N' ^
- {: C- A3 m$ o1 `
- break;9 B) { Y) [0 Z! X6 W6 i
- }
+ k' a# C" w* w; Y5 N$ ]3 X6 K- L - }
& ~% s+ U! z% `* c) k q - /* Get MACMIIDR value */
( b3 F# V, i( O" t2 j# a - *RegValue = (uint16_t)(ETH->MACMIIDR);+ ?- l1 {2 A+ R& ~: v2 n, [
- /* 从 PHY 中读取16bit的数据值 */
1 M/ R# Q, w# j. {4 \( I* \2 P3 k9 I - }
复制代码 保存可以正常运行,并且连上lan8742芯片) I \- l3 G6 y, ] H( H6 o' s
4 I8 L) E/ e$ _4 O2 u: j8 h) P# U3 k# w2 p5 H" h; d1 V' {3 x
下面开始移植lwp141,步骤就不说了,网上有 " L1 Q( J2 f7 ]1 i
* @$ u7 w! K6 _! h! ~2 p9 t% [ {: K" M- J! c9 C
7 N4 D: V7 q' E! V
! I, f) a! N$ X 直接给出代码7 ]! L7 G. h0 g, W3 R
- static void low_level_init(struct netif *netif)
! M! v5 Y7 e& M - {' N$ \4 \# B1 W5 p
- uint8_t macaddress[6]= { MAC_ADDR0, MAC_ADDR1, MAC_ADDR2, MAC_ADDR3, MAC_ADDR4, MAC_ADDR5 };
( ^0 M+ U U6 w( ? - 9 N* P" v" t3 S4 q
- EthHandle.Instance = ETH; , G) _& R( ?) X
- EthHandle.Init.MACAddr = macaddress;
7 q- N7 X/ s7 E9 o! q4 N - EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
; S, r) V# I, b8 t2 m5 i0 g) p - EthHandle.Init.Speed = ETH_SPEED_100M;1 k7 k: i- M* ]& q- F: v
- EthHandle.Init.DuplexMode = ETH_MODE_FULLDUPLEX;' M l( K% x& \, J) X! K l1 b* ^
- EthHandle.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
" I0 G; z% l1 H$ Z$ G: \0 @ - EthHandle.Init.RxMode = ETH_RXINTERRUPT_MODE;( q) v# _* L# q7 ^ c. E3 v* I
- EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;' D+ K) m! [* l3 `2 h2 r/ I( n
- EthHandle.Init.PhyAddress = LAN8742A_PHY_ADDRESS;) h$ K$ I+ V, c5 F5 A% O
- /* configure ethernet peripheral (GPIOs, clocks, MAC, DMA) */: `% p3 m2 N4 j
- lan8742_init(&EthHandle);
4 s" @& \* ~& g2 a - /* Initialize Tx Descriptors list: Chain Mode */0 V4 N& O( c7 f% A4 w4 h" Y
- HAL_ETH_DMATxDescListInit(&EthHandle, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
5 q6 Q, @/ ^4 Q( U; J -
/ r/ C) X4 v% t5 Y( L0 s - /* Initialize Rx Descriptors list: Chain Mode */- P# i- U, Z2 L4 R- O4 H
- HAL_ETH_DMARxDescListInit(&EthHandle, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
5 t8 Z) g) o( V& S -
# B# t( g3 r" q$ c. ] - /* Set netif link flag */
* J n! n, I8 M0 ~. L - netif->flags |= NETIF_FLAG_LINK_UP;
% r4 D; O6 N2 B% u - /* set netif MAC hardware address length */7 Z) S- |' F5 R8 a
- netif->hwaddr_len = ETHARP_HWADDR_LEN;$ ?; b7 }' }7 x1 |( Z9 C$ ~; M7 `
- 5 O2 G2 N- P+ ? F0 l9 Z! x7 x3 I
- /* set netif MAC hardware address */6 P( F3 J; k, v a
- netif->hwaddr[0] = MAC_ADDR0;) c/ S# m: U6 k1 c7 }! H2 I
- netif->hwaddr[1] = MAC_ADDR1;/ [( b: x% S9 J: m; c
- netif->hwaddr[2] = MAC_ADDR2;
. \% V6 ?! G6 S* `/ V0 O - netif->hwaddr[3] = MAC_ADDR3;
' A& f1 F6 Z. _- T% v' M$ I& p# ] - netif->hwaddr[4] = MAC_ADDR4; R+ l* l$ S* [* L* n3 k0 a
- netif->hwaddr[5] = MAC_ADDR5;& a# ^+ }; w. x# l
# z1 I6 H/ Q; U- S& t5 [- /* set netif maximum transfer unit */
' w1 t9 m. ~: j4 c - netif->mtu = 1500;3 w4 ]9 m1 }. l
: o: z' d9 `# c2 F5 @$ j/ N- /* Accept broadcast address and ARP traffic */2 W. i- \# M0 q; ^. {& a
- netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;7 q' z0 v& u2 k3 v
-
; o) W; F, x' G& Z - }
, F* P N, i; r! F- ~, G - err_t low_level_output(struct netif *netif, struct pbuf *p); L6 s2 g0 q# M. _
- {& F) L% {' k* d% {
- err_t errval;7 e0 i( K! M) X* Q- b# _5 _
- struct pbuf *q;+ t$ V# z7 e( F f
- uint8_t *buffer = (uint8_t *)(EthHandle.TxDesc->Buffer1Addr);" J5 K+ P# \3 j+ X# a
- __IO ETH_DMADescTypeDef *DmaTxDesc;# z- k ?4 }1 f8 h; J- f, ]
- uint32_t framelength = 0;
! W5 p, s* m6 O2 t* e0 b - uint32_t bufferoffset = 0;
$ j. C2 U1 T$ i) p+ x9 \* v( } - uint32_t byteslefttocopy = 0;9 t$ t( l7 Y! g+ ?! h
- uint32_t payloadoffset = 0;
r! [* G1 N& R7 C: K
2 `: q# a' |- P6 G1 H& S& ^0 n- DmaTxDesc = EthHandle.TxDesc;
! Q6 e( S2 {. g6 Y* g6 J: [ - bufferoffset = 0;- M6 i" W- P3 a( H* ^4 K
- " H+ v6 c" O S; L) [
- /* copy frame from pbufs to driver buffers */
* e/ ]5 s. q" X3 |( x3 S5 u* G - for(q = p; q != NULL; q = q->next)
( w* s, M7 d) P8 a2 U - {
5 c E- v# V- q% ~. B5 A - /* Is this buffer available? If not, goto error */
1 p' m6 O' z4 J% D - if((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)" W0 C' o" g/ X! T
- {
( d4 Z2 y4 q5 N8 ]# T - errval = ERR_USE;
. C8 E" N. E0 ~1 Q. G+ _ - goto error;1 n: z3 Y8 ?4 ]. K
- }7 j" {: H' T* W+ } `
- 1 h; o+ g! e4 l: O( n
- /* Get bytes in current lwIP buffer */
7 L2 S* }9 s' y0 i, ]4 A4 W: W - byteslefttocopy = q->len;) x2 A+ O0 W7 Y
- payloadoffset = 0;
6 R( U( ^0 S$ z' T - 6 f) `9 O& P/ A. J3 A* h
- /* Check if the length of data to copy is bigger than Tx buffer size*/* @8 \/ s+ e' M: B- ], k7 x% G$ ^
- while( (byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE )) e% c2 Y: B8 @ Q8 a
- {
& o: D2 B3 b& G( O9 C - /* Copy data to Tx buffer*/1 U" ^) H( {0 W+ D* `
- memcpy( (uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset) );7 T" d# @6 Y" {% Y2 `) X! u
- 0 M8 v" y* [6 i5 W; |5 B
- /* Point to next descriptor */: A. L- g g5 X8 {, z7 b" ^' f
- DmaTxDesc = (ETH_DMADescTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);
5 r# h" }& C8 V b+ w - 6 z6 [+ S/ J b! n
- /* Check if the buffer is available */
m9 U9 h2 r4 p, _' w E - if((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET) k7 z/ I4 C5 m( u' V+ i
- {8 Y3 X% ]8 K: z3 D7 F) G
- errval = ERR_USE;
) j$ w) d3 `. z - goto error;1 A5 w' \% D' t0 F+ B2 F3 b$ W h
- }4 K. d' r6 N6 l
- ( J L4 J) a9 E9 u* `0 k
- buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr);
" d) }, u# ?* X) t -
; |; t3 V! A' ~2 s# P; I: v$ ^7 L - byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);- O N3 R- e/ h8 V; v
- payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);2 w" x% t& T6 j) z" N, ~
- framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);5 d! o) d( w# k4 ?# j
- bufferoffset = 0;% c0 q) r9 K0 k7 A$ U }6 S( Y" Z! l
- }
( S$ S5 u7 R) R1 }. |" _ -
& l$ s4 N3 S# ?; V. L% a1 R - /* Copy the remaining bytes */! z0 u' x, j2 h- x- Q H
- memcpy( (uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), byteslefttocopy );
- ^/ K# N- Y' |6 f6 }+ S( T - bufferoffset = bufferoffset + byteslefttocopy;6 t; h/ H& E d+ f: V
- framelength = framelength + byteslefttocopy;
/ }& E4 @* f1 S; P3 @* Q - }
9 R9 s' j8 n( C3 g% H
6 ~- D+ B( H3 B4 R) v- /* Clean and Invalidate data cache */
7 y- v# O: @3 D6 F( b - SCB_CleanInvalidateDCache ();
3 ]6 A9 t o; a7 X. ?, v - /* Prepare transmit descriptors to give to DMA */ # \, g* X6 @3 I0 u& Q% k1 w+ z
- HAL_ETH_TransmitFrame(&EthHandle, framelength);
2 R& h- a E$ v' h. T - + k# ~6 D) B0 C0 v
- errval = ERR_OK;: S6 W( ?+ `/ V3 n: z
-
3 j$ n& H4 m; g5 F: w' D2 [% h - error:% z$ U5 X8 T/ ?( D0 ~
- / `2 q+ i( }: Y2 F3 b. j
- /* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */% q9 _! V/ w& u8 G2 Q! t& F2 ]8 d+ ]
- if ((EthHandle.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET)
0 L, s, w c1 W( w( Z: f - {) _ r+ \% ~0 o, g
- /* Clear TUS ETHERNET DMA flag */ w' H" A6 d( o6 @$ }
- EthHandle.Instance->DMASR = ETH_DMASR_TUS;
' f' h7 _3 R: D) P e8 p0 I -
+ g1 G. c, [! Z& F0 z' V - /* Resume DMA transmission*/
$ s( U3 P3 o3 z* D; u$ \. h$ I: X - EthHandle.Instance->DMATPDR = 0;" M2 @1 c" g# |0 w
- }3 i) a# m; F7 e8 {% K
- return errval;
* M- _) ?/ k& u - }0 @4 m# i% z; K3 W/ U% N, T
- 1 U) p! R% E3 ]1 i ?
- /**0 R6 }) d1 E' P' B2 _. b
- * [url=home.php?mod=space&uid=159083]@brief[/url] Should allocate a pbuf and transfer the bytes of the incoming
$ j8 {9 K+ }# u1 P6 C - * packet from the interface into the pbuf./ s: v& b$ U2 I
- *
$ N* b! b* S( |) B' O5 p7 P - * @param netif the lwip network interface structure for this ethernetif" e/ F: q! O7 G2 H' j# Z! H3 q0 g9 D
- * [url=home.php?mod=space&uid=784970]@return[/url] a pbuf filled with the received packet (including MAC header)2 p. e, C# p: m5 J7 X
- * NULL on memory error
0 H0 b; D( D: r9 ]& _ - */" \# Z& S. K0 U
- struct pbuf * low_level_input(struct netif *netif)
$ S" a0 D6 c7 Y7 d/ _ - {* M6 U9 E( d% {& X
- struct pbuf *p = NULL, *q = NULL;
i4 v+ q k7 ]# H4 R1 C+ c+ U - uint16_t len = 0;
. ]: }: ]. j+ A) w; J - uint8_t *buffer;
- b9 R+ y: ^. K* I+ T - __IO ETH_DMADescTypeDef *dmarxdesc;1 F! A9 z0 o- N) d- ?9 X9 v
- uint32_t bufferoffset = 0;) t" i7 M, P; U
- uint32_t payloadoffset = 0;( V% p3 h s) [+ W# I
- uint32_t byteslefttocopy = 0;9 ~1 _* I2 U# `2 P
- uint32_t i=0;
1 p7 q) ]5 A) D- j - ; U7 d# M; p9 _& \2 F$ N. n0 I
- /* get received frame */
- ]. m% E7 J5 }3 v9 D* ^ - if(ETH_GetReceivedFrame(&EthHandle) != 0)
! ]4 w% w$ F [% x& c! t - return NULL;
, ~; \4 ]+ J3 H2 }- M -
6 T. a8 x4 R; X' m; a% u - /* Obtain the size of the packet and put it into the "len" variable. */
4 Q7 o3 X% h5 ~ - len = EthHandle.RxFrameInfos.length;
: P" ]2 c3 w: Z - buffer = (uint8_t *)EthHandle.RxFrameInfos.buffer;. m' R. \. n, `1 M& f9 e+ {5 B: y
- & ]8 q. ]8 Q' x) Q* x7 e
- if (len > 0)6 f% `) \# e" H3 p/ n! J- `
- {1 j9 o \! @0 y Z% U
- /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
8 g% h5 q/ B, ?) L) r8 S - p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);, y+ c" D) {$ t4 L/ z( M# N" @
- printf("recv is ok\r\n");& a. K3 w+ ~ |6 |' s, M3 T
- }8 [+ h5 t: E: w) |# C# F
- : E t# {9 p* o! K% {0 {0 I1 z3 L
- /* Clean and Invalidate data cache */. ?- |* D7 ]0 h- I @: S7 k
- SCB_CleanInvalidateDCache ();
1 A e7 L+ y% R. g6 e/ i. f - / \4 n2 Y2 O- Y( B# v. j! \. T
- if (p != NULL)
4 h- q! o9 c ]5 |+ g: i - {. a8 b; [$ |- B. w
- dmarxdesc = EthHandle.RxFrameInfos.FSRxDesc;
3 f% ~- A6 o4 j1 f' J& m; S - bufferoffset = 0;. O( r8 ~* T. o' h( y
-
, v1 U0 {: C- @4 t6 m- S$ m6 {0 q! s - for(q = p; q != NULL; q = q->next)8 a& T6 }1 d! T6 Z& o) J6 \) t/ c3 Z7 g
- {
( x& \ v' H: _) I - byteslefttocopy = q->len;. D" y6 A' d5 Y( }# O
- payloadoffset = 0;! o3 x) q' b7 l: j, E) Y. t1 ^
- 1 `- ~: \8 t5 \* x' a
- /* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size */ D. J _8 N5 g! J& s3 q, B
- while( (byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE )9 ^1 O+ l4 v! }2 K# ]( `0 V
- {
- K8 [. j; c+ r - /* Copy data to pbuf */
: p. q- s3 I `1 J5 C - memcpy( (uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));( F5 b) n' q* u8 k6 c, l8 b
- 5 l* p" O" [# f" [' a9 q. e6 I
- /* Point to next descriptor */1 R3 n3 _ B0 `7 i) d0 ^% j
- dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
9 I6 w: C# d7 ?4 L6 Y, P1 J - buffer = (uint8_t *)(dmarxdesc->Buffer1Addr);
2 {& r, _/ _- C3 `/ U - 6 G8 q, m2 ]; b6 z" v/ e; z0 W
- byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
" h1 c, ~+ \% a+ O0 i - payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
. \/ v. v' L" i# h- K! ^1 R% w - bufferoffset = 0;7 F8 `( l" ~; I) H" A, R. ~
- }: l* t8 u+ O9 \; A7 Y
-
0 U y. F+ O; g. J: b - /* Copy remaining data in pbuf */
3 U7 @' R3 L* q8 V - memcpy( (uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), byteslefttocopy);. Z9 O+ C: u( c+ T5 Y) u
- bufferoffset = bufferoffset + byteslefttocopy;+ p8 B' V( r2 v O( E3 ^: H
- }6 ?. c$ Z R% _0 J ~ T
- }
3 v# M$ i' \- \; W; u) S+ J9 W -
2 c, t7 z0 E' s" I5 Z- e) V7 O - /* Release descriptors to DMA */
, \$ I) A% A C" P$ \ - /* Point to first descriptor */1 I- i* P: U. `4 H5 w
- dmarxdesc = EthHandle.RxFrameInfos.FSRxDesc;
1 \; d* N' D# Z, J% h ?7 l - /* Set Own bit in Rx descriptors: gives the buffers back to DMA */+ S+ h4 q; F5 {9 V
- for (i=0; i< EthHandle.RxFrameInfos.SegCount; i++)# Z8 S) @3 l2 i7 f6 f
- {
5 ~$ [9 ?- i3 c& E - dmarxdesc->Status |= ETH_DMARXDESC_OWN;3 W, e- {! V/ B0 n7 E+ p4 v
- dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);6 `% [; w( D, Z% m a6 y3 F2 ?
- }
: C. X- [ ~& y j* Q- O4 _0 D -
, ~* N4 u: e3 l$ F ^: S - /* Clear Segment_Count */
- \9 B( u4 A6 i3 @8 Y& I - EthHandle.RxFrameInfos.SegCount =0;+ O# P; T; V; J; A8 o! F! n
-
5 t+ {9 l; D* m, g& L - /* When Rx Buffer unavailable flag is set: clear it and resume reception */9 ^, D' _& C, R+ {; }) L
- if ((EthHandle.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET)
. A5 y, u; |# I7 s - {
/ u! v4 |, F2 q- G2 O - /* Clear RBUS ETHERNET DMA flag */" b2 r, H0 D* K- y
- EthHandle.Instance->DMASR = ETH_DMASR_RBUS;" S5 [% c8 U$ q: _& H
- /* Resume DMA reception */6 }3 p4 J: j* o
- EthHandle.Instance->DMARPDR = 0;/ O1 {5 X, `0 X; P3 Z4 D5 M
- }
3 G/ \ [5 T O( [7 _% ?; ^ - return p;
! R* v0 y8 @% i5 c: L: t0 r' Y - }$ y- g# J1 \ h
- void ethernetif_input( void const * argument )' M0 r# A6 |: u7 j8 K& q7 Q5 |
- {" q' j U2 E3 [: L' u& H
- struct pbuf *p;
/ K2 a, Z+ ]! a' x7 D4 _ - struct netif *netif = (struct netif *) argument;
! k Q. e/ q! } - : G* g: j) h$ M3 y1 w$ D( h
- ( z; j2 F4 h, M! Z
- 2 [% Q+ d/ l/ `: z
- ) T7 ^9 \& u1 }0 t4 u
- p = low_level_input( netif );
* t2 Z/ A% ]$ m - if (p != NULL)
& _, O$ o9 O) w1 a - {
' W: w( G2 y. s3 O - if (netif->input( p, netif) != ERR_OK )5 z$ U* r, j" u- ]4 P2 r3 E
- {5 i- f- C/ V" b& d
- LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));4 S4 \- E; @4 @8 r' Z
- pbuf_free(p);
5 ^- W6 S8 f( s6 W; k+ } - }
- L; c$ E; L- i - }% r' G# L* t- u2 m2 @+ ]
- " c) a1 O5 b0 c8 r& E
- . v4 @; L/ ]! ?, v7 ?" j+ C2 B
- }
. s4 Q4 t' M( E6 U! r# X - err_t ethernetif_init(struct netif *netif), [' s, P. A' z2 T" c7 p! t7 r
- {
2 [7 Q9 V' H2 C$ ~2 i - LWIP_ASSERT("netif != NULL", (netif != NULL));
& y0 i- k; H. J; I - * U/ Q* p6 C: X" n
- #if LWIP_NETIF_HOSTNAME5 A* i, ?7 o" q; d Q
- /* Initialize interface hostname */
; p; p o+ [% u/ l$ V+ g% J - netif->hostname = "lwip";8 M5 t8 ~$ |& q* n# ^$ o
- #endif /* LWIP_NETIF_HOSTNAME */* L9 u+ l4 Q6 m$ Z7 z2 v
- : D& Y- O6 |4 u' g9 p1 Y
- netif->name[0] = IFNAME0;
& ?# p! Y/ ~ L7 @! Q$ a) B - netif->name[1] = IFNAME1;' i4 x; w$ a- Y# ]
- 7 `2 C7 [. v1 Y# [5 l: C
- /* We directly use etharp_output() here to save a function call.8 r) ]+ R( F# h' B( r
- * You can instead declare your own function an call etharp_output()* ~8 I# [9 W$ U
- * from it if you have to do some checks before sending (e.g. if link2 V% Z, G0 v; ]3 V/ ^% z
- * is available...) */, `6 A }4 a0 `; Q
- netif->output = etharp_output;" |' B3 U7 y3 h! y
- netif->linkoutput = low_level_output;
# J2 f% F5 [" M* ^4 r9 `$ k; v5 f - 5 f- _; Y& a* H( D; m
- /* initialize the hardware */0 ^' g Q3 O( q
- low_level_init(netif);
+ z) v7 h; G$ w4 m3 V2 C8 J
) ^0 [- A# h0 j& k" _* @. ]+ c; w- return ERR_OK;
1 e3 l8 \+ }9 T - }9 p) S/ I8 o: J7 p
复制代码 编译正常,然后开始网络的配置
/ z4 Y4 Y) k) @" Y5 e t5 v4 h- static void Netif_Config(void)/ O9 S' m- C0 j9 ?# ]( n! X
- {
, [* k) w4 z" \# M - ip_addr_t ipaddr;
+ s* m3 L* Y8 A: z& o& ~ - ip_addr_t netmask;
+ D+ A& [ W( y J* R - ip_addr_t gw; p: K% U, @) e% M4 `1 [
- uint8_t iptab[4] = {0};' c. z" h8 ~* J* \
- uint8_t iptxt[20];$ `3 N% X# }( k
- uint8_t netmasktab[4]={0};% \. `& u: X+ `0 W: c! `
- uint8_t netmasktxt[30];; n, Y7 Z& { Z: P2 O5 x9 D
- : \0 z( Q( ]% U' ]/ e& J" A
- uint8_t gwtab[4]={0};
0 \$ g1 y }3 b2 d) a# c - uint8_t gwtxt[30];
- Q/ W# t: H7 r7 H6 w5 X -
- `( n z6 ~5 a# z. A9 ^ -
1 g' V) V2 G+ [/ b7 m - mem_init(); //3?ê??ˉ?ˉì??ú′???$ o0 S, T( a6 P) o. c
8 Z& |8 Y2 b; k; @- memp_init(); //3?ê??ˉ?ú′?3?
* r6 r9 G! m" w, _$ Z9 t2 _ o -
% N4 m7 P, t4 t7 u+ c9 d7 q' v/ Z& W - #ifdef USE_DHCP
7 Z& W: M4 q& m/ O1 u9 }2 Z& ~ - ipaddr.addr = 0;
! q6 v1 @! g0 g$ A$ t - netmask.addr = 0;) m4 E# a# s1 h3 q/ _8 t2 m7 q, F
- gw.addr = 0;" s% M* y1 _$ o2 f: X7 b) X' W
- #else
; v: d1 ~% M7 B; W - IP4_ADDR(&ipaddr,IP_ADDR0,IP_ADDR1,IP_ADDR2,IP_ADDR3);8 q. r* |% G9 @
- IP4_ADDR(&netmask,NETMASK_ADDR0,NETMASK_ADDR1,NETMASK_ADDR2,NETMASK_ADDR3);; Y! D) f4 I" E+ }4 o
- IP4_ADDR(&gw,GW_ADDR0,GW_ADDR1,GW_ADDR2,GW_ADDR3);
6 h" y1 x: {" k- _: D: [0 F - #endif /* USE_DHCP */9 @. N9 C1 \# X3 z" A- q4 s, \
-
/ I: c/ B6 Q% t - netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, eernetif_init, eernet_input);
" f$ U) C ^+ w# O2 p -
% P2 d& J2 p# ?) t, {. K - /* Registers the default network interface. */* m" ], u( s8 t" O
- netif_set_default(&gnetif);4 E0 O5 B. \) A3 f8 p7 b
-
; ?( h6 k* y. C - if (netif_is_link_up(&gnetif))
7 W* J6 n; ~* H7 Z! M2 |$ r) z" Y - {
6 e$ m d# q( M7 w5 B - /* When the netif is fully configured this function must be called.*/2 s! ~: ~, D/ f
- netif_set_up(&gnetif);
4 |6 x' M& B5 u# p( L0 [( g - iptab[0] = IP_ADDR3;
/ n6 D" w0 e/ o3 l# G - iptab[1] = IP_ADDR2;
3 O# A$ i) Z/ ^! j - iptab[2] = IP_ADDR1;0 _% O) S0 I5 G, w9 r, f
- iptab[3] = IP_ADDR0;
$ r$ d6 [! w# h: p -
) W4 s5 t$ h+ U } - netmasktab[0]=NETMASK_ADDR3;
& `) u$ H' w7 f+ G - netmasktab[1]=NETMASK_ADDR2; t; |" O/ d8 ~8 j1 Q7 w( s# S
- netmasktab[2]=NETMASK_ADDR1;
l8 `/ o3 H& P/ N8 r - netmasktab[3]=NETMASK_ADDR0;8 J9 W. Q, w, ` e
- ; e( R% t) U' C: T U* Y' z
- gwtab[0]=GW_ADDR3;
, e% J; W/ K* ]1 T1 f$ a - gwtab[1]=GW_ADDR2;
2 ^+ t: w; n: B1 p - gwtab[2]=GW_ADDR1;
" K" { v) f* [& Y& A( p3 _ - gwtab[3]=GW_ADDR0;; \7 j) f; N2 [6 u E( m
. y% F: d$ @. c/ @( X( y( i- //
1 y' a7 F0 X$ a) Y5 |& o8 e3 u - sprintf((char*)iptxt, " %d.%d.%d.%d", iptab[3], iptab[2], iptab[1], iptab[0]);
" l" l0 ]1 ^" a6 ^/ e% F - ; U I: C" |6 W
- sprintf((char*)netmasktxt, "%d.%d.%d.%d",netmasktab[3],netmasktab[2],netmasktab[1],netmasktab[0]);8 n* Y) r7 q- n3 V; w; I5 Q2 l: Q! ?
- ; V2 q* O, \+ g" h7 Z* j
- sprintf((char*)gwtxt,"%d.%d.%d.%d",gwtab[3],gwtab[2],gwtab[1],gwtab[0]);
6 Z. R% l! Q* A - 3 ~) Q) T7 K. S& b+ ?. W
- //
9 ]# f* D1 y# D* U, d - printf("\r\n");- B% K1 Y) ~: G9 Q8 ?% T, e. F9 }$ P
- printf("\r\n");
+ y1 b! U* K$ M. E( d - printf(" Network Cable is connected \r\n");
5 M" E8 O3 d \5 ~! |$ W2 c4 U - printf(" This is lwip1.4.1-ping demo test \r\n");& h& j! j- f& B' O
- printf(" The stm32f769 ip address is: %s\r\n",iptxt);4 M9 ]) @& @/ ^5 g5 y5 k! Z* L6 B
- printf("The stm32f769 netmask address is: %s\r\n",netmasktxt);9 N# C. k0 R* k& E3 M/ ^* E9 @; q
- printf(" The stm32f769 gw address is: %s\r\n",gwtxt);
a, w. ]7 h" v/ V( b - printf("\r\n");& x6 l5 E4 g3 p* i% r. ]; ?- ~1 `
- printf("\r\n");
: y6 ]; V3 \6 S- l% S, |' [ - printf("\r\n");6 w. O4 K t% ~$ }. d! \; h
- }. d; `3 a/ ^% A7 I; O! V; Z! a z
- else
. b8 K6 P7 ~6 N' B/ w: \3 ]' j - {; U/ \: t/ C! u }; A
- /* When the netif link is down this function must be called */9 y+ z+ U. Y- d% d
- netif_set_down(&gnetif);
) m' z1 F: r( t) P( k - printf(" Network Cable is not connected \r\n");
* A& k1 W2 B" O3 S5 d+ Z4 Y" U( M - }
$ u8 s; D" t; v7 w - }
复制代码 完成后,实现网络数据的处理
: @9 D( M# [# X$ u' I, g1 h- void LwIP_Pkt_Handle(void)% A6 Q, F" d* m* q6 W
- {' Z( d/ P) P- a9 W3 O8 v
- /* Read a received packet from the Ethernet buffers and send it to the lwIP for handling */
3 l3 Q3 T. x4 B+ `) l - ethernetif_input(&gnetif);! V6 R2 N. O; ^, T$ R* P" |9 v
- }
3 Q/ R! y& a3 C$ M: ~# d3 f( X @( ` - void LwIP_Periodic_Handle(__IO uint32_t localtime). e- x; E# f( M
- {/ g4 }% C6 k/ F
- #if LWIP_TCP
2 p8 X% |' N/ L8 J. O) z, Y. @ - /* TCP periodic process every 250 ms */; u- d2 s* h5 h4 ]1 G9 M1 T7 b, o
- if (localtime - TCPTimer >= TCP_TMR_INTERVAL)
3 G2 e3 g2 h1 P1 w7 O - {
V1 d9 T1 r2 g/ W) [ - TCPTimer = localtime;; ^; k8 s. F2 N+ e3 [0 @) G9 c! V
- tcp_tmr(); b. c1 s! D0 U3 l4 U
- }
) h) ~" D8 c0 b) S- e& [ - #endif
$ }( h7 v. j1 P - 7 R9 b8 K1 z0 O5 @& Y. r
- 0 Z" v% X$ m. b9 T. ]9 D7 _+ \1 d- t
- etharp_tmr();
' P$ E: A6 r/ E$ h; y( f" o - % F" Z- y( v! m) @# U+ ]+ y* ^
- }
复制代码 在main函数添加网路初始化,及数据处理
. D [8 v" g' v ^- Netif_Config();
& t; a! F. p& h7 ?! e) B. j$ D - % ^& }/ N, e0 U& E: r# F
- while(1)6 t, J* j) w: o, n, J5 H- F3 C. p8 j, f
- {. C; B, e8 r) K9 w% L& G( Y% |
- if (ETH_GetReceivedFrame(&EthHandle)) //?ì2éê?·??óê?μ?êy?Y°ü% I& X% Z7 V' N8 O8 m+ ]% t' [
- { , ~* q/ T9 y3 F+ B
- LwIP_Pkt_Handle(); //
" G! g" q; T8 ^! F5 `8 B, f - }
+ C4 @6 J, V u7 S% C - /* handle periodic timers for LwIP */
4 ^ p- l+ M1 _" C* N7 C7 C - LwIP_Periodic_Handle(LocalTime);
. v$ N! Z9 \: G$ Z" f# z - led_toggle();* j2 J% x! i. L' Y, b( d+ h. w
- delay_ms(5000);* b: Q. ^2 `) z1 U, d
- }
复制代码 $ }* ?) x h5 u+ [- u
( }6 m$ L5 @: t! d4 P$ n& s. H
其他功能目前还在研究
; P* `1 t7 y) g7 D! q) x% ~; e2 ?2 z/ f9 k6 g, }$ h3 O
|
https://www.stmcu.org.cn/module/forum/thread-615497-1-1.html