drv_eth.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-02-16 Tuber first version
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #include "board.h"
  13. #include <netif/ethernetif.h>
  14. #include "drv_eth.h"
  15. #ifdef BSP_USING_ETH
  16. static struct eth_device eth_device;
  17. //DMA接收内存区,必须4字节对齐
  18. __align(4) UINT8 eth_dma_tx_buf[ETH_BUF_SIZE];
  19. __align(4) UINT8 eth_dma_rx_buf[ETH_BUF_SIZE];
  20. UINT16 eth_rx_len = 0; //接收状态和长度
  21. UINT8 eth_rx_buf[ETH_BUF_SIZE]; //中间缓冲区
  22. UINT8 eth_mac_addr[] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
  23. static rt_err_t eth_init(rt_device_t dev)
  24. {
  25. return RT_EOK;
  26. }
  27. static rt_err_t eth_open(rt_device_t dev, rt_uint16_t oflag)
  28. {
  29. return RT_EOK;
  30. }
  31. static rt_err_t eth_close(rt_device_t dev)
  32. {
  33. return RT_EOK;
  34. }
  35. static rt_size_t eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  36. {
  37. rt_set_errno(-RT_ENOSYS);
  38. return 0;
  39. }
  40. static rt_size_t eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  41. {
  42. rt_set_errno(-RT_ENOSYS);
  43. return 0;
  44. }
  45. static rt_err_t eth_control(rt_device_t dev, int cmd, void *args)
  46. {
  47. switch (cmd)
  48. {
  49. case NIOCTL_GADDR:
  50. /* get mac address */
  51. if (args) rt_memcpy(args, eth_mac_addr, 6);
  52. else return -RT_ERROR;
  53. break;
  54. default :
  55. break;
  56. }
  57. return RT_EOK;
  58. }
  59. rt_err_t eth_tx(rt_device_t dev, struct pbuf *p)
  60. {
  61. //判断eth是否处于发送状态
  62. if ((R8_ETH_ECON1 & RB_ETH_ECON1_TXRTS) != 0x00)
  63. {
  64. return ERR_INPROGRESS;
  65. }
  66. //确定缓冲区是否足够
  67. if (p->tot_len > sizeof(eth_dma_tx_buf))
  68. {
  69. return ERR_MEM;
  70. }
  71. //拷贝数据到dma缓冲区
  72. rt_memcpy(eth_dma_tx_buf, p->payload, p->tot_len);
  73. //设置数据长度
  74. R16_ETH_ETXLN = p->tot_len;
  75. //开始发送
  76. R8_ETH_ECON1 |= RB_ETH_ECON1_TXRTS;
  77. return ERR_OK;
  78. }
  79. struct pbuf *eth_rx(rt_device_t dev)
  80. {
  81. struct pbuf *p = NULL;
  82. //检查是否有数据
  83. if (eth_rx_len == 0)
  84. {
  85. return NULL;
  86. }
  87. p = pbuf_alloc(PBUF_RAW, eth_rx_len, PBUF_POOL);
  88. if (p == NULL)
  89. {
  90. rt_kprintf("eth_rx: pbuf_alloc failed\n");
  91. eth_rx_len = 0;
  92. return NULL;
  93. }
  94. //拷贝数据到pbuf
  95. rt_memcpy((uint8_t *)((uint8_t *)p->payload), (uint8_t *)((uint8_t *)eth_rx_buf), eth_rx_len);
  96. //恢复状态
  97. eth_rx_len = 0;
  98. return p;
  99. }
  100. int read_eth_link_status()
  101. {
  102. R8_ETH_MIREGADR = 0x01;//状态寄存器
  103. R8_ETH_MISTAT |= 0x00; //读MII寄存器
  104. //获取link状态
  105. if ((R16_ETH_MIRD & 0x04) != 0)
  106. {
  107. return 1; //已插入
  108. }
  109. return 0;
  110. }
  111. void ETH_IRQHandler(void) /* 以太网中断 */
  112. {
  113. rt_interrupt_enter();
  114. //接收到数据包
  115. if ((R8_ETH_EIR & RB_ETH_EIR_RXIF) != 0)
  116. {
  117. //判断缓存区是否有数据
  118. if (eth_rx_len == 0)
  119. {
  120. rt_memcpy(eth_rx_buf, eth_dma_rx_buf, R16_ETH_ERXLN);
  121. eth_rx_len = R16_ETH_ERXLN;
  122. //通知拿数据
  123. eth_device_ready(&eth_device);
  124. }
  125. R8_ETH_EIR |= RB_ETH_EIR_RXIF; //清除中断
  126. }
  127. //接收错误
  128. if ((R8_ETH_EIR & RB_ETH_EIE_RXERIE) != 0)
  129. {
  130. R8_ETH_EIR |= RB_ETH_EIE_RXERIE; //清除中断
  131. }
  132. //发送完成
  133. if ((R8_ETH_EIR & RB_ETH_EIR_TXIF) != 0)
  134. {
  135. R8_ETH_EIR |= RB_ETH_EIR_TXIF; //清除中断
  136. }
  137. //发送错误
  138. if ((R8_ETH_EIR & RB_ETH_EIE_TXERIE) != 0)
  139. {
  140. R8_ETH_EIR |= RB_ETH_EIE_TXERIE; //清除中断
  141. }
  142. //Link 变化标志
  143. if ((R8_ETH_EIR & RB_ETH_EIR_LINKIF) != 0)
  144. {
  145. //获取连接状态
  146. if (read_eth_link_status())
  147. {
  148. eth_device_linkchange(&eth_device, RT_TRUE);
  149. rt_kprintf("eth1: link is up\n");
  150. }
  151. else
  152. {
  153. eth_device_linkchange(&eth_device, RT_FALSE);
  154. rt_kprintf("eth1: link is down\n");
  155. }
  156. R8_ETH_EIR |= RB_ETH_EIR_LINKIF; //清除中断
  157. }
  158. rt_interrupt_leave();
  159. }
  160. int rt_hw_eth_init(void)
  161. {
  162. //使能ETH引脚
  163. R16_PIN_ANALOG_IE |= RB_PIN_ETH_IE;
  164. //进入安全访问模式
  165. R8_SAFE_ACCESS_SIG = 0x57;
  166. R8_SAFE_ACCESS_SIG = 0xA8;
  167. //打开以太网时钟
  168. R8_SLP_CLK_OFF1 &= (~RB_SLP_CLK_ETH);
  169. //打开以太网电源
  170. R8_SLP_POWER_CTRL &= (~RB_SLP_ETH_PWR_DN);
  171. //退出安全访问模式
  172. R8_SAFE_ACCESS_SIG = 0x00;
  173. //开启以太网中断
  174. R8_ETH_EIE |= RB_ETH_EIE_INTIE;
  175. //启用以太网接收中断
  176. R8_ETH_EIE |= RB_ETH_EIE_RXIE;
  177. //R8_ETH_EIE |= RB_ETH_EIE_RXERIE;
  178. //启用以太网发送中断
  179. R8_ETH_EIE |= RB_ETH_EIR_TXIF;
  180. R8_ETH_EIE |= RB_ETH_EIR_TXERIF;
  181. //启用Link变化中断
  182. R8_ETH_EIE |= RB_ETH_EIE_LINKIE;
  183. //启用内置的50欧姆阻抗匹配电阻
  184. R8_ETH_EIE |= RB_ETH_EIE_R_EN50;
  185. //配置接收过滤模式
  186. R8_ETH_ERXFCON = RB_ETH_ERXFCON_ANDOR | RB_ETH_ERXFCON_CRCEN;
  187. //设置发送dma
  188. R16_ETH_ETXST = (uint32_t)eth_dma_tx_buf;
  189. //设置接收dma
  190. R16_ETH_ERXST = (uint32_t)eth_dma_rx_buf;
  191. //设置最大接收长度
  192. R16_ETH_MAMXFL = sizeof(eth_dma_rx_buf);
  193. //使能MAC层接收
  194. R8_ETH_MACON1 |= RB_ETH_MACON1_MARXEN;
  195. //开启硬件CRC
  196. R8_ETH_MACON2 |= RB_ETH_MACON2_TXCRCEN;
  197. //所有短包填充0至60字节,再4字节 CRC
  198. R8_ETH_MACON2 |= 0x20;
  199. //使能接收
  200. R8_ETH_ECON1 |= RB_ETH_ECON1_RXEN;
  201. //开启中断
  202. NVIC_EnableIRQ(ETH_IRQn);
  203. //设置回调函数
  204. eth_device.parent.init = eth_init;
  205. eth_device.parent.open = eth_open;
  206. eth_device.parent.close = eth_close;
  207. eth_device.parent.read = eth_read;
  208. eth_device.parent.write = eth_write;
  209. eth_device.parent.control = eth_control;
  210. eth_device.parent.user_data = RT_NULL;
  211. eth_device.eth_rx = eth_rx;
  212. eth_device.eth_tx = eth_tx;
  213. return eth_device_init(&(eth_device), "e0");
  214. }
  215. INIT_DEVICE_EXPORT(rt_hw_eth_init);
  216. #endif /* BSP_USING_ETH */