单片机/MCU论坛
直播中

王崇吉

8年用户 11经验值
擅长:嵌入式技术 接口/总线/驱动 控制/MCU
私信 关注

DM9051 SPI 接口以太网模块 + Nuvoton NuTinyM0516 + uIP 实现 web server

本帖最后由 jf7686 于 2016-2-19 14:40 编辑

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


1. DM9051NP硬体相关描述

      DM9051NP SPI接口以太网模块是联杰国际(DAVICOM)为了方便嵌入式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脚位的硬体连接如下:
M0516DM9051
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.         
  8.         /* Reset IP */
  9.         SYS_ResetModule(SPI1_RST);   
  10.         
  11.         /* Setup SPI1 multi-function pins */
  12.         SYS->P0_MFP = SYS_MFP_P04_SPISS1 | SYS_MFP_P05_MOSI_1 | SYS_MFP_P06_MISO_1 | SYS_MFP_P07_SPICLK1;
  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.         /* Enable the automatic hardware slave selection function. Select the SPI1_SS pin and configure as low-active. */
  19.         //SPI_EnableAutoSS(SPI1, SPI_SS, SPI_SS_ACTIVE_LOW);
  20.         SPI_DisableAutoSS(SPI1);
  21.         //SPI_ENABLE(SPI1);
  22.         SPI_EnableFIFO(SPI1, 3, 3);
  23. }

(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.         SPI_WRITE_TX0(SPI1, (uint32_t)Reg_Off);        //Read command + Register offset address
  6.         //SPI_TRIGGER(SPI1);
  7.         while(SPI_IS_BUSY(SPI1));

  8.         SPI_WRITE_TX0(SPI1, (uint32_t)0x0);                        //Dummy for read register value.
  9.         //SPI_TRIGGER(SPI1);
  10.         while(SPI_IS_BUSY(SPI1));

  11.         SPI_READ_RX0(SPI1); // dummy read, jump 1st byte.
  12.         
  13.         SPI_SET_SS_HIGH(SPI1);
  14.         
  15.         return (SPI_READ_RX0(SPI1) & 0xFF);
  16. }

(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.         //while(SPI_GET_TX_FIFO_FULL_FLAG(SPI1) == 0);
  10.         SPI_WRITE_TX0(SPI1, cmdaddr);                //Read command + Register offset address        
  11.         //SPI_TRIGGER(SPI1);
  12.         while(SPI_IS_BUSY(SPI1));
  13.         
  14.         SPI_WRITE_TX0(SPI1, (uint32_t)spi_data);
  15.         //SPI_TRIGGER(SPI1);
  16.         while(SPI_IS_BUSY(SPI1));
  17.         
  18.         /*Clear SPI RX FIFO*/
  19.         SPI_ClearRxFIFO(SPI1);
  20.         
  21.         SPI_SET_SS_HIGH(SPI1);
  22.         
  23.         return;
  24. }

(4) 连续读出 data 从spi array
  1. void DM9051_Read_Mem(uint8_t* pu8data, uint32_t datalen)
  2. {
  3.         uint32_t i;
  4.         //uint32_t mdata;
  5.         
  6.         // Read SPI_Data_Array back from the slave
  7.         uint8_t burstcmd = SPI_RD_BURST;
  8.         
  9.         SPI_SET_SS_LOW(SPI1);
  10.         
  11.         //SPI_ClearTxFIFO(SPI1);
  12.         SPI_WRITE_TX0(SPI1, (uint32_t)burstcmd);
  13.         while(SPI_IS_BUSY(SPI1));
  14.         SPI_READ_RX0(SPI1);                //Skip SPI RX FIFO

  15.         /* 1 level FIFO */
  16.         for(i = 0 ; i < datalen; i++)
  17.         {
  18.                 pu8data[i] = SPI_WRITE_TX0(SPI1, (uint32_t )0x0);
  19.                 //SPI_TRIGGER(SPI1);
  20.                 while(SPI_IS_BUSY(SPI1));
  21.                 pu8data[i] = (uint8_t)SPI_READ_RX0(SPI1);
  22.         }

  23.         //Clear SPI RX FIFO
  24.         //SPI_ClearRxFIFO(SPI1);
  25.         
  26.         SPI_SET_SS_HIGH(SPI1);
  27. }

(5) 连续写入data到spi array
  1. void DM9051_Write_Mem(uint8_t* pu8data, uint32_t datalen)
  2. {
  3.         uint32_t i;
  4.         
  5.         // Send the array to the slave
  6.         uint8_t burstcmd = SPI_WR_BURST;
  7.         
  8.         SPI_SET_SS_LOW(SPI1);

  9.         //SPI_ClearTxFIFO(SPI1);
  10.         SPI_WRITE_TX0(SPI1, (uint32_t)burstcmd);
  11.         //SPI_TRIGGER(SPI1);
  12.         while(SPI_IS_BUSY(SPI1));
  13.         SPI_READ_RX0(SPI1);                //Skip SPI RX FIFO

  14.         for(i=0; i
  15.                 while(SPI_GET_TX_FIFO_FULL_FLAG(SPI1));
  16.                 SPI_WRITE_TX0(SPI1, (uint32_t)pu8data[i]);
  17.         }
  18.         while(SPI_IS_BUSY(SPI1));
  19.         SPI_ClearRxFIFO(SPI1);         //Clear SPI RX FIFO
  20.         
  21.         SPI_SET_SS_HIGH(SPI1);
  22. }


   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
  2. PT_THREAD(handle_input(struct httpd_state *s))
  3. {
  4.         PSOCK_BEGIN(&s->sin);

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


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

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

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

  32.         /*  httpd_log_file(uip_conn->ripaddr, s->filename);*/

  33.         s->state = STATE_OUTPUT;

  34.         while(1) {
  35.                 PSOCK_READTO(&s->sin, ISO_nl);

  36.                 if(strncmp(s->inputbuf, http_referer, 8) == 0) {
  37.                         s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
  38.                         /*      httpd_log(&s->inputbuf[9]);*/
  39.                 }
  40.         }

  41.         PSOCK_END(&s->sin);
  42. }


(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位址

就可以透过web 控制LED,如下可以看到MCU +  DM9051相关讯息,最下面可以看到控制LED 选单,
按下on 、off 、Flash后网址后面会分别显示XXX.XXX.XXX.XXX / LED0、1、2让使用者可以知道目前设定




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

DM9051(I)-12-MCO-DS-P01_03302015.pdf (829.02 KB)
(下载次数: 77, 2016-2-19 14:07 上传)


NUC_M051_uIP_SPI1_DM9051_webserver.rar (492.96 KB)
(下载次数: 103, 2016-2-19 14:07 上传)





回帖(5)

xie402050431

2016-2-21 11:45:12
看看........................
举报

王崇吉

2016-2-23 09:29:13
引用: xie402050431 发表于 2016-2-21 11:45
看看........................

有问题或是其他建议可以提出,谢谢。
举报

吴晓良

2017-3-24 16:36:31
举报

陶志和

2018-11-9 12:50:47
谢谢分享啊!!!!!!!!!!
举报

叶继成

2019-1-3 14:40:06
怎么我AVR移植一直不可以,好尴尬哦
举报

更多回帖

发帖
×
20
完善资料,
赚取积分