DM9051 SPI 接口以太網模塊 + NuTinyM051 + uIP實現web server

       最近在某個論壇裡,看到這篇STM32F103+DM9051_UIP_SPI to 以太網,透過該版主拿到了DM9051NP 以太網卡,剛好手上有Nuvoton NuTiny M051 和 M451,就先用M051拿來做一個簡單的web server,透過web server 來控制開發板上的LED燈亮滅。

    1. DM9051NP硬體相關描述

       DM9051NP SPI介面網卡芯片是聯傑國際(DAVICOM)爲了方便MCU單片機系統進行乙太網通信而開發出的解決方案。DM9051NP晶片是帶有行業標準串列外設介面(Serial Peripheral Interface,SPI)的獨立乙太網控制器。DM9051NP符合IEEE 802.3 規範,它還支援以DMA 模式來傳輸,以實現資料傳送快速。DM9051NP通過1箇中斷引腳和SPI介面來進行與主控制器/MCU單片機的通信,資料傳輸規格爲10/100 M。相關介紹可以參考STM32F103+DM9051_UIP_SPI to 以太網。以下是DM9051NP 以太網卡特點:

      • 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℃  

        上圖是聯傑國際(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)


       上圖爲M051 + DM9051硬體連接示意圖。
           

     2.DM9051網卡驅動

       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 相關設定

void DM9051_Configuration(void)
{	
	/* Enable SPI1 peripheral clock */
	CLK_EnableModuleClock(SPI1_MODULE);
	/* Select HCLK as the clock source of SPI1 */
	CLK_SetModuleClock(SPI1_MODULE, CLK_CLKSEL1_SPI1_S_HCLK, MODULE_NoMsk);

	/* Reset IP */
	SYS_ResetModule(SPI1_RST);    

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

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

	SPI_EnableFIFO(SPI1, 3, 3);
}



(2) 透過read cmd 讀出register

/*------------------------------------------------------*/
/* DM9051_Read_Reg()                                    */
/* SPI read command: bit7 = 0,                          */
/*                   bit[6:0] = Reg. offset addr        */
/* Disable auto SPI slave chip select.                  */
/*------------------------------------------------------*/
uint8_t DM9051_Read_Reg(uint8_t Reg_Off)
{
		
    SPI_SET_SS_LOW(SPI1);
  
	/* SPI transfer DM9051 Read-Command and Reg. offset. */
	//SPI_WRITE_TX0(SPI1, (uint32_t)Reg_Off); //Read command + Register offset address
	while(SPI_GET_TX_FIFO_FULL_FLAG(SPI1));
	SPI_WRITE_TX0(SPI1, Reg_Off); //Read command + Register offset address
	while(SPI_IS_BUSY(SPI1));
	
	SPI_WRITE_TX0(SPI1, 0x0); //Dummy for read register value.
	while(SPI_IS_BUSY(SPI1));
	
	SPI_READ_RX0(SPI1); // dummy read, jump 1st byte.
	
	SPI_SET_SS_HIGH(SPI1);
	
	return (SPI_READ_RX0(SPI1) & 0xFF);
}





(3)透過write cmd 寫入register

/*------------------------------------------------------*/
/* DM9051_Write_Reg()                                   */
/* SPI write command: bit7 = 1,                         */
/*                   bit[6:0] = Reg. offset addr        */
/* Disable auto SPI slave chip select.                  */
/*------------------------------------------------------*/
void DM9051_Write_Reg(uint8_t Reg_Off, uint8_t spi_data)
{
	uint32_t cmdaddr;
	
	cmdaddr = (Reg_Off | 0x80);
	
	SPI_SET_SS_LOW(SPI1);
	
	/* SPI transfer DM9051 Read-Command and Reg. offset. */
	SPI_WRITE_TX0(SPI1, cmdaddr); //Read command + Register offset address	
	while(SPI_IS_BUSY(SPI1));
	
	SPI_WRITE_TX0(SPI1, (uint32_t)spi_data);
	while(SPI_IS_BUSY(SPI1));
	
	/*Clear SPI TX FIFO*/
	SPI_ClearRxFIFO(SPI1);
	
	SPI_SET_SS_HIGH(SPI1);
	
	return;
}


(4) 連續讀出 data 從spi array

/*------------------------------------------------------*/
/* DM9051_Read_Mem()                                    */
/*                                                      */
/* DM9051 burst read command: SPI_RD_BURST = 0x72       */
/* Disable auto SPI slave chip select.                  */
/*------------------------------------------------------*/
void DM9051_Read_Mem(uint8_t* pu8data, uint32_t datalen)
{
	uint32_t i;
	
	// Read SPI_Data_Array back from the slave
	uint8_t burstcmd = SPI_RD_BURST;
	
	SPI_SET_SS_LOW(SPI1);
	
	SPI_WRITE_TX0(SPI1, (uint32_t)burstcmd);
	while(SPI_IS_BUSY(SPI1));
	SPI_READ_RX0(SPI1);
	
	for(i = 0 ; i < datalen; i++){
		pu8data[i] = SPI_WRITE_TX0(SPI1, (uint32_t )0x0);
		while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
		pu8data[i] = (uint8_t)SPI_READ_RX0(SPI1);
	}
	
	while(SPI_IS_BUSY(SPI1));
	/*Clear SPI TX FIFO*/
	SPI_ClearTxFIFO(SPI1);
	
	SPI_SET_SS_HIGH(SPI1);
}






(5) 連續寫入data到spi array

/*------------------------------------------------------*/
/* DM9051_Write_Mem()                                   */
/*                                                      */
/* DM9051 burst write command: SPI_WR_BURST = 0xF8      */
/* Disable auto SPI slave chip select.                  */
/*------------------------------------------------------*/
void DM9051_Write_Mem(uint8_t* pu8data, uint32_t datalen)
{
	uint32_t i;
	uint8_t burstcmd = SPI_WR_BURST; /* Send the array to the slave*/

	SPI_SET_SS_LOW(SPI1);
	
	SPI_WRITE_TX0(SPI1, (uint32_t)burstcmd);
	while(SPI_IS_BUSY(SPI1));
	SPI_READ_RX0(SPI1);
	
	for(i = 0; i < datalen; i++){		
		while(SPI_GET_TX_FIFO_FULL_FLAG(SPI1));
		SPI_WRITE_TX0(SPI1, (uint32_t)pu8data[i]);
	}
	
	while(SPI_IS_BUSY(SPI1));
	/*Clear SPI RX FIFO*/
	SPI_ClearRxFIFO(SPI1);
	
	SPI_SET_SS_HIGH(SPI1);
}





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()新增判斷:

static PT_THREAD(handle_input(struct httpd_state *s))
{
  PSOCK_BEGIN(&s->sin);

  PSOCK_READTO(&s->sin, ISO_space);

  if(strncmp(s->inputbuf, http_get, 4) != 0) {
    PSOCK_CLOSE_EXIT(&s->sin);
  }

  PSOCK_READTO(&s->sin, ISO_space);

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

  if(s->inputbuf[1] == ISO_space) {		
    //strncpy(s->filename, http_index_html, sizeof(s->filename));
	strncpy(s->filename, http_webMain_html, sizeof(s->filename));
  } 
#if 1 //web control led
  /* Control led, 0 = OFF, 1 = ON, 2 = Flash */
  else if (s->inputbuf[3] == 'L','E','D' && ((s->inputbuf[4] == '0') || 
            (s->inputbuf[4] == '1') || (s->inputbuf[4] == '2'))){
    Set_LED_mode(s->inputbuf[4]);
    s->inputbuf[4]= 0;
    //strncpy(s->filename, "/home.html", 10);
    strncpy(s->filename, http_webMain_html, sizeof(s->filename));
  }
#endif
  else {
 	s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
   	strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename));
  }
  /*  httpd_log_file(uip_conn->ripaddr, s->filename);*/
  s->state = STATE_OUTPUT;

  while(1) {
    PSOCK_READTO(&s->sin, ISO_nl);
    if(strncmp(s->inputbuf, http_referer, 8) == 0) {
      s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
      /* httpd_log(&s->inputbuf[9]);*/
    }
  }
  PSOCK_END(&s->sin);
}



(2)LED 設定和控制判斷代碼如下:


void Set_LED_mode(char lkkcode)
{
	//int i;
	
	GPIO_SetMode(P3, BIT6, GPIO_PMD_OUTPUT);
	
	if(lkkcode == ('0')) // LED off
	{
		P36 = 1;
	}else if (lkkcode == '1'){ // LED on
		P36 = 0;
	}else if(lkkcode == '2') // LED Flash
	{
		//for(i = 0 ; i< 30 ; ++i)
		{
			P36 = 0;
			Delay(25);
			P36 = 1;
			Delay(25);
		}
	}
}



最後在網址列輸入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應用了,最後附上程序:

DM9051網卡 + NuTinyM051 + uIP實現web server


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章