[DemoCode下载] DM9051 SPI 接口以太网模块 + NuTinyM051 + uIP实现web server

[复制链接]
15062|176
 楼主| jf7686 发表于 2016-1-18 16:12 | 显示全部楼层 |阅读模式
本帖最后由 jf7686 于 2016-10-7 10:18 编辑

最近在论坛裡,看到qq280572 大大的这篇 STM32F103+DM9051_UIP_SPI to 以太网,在淘宝上买了几块DM9051 SPI 接口以太网模块,刚好手上有Nuvoton NuTiny M051 和 M451,就先用M051拿来做一个简单的web server,透过web server 来控制开发板上的LED灯亮灭。


1. DM9051NP硬体相关描述

      DM9051NP SPI接口以太网模块是联杰国际(DAVICOM)在推出DM9000系列的以太网芯片后,为了更方便在 嵌入式ARM、MCU单片机系统进行以太网通信而开发出新的解决方案。DM9051NP芯片是带有行业标准串列外设介面(Serial Peripheral Interface,SPI)的独立以太网控制器。DM9051NP符合IEEE 802.3 规范,它还支援以DMA 模式來传输,以实现资料传送快速。DM9051NP通过1个中断引脚和SPI介面來进行与主控制器MCU单片机的通信,资料传输规格为10/100 M。相關介紹可以參考 STM32F103+DM9051_UIP_SPI to 以太网

      • Package:32支接脚封装,QFN.
      • IEEE 802.3az Energy Efficient Ethernet (EEE)
      • Built-in integrated 3.3V to 1.8V regulator
      • 远端唤醒 (WOL)
      • 平行线/交叉线自动切换 HP Auto-MDIX
      • Support 光口介面      
      • 具有16KB SRAM静态随机存取**
      • EMI (Class B) and HBM ESD Rating 8KV
      • 工业温度规范: –40℃ to +85℃
      • 功率:(100/10 M) => 429/561 mW
      • 连续工作温度<60℃  

dm9051_demo_改.jpg
     上图是DAVICOM(聯傑國際) DM9051NP 以太网路卡SPI Pin的排列。

      NuTinyM051使用的是SPI1与DM9051NP SPI脚位的硬体连接如下:
M0516 DM9051
P0.7(Pin32) CLK  (pin07)
P0.6(Pin33) MISO (Pin05)
P0.5(Pin34) MOSI (Pin03)
P0.4(Pin35)CSS  (Pin01)

S__43581445.jpg
         
  上图为M0516 + DM9051硬体连接示意图


2.网卡驱动:

SPI 设定和 R/W data 参考M0516 Library SPI_Loopback sample code ,可到nuvoton 官网下载M0516 Library, 再参考STM32F103+DM9051_UIP_SPI to 以太网附件中的驱动,将DM9051_Configuration() SPI设定改为M0516 SPI1 Pin Group 设定和修改DM9051_Read_Reg(), DM9051_Write_Reg(), DM9051_Read_Mem(), DM9051_Writer_Mem() , 修改如下:。


(1) 首先配置M0516 SPI1 相关设定:
  1. void DM9051_Configuration(void)
  2. {        
  3.         /* Enable SPI1 peripheral clock */
  4.         CLK_EnableModuleClock(SPI1_MODULE);
  5.         /* Select HCLK as the clock source of SPI1 */
  6.         CLK_SetModuleClock(SPI1_MODULE, CLK_CLKSEL1_SPI1_S_HCLK, MODULE_NoMsk);

  7.         /* Reset IP */
  8.         SYS_ResetModule(SPI1_RST);   

  9.         /* Setup SPI1 multi-function pins */
  10.         SYS->P0_MFP = SYS_MFP_P04_SPISS1 | SYS_MFP_P05_MOSI_1 | SYS_MFP_P06_MISO_1 | SYS_MFP_P07_SPICLK1;

  11.         /*---------------------------------------------------------------------------------------------------------*/
  12.         /* Init SPI                                                                                                */
  13.         /*---------------------------------------------------------------------------------------------------------*/
  14.         /* Configure SPI1 as a master, SPI clock rate 200 KHz,
  15.                  clock idle low, 32-bit transaction, drive output on falling clock edge and latch input on rising edge. */
  16.         SPI_Open(SPI1, SPI_MASTER, SPI_MODE_0, 8, 25000000);
  17.         
  18.         /* Disable the automatic hardware slave selection function. Select the SPI1_SS pin and configure as low-active. */
  19.         SPI_DisableAutoSS(SPI1);

  20.         SPI_EnableFIFO(SPI1, 3, 3);
  21. }


(2) 透过read cmd 读出register
  1. uint8_t DM9051_Read_Reg(uint8_t Reg_Off)
  2. {        
  3.         SPI_SET_SS_LOW(SPI1);

  4.         /* SPI transfer DM9051 Read-Command and Reg. offset. */
  5.         while(SPI_GET_TX_FIFO_FULL_FLAG(SPI1));
  6.         SPI_WRITE_TX0(SPI1, Reg_Off);        //Read command + Register offset address
  7.         while(SPI_IS_BUSY(SPI1));
  8.         
  9.         SPI_WRITE_TX0(SPI1, 0x0);                        //Dummy for read register value.
  10.         while(SPI_IS_BUSY(SPI1));
  11.         
  12.         SPI_READ_RX0(SPI1); // dummy read, jump 1st byte.
  13.         
  14.         SPI_SET_SS_HIGH(SPI1);
  15.         
  16.         return (SPI_READ_RX0(SPI1) & 0xFF);
  17. }

(3)透过write cmd 写入register
  1. void DM9051_Write_Reg(uint8_t Reg_Off, uint8_t spi_data)
  2. {
  3.         uint32_t cmdaddr;
  4.         cmdaddr = (Reg_Off | 0x80);
  5.         
  6.         SPI_SET_SS_LOW(SPI1);
  7.         
  8.         /* SPI transfer DM9051 Read-Command and Reg. offset. */
  9.         SPI_WRITE_TX0(SPI1, cmdaddr);  //Read command + Register offset address        
  10.         while(SPI_IS_BUSY(SPI1));
  11.         
  12.         SPI_WRITE_TX0(SPI1, (uint32_t)spi_data);
  13.         while(SPI_IS_BUSY(SPI1));
  14.         
  15.         /*Clear SPI TX FIFO*/
  16.         SPI_ClearRxFIFO(SPI1);
  17.         
  18.         SPI_SET_SS_HIGH(SPI1);
  19.         
  20.         return;
  21. }


(4) 连续读出 data 从spi array
  1. void DM9051_Read_Mem(uint8_t* pu8data, uint32_t datalen)
  2. {
  3.         uint32_t i;
  4.         uint8_t burstcmd = SPI_RD_BURST;         /*  Read SPI_Data_Array back from the slave */
  5.         
  6.         SPI_SET_SS_LOW(SPI1);
  7.         
  8.         SPI_WRITE_TX0(SPI1, (uint32_t)burstcmd);
  9.         while(SPI_IS_BUSY(SPI1));
  10.         SPI_READ_RX0(SPI1);
  11.         
  12.         for(i = 0 ; i < datalen; i++){
  13.                 pu8data = SPI_WRITE_TX0(SPI1, (uint32_t )0x0);
  14.                 while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
  15.                 pu8data = (uint8_t)SPI_READ_RX0(SPI1);
  16.         }
  17.         while(SPI_IS_BUSY(SPI1));
  18.         /*Clear SPI TX FIFO*/
  19.         SPI_ClearTxFIFO(SPI1);
  20.         SPI_SET_SS_HIGH(SPI1);
  21. }


(5) 连续写入data到spi array
  1. void DM9051_Write_Mem(uint8_t* pu8data, uint32_t datalen)
  2. {
  3.         uint32_t i;
  4.         uint8_t burstcmd = SPI_WR_BURST;         /* Send the array to the slave */
  5.                            
  6.         SPI_SET_SS_LOW(SPI1);
  7.         
  8.         SPI_WRITE_TX0(SPI1, (uint32_t)burstcmd);
  9.         while(SPI_IS_BUSY(SPI1));
  10.         SPI_READ_RX0(SPI1);
  11.         
  12.         for(i = 0; i < datalen; i++)
  13.         {               
  14.                 while(SPI_GET_TX_FIFO_FULL_FLAG(SPI1));
  15.                 SPI_WRITE_TX0(SPI1, (uint32_t)pu8data);
  16.         }
  17.         while(SPI_IS_BUSY(SPI1));
  18.         /*Clear SPI RX FIFO*/
  19.         SPI_ClearRxFIFO(SPI1);
  20.         SPI_SET_SS_HIGH(SPI1);
  21. }


3. 简单的web server 控制 LED
                uIP就不多介绍了,网路上有许多相关资料可以参考,在上一部份将驱动设置好后,將tapdev_init()、tapdev_read()、tapdev_send()對應到DM9051_init()、DM9051_rx()、DM9051_tx() function即可, 附件可參考,在main()中加入在 http_init(); 然后在http.c 在handle_input中天加 控制 LED function,新增web_led.c 和web_led.h 如下:

(1)首先先在 http.c handle_input()新增判斷:
  1. static PT_THREAD(handle_input(struct httpd_state *s))
  2. {
  3.   PSOCK_BEGIN(&s->sin);

  4.   PSOCK_READTO(&s->sin, ISO_space);

  5.   if(strncmp(s->inputbuf, http_get, 4) != 0) {
  6.     PSOCK_CLOSE_EXIT(&s->sin);
  7.   }
  8.   PSOCK_READTO(&s->sin, ISO_space);

  9.   if(s->inputbuf[0] != ISO_slash) {
  10.     PSOCK_CLOSE_EXIT(&s->sin);
  11.   }

  12.   if(s->inputbuf[1] == ISO_space) {               
  13.     //strncpy(s->filename, http_index_html, sizeof(s->filename));
  14.     strncpy(s->filename, http_webMain_html, sizeof(s->filename));
  15.   }
  16. #if 1 //web control led cmd
  17.   /* Control led, 0 = OFF, 1 = ON, 2 = Flash */
  18.   else if (s->inputbuf[3] == 'L','E','D' && ((s->inputbuf[4] == '0') ||
  19.               (s->inputbuf[4] == '1') || (s->inputbuf[4] == '2'))){
  20.     Set_LED_mode(s->inputbuf[4]);</font>
  21.     s->inputbuf[4]= 0;
  22.     //strncpy(s->filename, "/home.html", 10);
  23.     strncpy(s->filename, http_webMain_html, sizeof(s->filename));
  24.    }
  25. #endif
  26.    else {
  27.     s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
  28.     strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename));
  29.   }
  30.   /*  httpd_log_file(uip_conn->ripaddr, s->filename);*/
  31.   s->state = STATE_OUTPUT;

  32.   while(1) {
  33.     PSOCK_READTO(&s->sin, ISO_nl);
  34.     if(strncmp(s->inputbuf, http_referer, 8) == 0) {
  35.       s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
  36.       /*      httpd_log(&s->inputbuf[9]);*/
  37.     }
  38.   }
  39.   PSOCK_END(&s->sin);
  40. }


(2)LED 设定和控制判断代码如下:
  1. void Set_LED_mode(char lkkcode)
  2. {
  3.         //int i;
  4.         
  5.         GPIO_SetMode(P3, BIT6, GPIO_PMD_OUTPUT);
  6.         
  7.         if(lkkcode == ('0')) // LED off
  8.         {
  9.                 P36 = 1;
  10.         }else if (lkkcode == '1'){ // LED on
  11.                 P36 = 0;
  12.         }else if(lkkcode == '2') // LED Flash
  13.         {
  14.                 //for(i = 0 ; i< 30 ; ++i)
  15.                 {
  16.                         P36 = 0;
  17.                         Delay(25);
  18.                         P36 = 1;
  19.                         Delay(25);
  20.                 }
  21.         }
  22. }

最后在网址列输入IP 192.168.XXX.XXX进入 uip web server控制LED,因为uip  有开DHCP 也可设定为固定IP ,看使用者设定输入正确的IP位址
Screenshot_2016-01-18_15-15-08.png
就可以透过web 控制LED,如下可以看到MCU +  DM9051相关讯息,最下面可以看到控制LED 选单,
按下on 、off 、Flash后网址后面会分别显示XXX.XXX.XXX.XXX / LED0、1、2让使用者可以知道目前设定


Screenshot_2016-01-18_15-12-33.png


以上完成后就是一个简单webserver 控制LED应用了,最後附上程序和DM9051NP datasheet:

DM9051(I)-12-MCO-DS-P01_03302015.pdf (829.02 KB, 下载次数: 98)

NUC_M051_uIP_SPI1_DM9051_webserver.rar (492.96 KB, 下载次数: 111)


打赏榜单

21ic小喇叭 打赏了 10.00 元 2016-01-26
理由:资料分享~~~

bkn1860 发表于 2016-1-18 16:41 | 显示全部楼层
qq280572 发表于 2016-1-18 17:10 | 显示全部楼层
楼主很强大,把UIP移植到芯唐M0系列上面了。:handshake
tsaime49 发表于 2016-1-18 17:11 | 显示全部楼层
赞! 请问设计占用多少SDRAM和Code Size?
 楼主| jf7686 发表于 2016-1-18 17:29 | 显示全部楼层
tsaime49 发表于 2016-1-18 17:11
赞! 请问设计占用多少SDRAM和Code Size?

RAM的部份用了3.14K
ROM的部份用了26.6K
RAM的部份比较吃紧一点
 楼主| jf7686 发表于 2016-1-18 17:30 | 显示全部楼层
本帖最后由 jf7686 于 2016-1-18 17:39 编辑
tsaime49 发表于 2016-1-18 17:11
赞! 请问设计占用多少SDRAM和Code Size?

RAM的部份用了3.14K
ROM的部份用了26.6K
RAM的部份比较吃紧一点
qq280572 发表于 2016-1-18 17:30 | 显示全部楼层
tsaime49 发表于 2016-1-18 17:11
赞! 请问设计占用多少SDRAM和Code Size?

你可以把程序下下来看下:
Program Size: Code=20968 RO-data=5972 RW-data=120 ZI-data=3096  
我刚打开应该是flash=26Kb,3K左右SRAM。
 楼主| jf7686 发表于 2016-1-18 17:36 | 显示全部楼层
本帖最后由 jf7686 于 2016-1-18 17:37 编辑
qq280572 发表于 2016-1-18 17:10
楼主很强大,把UIP移植到芯唐M0系列上面了。

NuTiny M051 Flash 有64 K移植上还好,因为RAM只有4K,应用上需要多注意RAM的使用,web server 部份我也是尽量的在缩小所以没有太多的特效等。感谢qq280572大大的DM9051 网卡
Rooney30 发表于 2016-1-18 20:23 | 显示全部楼层
控制网络的用这么长的线速度能上去吗
 楼主| jf7686 发表于 2016-1-18 21:51 | 显示全部楼层
本帖最后由 jf7686 于 2016-1-19 14:30 编辑
Rooney30 发表于 2016-1-18 20:23
控制网络的用这么长的线速度能上去吗

您好,线的部分目前手边只有这么长的,用杜邦线这样接,速度上是受限的,M051 CPU Clock 有50Mhz,SPI速度理论上可以有CPU clock的一半 25Mhz,网路速度部分就受到CPU与SPI的限制,网路速度测试部分等有空再来测试看看。如果大大有更好的建议也可以提供让小弟我改进,谢谢。
mybao 发表于 2016-1-19 08:41 | 显示全部楼层
DM9051网卡 + NuTinyM051 + uIP实现web serve
zjsx8192 发表于 2016-1-19 08:51 | 显示全部楼层
uip记号 ,
penguin008 发表于 2016-1-19 09:36 | 显示全部楼层
厉害!虽然只控制了个LED,但最基本的通道已经打通了
 楼主| jf7686 发表于 2016-1-19 10:56 | 显示全部楼层
本帖最后由 jf7686 于 2016-1-19 10:57 编辑
penguin008 发表于 2016-1-19 09:36
厉害!虽然只控制了个LED,但最基本的通道已经打通了

基本上简单的应用没问题,像tcp/udp Client/Server、telnet等,希望版上有大大能分享或提供一些想法或建议等,让小弟我能多学习,或是这份code 有其他问题能提出来让我改进,谢谢。
antlab 发表于 2016-1-19 14:08 | 显示全部楼层
好资料!
DreamofOven 发表于 2016-1-21 09:18 | 显示全部楼层
以前玩过dm9000,这个应该是新的网口芯片了吧
123654789 发表于 2016-1-21 09:33 | 显示全部楼层
这些东西到了最后,又是得个研究,又不能赚钱
 楼主| jf7686 发表于 2016-1-21 11:09 | 显示全部楼层
DreamofOven 发表于 2016-1-21 09:18
以前玩过dm9000,这个应该是新的网口芯片了吧

DM9000以前也玩过,这是新的芯片,主要是用SPI接口让没有网口的嵌入式系统或MCU有其他的方案。
 楼主| jf7686 发表于 2016-1-21 11:13 | 显示全部楼层
123654789 发表于 2016-1-21 09:33
这些东西到了最后,又是得个研究,又不能赚钱

总是要有人花点时间琢磨,至少多点选择也不错,目前简单的应用应该没问题,在深入一点就看版上有没有大大能提供一些想法跟建议。
qq280572 发表于 2016-1-21 14:13 | 显示全部楼层
123654789 发表于 2016-1-21 09:33
这些东西到了最后,又是得个研究,又不能赚钱

举一反三,集思广益,应用上有需求与之相符,即可赚钱啦。:D
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

57

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部