Marvell 88W8686 WiFi模块与SD内存卡同时插在SDIO总线上的初始化代码

本程序所用的单片机型号为:STM32F103RE
PB12端口为外接的WiFi模块电源开关,当PB12输出低电平时接通电源。

注意:WM-G-MR-09模块的芯片组(Chip Set)就是Marvell 88W8686。

SD内存卡和WiFi模块是完全连接在一起的,接到了STM32的SDIO接口上。

只能接1个WiFi模块和1张SD内存卡。WiFi模块必须接上,SD卡可插可不插。

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2. #include <stm32f10x.h>  
  3.   
  4. #define _BV(n) (1u << (n))  
  5.   
  6. uint16_t rca_sd, rca_wifi;  
  7.   
  8. // 延时n毫秒  
  9. void delay(uint16_t n)  
  10. {  
  11.     TIM6->ARR = 10 * n - 1; // nms  
  12.     TIM6->PSC = 7199; // 72MHz/7200=10kHz  
  13.     TIM6->CR1 = TIM_CR1_URS | TIM_CR1_OPM; // UG不置位UIF, 非循环模式  
  14.     TIM6->EGR = TIM_EGR_UG; // 保存设置  
  15.     TIM6->CR1 |= TIM_CR1_CEN; // 开始计时  
  16.     while ((TIM6->SR & TIM_SR_UIF) == 0); // 等待计时完毕  
  17.     TIM6->SR &= ~TIM_SR_UIF; // 清除溢出标志  
  18. }  
  19.   
  20. int fputc(int ch, FILE *fp)  
  21. {  
  22.     if (fp == stdout)  
  23.     {  
  24.         if (ch == '\n')  
  25.         {  
  26.             while ((USART1->SR & USART_SR_TXE) == 0);  
  27.             USART1->DR = '\r';  
  28.         }  
  29.         while ((USART1->SR & USART_SR_TXE) == 0);  
  30.         USART1->DR = ch;  
  31.     }  
  32.     return ch;  
  33. }  
  34.   
  35. // 检查命令是否收到了回应, 若没收到则重发命令  
  36. void Card_CheckCommand(void)  
  37. {  
  38.     while (SDIO->STA & SDIO_STA_CTIMEOUT)  
  39.     {  
  40.         SDIO->ICR = SDIO_ICR_CTIMEOUTC; // 清除标志  
  41.         SDIO->CMD = SDIO->CMD; // 重发  
  42.         printf("Timeout! Resend CMD%d\n", SDIO->CMD & SDIO_CMD_CMDINDEX);  
  43.         while (SDIO->STA & SDIO_STA_CMDACT);  
  44.     }  
  45. }  
  46.   
  47. void Card_SendCMD52(uint8_t is_write, uint8_t read_after_write, uint8_t function_number, uint32_t register_address, uint8_t data_to_write)  
  48. {  
  49.     SDIO->ARG = (is_write << 31) | (function_number << 28) | (read_after_write << 27) | (register_address << 9) | data_to_write;  
  50.     SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 52;  
  51.     while (SDIO->STA & SDIO_STA_CMDACT);  
  52. }  
  53.   
  54. void Card_ShowShortResponse(void)  
  55. {  
  56.     printf("Command response received: CMD%d, RESP_%08x\n", SDIO->RESPCMD, SDIO->RESP1);  
  57. }  
  58.   
  59. // 读寄存器  
  60. uint8_t Card_Read(uint8_t func_num, uint32_t addr)  
  61. {  
  62.     Card_SendCMD52(0, 0, func_num, addr, 0);  
  63.     if (SDIO->STA & SDIO_STA_CMDREND)  
  64.     {  
  65.         SDIO->ICR = SDIO_ICR_CMDRENDC;  
  66.         return SDIO->RESP1 & 0xff;  
  67.     }  
  68.     else  
  69.     {  
  70.         printf("Card_Read failed, SDIO->STA=0x%08x!\n", SDIO->STA);  
  71.         return 0;  
  72.     }  
  73. }  
  74.   
  75. // 写寄存器, 返回写入后寄存器的实际内容  
  76. uint8_t Card_Write(uint8_t func_num, uint32_t addr, uint8_t value)  
  77. {  
  78.     Card_SendCMD52(1, 1, func_num, addr, value);  
  79.     if (SDIO->STA & SDIO_STA_CMDREND)  
  80.     {  
  81.         SDIO->ICR = SDIO_ICR_CMDRENDC;  
  82.         return SDIO->RESP1 & 0xff;  
  83.     }  
  84.     else  
  85.     {  
  86.         printf("Card_Write failed, SDIO->STA=0x%08x!\n", SDIO->STA);  
  87.         return 0;  
  88.     }  
  89. }  
  90.   
  91. // 选中指定RCA地址的卡  
  92. void Card_Select(uint16_t rca)  
  93. {  
  94.     SDIO->ARG = rca << 16;  
  95.     SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 7;  
  96.     while (SDIO->STA & SDIO_STA_CMDACT);  
  97.     if (SDIO->STA & SDIO_STA_CMDREND)  
  98.     {  
  99.         SDIO->ICR = SDIO_ICR_CMDRENDC;  
  100.         printf("Card 0x%04x selected! status=0x%08x\n", rca, SDIO->RESP1);  
  101.     }  
  102.     else if (SDIO->STA & SDIO_STA_CTIMEOUT)  
  103.     {  
  104.         SDIO->ICR = SDIO_ICR_CTIMEOUTC;  
  105.         printf("Card not selected! CMD7 timeout!\n");  
  106.     }  
  107. }  
  108.   
  109. // SDIO Simplified Specification Version 3.00  
  110. // 3. SDIO Card Initialization  
  111. void Card_Init(void)  
  112. {  
  113.     uint8_t hcs;  
  114.     printf("Initialization begins...\n");  
  115.     SDIO->POWER = SDIO_POWER_PWRCTRL;  
  116.     SDIO->CLKCR = SDIO_CLKCR_CLKEN | 178; // 初始化时最高允许的频率: 72MHz/(178+2)=400kHz  
  117.     delay(5); // 延时可防止CMD5重发  
  118.       
  119.     /* 发送CMD0: GO_IDLE_STATE, 将SD内存卡复位 */  
  120.     SDIO->ARG = 0;  
  121.     SDIO->CMD = SDIO_CMD_CPSMEN;  
  122.     while (SDIO->STA & SDIO_STA_CMDACT);  
  123.     SDIO->ICR = SDIO_ICR_CMDSENTC;  
  124.       
  125.     /* 发送CMD8: SEND_IF_COND */  
  126.     SDIO->ARG = 0x138; // 2.7-3.6V, check pattern: 0x38  
  127.     SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 8;  
  128.     while (SDIO->STA & SDIO_STA_CMDACT);  
  129.     if (SDIO->STA & SDIO_STA_CMDREND)  
  130.     {  
  131.         SDIO->ICR = SDIO_ICR_CMDRENDC;  
  132.         hcs = 1;  
  133.     }  
  134.     else  
  135.     {  
  136.         SDIO->ICR = SDIO_ICR_CCRCFAILC | SDIO_ICR_CTIMEOUTC;  
  137.         hcs = 0;  
  138.     }  
  139.     printf("HCS=%d\n", hcs); // 根据CMD8有无回应确定hcs的值, 待会儿会传入ACMD41  
  140.       
  141.     /* 发送CMD5: IO_SEND_OP_COND */  
  142.     SDIO->ARG = 0;  
  143.     SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 5;  
  144.     while (SDIO->STA & SDIO_STA_CMDACT);  
  145.     Card_CheckCommand(); // 为了保险起见还是要检查一下是否要重发命令 (若没有插入WiFi模块, 则会一直重发该命令, 这里规定WiFi模块必须插入)  
  146.     if (SDIO->STA & SDIO_STA_CMDREND)  
  147.     {  
  148.         SDIO->ICR = SDIO_ICR_CMDRENDC;  
  149.         Card_ShowShortResponse();  
  150.     }  
  151.       
  152.     /* 设置参数VDD Voltage Window: 3.2~3.4V, 并再次发送CMD5 */  
  153.     SDIO->ARG = 0x300000;  
  154.     SDIO->CMD = SDIO->CMD;  
  155.     while (SDIO->STA & SDIO_STA_CMDACT);  
  156.     if (SDIO->STA & SDIO_STA_CMDREND)  
  157.     {  
  158.         SDIO->ICR = SDIO_ICR_CMDRENDC;  
  159.         Card_ShowShortResponse();  
  160.         if (SDIO->RESP1 & _BV(31))  
  161.         {  
  162.             // Card is ready to operate after initialization  
  163.             printf("Number of I/O Functions: %d\n", (SDIO->RESP1 >> 28) & 7);  
  164.             printf("Memory Present: %d\n", (SDIO->RESP1 & _BV(27)) != 0);  
  165.         }  
  166.     }  
  167.       
  168.     /* 获取Wi-Fi模块地址 (CMD3: SEND_RELATIVE_ADDR, Ask the card to publish a new relative address (RCA)) */  
  169.     SDIO->ARG = 0;  
  170.     SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 3;  
  171.     while (SDIO->STA & SDIO_STA_CMDACT);  
  172.     if (SDIO->STA & SDIO_STA_CMDREND)  
  173.     {  
  174.         SDIO->ICR = SDIO_ICR_CMDRENDC;  
  175.         rca_wifi = SDIO->RESP1 >> 16;  
  176.         printf("WiFi RCA: 0x%04x\n", rca_wifi);  
  177.     }  
  178.       
  179.     /* 选中Wi-Fi模块 (CMD7: SELECT/DESELECT_CARD), 禁用CMD3 */  
  180.     Card_Select(rca_wifi);  
  181.       
  182.     /* 继续初始化SD内存卡, 发送ACMD41 */  
  183.     rca_sd = 1;  
  184.     do  
  185.     {  
  186.         SDIO->ARG = 0;  
  187.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 55;  
  188.         while (SDIO->STA & SDIO_STA_CMDACT);  
  189.         if (SDIO->STA & SDIO_STA_CTIMEOUT)  
  190.         {  
  191.             // 若前导命令CMD55未被响应, 则说明没有插入SD卡, 退出  
  192.             SDIO->ICR = SDIO_ICR_CTIMEOUTC;  
  193.             rca_sd = 0;  
  194.             printf("No SD memory card inserted!\n");  
  195.             break;  
  196.         }  
  197.         else if (SDIO->STA & SDIO_STA_CMDREND)  
  198.         {  
  199.             SDIO->ICR = SDIO_ICR_CMDRENDC;  
  200.               
  201.             SDIO->ARG = (hcs << 30) | 0xff8000; // HCS + OCR  
  202.             SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 41;  
  203.             while (SDIO->STA & SDIO_STA_CMDACT);  
  204.   
  205.             SDIO->ICR = SDIO_ICR_CMDRENDC | SDIO_ICR_CCRCFAILC; // ACMD41的回应CRC一定为0x7f, 所以CRC校验一定出错  
  206.         }  
  207.     } while ((SDIO->RESP1 & _BV(31)) == 0);  
  208.       
  209.     if (rca_sd) // 若插入了SD卡, 则继续初始化  
  210.     {  
  211.         if (SDIO->RESP1 & _BV(30))  
  212.             printf("SDHC/SDXC Card!\n");  
  213.         else  
  214.             printf("SDSC Card!\n");  
  215.           
  216.         SDIO->ARG = 0;  
  217.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP | 2; // CMD2是长回应  
  218.         while (SDIO->STA & SDIO_STA_CMDACT);  
  219.         if (SDIO->STA & SDIO_STA_CMDREND)  
  220.         {  
  221.             SDIO->ICR = SDIO_ICR_CMDRENDC;  
  222.             printf("Memory CID: 0x%08x 0x%08x 0x%08x 0x%08x\n", SDIO->RESP1, SDIO->RESP2, SDIO->RESP3, SDIO->RESP4);  
  223.         }  
  224.           
  225.         /* 获取SD内存卡的RCA相对地址 */  
  226.         // WiFi模块的CMD3已被禁用, 所以不会和这里的CMD3碰撞  
  227.         do  
  228.         {  
  229.             SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 3;  
  230.             while (SDIO->STA & SDIO_STA_CMDACT);  
  231.             if (SDIO->STA & SDIO_STA_CMDREND)  
  232.             {  
  233.                 SDIO->ICR = SDIO_ICR_CMDRENDC;  
  234.                 rca_sd = SDIO->RESP1 >> 16;  
  235.             }  
  236.         } while (rca_sd == rca_wifi); // 若SD卡的RCA地址与WiFi模块的重复, 则重发CMD3更换一个新的  
  237.         printf("Memory RCA: 0x%04x\n", rca_sd);  
  238.     }  
  239.     // 若没有插入SD内存卡, 则rca_sd=0  
  240.       
  241.     // 提高时钟频率  
  242.     SDIO->CLKCR = (SDIO->CLKCR & ~SDIO_CLKCR_CLKDIV) | 70; // 72MHz/(70+2)=1MHz  
  243.     SDIO->DTIMER = 1000000; // 当频率为1MHz时, 超时时间为1秒  
  244.     //SDIO->CLKCR = (SDIO->CLKCR & ~SDIO_CLKCR_CLKDIV) | 1; // 72MHz/(1+2)=24MHz  
  245.       
  246.     /* 发送CMD52, 设置WiFi模块的总线宽度 */  
  247.     Card_Write(0, 0x07, Card_Read(0, 0x07) | 0x02); // Bus Width: 4-bit bus  
  248.       
  249.     /* 发送ACMD6, 设置SD内存卡的总线宽度 */  
  250.     if (rca_sd)  
  251.     {  
  252.         Card_Select(rca_sd); // 使用CMD7命令选中SD内存卡  
  253.         SDIO->ARG = rca_sd << 16; // 这回CMD55是发给SD内存卡的  
  254.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 55;  
  255.         while (SDIO->STA & SDIO_STA_CMDACT);  
  256.         SDIO->ICR = SDIO_ICR_CMDRENDC;  
  257.         SDIO->ARG = 2; // ACMD6的参数: 4-bit bus  
  258.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 6; // SET_BUS_WIDTH  
  259.         while (SDIO->STA & SDIO_STA_CMDACT);  
  260.         if (SDIO->STA & SDIO_STA_CMDREND)  
  261.         {  
  262.             SDIO->ICR = SDIO_ICR_CMDRENDC;  
  263.             printf("Memory bus width is changed! status=0x%08x\n", SDIO->RESP1);  
  264.         }  
  265.     }  
  266.       
  267.     SDIO->CLKCR |= SDIO_CLKCR_WIDBUS_0; // 将STM32上的SDIO外设设为4位数据宽度  
  268.     Card_Select(rca_wifi); // 选中WiFi模块  
  269. }  
  270.   
  271. int main(void)  
  272. {  
  273.     uint32_t sta;  
  274.     RCC->AHBENR = RCC_AHBENR_SDIOEN;  
  275.     RCC->APB1ENR = RCC_APB1ENR_TIM6EN;  
  276.     RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN| RCC_APB2ENR_USART1EN;  
  277.       
  278.     GPIOA->CRH = 0x000004b0;  
  279.     GPIOB->CRH = 0x00030000; // PB12为WiFi模块电源开关, PB12=0时打开WiFi模块  
  280.     GPIOC->CRH = 0x000bbbbb;  
  281.     GPIOD->CRL = 0x00000b00;  
  282.       
  283.     USART1->BRR = 0x271;  
  284.     USART1->CR1 = USART_CR1_UE | USART_CR1_TE;  
  285.       
  286.     Card_Init();  
  287.       
  288.     while (1)  
  289.     {  
  290.         sta = SDIO->STA;  
  291.         printf("SDIO->STA=0x%08x\n", sta);  
  292.         while (sta == SDIO->STA);  
  293.     }  
  294. }  


【SD内存卡插上时程序的运行结果】

[plain]  view plain  copy
  1. Initialization begins...  
  2. HCS=1  
  3. Command response received: CMD63, RESP_90ff8000  
  4. Command response received: CMD63, RESP_90300000  
  5. Number of I/O Functions: 1  
  6. Memory Present: 0  
  7. WiFi RCA: 0x0001  
  8. Card 0x0001 selected! status=0x00001e00  
  9. SDHC/SDXC Card!  
  10. Memory CID: 0x12345653 0x44000000 0x00000000 0x180109ee  
  11. Memory RCA: 0x0002  
  12. Card 0x0002 selected! status=0x00800700  
  13. Memory bus width is changed! status=0x00000900  
  14. Card 0x0001 selected! status=0x00001e00  
  15. SDIO->STA=0x00000000  

【不插内存卡时程序的运行结果】

[plain]  view plain  copy
  1. Initialization begins...  
  2. HCS=0  
  3. Command response received: CMD63, RESP_90ff8000  
  4. Command response received: CMD63, RESP_90300000  
  5. Number of I/O Functions: 1  
  6. Memory Present: 0  
  7. WiFi RCA: 0x0001  
  8. Card 0x0001 selected! status=0x00001e00  
  9. No SD memory card inserted!  
  10. Card 0x0001 selected! status=0x00001e00  
  11. SDIO->STA=0x00000000  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值