本帖最后由 jf7686 于 2016-10-7 10:14 编辑
在前几个礼拜发了一篇 DM9051 SPI 接口以太网模块 + NuTinyM051 + uIP实现web server后,原本想在发一篇 DM9051 SPI 接口以太网模块 + NuTinyM451 + uIP,但 Nu_Micro大大已经先PO了 M451+DM9051(SPI接口网络芯片)的uIP demo code移植,所以我直接参考,再移植过程中发现DM9051的驱动与我之前的M0516 + DM9051写法有些不太一样,两者差异在M0516 SPI有4 level FIFO, M451 SPI支援8 level FIFO,所以直接参考修改,所以修改了部份的驅動且加上FreeRTOS OS,一样实现web server。
1.硬件描述
(1) 首先DM9051NP SPI接口以太网模块:
相关描述就不多说了,可以参考DM9051 SPI 接口以太网模块 + NuTinyM051 + uIP实现web server,或 STM32F103+DM9051_UIP_SPI to 以太网。
(2) NuTinyM451使用的是SPI0与DM9051NP SPI脚位硬体连接:
| NuTinyM451 | DM9051NP | CSS | PB.4 (Pin 95) | (Pin 01) | MOSI | PB.5 (Pin 04) | (Pin 03) | MISO | PB.3 (Pin 94) | (Pin 05) | CLK | PB.2 (Pin 93) | (Pin 07) |
下图是NuTinyM451 + DM9051NP 接线示意图:
2.驱动说明
在移植过程中发现,M451+DM9051(SPI接口网络芯片)的uIP demo code移植中的驱动写得有些复杂,所以我参考M051的驱动修改,修改完后正常动作且SPI Frequence 最高能设到24 Mhz。
(1). 首先配置M451 SPI0 相关设定void DM9051_Configuration(void)
{
/* Enable SPI0 Module clock */
CLK_EnableModuleClock(SPI0_MODULE);
/* SPI0 module clock from EXT */
CLK_SetModuleClock(SPI0_MODULE, CLK_CLKSEL2_SPI0SEL_PCLK0, MODULE_NoMsk);
/* Reset IP */
SYS_ResetModule(SPI0_RST);
SYS->GPB_MFPL &= ~(SYS_GPB_MFPL_PB2MFP_Msk | SYS_GPB_MFPL_PB3MFP_Msk | SYS_GPB_MFPL_PB4MFP_Msk | SYS_GPB_MFPL_PB5MFP_Msk);
SYS->GPB_MFPL |= (SYS_GPB_MFPL_PB2MFP_SPI0_CLK | SYS_GPB_MFPL_PB3MFP_SPI0_MISO0 | SYS_GPB_MFPL_PB4MFP_SPI0_SS | SYS_GPB_MFPL_PB5MFP_SPI0_MOSI0);
/*---------------------------------------------------------------------------------------------------------*/
/* Init SPI */
/*---------------------------------------------------------------------------------------------------------*/
/* Configure SPI0 as a master, SPI clock rate 24 MHz,
clock idle low, 32-bit transaction, drive output on falling clock edge and latch input on rising edge. */
SPI_Open(SPI0, SPI_MASTER, SPI_MODE_0, 8, 24000000);
/* Enable the automatic hardware slave selection function. Select the SPI0_SS pin and configure as low-active. */
//SPI_EnableAutoSS(SPI0, SPI_SS, SPI_SS_ACTIVE_LOW);
SPI_DisableAutoSS(SPI0);
SPI_ENABLE(SPI0);
SPI_SetFIFO(SPI0, 7, 7);
}
与Nu_Micro的M451+DM9051(SPI接口网络芯片)的uIP demo code移植的DM9051驱动改较多的部份是,SPI R/W spi array data, 修改如下:
(2). 连续读出 data 从spi array
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(SPI0);
SPI_WRITE_TX(SPI0, (uint32_t)burstcmd);
while(SPI_IS_BUSY(SPI0));
SPI_READ_RX(SPI0); //Skip SPI RX FIFO
for(i = 0 ; i < datalen; i++)
{
pu8data[i] = SPI_WRITE_TX(SPI0, (uint32_t )0x0);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
pu8data[i] = (uint8_t)SPI_READ_RX(SPI0);
}
SPI_SET_SS_HIGH(SPI0);
}
(3). 连续写入data到spi array
void DM9051_Write_Mem(uint8_t* pu8data, uint32_t datalen)
{
uint32_t i;
// Send the array to the slave
uint8_t burstcmd = SPI_WR_BURST;
SPI_SET_SS_LOW(SPI0);
SPI_WRITE_TX(SPI0, (uint32_t)burstcmd);
while(SPI_IS_BUSY(SPI0));
SPI_READ_RX(SPI0); //Skip SPI RX FIFO
for(i = 0; i < datalen; i++)
{
while(SPI_GET_TX_FIFO_FULL_FLAG(SPI0));
SPI_WRITE_TX(SPI0, (uint32_t)pu8data[i]);
}
while(SPI_IS_BUSY(SPI0));
SPI_ClearRxFIFO(SPI0);
SPI_SET_SS_HIGH(SPI0);
}
3.FreeRTOS说明
FreeRTOS的部分可参考M451SeriesBSP_CMSIS Library 里的Sample做相关移植或网上找有满多相关说明,我直接拿Library 的sample把里面一些原本的Task拿掉只留下uIP 跟 LED 控制的 Task:
(1). Create Task
int main( void )
{
/* Init System */
prvSetupHardware();
/* create task */
xTaskCreate( vuIP_Task, ( signed portCHAR * ) "uIP", configMINIMAL_STACK_SIZE * 3, NULL, tskIDLE_PRIORITY + 4, NULL );
xTaskCreate( vLEDTask, ( signed portCHAR * ) "LED", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL );
printf("FreeRTOS is starting ...\n");
/* start OS */
vTaskStartScheduler();
for(;;);
}
(2). LED Task
void vLEDTask( void *pvParameters )
{
/* Set LED */
GPIO_EnableInt(PC, 9, GPIO_INT_FALLING);
GPIO_SetMode(PC, BIT9, GPIO_MODE_OUTPUT);
for( ;; )
{
if(Web_LED_FLASH == 1){
PC9 = 1;
vTaskDelay( 500 / portTICK_RATE_MS );
PC9 = 0;
vTaskDelay( 500 / portTICK_RATE_MS );
}
}
}
(3). uIP Task
uIP Task 里面的写法与设定只是将原本的uIP的main()改成void vuIP_Task( void *pvParameters )在这就不多做介绍,在设定FreeRTOS Task Delay Timer 在while(1) 加上
#ifdef __DHCPC_H__
else if (timer_expired(&dhcp_timer)) {
// for now turn off the led when we start the dhcp process
//led_low();
dhcpc_renew();
timer_reset(&dhcp_timer);
}
#endif // __DHCPC_H__
else{
/* task delay */
vTaskDelayUntil( &xLastWakeTime, xFrequency );
//vTaskDelay( 100 / portTICK_RATE_MS );
}
}
// return 0;
}
4.简单的web server 控制 LED
Web Server与 DM9051 SPI 接口以太网模块 + NuTinyM051 + uIP实现web server 的设定大致相同一样能看到MCU 与 IP 相关讯息和控制LED,只是新增了一个选项Task_CON, 原本的设定FreeRTOS Task就是跑uIP 和LED闪烁,但进入网页后为了能使网页控制LED 设定的一个Web_LED_FLASH Flag 来判断目前LED状态,网页后按下ON、OFF、FLASH会暂停FreeRTOS 的LED Task , 在user 不想用网页控制时,在按下Task_Con就能切换为FreeRTOS控制。
一样输入IP地址 192.168.XXX.XXX进入 uip web server控制LED,因为uip 有开DHCP 也可设定为固定IP ,看使用者设定输入正确的IP地址
进入网页后就能控制LED,如下可以看到MCU + DM9051相关讯息,最下面可以看到控制LED 选单,按下on 、off 、Flash、Task_CON后网址后面会分别显示XXX.XXX.XXX.XXX / LED0、1、2、3让使用者可以知道目前设定
以上完成后就是一个简单webserver 控制LED应用了,最后一樣附上程序:
RAM 大约使用了 12264 ( 11.98kB)
ROM 大约使用了 43860 ( 42.83kB),因为有OS的关係,版上各位在应用上有想法或是问题都可以提出一起讨论,谢谢。
NUC-M451_FreeRTOS_uIP_DM9051_WebServer.rar
(895.01 KB)
|