88W8801 SPI方式连线 [tr]模块引脚名称SPI引脚名称I/O口[/tr]
D3 |
CS(或NSS) |
PC11 |
CLK |
SCK |
PC12 |
D0 |
MISO |
PC8 |
CMD |
MOSI |
PD2 |
D1 |
INT |
PC9 |
PDN |
|
PD14 |
RESET |
|
悬空 |
VCC |
|
3.3V |
【笔者所用的开发板和WiFi模块】
在笔者所用的开发板上,Wi-Fi模块的VCC不是直接接到电源上的,而是串联了一个场效应管,当PA15为低电平时Wi-Fi模块通电。
【Keil4工程截图】
【程序运行结果】
【主要代码】
// 定义与单片机寄存器操作相关的函数, 方便在不同平台间移植
#include
#include
#include "common.h"
#include "WiFi.h"
#define CS_0 GPIO_WriteBit(GPIOC, GPIO_Pin_11, Bit_RESET)
#define CS_1 GPIO_WriteBit(GPIOC, GPIO_Pin_11, Bit_SET)
#define SCK_0 GPIO_WriteBit(GPIOC, GPIO_Pin_12, Bit_RESET)
#define SCK_1 GPIO_WriteBit(GPIOC, GPIO_Pin_12, Bit_SET)
#define MISO (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_8) == Bit_SET)
#define MOSI_0 GPIO_WriteBit(GPIOD, GPIO_Pin_2, Bit_RESET)
#define MOSI_1 GPIO_WriteBit(GPIOD, GPIO_Pin_2, Bit_SET)
#define CMD52_WRITE _BV(31)
#define CMD52_READAFTERWRITE _BV(27)
#define CMD53_WRITE _BV(31)
#define CMD53_BLOCKMODE _BV(27)
#define CMD53_INCREMENTING _BV(26)
static uint8_t WiFi_LowLevel_CalcCRC7(const void *data, uint16_t len);
static void WiFi_LowLevel_GPIOInit(void);
static void WiFi_LowLevel_ReceiveResponse(uint8_t *resp, uint8_t resp_len);
static void WiFi_LowLevel_SDIOInit(void);
static void WiFi_LowLevel_SendCMD52(uint8_t func, uint32_t addr, uint8_t data, uint32_t flags, uint8_t *resp, uint8_t resp_len);
static void WiFi_LowLevel_Send(uint8_t *data, uint16_t len);
static uint8_t WiFi_LowLevel_SendByte(uint8_t data);
static void WiFi_LowLevel_SendCommand(uint8_t index, uint32_t argument, uint8_t *resp, uint8_t resp_len);
static uint8_t sdio_func_num = 0; // 功能区总数 (0号功能区除外)
/* 计算CRC7校验码 */
static uint8_t WiFi_LowLevel_CalcCRC7(const void *data, uint16_t len)
{
const uint8_t *p = data;
const uint8_t polynomial = 0x89;
uint8_t j;
uint16_t temp = p[0] << 8;
uint16_t i;
for (i = 1; i <= len; i++)
{
if (i != len)
temp |= p
; for (j = 0; j < 8; j++) { if (temp & 0x8000) temp ^= polynomial << 8; temp <<= 1; } } return temp >> 9; }
/* 获取WiFi模块支持SDIO功能区个数 (0号功能区除外) */ uint8_t WiFi_LowLevel_GetFunctionNum(void) { return sdio_func_num; }
/* 判断是否触发了网卡中断 */ uint8_t WiFi_LowLevel_GetITStatus(uint8_t clear) { if (EXTI_GetFlagStatus(EXTI_Line9) == SET) { if (clear) EXTI_ClearFlag(EXTI_Line9); return 1; } else return 0; }
/* 初始化WiFi模块有关的所有GPIO引脚 */ static void WiFi_LowLevel_GPIOInit(void) { EXTI_InitTypeDef exti; GPIO_InitTypeDef gpio;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
// 使Wi-Fi模块复位信号(PDN)有效 gpio.GPIO_Mode = GPIO_Mode_OUT; gpio.GPIO_OType = GPIO_OType_PP; gpio.GPIO_Pin = GPIO_Pin_14; gpio.GPIO_PuPd = GPIO_PuPd_NOPULL; gpio.GPIO_Speed = GPIO_Low_Speed; GPIO_Init(GPIOD, &gpio); GPIO_WriteBit(GPIOD, GPIO_Pin_14, Bit_RESET);
// PA15为MOS管控制的Wi-Fi模块电源开关, 低电平时Wi-Fi模块通电 gpio.GPIO_Pin = GPIO_Pin_15; GPIO_Init(GPIOA, &gpio); GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET);
// 撤销Wi-Fi模块的复位信号 delay(10); // 延时一段时间, 使WiFi模块能够正确复位 GPIO_WriteBit(GPIOD, GPIO_Pin_14, Bit_SET);
// SDIO相关引脚 // PC8: MISO, 设为浮空输入 gpio.GPIO_Mode = GPIO_Mode_IN; gpio.GPIO_Pin = GPIO_Pin_8; gpio.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOC, &gpio);
// PC9: INT, 设为带上拉电阻的输入 gpio.GPIO_Mode = GPIO_Mode_IN; gpio.GPIO_Pin = GPIO_Pin_9; gpio.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOC, &gpio);
// PC11: CS, PC12: SCK, 设为推挽输出 CS_1; gpio.GPIO_Mode = GPIO_Mode_OUT; gpio.GPIO_OType = GPIO_OType_PP; gpio.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; gpio.GPIO_PuPd = GPIO_PuPd_NOPULL; gpio.GPIO_Speed = GPIO_High_Speed; GPIO_Init(GPIOC, &gpio);
// PD2: MOSI, 设为推挽输出 gpio.GPIO_Pin = GPIO_Pin_2; GPIO_Init(GPIOD, &gpio);
// 配置外部中断 SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource9); exti.EXTI_Line = EXTI_Line9; exti.EXTI_LineCmd = ENABLE; exti.EXTI_Mode = EXTI_Mode_Interrupt; exti.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_Init(&exti); }
void WiFi_LowLevel_Init(void) { WiFi_LowLevel_GPIOInit(); WiFi_LowLevel_SDIOInit(); }
/* 读SDIO寄存器 */ uint8_t WiFi_LowLevel_ReadReg(uint8_t func, uint32_t addr) { uint8_t resp[2];
WiFi_LowLevel_SendCMD52(func, addr, 0, 0, resp, sizeof(resp)); return resp[1]; }
/* 接收指定长度的SDIO命令回应 */ // 7.3.2.1 Format R1 // 7.5.1.1 Host Command to Card Response - Card is ready // 7.5.4 Timing Values static void WiFi_LowLevel_ReceiveResponse(uint8_t *resp, uint8_t resp_len) { uint8_t i, temp;
// 等待回应期间 (NCR), MISO始终为高电平 // Modified R1回应的最高位为0, 当接收到的字节的最高位为0时退出循环 do { temp = WiFi_LowLevel_SendByte(0xff); } while (temp & 0x80);
resp[0] = temp; for (i = 1; i < resp_len; i++) resp= WiFi_LowLevel_SendByte(0xff); }
static void WiFi_LowLevel_SDIOInit(void) { uint8_t resp[5];
// 延时可防止CMD5重发 (6.4 Power Scheme) delay(100); WiFi_LowLevel_SendByte(0xff); // 在CS=1的情况下发送8个空时钟
/* 切换到SPI模式 (CMD0: Used to change from SD to SPI mode) */ WiFi_LowLevel_SendCommand(0, 0, resp, 1); printf("CMD0, R1_%02Xn", resp[0]);
/* 发送CMD5: IO_SEND_OP_COND */ WiFi_LowLevel_SendCommand(5, 0, resp, sizeof(resp)); printf("CMD5, R1_%02X, RESP1_%02x%02x%02x%02xn", resp[0], resp[1], resp[2], resp[3], resp[4]);
/* 设置参数VDD Voltage Window: 3.2~3.4V, 并再次发送CMD5 */ WiFi_LowLevel_SendCommand(5, 0x300000, resp, sizeof(resp)); printf("CMD5, R1_%02X, RESP1_%02x%02x%02x%02xn", resp[0], resp[1], resp[2], resp[3], resp[4]); if (resp[1] & _BV(7)) { // Card is ready to operate after initialization sdio_func_num = (resp[1] >> 4) & 7; printf("Number of I/O Functions: %dn", sdio_func_num); printf("Memory Present: %dn", (resp[1] & _BV(3)) != 0); }
// SPI模式不支持CMD3和CMD7, 所以不需要发送这两个命令 }
static void WiFi_LowLevel_Send(uint8_t *data, uint16_t len) { uint16_t i; for (i = 0; i < len; i++) data= WiFi_LowLevel_SendByte(data); }
static uint8_t WiFi_LowLevel_SendByte(uint8_t data) { uint8_t i; uint8_t recved = 0;
for (i = 0; i < 8; i++) { if (data & 0x80) MOSI_1; else MOSI_0; data <<= 1;
SCK_1; recved <<= 1; if (MISO) recved |= 1; SCK_0; } return recved; }
static void WiFi_LowLevel_SendCMD52(uint8_t func, uint32_t addr, uint8_t data, uint32_t flags, uint8_t *resp, uint8_t resp_len) { uint32_t arg = (func << 28) | (addr << 9) | data | flags;
WiFi_LowLevel_SendCommand(52, arg, resp, resp_len); }
static void WiFi_LowLevel_SendCommand(uint8_t index, uint32_t argument, uint8_t *resp, uint8_t resp_len) { uint8_t crc; uint8_t data[6];
data[0] = index | 0x40; // 最高位为起始位, 始终为0, SD卡从起始位开始接收命令 data[1] = argument >> 24; data[2] = argument >> 16; data[3] = argument >> 8; data[4] = argument; crc = WiFi_LowLevel_CalcCRC7(data, 5); data[5] = (crc << 1) | 1;
CS_0; WiFi_LowLevel_Send(data, sizeof(data)); WiFi_LowLevel_ReceiveResponse(resp, resp_len); CS_1; }
/* 写寄存器, 返回写入后寄存器的实际内容 */ uint8_t WiFi_LowLevel_WriteReg(uint8_t func, uint32_t addr, uint8_t value) { uint8_t resp[2];
WiFi_LowLevel_SendCMD52(func, addr, value, CMD52_WRITE | CMD52_READAFTERWRITE, resp, sizeof(resp)); return resp[1]; }
|