#include <stdio.h> #include <stm32f10x.h>
#define _BV(n) (1u << (n))
uint16_t rca;
// 延時n毫秒 void delay(uint16_t n) { TIM6->ARR = 10 * n - 1; // nms TIM6->PSC = 7199; // 72MHz/7200=10kHz TIM6->CR1 = TIM_CR1_URS | TIM_CR1_OPM; // UG不置位UIF, 非循環模式 TIM6->EGR = TIM_EGR_UG; // 保存設置 TIM6->CR1 |= TIM_CR1_CEN; // 開始計時 while ((TIM6->SR & TIM_SR_UIF) == 0); // 等待計時完畢 TIM6->SR &= ~TIM_SR_UIF; // 清除溢出標誌 }
int fputc(int ch, FILE *fp) { if (fp == stdout) { if (ch == '\n') { while ((USART1->SR & USART_SR_TXE) == 0); USART1->DR = '\r'; } while ((USART1->SR & USART_SR_TXE) == 0); USART1->DR = ch; } return ch; }
// 檢查命令是否收到了回應, 若沒收到則重發命令 void Card_CheckCommand(void) { while (SDIO->STA & SDIO_STA_CTIMEOUT) { SDIO->ICR = SDIO_ICR_CTIMEOUTC; // 清除標誌 SDIO->CMD = SDIO->CMD; // 重發 printf("Timeout! Resend CMD%d\n", SDIO->CMD & SDIO_CMD_CMDINDEX); while (SDIO->STA & SDIO_STA_CMDACT); } }
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) { SDIO->ARG = (is_write << 31) | (function_number << 28) | (read_after_write << 27) | (register_address << 9) | data_to_write; SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 52; while (SDIO->STA & SDIO_STA_CMDACT); }
void Card_ShowShortResponse(void) { printf("Command response received: CMD%d, RESP_%08x\n", SDIO->RESPCMD, SDIO->RESP1); }
// 讀寄存器 uint8_t Card_Read(uint8_t func_num, uint32_t addr) { Card_SendCMD52(0, 0, func_num, addr, 0); if (SDIO->STA & SDIO_STA_CMDREND) { SDIO->ICR = SDIO_ICR_CMDRENDC; return SDIO->RESP1 & 0xff; } else { printf("Card_Read failed, SDIO->STA=0x%08x!\n", SDIO->STA); return 0; } }
// 寫寄存器, 返回寫入後寄存器的實際內容 uint8_t Card_Write(uint8_t func_num, uint32_t addr, uint8_t value) { Card_SendCMD52(1, 1, func_num, addr, value); if (SDIO->STA & SDIO_STA_CMDREND) { SDIO->ICR = SDIO_ICR_CMDRENDC; return SDIO->RESP1 & 0xff; } else { printf("Card_Write failed, SDIO->STA=0x%08x!\n", SDIO->STA); return 0; } }
// SDIO Simplified Specification Version 3.00 // 3. SDIO Card Initialization void Card_Init(void) { printf("Initialization begins...\n"); SDIO->POWER = SDIO_POWER_PWRCTRL; SDIO->CLKCR = SDIO_CLKCR_CLKEN | 178; // 初始化時最高允許的頻率: 72MHz/(178+2)=400kHz delay(5); // 延時可防止CMD5重發 // 不需要發送CMD0, 因為SD I/O card的初始化命令是CMD52 // An I/O only card or the I/O portion of a combo card is NOT reset by CMD0. (See 4.4 Reset for SDIO) /* 發送CMD5: IO_SEND_OP_COND */ SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 5; while (SDIO->STA & SDIO_STA_CMDACT); Card_CheckCommand(); // 為了保險起見還是要檢查一下是否要重發命令 if (SDIO->STA & SDIO_STA_CMDREND) { SDIO->ICR = SDIO_ICR_CMDRENDC; Card_ShowShortResponse(); } /* 設置參數VDD Voltage Window: 3.2~3.4V, 並再次發送CMD5 */ SDIO->ARG = 0x300000; SDIO->CMD = SDIO->CMD; while (SDIO->STA & SDIO_STA_CMDACT); if (SDIO->STA & SDIO_STA_CMDREND) { SDIO->ICR = SDIO_ICR_CMDRENDC; Card_ShowShortResponse(); if (SDIO->RESP1 & _BV(31)) { // Card is ready to operate after initialization printf("Number of I/O Functions: %d\n", (SDIO->RESP1 >> 28) & 7); printf("Memory Present: %d\n", (SDIO->RESP1 & _BV(27)) != 0); } } /* 獲取Wi-Fi模塊地址 (CMD3: SEND_RELATIVE_ADDR, Ask the card to publish a new relative address (RCA)) */ SDIO->ARG = 0; SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 3; while (SDIO->STA & SDIO_STA_CMDACT); if (SDIO->STA & SDIO_STA_CMDREND) { SDIO->ICR = SDIO_ICR_CMDRENDC; rca = SDIO->RESP1 >> 16; printf("Relative card address: 0x%04x\n", rca); } /* 選中Wi-Fi模塊 (CMD7: SELECT/DESELECT_CARD) */ SDIO->ARG = rca << 16; SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 7; while (SDIO->STA & SDIO_STA_CMDACT); if (SDIO->STA & SDIO_STA_CMDREND) { SDIO->ICR = SDIO_ICR_CMDRENDC; printf("Card selected! status=0x%08x\n", SDIO->RESP1); } // 提高時鐘頻率 SDIO->CLKCR = (SDIO->CLKCR & ~SDIO_CLKCR_CLKDIV) | 70; // 72MHz/(70+2)=1MHz SDIO->DTIMER = 1000000; // 當頻率為1MHz時, 超時時間為1秒 //SDIO->CLKCR = (SDIO->CLKCR & ~SDIO_CLKCR_CLKDIV) | 1; // 72MHz/(1+2)=24MHz /* 選擇總線寬度 (Wide Bus Selection) */ // For an SDIO card a write to the CCCR using CMD52 is used to select bus width. (See 4.5 Bus Width) // CMD52: IO_RW_DIRECT, CCCR: Card Common Control Registers Card_Write(0, 0x07, Card_Read(0, 0x07) | 0x02); // Bus Width: 4-bit bus SDIO->CLKCR |= SDIO_CLKCR_WIDBUS_0; }
int main(void) { RCC->AHBENR = RCC_AHBENR_SDIOEN; RCC->APB1ENR = RCC_APB1ENR_TIM6EN; RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN| RCC_APB2ENR_USART1EN; GPIOA->CRH = 0x000004b0; GPIOB->CRH = 0x00030000; // PB12為WiFi模塊電源開關, PB12=0時打開WiFi模塊 GPIOC->CRH = 0x000bbbbb; GPIOD->CRL = 0x00000b00; USART1->BRR = 0x271; USART1->CR1 = USART_CR1_UE | USART_CR1_TE; Card_Init(); while (1); }
|