测试时使用的程序:Marvell 88W8801 WiFi模块创建或连接热点,并使用lwip2.1.2建立http服务器(20200208版)(F1程序/HAL库版本SDIO接口)
一、修改前的速度:
TCP:
很慢很慢,才7KB/s。。。
收到747520字节,用时100.64秒,速率7.25KB/s
收到747520字节,用时100.84秒,速率7.24KB/s
收到747520字节,用时102.21秒,速率7.14KB/s
收到747520字节,用时101.12秒,速率7.22KB/s
收到747520字节,用时101.39秒,速率7.20KB/s
收到747520字节,用时101.14秒,速率7.22KB/s
收到747520字节,用时101.88秒,速率7.17KB/s
收到747520字节,用时102.31秒,速率7.14KB/s
收到747520字节,用时102.77秒,速率7.10KB/s
收到747520字节,用时102.62秒,速率7.11KB/s
UDP:
收到1024个数据包,用时10.83秒,速率120.08KB/s
收到1024个数据包,用时7.29秒,速率178.45KB/s
收到1024个数据包,用时7.29秒,速率178.45KB/s
收到1024个数据包,用时7.32秒,速率177.67KB/s
收到1024个数据包,用时7.41秒,速率175.44KB/s
收到1024个数据包,用时7.29秒,速率178.45KB/s
收到1024个数据包,用时7.30秒,速率178.06KB/s
收到1024个数据包,用时7.33秒,速率177.30KB/s
收到1024个数据包,用时7.29秒,速率178.42KB/s
收到1024个数据包,用时7.79秒,速率166.99KB/s
从串口打印中可以看出,每个数据包的时间间隔都是75ms:
二、提高UDP的传输速率
只需要关闭串口打印输出就可以提速了。
(方法一:完全屏蔽串口输出)打开common.c,注释掉usart_send函数里面的内容,关闭串口打印输出。
(方法二:关闭部分串口输出,推荐用此方法)
WiFi/wifi.h:WIFI_DISPLAY_RESPTIME改为0
lwip-2.1.2/include/netif/ethernetif.h:WIFI_DISPLAY_PACKET_SIZE改为0
修改后测速结果:
收到1024个数据包,用时0.86秒,速率1515.15KB/s
收到1024个数据包,用时1.45秒,速率895.93KB/s
收到1017个数据包,用时5.16秒,速率250.02KB/s
收到1024个数据包,用时1.08秒,速率1208.18KB/s
收到1024个数据包,用时7.78秒,速率167.01KB/s
收到1023个数据包,用时1.01秒,速率1280.80KB/s
收到1024个数据包,用时6.40秒,速率203.25KB/s
收到1024个数据包,用时2.78秒,速率468.13KB/s
收到1024个数据包,用时1.37秒,速率947.52KB/s
收到1024个数据包,用时1.20秒,速率1082.43KB/s
收到1024个数据包,用时1.28秒,速率1016.42KB/s
收到1024个数据包,用时1.06秒,速率1225.26KB/s
收到1024个数据包,用时2.11秒,速率617.28KB/s
收到1024个数据包,用时1.19秒,速率1096.12KB/s
收到1024个数据包,用时1.26秒,速率1029.30KB/s
收到1024个数据包,用时1.08秒,速率1208.18KB/s
收到1024个数据包,用时1.20秒,速率1082.43KB/s
收到1024个数据包,用时12.14秒,速率107.11KB/s
收到1024个数据包,用时1.26秒,速率1028.48KB/s
收到1024个数据包,用时10.17秒,速率127.81KB/s
三、提高TCP的传输速率
打开lwipopts.h,添加三行代码:
#define TCP_WND (10 * TCP_MSS)
#define TCP_SND_BUF (10 * TCP_MSS)
#define MEMP_NUM_TCP_SEG 50
打开wifi_test.c,将tcp_tester_buffer数组的长度改大,越大越好,把整个单片机的SRAM全部占满!
修改后的测速结果:
收到748400字节,用时0.56秒,速率1302.78KB/s
收到760196字节,用时0.53秒,速率1398.08KB/s
收到760480字节,用时0.47秒,速率1586.87KB/s
收到755228字节,用时0.42秒,速率1751.85KB/s
收到764388字节,用时0.45秒,速率1651.49KB/s
收到749860字节,用时0.44秒,速率1675.71KB/s
收到760480字节,用时0.48秒,速率1537.59KB/s
收到755228字节,用时0.47秒,速率1575.91KB/s
收到753768字节,用时0.50秒,速率1475.15KB/s
收到747528字节,用时0.42秒,速率1729.88KB/s
到这个时候才发现,速度大于1MB/s的时候,测速就不精确了。因为测速器选择的数据量太小了,时间哪怕差个零点零几秒,算出来的速率值的差异都很大。
当时做这个测速器的时候,根本没有想过单片机驱动88W8801会有这么快的速度。
收到754640字节,用时1.08秒,速率684.90KB/s
收到752780字节,用时0.83秒,速率888.92KB/s
收到754240字节,用时1.29秒,速率568.77KB/s
收到751320字节,用时0.89秒,速率825.32KB/s
收到751320字节,用时1.31秒,速率559.66KB/s
收到753368字节,用时1.33秒,速率554.83KB/s
收到748988字节,用时1.00秒,速率732.90KB/s
收到751908字节,用时0.76秒,速率961.11KB/s
收到759208字节,用时1.25秒,速率594.08KB/s
收到751908字节,用时1.14秒,速率645.24KB/s
收到751320字节,用时0.83秒,速率887.20KB/s
收到763000字节,用时1.14秒,速率654.19KB/s
收到752780字节,用时1.37秒,速率535.81KB/s
收到749860字节,用时0.48秒,速率1516.12KB/s
收到757748字节,用时0.45秒,速率1633.53KB/s
收到752780字节,用时0.64秒,速率1150.45KB/s
收到751908字节,用时1.14秒,速率644.68KB/s
收到753368字节,用时0.97秒,速率760.82KB/s
收到746940字节,用时1.04秒,速率698.02KB/s
收到739828字节,用时0.80秒,速率908.79KB/s
注意:SDIO标准规定的是SDIO中断是低电平有效,但是STM32单片机的SDIO却实现成了下降沿有效。因此SDIO中断有漏检的可能,尤其是发送数据特别快的情况下。
如果在窗口里面经常看到漏掉SDIO中断(WiFi_CheckTimeout: missed an interrupt!),可以在WiFi_CheckTimeout里面把if (diff > 3000)的数值3000(毫秒)改小(比如10),或者使能WIFI_LOWLEVEL_NOINTPIN宏。
四、测速环境
WiFi模块和无线路由器的距离为1米左右。
用的无线路由器是装宽带的时候送的。电脑和路由器之间是有线连接(黄色网线)。
五、STM32F4的情况
接下来我们来看一下F4单片机下的情况。测试时采用的是STM32F407VE单片机,SRAM容量为192KB,Flash容量为512KB。选择SDIO接口,使能DMA,频率为24MHz。
相比较而言,STM32F103RE单片机的SRAM为64KB,Flash容量为512KB。
测试程序是带FreeRTOS系统的,FreeRTOS开了50KB的内存(configTOTAL_HEAP_SIZE=50*1024),tcp_tester_buffer的大小为15000。
整个工程用了大约106KB的内存(Program Size: Code=195864 RO-data=7348 RW-data=512 ZI-data=107856)。
总共192KB的SRAM,用掉106KB,还有86KB的内存没有使用,可以拿来做其他应用。另外还有4KB的BKPSRAM(0x40024000~0x40024fff)没有统计在内。
而且,wifi_test.c还是用socket API写的:(代码位于https://blog.csdn.net/ZLK1214/article/details/112718423)
TCP测试结果:
收到767828字节,用时0.44秒,速率1719.80KB/s
收到767048字节,用时0.47秒,速率1600.58KB/s
收到770748字节,用时0.39秒,速率1929.96KB/s
收到768228字节,用时0.44秒,速率1716.76KB/s
收到776588字节,用时0.39秒,速率1944.58KB/s
收到750188字节,用时0.39秒,速率1878.48KB/s
收到772208字节,用时0.47秒,速率1611.34KB/s
收到774540字节,用时0.41秒,速率1863.02KB/s
收到763520字节,用时0.45秒,速率1649.61KB/s
收到766060字节,用时0.42秒,速率1776.97KB/s
UDP测试结果:
收到1024个数据包,用时0.56秒,速率2317.29KB/s
收到1024个数据包,用时0.58秒,速率2253.03KB/s
收到1024个数据包,用时0.59秒,速率2192.24KB/s
收到1024个数据包,用时0.55秒,速率2380.95KB/s
收到1022个数据包,用时0.53秒,速率2443.43KB/s
收到1024个数据包,用时0.59秒,速率2192.24KB/s
收到1016个数据包,用时0.52秒,速率2504.55KB/s
收到1024个数据包,用时0.61秒,速率2134.65KB/s
收到1022个数据包,用时0.56秒,速率2312.76KB/s
收到1024个数据包,用时0.53秒,速率2452.83KB/s
UDP的数据包大小没变,仍然是1300字节,但速度最高可以达到2.5MB/s。
可见STM32F4的代码执行速度比STM32F1快得多,而且SRAM内存也比F1大,更适合用来做项目。不用像F1那样把整个单片机的内存全部占满才能提速。
六、SPI接口(GPIO模拟)的速度
88W8801不仅支持SDIO接口,还支持SPI接口。SPI例程里面采用的是引脚不变,GPIO原地模拟SPI的方式驱动88W8801。
SPI_NSS PC11 D3
SPI_SCK PC12 CLK
SPI_MISO PC8 D0
SPI_MOSI PD2 CMD
模块复位 PD14 PDN
中断 PC9 D1
(一定要确保中断引脚没有接上拉电阻,否则会不断出现missed an interrupt的错误)
测试时,采用的单片机为STM32F407VE,tcp_tester_buffer大小为13000。这次测试不带操作系统,用的是原始的例程。
TCP测试结果:
收到765520字节,用时9.13秒,速率81.92KB/s
收到765520字节,用时9.13秒,速率81.92KB/s
收到762600字节,用时9.11秒,速率81.74KB/s
收到761140字节,用时9.08秒,速率81.87KB/s
收到764060字节,用时9.11秒,速率81.90KB/s
收到765520字节,用时9.13秒,速率81.92KB/s
收到765520字节,用时9.13秒,速率81.92KB/s
收到765520字节,用时9.13秒,速率81.92KB/s
收到765520字节,用时9.14秒,速率81.78KB/s
收到766108字节,用时9.38秒,速率79.79KB/s
UDP测试结果:
收到1024个数据包,用时14.54秒,速率89.41KB/s
收到1024个数据包,用时14.55秒,速率89.32KB/s
收到1024个数据包,用时14.55秒,速率89.32KB/s
收到1024个数据包,用时14.56秒,速率89.32KB/s
收到1024个数据包,用时14.56秒,速率89.32KB/s
收到1024个数据包,用时14.54秒,速率89.41KB/s
收到1024个数据包,用时14.54秒,速率89.41KB/s
收到1024个数据包,用时14.56秒,速率89.32KB/s
收到1024个数据包,用时14.56秒,速率89.32KB/s
收到1024个数据包,用时14.56秒,速率89.32KB/s
TCP和UDP的速率均为80KB/s左右。为什么会这么慢呢?
这是因为,GPIO模拟SPI时,必须要软件来计算CRC7和CRC16,这是最耗时的部分!
#define POLYNOMIAL_CRC7 0x89ul
#define POLYNOMIAL_CRC16 0x11021ul
/* 计算CRC7校验码 */
static uint8_t WiFi_LowLevel_CalcCRC7(const void *data, int len)
{
const uint8_t *p = data;
int i, j;
uint16_t temp = 0;
if (len != 0)
temp = p[0] << 8;
for (i = 1; i <= len; i++)
{
if (i != len)
temp |= p[i];
for (j = 0; j < 8; j++)
{
if (temp & 0x8000)
temp ^= POLYNOMIAL_CRC7 << 8;
temp <<= 1;
}
}
return temp >> 9;
}
/* 计算CRC16校验码 */
static uint16_t WiFi_LowLevel_CalcCRC16(const void *data, int len)
{
const uint8_t *p = data;
int i, j;
uint32_t temp = 0;
if (len & 1)
{
printf("%s: data size %d is odd!\n", __FUNCTION__, len);
len--; // 不允许出现奇数长度
}
if (len != 0)
temp = (p[0] << 24) | (p[1] << 16); // 填充前二分之一
if (len > 2)
temp |= p[2] << 8; // 填充到四分之三
for (i = 3; i <= len + 2; i++)
{
if (i < len)
temp |= p[i]; // 每次都填充最后四分之一的空间
// 从左数第0~7位计算到左数第16~23位
for (j = 0; j < 8; j++)
{
if (temp & 0x80000000)
temp ^= POLYNOMIAL_CRC16 << 15;
temp <<= 1;
}
}
return temp >> 16;
}
还有就是GPIO模拟SPI本身速度就不快,示波器测出来SPI的时钟频率为995kHz:
STM32F4自带的硬件CRC(CRC calculation unit)只能计算多项式为0x4C11DB7的CRC32校验码,无法用于本项目中。
但硬件SPI里面也有一个CRC calculation的功能,可以计算CRC8和CRC16,多项式可由SPI->CRCPR寄存器指定。
如果用好STM32F4的硬件SPI、DMA以及硬件SPI里面的CRC计算功能,说不定就能提升SPI方式的通信速率。