æè¿ã USB倧容éèšæ¶è£ 眮ãšããŠããŸãã¯USBãã©ãã·ã¥ãã©ã€ããšããŠãã·ã¢èªã§ãããã€ã¹ãSTM32F103ãã€ã¯ãã³ã³ãããŒã©ãŒã«æ¥ç¶ããããšãããã£ãŠããŸããã ãã¹ãŠãæ¯èŒçåçŽãªããã§ãïŒã°ã©ãã£ã«ã«ã³ã³ãã£ã®ã¥ã¬ãŒã¿STM32CubeMXã§ã¯ã2ã3åã¯ãªãã¯ããã ãã§ã³ãŒããçæãããSDã«ãŒããã©ã€ããŒãè¿œå ãããåºæ¥äžãããŸããããã¹ãŠãæ©èœããŸãã éåžžã«ãã£ãã-ãã«ã¹ããŒãã¢ãŒãã§ã®USBãã¹ã®åž¯åå¹ ãã¯ããã«é«ããšããäºå®ã«ããããããã200 kB / s-12 mB / sïŒçŽ1.2 MB / sïŒã ããã«ããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã§ã®ãã©ãã·ã¥ãã©ã€ãã®éå§æéã¯çŽ50ç§ã§ãããããã¯åã«ä»äºäžäžå¿«ã§ãã ç§ã¯ãã®ãšãªã¢ã«é£ã³èŸŒãã ã®ã§ãäŒéé床ãä¿®æ£ããŠã¿ãŸãããã
å®éã SDã«ãŒãçšã®ãã©ã€ã㌠ïŒããæ£ç¢ºã«ã¯SPIãã©ã€ããŒïŒ ãæ¢ã«äœæããŸãã ãããã¯DMAãä»ããŠåäœããæ倧500 kb / sã®é床ãæäŸããŸããã æ®å¿µãªãããUSBã®ã³ã³ããã¹ãã§ã¯ããã®ãã©ã€ããŒã¯æ©èœããŸããã§ããã ãã®çç±ã¯ãUSBéä¿¡ã¢ãã«èªäœã§ãããã¹ãŠãå²ã蟌ã¿ã§è¡ããããã©ã€ããŒã¯éåžžã®ã¹ããªãŒã ã§åäœããããã«èª¿æŽãããŠããŸãã ã¯ããç²æ«åãããããªããã£ãã®åæFreeRTOSã
ãã®èšäºã§ã¯ãSPIãä»ããŠSTM32F103ãã€ã¯ãã³ã³ãããŒã©ãŒã«æ¥ç¶ãããå€æ°ã®USBã«ãŒããšSDã«ãŒããæ倧éã«æŽ»çšã§ããããã«ãããã€ãã®ãã§ã€ã³ããäœæããŸããã ãŸããFreeRTOSãåæãªããžã§ã¯ããããã³DMAãä»ããããŒã¿è»¢éã®äžè¬çãªã¢ãããŒãã«ã€ããŠã説æããŸãã ã§ãããããã®èšäºã¯STM32ã³ã³ãããŒã©ãŒãDMAãªã©ã®ããŒã«ã«ç²ŸéããŠãã人ãããã³FreeRTOSã§äœæ¥ããéã®ã¢ãããŒãã«åœ¹ç«ã€ãšæããŸãã ãã®ã³ãŒãã¯ã STM32Cubeããã±ãŒãžã®HALããã³USBããã«ãŠã§ã¢ã©ã€ãã©ãªãããã³SDã«ãŒããæäœããããã®SdFatã«åºã¥ããŠããŸãã
ã¢ãŒããã¯ãã£ã®æŠèŠ
åã ã®ã³ã³ããŒãã³ãã®è©³çŽ°ã«è§Šããªãå Žåããã€ã¯ãã³ã³ãããŒã©ãŒã®åŽã®å€§å®¹éèšæ¶è£ 眮ïŒå¥åã倧容éèšæ¶ã¯ã©ã¹-MSCïŒã®å®è£ ã¯æ¯èŒçç°¡åã§ãã
äžæ¹ã«ã¯USBã³ã¢ã©ã€ãã©ãªããããŸãã 圌女ã¯ãã¹ããšã®éä¿¡ã«åŸäºããŠãããããã€ã¹ã®ç»é²ãæäŸããããããçš®é¡ã®äœã¬ãã«ã®USBãå®è£ ããŠããŸãã
ïŒUSBã«ãŒãã«ã䜿çšããïŒå€§å®¹éèšæ¶è£ 眮ãã©ã€ããŒã¯ããã¹ããšã®éã§ããŒã¿ãéåä¿¡ã§ããŸãã COMããŒããšåæ§ã«ãããŒã¿ã®ã¿ããããã¯ã§éä¿¡ãããŸãã ããã§ã¯ããã®ããŒã¿ã®ã»ãã³ãã£ãã¯ã³ã³ãã³ããéèŠã§ããSCSIã³ãã³ããšããŒã¿ãéä¿¡ãããŸãã ããã«ãå®è¡ããã³ãã³ãã¯æ°çš®é¡ãããããŸãããããŒã¿ã®èªã¿åããããŒã¿ã®æžã蟌ã¿ãã¹ãã¬ãŒãžããã€ã¹ã®ãµã€ãºã®ç¢ºèªãããã€ã¹ã®æºåç¶æ³ã®ç¢ºèªã§ãã
MSCãã©ã€ããŒã®ã¿ã¹ã¯ã¯ãSCSIã³ãã³ãã解éããã¹ãã¬ãŒãžãã©ã€ããŒã«åŒã³åºãããªãã€ã¬ã¯ãããããšã§ãã ãããã¯ã¢ã¯ã»ã¹ãå¯èœãªä»»æã®ã¹ãã¬ãŒãžããã€ã¹ïŒRAMãã£ã¹ã¯ããã©ãã·ã¥ãã©ã€ãããããã¯ãŒã¯ã¹ãã¬ãŒãžãCDãªã©ïŒã䜿çšã§ããŸãã ç§ã®å Žåãã¹ãã¬ãŒãžããã€ã¹ã¯SPIãä»ããŠæ¥ç¶ãããmicroSDã«ãŒãã§ãã ãã©ã€ããŒã«å¿ èŠãªäžé£ã®æ©èœã¯ã»ãŒåãã§ãïŒèªã¿åããæžã蟌ã¿ããµã€ãºã®æå®ãæºåå®äºç¶æ ã
ãããŠãããã§ã¯ã1ã€ã®éèŠãªãã¥ã¢ã³ã¹ã衚瀺ãããŸãã å®éã®ãšãããUSBãããã³ã«ã¯ãã¹ãæåã§ãã ãã¹ãã®ã¿ããã©ã³ã¶ã¯ã·ã§ã³ãéå§ããããŒã¿ãéåä¿¡ã§ããŸãã ãã€ã¯ãã³ã³ãããŒã©ãŒã®èŠ³ç¹ããèŠããšãããã¯USBã«é¢é£ãããã¹ãŠã®ã¢ã¯ãã£ããã£ãå²ã蟌ã¿ã®ã³ã³ããã¹ãã§è¡ãããããšãæå³ããŸãã ãã®å Žåã察å¿ãããã³ãã©ãŒãMSCãã©ã€ããŒã§åŒã³åºãããŸãã
ãã€ã¯ãã³ã³ãããŒã©ãŒãããã¹ãã«ããŒã¿ãéä¿¡ããå Žåã ãã€ã¯ãã³ã³ãããŒã©ã¯ãããèªäœã§ããŒã¿è»¢éãéå§ã§ããŸããã ãã€ã¯ãã³ã³ãããŒã©ãŒãUSBã³ã¢ã«éç¥ã§ããæ倧å€ã¯ããã¹ããååŸã§ããããŒã¿ãããããšã§ãã
SDã«ãŒãèªäœã«ã€ããŠããããã»ã©åçŽã§ã¯ãããŸããã å®éãã«ãŒãã¯è€éãªããã€ã¹ã§ããïŒæããã«ç¬èªã®ãã€ã¯ãã³ã³ãããŒã©ãŒãåããŠããïŒãéä¿¡ãããã³ã«ã¯éåžžã«éèŠã§ãã ããªãã¡ ç¹å®ã®ã¢ãã¬ã¹ã«ããŒã¿ãéä¿¡/åä¿¡ããã ãã§ã¯ãããŸããïŒäœããã®I2C EEPROMã¢ãžã¥ãŒã«ã®å Žåã®ããã«ïŒã ã«ãŒããšéä¿¡ããããã®ãããã³ã«ã¯ãããŸããŸãªã³ãã³ããšç¢ºèªããã§ãã¯ãµã ãããã³ã¿ã€ã ã¢ãŠãã®ã»ããå šäœãæäŸããŸãã
ç§ã¯SdFatã©ã€ãã©ãªã䜿çšããŠããŸã ã ç§ã®ããã€ã¹ã§ç©æ¥µçã«äœ¿çšããŠããFATãã¡ã€ã«ã·ã¹ãã ã¬ãã«ã®SDã«ãŒãã§ã®äœæ¥ãå®è£ ããŠããŸãã USBæ¥ç¶ã®å Žåããã¡ã€ã«ã·ã¹ãã ã«æ¥ç¶ãããŠãããã®ã¯ãã¹ãŠåæãããŸãïŒãã®åœ¹å²ã¯ãã¹ãã«è»¢éãããŸãïŒã ããããéèŠãªããšã¯ãã©ã€ãã©ãªã¯ãMSCãã©ã€ããŒãæããã®ãšã»ãŒåãã€ã³ã¿ãŒãã§ãŒã¹ïŒèªã¿åããæžã蟌ã¿ããµã€ãºã®ç¢ºèªïŒãæã€ã«ãŒããã©ã€ããŒãåå¥ã«å²ãåœãŠãŸãã
ã«ãŒããã©ã€ãã¯ãSPIãä»ããŠã«ãŒããšéä¿¡ããããã®ãããã³ã«ãå®è£ ããŸãã 圌ã¯ãã©ã®ã³ãã³ãããããã«éä¿¡ããããã©ã®é åºã§ãã©ã®ã³ãã³ããåŸ ã€ã®ããæ£ç¢ºã«ç¥ã£ãŠããŸãã ãããããã©ã€ããŒèªäœã¯éãæ±ããŸããã ãã®ããã«ããã1ã€ã®æœè±¡åã¬ãã«ãæäŸãããŸã-åã ã®ãããã¯ã®èªã¿åã/æžã蟌ã¿èŠæ±ãSPIãã¹ãä»ããå®éã®ããŒã¿è»¢éã«å€æããSPIãã©ã€ããŒã ãã®å Žæã§DMAãä»ããããŒã¿è»¢éãæŽçã§ãããããéåžžã¢ãŒãã§ã®ããŒã¿è»¢éé床ã¯åäžããŸããããUSBã®å Žåã¯ãã¹ãŠã®ã©ãºããªãŒãå£ããŸããïŒæçµçã«DMAãç¡å¹ã«ããå¿ èŠããããŸããïŒ
ãããããŸãæåã«ã
ã©ã®ãããªåé¡ã解決ããŸããïŒ
ãã®è³ªåã¯ååããããèãããæè¡çãªè«äºäžã«å¯Ÿè«è ãå°æãããŸãã
ãã®ãããã³ã«ã¯ãã¹ãŠ2ã€ã®åé¡ããããŸãã
- USBã§äœæ¥ããå Žåã®äœçŽç·é床ã äž»ã«åæèªã¿åã/æžã蟌ã¿æäœã«ãããã®
- é«ããã»ããµè² è·ïŒæ倧100ïŒ ïŒ-ããã€ã¹ã¯äœ¿çšã§ããªããªããŸãã ãã®çç±ã¯ãDMAãç¡å¹ã«ãªã£ãŠãããããã»ããµã䜿çšããŠããŒã¿ãé§åããå¿ èŠãããããã§ãã
ããããããã¯ã³ã³ãããŒã©ãŒåŽããã®ãã®ã§ãããUSB Mass Storageãããã³ã«ã«ã¯ãŸã åŽé¢ããããŸãã USB Wiresharkã¹ããã¡ãŒãã€ã³ã¹ããŒã«ãããã¹äžã§å®è¡ãããŠãããã±ãããæ£ç¢ºã«èª¿ã¹ããšãããäœéã®åå ãå°ãªããšã3ã€ããããšãããããŸããã
- ãã¹ããéä¿¡ãããã©ã³ã¶ã¯ã·ã§ã³ãå€ããã
- æéãšãšãã«åŒã䌞ã°ããããã©ã³ã¶ã¯ã·ã§ã³
- èªã¿åã/æžã蟌ã¿æäœèªäœã¯åæçã«çºçããçµäºãåŸ æ©ããŸã
ãã©ã³ã¶ã¯ã·ã§ã³æ°ã®åé¡ã¯éåžžã«ç°¡åã«è§£æ±ºã§ããŸãã ããã€ã¹ãæ¥ç¶ãããšãOSãFATããŒãã«å šäœãèªã¿åãããã£ã¬ã¯ããªãšMBRã®ããŸããŸãªå°ããªèªã¿åããè¡ãããšãå€æããŸããã ã¯ã©ã¹ã¿ãŒãµã€ãºã4kbã®FAT32ã§ãã©ãŒãããããã8ã®ã¬ã®ãã©ãã·ã¥ãã©ã€ãããããŸãã FATããŒãã«ã«ã¯çŽ8 MBå¿ èŠã§ãã 200 kb / sã®ç·åœ¢äŒéé床ã§ã¯ãã»ãŒ40ç§ã«ãªããŸãã
ããã€ã¹ãæ¥ç¶ãããšãã«èªã¿åãæäœã®æ°ãæžããæãç°¡åãªæ¹æ³ã¯ãFATããŒãã«ãæžããããšã§ãã USBãã©ãã·ã¥ãã©ã€ããåãã©ãŒãããããã¯ã©ã¹ã¿ãŒãµã€ãºãå¢ããã ãã§ååã§ãïŒããã«ããããã®æ°ãšããŒãã«ãµã€ãºãå°ãããªããŸãïŒã ã¯ã©ã¹ã¿ãµã€ãºã16kã«èšå®ããŠã«ãŒãããã©ãŒãããããŸãã-FATããŒãã«ãµã€ãºã¯2 MBãããããã«å°ãããªããåæåæéã¯20ç§ã«ççž®ãããŸããã
åžžã«ããè¯ããšã¯éããªã
ç§ã®ããã€ã¹ã§ã¯ã8ã®ã¬ãã©ãã·ã¥ãã©ã€ããå€ããããããããã»ã©å¿
èŠãªãããšã«æ°ä»ããŸããã 1ã®ã¬ãã€ãããŸãã¯512ã¡ã¬ãã€ãã§ååã§ãã ãã®ãããªãã©ãã·ã¥ãã©ã€ãã¯ãŸã æå
ã«ãããŸããã ãŸããçŸåšã§ã販売ãããŠããŸããã ãžã³ãã«ãåãåããªããã°ãªããŸããã ç§ãèŠã€ããããã«ãç§ã¯ããããšããŸãã
ãããã«ããããã©ãã·ã¥ãã©ã€ããåãã©ãŒãããããŠããç·åœ¢é床ã®åé¡ïŒå€§ããªãã¡ã€ã«ãé 次èªã¿åãããé床ïŒã¯è§£æ±ºãããŸããã ããã§ã200 kb / sã®ãŸãŸã§ãããã»ããµãã»ãšãã©ããŒãããŸããã ããã«ã€ããŠäœãã§ãããèŠãŠã¿ãŸãããã
USB DMAã®äœãåé¡ã«ãªã£ãŠããŸããïŒ
æåŸã«ãã³ãŒãã«ç§»ãããã©ãã·ã¥ã«ãŒãã§ã®èªã¿åã/æžã蟌ã¿ã®é 眮æ¹æ³ã確èªããŸãïŒSPIãã©ã€ããŒïŒ
ç§ã®ãããžã§ã¯ãã§ã¯ãFreeRTOSã䜿çšããŠããŸãã ããã¯ãããã€ã¹ã®åæ©èœãåå¥ã®ã¹ã¬ããïŒã¿ã¹ã¯ïŒã§åŠçã§ããçŽ æŽãããããŒã«ã§ãã ç§ã¯ãªããšã巚倧ãªã¹ããŒããã·ã³ãæããããšãã§ããã³ãŒãã¯ã¯ããã«ã·ã³ãã«ã§ç解ãããããªããŸããã ãã¹ãŠã®ã¿ã¹ã¯ã¯åæã«æ©èœããäºãã«è²æ©ããå¿ èŠã«å¿ããŠåæããŸãã ããŠããã¹ãŠã®ã¹ã¬ãããäœããã®ã€ãã³ããäºæããŠã¹ãªãŒãç¶æ ã«ãªã£ãå Žåããã€ã¯ãã³ã³ãããŒã©ãŒã®çé»åã¢ãŒãã䜿çšã§ããŸãã
SDã«ãŒãã§æ©èœããã³ãŒãã¯ãå¥ã®ã¹ã¬ããã§ãæ©èœããŸãã ããã«ãããèªã¿åã/æžã蟌ã¿æ©èœãéåžžã«ãšã¬ã¬ã³ãã«äœæã§ããŸããã
DMAã䜿çšããŠSDã«ãŒãã«ããŒã¿ãèªã¿æžãããããã®SPIãã©ã€ããŒ
uint8_t SdFatSPIDriver::receive(uint8_t* buf, size_t n) { // Start data transfer memset(buf, 0xff, n); HAL_SPI_TransmitReceive_DMA(&spiHandle, buf, buf, n); // Wait until transfer is completed xSemaphoreTake(xSema, 100); return 0; // Ok status } void SdFatSPIDriver::send(const uint8_t* buf, size_t n) { // Start data transfer HAL_SPI_Transmit_DMA(&spiHandle, (uint8_t*)buf, n); // Wait until transfer is completed xSemaphoreTake(xSema, 100); } void SdFatSPIDriver::dmaTransferCompletedCB() { // Resume SD thread xSemaphoreGiveFromISR(xSema, NULL); }
ããã§ã®å šäœã®é åã¯ã倧ããªããŒã¿ãããã¯ãèªã¿æžãããå¿ èŠããããšãããã®ã³ãŒããå®äºãåŸ ããªãããšã§ãã 代ããã«ãDMAãä»ããããŒã¿è»¢éãéå§ãããã¹ããªãŒã ãã¹ãªãŒãç¶æ ã«ãªããŸãã ãã®å Žåãããã»ããµãŒã¯ããžãã¹ã«åãæããããšãã§ããå¶åŸ¡ã®è»¢éã¯ä»ã®ã¹ã¬ããã«ç§»ããŸãã 転éãå®äºãããšãDMAããã®å²ã蟌ã¿ãåŒã³åºãããããŒã¿ã®è»¢éãåŸ æ©ããŠããã¹ããªãŒã ãèµ·åããŸãã
誰ãããã«ããŸããïŒ
åé¡ã¯ãäœæ¥ã®ãã¹ãŠã®ããžãã¯ãéåžžã®å®è¡ã¹ã¬ããã§ã¯ãªããå²ã蟌ã¿ã§çºçããUSBââã¢ãã«ã§ã¯ããã®ãããªã¢ãããŒããé£ããããšã§ãã ããªãã¡ å²ã蟌ã¿ã§èªã¿åã/æžã蟌ã¿èŠæ±ãåä¿¡ããããŒã¿è»¢éã®å®äºãåãå²ã蟌ã¿ã§åŸ æ©ããå¿ èŠããããŸãã
ãã¡ãããäžæã®ã³ã³ããã¹ãã§DMAãä»ãã転éãæé ããããšãã§ããŸãããããã«ã¯ã»ãšãã©æå³ããããŸããã DMAã¯ã転éãéå§ããããŒã¿è»¢éãçµäºãããŸã§ããã»ããµãä»ã®æçšãªäœæ¥ã«åãæ¿ããããšãã§ããå Žæã§ããŸãæ©èœããŸãã ããããå²ã蟌ã¿ãã転éãéå§ãããšãå²ã蟌ã¿ãäžæããããšã¯ã§ããªããªãïŒããŒãããžãŒã«ã€ããŠã¯ããããªããïŒãããžãã¹ãç¶ããããšãã§ããªããªããŸãã ããã«ãã³ã°ã¢ãããã転éã®çµäºãåŸ ã€å¿ èŠããããŸãã ããªãã¡ æäœã¯åæãããåèšæéã¯DMAãªãã®å Žåãšåãã«ãªããŸãã
ããã§ããã¹ãã®èŠæ±ã«å¿ããŠãDMAãä»ããŠããŒã¿ã®éä¿¡ãéå§ããå²ã蟌ã¿ãçµäºããæ¹ãã¯ããã«èå³æ·±ãã§ãããã ãããŠãã©ãããããããè¡ãããäœæ¥ã«é¢ãã次ã®äžæã¬ããŒãã§ã
ããããããã¯å šäœåã§ã¯ãããŸããã ã«ãŒãããã®èªã¿åããããŒã¿ãããã¯ã®éä¿¡ã®ã¿ã§æ§æãããŠããå Žåããã®ã¢ãããŒãã®å®è£ ã¯é£ãããããŸããã ããããSPIäŒéã¯æãéèŠãªéšåã§ãããããã ãã§ã¯ãããŸããã ããããã©ã€ããŒã®ã¬ãã«ã§ããŒã¿ãããã¯ã®èªã¿åã/æžã蟌ã¿ãèŠããšãããã»ã¹ã¯æ¬¡ã®ããã«ãªããŸãã
- ã«ãŒãã«ã³ãã³ããéä¿¡ããåŸ æ©ããŠå¿çã確èªããŸã
- ã«ãŒãã®æºåãã§ãããŸã§åŸ ã¡ãŸã
- ããŒã¿ã転éããŸãïŒããã§äžã«åŒçšããã®ãšåãé¢æ°ããããŸãïŒ
- ãã§ãã¯ãµã ãèšç®ããã«ãŒãã®æèŠãšæ¯èŒããŸã
- å®å šãªè»¢é
ãã®äžèŠç·åœ¢ã®ã¢ã«ãŽãªãºã ãäžé£ã®ãã¹ããããé¢æ°åŒã³åºãã«ãã£ãŠå®è£ ãããŠããããšãèãããšãéäžã§ã«ããããããšã¯ããŸãåççã§ã¯ãããŸããã ã©ã€ãã©ãªå šäœãé©åã«ç²ç ããå¿ èŠããããŸãã å Žåã«ãã£ãŠã¯ã転éã1ã€ã®ããŒã¹ã§ã¯ãªããäžé£ã®å°ããªãããã¯ã䜿çšãããµã€ã¯ã«ã§å®è¡ã§ããããšãèæ ®ãããšãã¿ã¹ã¯ã¯å®å šã«äžå¯èœã«ãªããŸãã
ãããããã¹ãŠãããã»ã©æªãããã§ã¯ãããŸããã MSCãã©ã€ããŒã®ã¬ãã«ã§ããã«é«ãèŠããšãDMAã䜿çšããŠããŸãã¯äœ¿çšããã«ã1ãããã¯ãŸãã¯è€æ°ãããã¯ã®ããŒã¿ãã©ã®çšåºŠæ£ç¢ºã«éä¿¡ãããããäžè¬çã«ããããŸãã äž»ãªããšã¯ãããŒã¿ãéä¿¡ããã¹ããŒã¿ã¹ãå ±åããããšã§ãã
å®éšããçæ³çãªå Žæã¯ãMSCãã©ã€ããŒãšã«ãŒããã©ã€ããŒã®éã®ã¬ã€ã€ãŒã§ãã ãããã®åã¯ããã®ã³ã³ããŒãã³ãã¯éåžžã«ç°¡åã«èŠããŸãããå®éãMSCãã©ã€ããŒã確èªãããã€ã³ã¿ãŒãã§ã€ã¹ãšã«ãŒããã©ã€ããŒãæäŸãããã®ãšã®éã®ã¢ããã¿ãŒã§ãã
ãªãªãžãã«ã®ã¢ããã¿ãŒå®è£
int8_t SD_MSC_Read (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { (void)lun; // Not used if(!card.readBlocks(blk_addr, buf, blk_len)) return USBD_FAIL; return (USBD_OK); } int8_t SD_MSC_Write (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { (void)lun; // Not used if(!card.writeBlocks(blk_addr, buf, blk_len)) return USBD_FAIL; return (USBD_OK); }
æ¢ã«è¿°ã¹ãããã«ãå²ã蟌ã¿ã®äžããåŒã³åºãããå Žåãã«ãŒããã©ã€ããŒã¯æ©èœããŸããã ããããéåžžã®ã¹ã¬ããã§ã¯ããŸãæ©èœããŸãã ããã§ã¯ãå¥ã®ã¹ã¬ãããéå§ããŸãããã
ãã®ã¹ã¬ããã¯ããã¥ãŒãä»ããŠèªã¿åãããã³æžã蟌ã¿èŠæ±ãåãåããŸãã åèŠæ±ã«ã¯ãæäœã®çš®é¡ïŒèªã¿åã/æžã蟌ã¿ïŒãèªã¿åããŸãã¯æžã蟌ã¿ãè¡ããããã¯ã®æ°ããããã¯ã®æ°ãããã³ããŒã¿ãããã¡ãŒãžã®ãã€ã³ã¿ãŒã«é¢ããæ å ±ãå«ãŸããŸãã ãŸããæäœã®ã³ã³ããã¹ããžã®ãã€ã³ã¿ãååŸããŸãããå°ãåŸã§å¿ èŠã«ãªããŸãã
èªã¿åã/æžã蟌ã¿èŠæ±ãã¥ãŒ
enum IOOperation { IO_Read, IO_Write }; struct IOMsg { IOOperation op; uint32_t lba; uint8_t * buf; uint16_t len; void * context; }; // A queue of IO commands to execute in a separate thread QueueHandle_t sdCmdQueue = NULL; // Initialize thread responsible for communication with SD card bool initSDIOThread() { // Initialize synchronisation sdCmdQueue = xQueueCreate(1, sizeof(IOMsg)); bool res = card.begin(&spiDriver, PA4, SPI_FULL_SPEED); return res; }
ã¹ã¬ããèªäœã¯ã³ãã³ããåŸ ã£ãŠã¹ãªãŒãããŠããŸãã ã³ãã³ããå°çãããšãç®çã®æäœãããã«åæçã«å®è¡ãããŸãã æäœã®æåŸã«ã³ãŒã«ããã¯ãåŒã³åºããŸããã³ãŒã«ããã¯ã¯ãå®è£ ã«å¿ããŠãèªã¿åã/æžã蟌ã¿æäœã®æåŸã«å¿ èŠãªåŠçãè¡ããŸãã
ã«ãŒããžã®èªã¿åã/æžã蟌ã¿ãæäŸããã¹ããªãŒã
extern "C" void cardReadCompletedCB(uint8_t res, void * context); extern "C" void cardWriteCompletedCB(uint8_t res, void * context); void xSDIOThread(void *pvParameters) { while(true) { IOMsg msg; if(xQueueReceive(sdCmdQueue, &msg, portMAX_DELAY)) { switch(msg.op) { case IO_Read: { bool res = card.readBlocks(msg.lba, msg.buf, msg.len); cardReadCompletedCB(res ? 0 : 0xff, msg.context); break; } case IO_Write: { bool res = card.writeBlocks(msg.lba, msg.buf, msg.len); cardWriteCompletedCB(res? 0 : 0xff, msg.context); break; } default: break; } } } }
ãããã¯ãã¹ãŠéåžžã®ãããŒã®äžéšãšããŠå®è¡ããããããå éšã®ã«ãŒããã©ã€ããŒã¯DMAãšFreeRTOSã®åæã䜿çšã§ããŸãã
MSCé¢æ°ã¯ããå°ãè€éã«ãªããŸããããããã»ã©è€éã§ã¯ãããŸããã çŸåšããã®ã³ãŒãã¯çŽæ¥èªã¿æžããã代ããã«ã察å¿ããã¹ããªãŒã ã«ãªã¯ãšã¹ããéä¿¡ããŸãã
èªã¿åã/æžã蟌ã¿èŠæ±ã®éä¿¡
int8_t SD_MSC_Read (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len, void * context) { // Send read command to IO executor thread IOMsg msg; msg.op = IO_Read; msg.lba = blk_addr; msg.len = blk_len; msg.buf = buf; msg.context = context; if(xQueueSendFromISR(sdCmdQueue, &msg, NULL) != pdPASS) return USBD_FAIL; return (USBD_OK); } int8_t SD_MSC_Write (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len, void * context) { // Send read command to IO executor thread IOMsg msg; msg.op = IO_Write; msg.lba = blk_addr; msg.len = blk_len; msg.buf = buf; msg.context = context; if(xQueueSendFromISR(sdCmdQueue, &msg, NULL) != pdPASS) return USBD_FAIL; return (USBD_OK); }
éèŠãªãã€ã³ãããããŸã-ãããã®é¢æ°ã®ã»ãã³ãã£ã¯ã¹ãå€æŽãããŸããã çŸåšããããã¯éåæãã€ãŸã æäœã®å®éã®çµäºãåŸ ããªãã§ãã ããã ãã®ãããããããåŒã³åºãã³ãŒãã埮調æŽããå¿ èŠããããŸãããããã«ã€ããŠã¯å°ãåŸã§èª¬æããŸãã
ãããŸã§ã®éããããã®é¢æ°ããã¹ãããããã«ãå¥ã®ãã¹ãã¹ã¬ãããäœæããŸãã USBã³ã¢ããšãã¥ã¬ãŒãããèªã¿åãèŠæ±ãéä¿¡ããŸãã
ãã¹ãã¹ããªãŒã
uint8_t io_buf[1024]; static TaskHandle_t xTestTask = NULL; void cardReadCompletedCB(bool res, void * context) { xTaskNotifyGive(xTestTask); } void cardWriteCompletedCB(bool res, void * context) { xTaskNotifyGive(xTestTask); } void xSDTestThread(void *pvParameters) { xTestTask = xTaskGetCurrentTaskHandle(); uint32_t prev = HAL_GetTick(); uint32_t opsPer1s = 0; uint32_t cardSize = card.cardSize(); for(uint32_t i=0; i<cardSize; i++) { opsPer1s++; if(SD_MSC_Read(0, io_buf, i, 2, NULL) != 0) usbDebugWrite("Failed to read block %d\r\n", i); ulTaskNotifyTake(pdTRUE, portMAX_DELAY); if(HAL_GetTick() - prev > 1000) { prev = HAL_GetTick(); usbDebugWrite("Reading speed: %d kbytes/s\r\n", opsPer1s); opsPer1s = 0; } } while(true) ; }
ãã®ã³ãŒãã¯ã1kbã®ãããã¯ã§ã«ãŒãå šäœãæåããæåŸãŸã§èªã¿åããèªã¿åãé床ã枬å®ããŸãã åèªã¿åãæäœã¯ãèŠæ±ãSDã«ãŒãã¹ããªãŒã ã«éä¿¡ããŸãã ããã§ãåæçã«èªã¿åããè¡ãããã³ãŒã«ããã¯ãä»ããŠçµäºãå ±åãããŸãã ãã®ã³ãŒã«ããã¯ã®å®è£ ã眮ãæããŸããããã®ã³ãŒã«ããã¯ã¯ããã¹ãã¹ã¬ããã«ç¶è¡ã§ããããšãéç¥ããã ãã§ãïŒãã¹ãã¹ã¬ããã¯ãulTaskââNotifyTakeïŒïŒé¢æ°ã§åžžã«ã¹ãªãŒãç¶æ ã«ãªã£ãŠããŸãïŒã
ããããæãéèŠãªããšã¯ããã®ããŒãžã§ã³ã®èªã¿åãé床ã¯çŽ450kb / sã§ãããããã»ããµã®è² è·ã¯3ã4ïŒ ã«éããªãããšã§ãã ç§ã®æèŠã§ã¯ãæªããªãã
ãã©ã€ããŒMSCããã³ãããŸã
ããã§ãDMAãæå¹ã«ããŠã«ãŒããã©ã€ããŒãç²åŸããŸããã ãã ããèªã¿åã/æžã蟌ã¿ã®ã»ãã³ãã£ã¯ã¹ã¯åæããéåæã«å€æŽãããŠããŸãã 次ã«ãMSCã®å®è£ ã埮調æŽããŠãéåæåŒã³åºãã®æäœæ¹æ³ãæããå¿ èŠããããŸãã ããªãã¡ DMAãä»ãããã¹ãããã®æåã®èŠæ±ãžã®è»¢éãéå§ãããåã®æäœã¯ãŸã çµäºããŠããªãã®ã§ãåŸã§ç¢ºèªããŠãã ããããšèšã£ãŠãåŸç¶ã®ãã¹ãŠã®èŠæ±ã«äœããã®æ¹æ³ã§å¿çããå¿ èŠããããŸã
å®éã USBãããã³ã«ã¯ãã®ãããªã¡ã«ããºã ãããã«äœ¿çšã§ããŸã ã åä¿¡åŽã¯ãç¹å®ã®ã¹ããŒã¿ã¹ã§ããŒã¿ã®è»¢éã確èªããŸãã ããŒã¿ãæ£åžžã«åä¿¡ããã³åŠçããããšãåä¿¡è ã¯ACKã¹ããŒã¿ã¹ã§ãã©ã³ã¶ã¯ã·ã§ã³ã確èªããŸãã ããã€ã¹ããã©ã³ã¶ã¯ã·ã§ã³ãåŠçã§ããªãå ŽåïŒåæåãããŠããªãããšã©ãŒç¶æ ã«ããããŸãã¯ãã®ä»ã®çç±ã§æ©èœããªãïŒãå¿çã¯ã¹ããŒã¿ã¹STALLã«ãªããŸãã
ããããããã€ã¹ããã©ã³ã¶ã¯ã·ã§ã³ãèªèããå¥å šãªç¶æ ã«ããããããŒã¿ã®æºåããŸã æŽã£ãŠããªãå Žåãããã€ã¹ã¯NAKã«å¿çã§ããŸãã ãã®å Žåããã¹ãã¯å°ãé ããŠãŸã£ããåããªã¯ãšã¹ãã§ããã€ã¹ã«æ¥ç¶ããå¿ èŠããããŸãã ãã®ã¹ããŒã¿ã¹ãé 延èªã¿åã/æžã蟌ã¿ã«äœ¿çšã§ããŸãããã¹ããžã®æåã®åŒã³åºãã§ãDMAãä»ããŠããŒã¿ã®éä¿¡ãéå§ããŸããããã©ã³ã¶ã¯ã·ã§ã³NAKã«å¿çããŸãã ãã¹ããç¹°ãè¿ããã©ã³ã¶ã¯ã·ã§ã³ãéå§ããDMAãä»ãã転éããã§ã«çµäºããŠããå ŽåãACKã§å¿çããŸãã
æ®å¿µãªãããSTããUSBã©ã€ãã©ãªã§NAKä¿¡å·ãéä¿¡ããè¯ãæ¹æ³ãèŠã€ãããŸããã§ããã é¢æ°ã®æ»ãã³ãŒãã¯ãã§ãã¯ãããªããã2ã€ã®ç¶æ ããåŠçã§ããŸãã-ãã¹ãŠãæ£åžžã§ãããããšã©ãŒã§ãã 2çªç®ã®å Žåããã¹ãŠã®ãšã³ããã€ã³ããéããããã¹ããŒã¿ã¹STALLããã¹ãŠã®å Žæã«èšå®ãããŸãã
USBãã©ã€ããŒã®æäžäœã¬ãã«ã§ã¯ãNAK確èªãéåžžã«ç©æ¥µçã«äœ¿çšãããŠãããšæãããŸãããã¯ã©ã¹ãã©ã€ããŒã¬ãã«ã§NAKãé©åã«äœ¿çšããæ¹æ³ã¯ããããŸããã§ããã
ã©ããããSTã®ã©ã€ãã©ãªã®äœæè ã¯ãããŸããŸãªç¢ºèªã®ä»£ããã«ããã人éçãªã€ã³ã¿ãŒãã§ãŒã¹ãæäŸããŸããã ããã€ã¹ããã¹ãã«éä¿¡ãããã®ãæã£ãŠããå ŽåãUSBD_LL_TransmitïŒïŒé¢æ°ãåŒã³åºããŸã-ãã¹ãèªäœãæäŸãããããŒã¿ãååŸããŸãã é¢æ°ãåŒã³åºãããªãã£ãå Žåãããã€ã¹ã¯èªåçã«NAKå¿çã§å¿çããŸãã ããŒã¿ã®åä¿¡ãšã»ãŒåãç¶æ³ã ããã€ã¹ã®åä¿¡æºåãã§ããŠããå ŽåãUSBD_LL_PrepareReceiveïŒïŒé¢æ°ãåŒã³åºããŸãã ãã以å€ã®å Žåããã¹ããããŒã¿ãéä¿¡ããããšãããšãããã€ã¹ã¯NAKã«å¿çããŸãã ãã®ç¥èã䜿çšããŠãMSCãã©ã€ããŒãå®è£ ããŸãã
USBãã¹ã§å®è¡ããããã©ã³ã¶ã¯ã·ã§ã³ãèŠãŠã¿ãŸãããïŒåæã¯ãã«ãŒããã©ã€ããŒã®å€æŽåã«å®è¡ãããŸããïŒã
ããã§èå³æ·±ãã®ã¯ãã©ã³ã¶ã¯ã·ã§ã³èªäœã§ã¯ãªãããããã®ã¿ã€ã ã¹ã¿ã³ãã§ãã ãã®å³ã®ãã©ã³ã¶ã¯ã·ã§ã³ã¯ããã©ã€ãã-åŠçãå¿ èŠãšããªããã©ã³ã¶ã¯ã·ã§ã³ãéžæããŸããã ãã€ã¯ãã³ã³ãããŒã©ã¯ããã®ãããªãªã¯ãšã¹ãã«ããŒãã³ãŒããããå¿çã§ãããŸãèããã«å¿çããŸãã ããã§éèŠãªããšã¯ããã¹ãããã©ã³ã¶ã¯ã·ã§ã³ãé£ç¶ã¹ããªãŒã ã§ãã©ããã£ã³ã°ããªãããšã§ãã ãã©ã³ã¶ã¯ã·ã§ã³ã¯1ããªç§ããšã«1åããå®è¡ãããŸããã åçãããã«æºåã§ãããšããŠãããã¹ãã¯æ¬¡ã®ãã©ã³ã¶ã¯ã·ã§ã³ã§ã®ã¿1msã§åçãååŸããŸãã
ããã¯ãUSBãã¹äžã®ãã©ã³ã¶ã¯ã·ã§ã³ã«é¢ããŠã1ãããã¯ã®ããŒã¿ãèªã¿åãæ¹æ³ã®ããã§ãã
æåã«ããã¹ãã¯SCSIèªã¿åãã³ãã³ããéä¿¡ãã次ã«å¥ã®ãã©ã³ã¶ã¯ã·ã§ã³ã§ããŒã¿ïŒ2è¡ç®ïŒãšã¹ããŒã¿ã¹ïŒ3è¡ç®ïŒãèªã¿åããŸãã æåã®ãã©ã³ã¶ã¯ã·ã§ã³ã¯æé·ã§ãã ãã®ãã©ã³ã¶ã¯ã·ã§ã³ã®åŠçäžããã€ã¯ãã³ã³ãããŒã©ãŒã¯ã«ãŒãããã®æ§é€ã«é¢äžããŸãã ãŸãããã©ã³ã¶ã¯ã·ã§ã³éã§ããã¹ãã¯1ããªç§éåæ¢ããŸãã
ãšããã§ã
USBã®çšèªã§ã¯ããã¹ãããããã€ã¹ãžã®æ¹åã¯OUTãšåŒã°ããŸãããã³ã³ãããŒã©ãŒã®å Žåãããã¯ææ³ã§ãã éã«ãããã€ã¹ãããã¹ããžã®æ¹åã¯INãšåŒã°ããŸãããç§ãã¡ã«ãšã£ãŠããã¯ããŒã¿ã®éä¿¡ãæå³ããŸãã
ãã€ã¯ãã³ã³ãããŒã©ãŒåŽã®MSCãã©ã€ããŒã¢ã«ãŽãªãºã ã¯æ¬¡ã®ããã«ãªããŸã
- SCSIãã©ã³ã¶ã¯ã·ã§ã³ïŒèªã¿åãïŒ10ïŒLUNïŒ0x00ïŒLBAïŒ0x00000000ãLenïŒ1ïŒ
- ãã¹ãã¯èªã¿åãã³ãã³ããéä¿¡ããŸãã ãã€ã¯ãã³ã³ãããŒã©ãŒåŽã§ã¯ãMSC_BOT_DataOutïŒïŒé¢æ°ãåŒã³åºãããŸã
- ã³ãã³ãã¯ãäžé£ã®é¢æ°MSC_BOT_DataOutïŒïŒ-> MSC_BOT_CBW_DecodeïŒïŒ-> SCSI_ProcessCmdïŒïŒ-> SCSI_Read10ïŒïŒã«ãã£ãŠåŠçãããŸãã
- ãã©ã€ããŒã¯hmsc-> bot_state == USBD_BOT_IDLEç¶æ ã«ãããããèªã¿åãæé ãæºåãããŠããŸããã³ãã³ããã©ã¡ãŒã¿ãŒããã§ãã¯ãããèªã¿åããå¿ èŠãªåèšãããã¯æ°ã確èªãããæåã®ãããã¯ã®èªã¿åãèŠæ±ãšãšãã«SCSI_ProcessReadïŒïŒé¢æ°ã«å¶åŸ¡ã転éãããŸã
- SCSI_ProcessReadïŒïŒé¢æ°ã¯ãããŒã¿ãåæçã«èªã¿åããŸãã ããã¯ãã»ãšãã©ã®å Žåããã€ã¯ãã³ã³ãããŒã©ãå¿ããå Žæã§ãã
- ããŒã¿ãåä¿¡ããããšãïŒUSBD_LL_TransmitïŒïŒé¢æ°ã䜿çšããŠïŒããŒã¿ããšã³ããã€ã³ãMSC_INã®åºåãããã¡ãŒã«è»¢éããããã¹ãããããååŸã§ããããã«ãªããŸãã
- ãã©ã€ããŒã¯hmsc-> bot_state = USBD_BOT_DATA_INç¶æ ã«ãªããŸã
- SCSIãã©ã³ã¶ã¯ã·ã§ã³ïŒããŒã¿å
¥å
- ãã¹ãã¯ããã€ã¯ãã³ã³ãããŒã©ãŒã®åºåãããã¡ãŒãã64ãã€ãã®ãã±ããã§ããŒã¿ãåéããŸãïŒUSBãã«ã¹ããŒãããã€ã¹ã®æ倧æšå¥šãã±ãããµã€ãºïŒã ãããã¯ãã¹ãŠUSBã³ã¢ã®æäžäœã¬ãã«ã§çºçããMSCãã©ã€ããŒã¯é¢äžããŸãã
- ãã¹ãããã¹ãŠã®ããŒã¿ãååŸãããšãData Inã€ãã³ããçºçããŸãã å¶åŸ¡ã¯MSC_BOT_DataInïŒïŒé¢æ°ã«æž¡ãããŸãã ãã®é¢æ°ã¯ãå®éã®ããŒã¿éä¿¡åŸã«åŒã³åºãããããšã匷調ããŸãã
- ãã©ã€ããŒã®ç¶æ ã¯hmsc-> bot_state == USBD_BOT_DATA_INã§ããããã¯ãèªã¿åãã¢ãŒãã®ãŸãŸã§ããããšãæå³ããŸãã
- ãã¹ãŠã®é åºä»ãããããããã¯ããŸã èªã¿åãããŠããªãå Žåã次ã®ããŒã¹ã®èªã¿åããéå§ããå®äºãåŸ æ©ããåºåãããã¡ãŒã«ã·ããããŠããã¹ããããŒã¿ãååŸãããŸã§åŸ æ©ããŸãã ã¢ã«ãŽãªãºã ã®ç¹°ãè¿ã
- ãã¹ãŠã®ãããã¯ãèªã¿åããããšããã©ã€ããŒã¯USBD_BOT_LAST_DATA_INã«åãæ¿ãããã³ãã³ãã®æçµã¹ããŒã¿ã¹ãéä¿¡ããŸã
- SCSIãã©ã³ã¶ã¯ã·ã§ã³ïŒå¿ç
- ãã®æç¹ã§ãåºç»ããŒã¿ã¯ãã§ã«éä¿¡ãããŠããŸã
- ãã©ã€ããŒã¯ããã«é¢ããéç¥ã®ã¿ãåãåããUSBD_BOT_IDLEç¶æ ã«ãªããŸã
ãã®ã¹ããŒã ã§æãé·ãæäœã¯ãå®éã«ã¯ã«ãŒãããã®èªã¿åãã§ãã ç§ã®æž¬å®ã«ãããšãåæã¢ãŒãã§ã®èªã¿åãã«ã¯çŽ2ã3msããããŸãã ããã«ã転éã¯ããã»ããµãŒã«ãã£ãŠè¡ãããããã¯ãã¹ãŠå²ã蟌ã¿USBã§è¡ãããŸãã æ¯èŒã®ããã«ãDMAãä»ããŠé·ã512ã®1ãããã¯ãæžç®ããã«ã¯ã1ããªç§ä»¥äžããããŸãã
ããŒã¿ã®èªã¿åããå€§å¹ ã«ïŒããšãã°1Mb / sãŸã§ïŒã¹ããŒãã¢ããã§ããŸããã§ãã-ããã¯ãSPIãä»ããŠæ¥ç¶ãããã«ãŒãã®åž¯åå¹ ã§ãã ãããããã©ã³ã¶ã¯ã·ã§ã³ã®éã«1ããªç§ã®äŒæ¢ããµãŒãã¹ã«çœ®ãããšãè©Šã¿ãããšãã§ããŸãã
ãã®ããã«èŠããŸãïŒãããã«ç°¡ç¥åãããŠããŸãïŒ
- SCSIãã©ã³ã¶ã¯ã·ã§ã³ïŒèªã¿åãïŒ10ïŒLUNïŒ0x00ïŒLBAïŒ0x00000000ãLenïŒ1ïŒ
- ãã€ã¯ãã³ã³ãããŒã©ãŒã¯èªã¿åãã³ãã³ããåä¿¡ãããã¹ãŠã®ãã©ã¡ãŒã¿ãŒããã§ãã¯ããèªã¿åããå¿ èŠãªãããã¯ã®æ°ãèšæ¶ããŸã
- ãã€ã¯ãã³ã³ãããŒã©ãŒã¯ãéåæã¢ãŒãã§æåã®ãããã¯ã®èªã¿åããéå§ããŸã
- èªã¿åãã®çµäºãåŸ ããã«å²ã蟌ã¿ãçµäºããŸã
- èªã¿åããçµäºãããšãã³ãŒã«ããã¯ãåŒã³åºãããŸã
- èªã¿åãããŒã¿ã¯åºåãããã¡ãŒã«éä¿¡ãããŸãã
- ãã¹ãã¯MSCãã©ã€ããŒãªãã§ããããèªã¿åããŸã
- SCSIãã©ã³ã¶ã¯ã·ã§ã³ïŒããŒã¿å
¥å
- ã³ãŒã«ããã¯é¢æ°DataInïŒïŒãåŒã³åºãããŸããããã¯ããã¹ããããŒã¿ãååŸãã次ã®èªã¿åããå®è¡ã§ããããšãéç¥ããŸã
- 次ã®ãããã¯ã®èªã¿åããéå§ããŸãã ã¢ã«ãŽãªãºã ã¯èªã¿åãå®äºã³ãŒã«ããã¯ããç¹°ãè¿ããŸã
- ãã¹ãŠã®ãããã¯ãèªã¿åãããå Žåãã¹ããŒã¿ã¹ãã±ãããéä¿¡ããŸã
- SCSIãã©ã³ã¶ã¯ã·ã§ã³ïŒå¿ç
- ãã®æç¹ã§ãåºç»ããŒã¿ã¯ãã§ã«éä¿¡ãããŠããŸã
- 次ã®ãã©ã³ã¶ã¯ã·ã§ã³ã®æºåãããŠããŸãã
SCSI_ProcessReadïŒïŒé¢æ°ã¯ãåããšãåŸãã«ç°¡åã«åå²ãããããããã®ã¢ãããŒããå®è£ ããŠã¿ãŸãããã ã€ãŸããèªã¿åããéå§ããã³ãŒãã¯å²ã蟌ã¿ã®ã³ã³ããã¹ãã§å®è¡ãããæ®ãã®ã³ãŒãã¯ã³ãŒã«ããã¯ã«ç§»åããŸãã ãã®ã³ãŒã«ããã¯ã®ã¿ã¹ã¯ã¯ãèªã¿åãããããŒã¿ãåºåãããã¡ãŒã«ããã·ã¥ããããšã§ãïŒãã¹ãã¯äœããã®æ¹æ³ã§å¯Ÿå¿ããèŠæ±ã§ãã®ããŒã¿ãååŸããŸãïŒ
éåæèªã¿åãã«é©åããSCSI_ProcessReadïŒïŒé¢æ°
/** * @brief SCSI_ProcessRead * Handle Read Process * @param lun: Logical unit number * @retval status */ static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev, uint8_t lun) { USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassDataMSC; uint32_t len; len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); if( pdev->pClassSpecificInterfaceMSC->Read(lun , hmsc->bot_data, hmsc->scsi_blk_addr / hmsc->scsi_blk_size, len / hmsc->scsi_blk_size, pdev) < 0) { SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, UNRECOVERED_READ_ERROR); return -1; } hmsc->bot_state = USBD_BOT_DATA_IN; return 0; } void cardReadCompletedCB(uint8_t res, void * context) { USBD_HandleTypeDef * pdev = (USBD_HandleTypeDef *)context; USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassDataMSC; uint8_t lun = hmsc->cbw.bLUN; uint32_t len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); if(res != 0) { SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, UNRECOVERED_READ_ERROR); return; } USBD_LL_Transmit (pdev, MSC_IN_EP, hmsc->bot_data, len); hmsc->scsi_blk_addr += len; hmsc->scsi_blk_len -= len; /* case 6 : Hi = Di */ hmsc->csw.dDataResidue -= len; if (hmsc->scsi_blk_len == 0) { hmsc->bot_state = USBD_BOT_LAST_DATA_IN; } }
ã³ãŒã«ããã¯ã§ã¯ãSCSI_ProcessReadïŒïŒé¢æ°ã§å®çŸ©ãããŠããããã€ãã®å€æ°ïŒUSBãã³ãã«ãžã®ãã€ã³ã¿ãŒãéä¿¡ããããããã¯ã®é·ããLUNïŒã«ã¢ã¯ã»ã¹ããå¿ èŠããããŸãã ããã¯ãã³ã³ããã¹ããã©ã¡ãŒã¿ã䟿å©ãªå Žæã§ãã 確ãã«ãç§ã¯ãã¹ãŠãéä¿¡ããã®ã§ã¯ãªããpdevã®ã¿ãéä¿¡ããŸããã ç§ã«ãšã£ãŠã¯ããã®ã¢ãããŒãã¯ãæ§é å šäœãç®çã®ãã£ãŒã«ãã§ãã«ãããããç°¡åã§ãã ãããŠããããã«ãããããã¯ããã€ãã®ã°ããŒãã«å€æ°ãæã€ãããåªããŠããŸãã
ããã«ãããã¡ãŒãè¿œå ãã
äžè¬ã«ããã®ã¢ãããŒãã¯æ©èœããŸããããé床ã¯äŸç¶ãšããŠ200kb / sãå°ãäžåããŸããïŒãã ããããã»ããµã®è² è·ã¯ä¿®åŸ©ãããçŽ2ã3ïŒ ã«ãªããŸããïŒã ç§ãã¡ãããéãåãããšã劚ãããã®ãç解ããŸãããã
ç§ã®èšäºã®1ã€ã«å¯Ÿããã³ã¡ã³ãã®ã¢ããã€ã¹ã§ãç§ã¯ãŸã ãªã·ãã¹ã³ãŒããå ¥æããŸããïŒå®äŸ¡ãªãã®ã§ããïŒã 圌ã¯ããã§äœãèµ·ãã£ãŠããã®ããç解ããã®ã«éåžžã«åœ¹ç«ã¡ãŸããã æªäœ¿çšã®ãã³ãåããèªã¿åãåã«1ã«èšå®ããèªã¿åãçµäºåŸã«ãŒãã«èšå®ããŸããã ãªã·ãã¹ã³ãŒãã§ã¯ãèªã¿åãããã»ã¹ã¯æ¬¡ã®ããã«ãªããŸããã
ããªãã¡ 512ãã€ãã®èªã¿åãã«ã¯1mså°ãããããŸãã ã«ãŒãããã®èªã¿åããçµäºãããšãããŒã¿ã¯åºåãããã¡ãŒã«è»¢éããããã¹ãã¯æ¬¡ã®1ããªç§ã§ããŒã¿ãååŸããŸãã ããªãã¡ ããã§ã¯ãã«ãŒãããèªã¿åããUSBçµç±ã§è»¢éããŸãããåæã«ã§ã¯ãããŸããã
éåžžããã®ç¶æ³ã¯ããã«ãããã¡ãªã³ã°ã«ãã£ãŠè§£æ±ºãããŸãã ããã«ãSTM32F103ãã€ã¯ãã³ã³ãããŒã©USBåšèŸºæ©åšã¯ããã§ã«ãã¥ã¢ã«ãããã¡ãªã³ã°ã¡ã«ããºã ãæäŸããŠããŸãã 次ã®2ã€ã®çç±ã§ããããã ããç§ãã¡ã«åããªãã§ãããã
- ãã€ã¯ãã³ã³ãããŒã©èªäœãæäŸããããã«ãããã¡ãªã³ã°ã䜿çšããã«ã¯ãUSBã³ã¢ãšMSCå®è£ ãåæç»ããå¿ èŠãããå ŽåããããŸã
- ãããã¡ãµã€ãºã¯64ãã€ãã®ã¿ã§ãããSDã«ãŒãã¯512ãã€ãæªæºã®ãããã¯ã§ã¯æ©èœããŸããã
ãã®ãããå®è£ ãèæ¡ããå¿ èŠããããŸãã ãã ããããã¯é£ãããããŸããã æåã«ã2çªç®ã®ãããã¡ãŒçšã®å ŽæãäºçŽããŸãã ç§ã¯åœŒã®ããã«å¥ã®å€æ°ãéå§ããŸããã§ããããåã«æ¢åã®ãããã¡ãŒã2åã«å¢ãããŸããã ãŸããå€æ°bot_data_idxãäœæããå¿ èŠããããŸãããããã¯ããã®ããã«ãããã¡ãŒã®ã©ã®ååãçŸåšäœ¿çšãããŠãããã瀺ããŸãã0-ååã1-2çªç®ã
ããã«ãããã¡ãŒ
typedef struct _USBD_MSC_BOT_HandleTypeDef { ... USBD_MSC_BOT_CBWTypeDef cbw; USBD_MSC_BOT_CSWTypeDef csw; uint16_t bot_data_length; uint8_t bot_data[2 * MSC_MEDIA_PACKET]; uint8_t bot_data_idx; ... } USBD_MSC_BOT_HandleTypeDef;
ãšããã§ãcbwæ§é ãšcswæ§é ã¯ã¢ã©ã€ã¡ã³ãã«éåžžã«ææã§ãã äžéšã®å€ã¯ããããã®æ§é äœã®ãã£ãŒã«ãã«å¯ŸããŠèª€ã£ãŠæžã蟌ãŸãããèªã¿åããããããŸããã ãã®ãããããŒã¿ãããã¡ãããé«ã転éããå¿ èŠããããŸããã
å ã®å®è£ ã¯ãDataInå²ã蟌ã¿ïŒããŒã¿ãéä¿¡ããããšããã·ã°ãã«ïŒã§æ©èœããŠããŸããã ããªãã¡ ãã¹ãããã®ã³ãã³ãã«ãããèªã¿åããéå§ããããã®åŸããŒã¿ãåºåãããã¡ãŒã«è»¢éãããŸããã ããŒã¿ã®æ¬¡ã®ãããã®èªã¿åãã¯ãDataInãäžæããããšã§ããªãã£ãŒãžããããŸããã ãã®ãªãã·ã§ã³ã¯é©åã§ã¯ãããŸããã ååã®èªã¿åããçµäºããçŽåŸã«èªã¿åããéå§ããŸãã
åã®èªã¿åããçµäºããçŽåŸã«èªã¿åãå€ãå
é»ãã
void cardReadCompletedCB(uint8_t res, void * context) { USBD_HandleTypeDef * pdev = (USBD_HandleTypeDef *)context; USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassDataMSC; uint8_t lun = hmsc->cbw.bLUN; uint32_t len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); if(res != 0) { SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, UNRECOVERED_READ_ERROR); return; } // Synchronization to avoid several transmits at a time // This must be located here as it waits finishing previous USB transfer // while the code below prepares next one pdev->pClassSpecificInterfaceMSC->OnFinishOp(); // Save these values for transmitting data uint8_t * txBuf = hmsc->bot_data + hmsc->bot_data_idx * MSC_MEDIA_PACKET; uint16_t txSize = len; // But before transmitting set the correct state // Note: we are in context of SD thread, not the USB interrupt // So values have to be correct when DataIn interrupt occurrs hmsc->scsi_blk_addr += len; hmsc->scsi_blk_len -= len; /* case 6 : Hi = Di */ hmsc->csw.dDataResidue -= len; if (hmsc->scsi_blk_len == 0) { hmsc->bot_state = USBD_BOT_LAST_DATA_IN; } else { hmsc->bot_data_idx ^= 1; hmsc->bot_data_length = MSC_MEDIA_PACKET; SCSI_ProcessRead(pdev, lun); // Not checking error code - SCSI_ProcessRead() already enters error state in case of read failure } // Now we can transmit data read from SD USBD_LL_Transmit (pdev, MSC_IN_EP, txBuf, txSize); }
ãã®é¢æ°ã¯ãæ§é ããããã«å€æŽããŸããããŸããããã§ããã«ãããã¡ãªã³ã°ãå®è£ ãããŸãããã®é¢æ°ã¯ã«ãŒãããã®èªã¿åããçµäºãããšåŒã³åºããããããSCSI_ProcessReadïŒïŒãåŒã³åºãããšã§ãããã«æ¬¡ã®èªã¿åããéå§ã§ããŸããæ°ããèªã¿åãå€ãèªã¿åãããã°ããã®ããŒã¿ãæ¶å»ããªãããã«ã2çªç®ã®ãããã¡ãŒã䜿çšããŸããå€æ°bot_data_idxã¯ããããã¡ãŒã®åãæ¿ããæ åœããŸãã
ããããããã ãã§ã¯ãããŸããã第äºã«ãã¢ã¯ã·ã§ã³ã®ã·ãŒã±ã³ã¹ãå€æŽãããŸãããçŸåšã次ã®ããŒã¿ãããã¯ã®èªã¿åããæåã«èª²éãããUSBD_LL_TransmitïŒïŒãåŒã³åºãããŸããããã¯ãcardReadCompletedCBïŒïŒé¢æ°ãéåžžã®ã¹ã¬ããã®ã³ã³ããã¹ãã§åŒã³åºãããããã§ããæåã«USBD_LL_TransmitïŒïŒãåŒã³åºããŠããhmscãã£ãŒã«ãã®å€ãå€æŽãããšãçŸæç¹ã§USBããã®å²ã蟌ã¿ãçºçããå¯èœæ§ãããããããã®ãã£ãŒã«ããå€æŽããå¿ èŠããããŸãã
第äžã«ãè¿œå ã®åæã匷åããå¿ èŠããããŸãããå®éã«ã¯ãéåžžãã«ãŒãããã®èªã¿åãã«ã¯USBçµç±ã®è»¢éãããå°ãæéãããããŸãããã ããéã®å Žåãããã次ã®ãããã¯ã®USBD_LL_TransmitïŒïŒåŒã³åºãã¯ãåã®ãããã¯ãå®å šã«éä¿¡ãããåã«çºçããŸãã USBã³ã¢ã¯ãã®ãããªåããŸããããã ãŸãããããŒã¿ã¯æ£ããéä¿¡ãããŸããã
ããŒã¿ã®éä¿¡ïŒéä¿¡ïŒã¯ããŒã¿å ¥åã€ãã³ãã«ãã£ãŠç¢ºèªãããŸãããè€æ°ã®éä¿¡ãé£ç¶ããŠçºçããå ŽåããããŸãããã®ãããªå Žåãåæãå¿ èŠã§ãã
ããã¯ãå°ãã®åæãè¿œå ããã ãã§éåžžã«ç°¡åã«è§£æ±ºãããŸãã USBD_StorageTypeDefã€ã³ã¿ãŒãã§ã€ã¹ã«ãããªãåçŽãªå®è£ ã®é¢æ°ãããã€ãè¿œå ããŸããïŒãã ããããããååã¯ããŸãæåããŠããŸããïŒãå®è£ ã¯ãã·ã°ãã«åŸ æ©ã¢ãŒãã§éåžžã®ã»ããã©ã䜿çšããŸããã³ãŒã«ããã¯ã§åŒã³åºãããOnFinishOpïŒïŒcardReadCompletedCBïŒïŒã¯ã¹ãªãŒãããåã®ããŒã¿ãã±ãããéä¿¡ããããŸã§åŸ æ©ããŸãã
éä¿¡ã®äºå®ã¯DataInã€ãã³ãã«ãã£ãŠç¢ºèªãããŸãããã®ã€ãã³ãã¯SCSI_Read10ïŒïŒé¢æ°ã«ãã£ãŠåŠçãããOnStartOpïŒïŒãåŒã³åºããŸããOnStartOpïŒïŒã¯OnFinishOpïŒïŒãããã¯è§£é€ãã次ã®ããŒã¿ãã±ãã
åææ©èœãå®è£
ãã
void SD_MSC_OnStartOp() { xSemaphoreGiveFromISR(usbTransmitSema, NULL); } void SD_MSC_OnFinishOp() { xSemaphoreTake(usbTransmitSema, portMAX_DELAY); }
ãã®ãããªåæã«ãããç»åã¯æ¬¡ã®åœ¢åŒãåããŸãã
èµ€ãç¢å°ã¯åæã瀺ããŸããæåŸã®éä¿¡ã¯ãåã®ããŒã¿å ¥åãåŸ ã£ãŠããŸãã
ããºã«ã®æåŸã®ããŒã¹ã¯ãSCSI_Read10ïŒïŒé¢æ°ã§ãã
é¢æ°SCSI_Read10ïŒïŒãããŒã¿å
¥åã€ãã³ãã«ãã£ãŠåŒã³åºãããŸã
/** * @brief SCSI_Read10 * Process Read10 command * @param lun: Logical unit number * @param params: Command parameters * @retval status */ static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params) { USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassDataMSC; // Synchronization to avoid several transmits at a time pdev->pClassSpecificInterfaceMSC->OnStartOp(); if(hmsc->bot_state == USBD_BOT_IDLE) /* Idle */ { // Params checking ⊠hmsc->scsi_blk_addr = ... hmsc->scsi_blk_len = ... hmsc->bot_state = USBD_BOT_DATA_IN; ... hmsc->bot_data_idx = 0; hmsc->bot_data_length = MSC_MEDIA_PACKET; return SCSI_ProcessRead(pdev, lun); } return 0; }
SCSI_Read10ïŒïŒã®å ã®å®è£ ã§ã¯ãé¢æ°ãžã®æåã®åŒã³åºãã§ãã©ã¡ãŒã¿ãŒããã§ãã¯ãããæåã®ãããã¯ã®èªã¿åãããã»ã¹ãéå§ãããŸãããåã®ãã±ãããæ¢ã«éä¿¡ãããŠããŠã次ã®ãã±ããã®èªã¿åããéå§ããå¿ èŠããããšãã«DataInãäžæããããšãåŸã§åãé¢æ°ãåŒã³åºãããŸããäž¡æ¹ã®ãã©ã³ãã¯ãSCSI_ProcessReadïŒïŒé¢æ°ã䜿çšããŠèªã¿åããéå§ããŸããã
æ°ããå®è£ ã§ã¯ãSCSI_ProcessReadïŒïŒã®åŒã³åºãã¯ifå ã«ç§»åããæåã®ãããã¯ïŒbot_state == USBD_BOT_IDLEïŒãèªã¿åãããã ãã«åŒã³åºãããåŸç¶ã®ãããã¯ã®èªã¿åãã¯cardReadCompletedCBïŒïŒããéå§ãããŸãã
ãã®çµæãèŠãŠã¿ãŸãããããªã·ãã¹ã³ãŒãã§ãã®ãããªããããèŠãããã«ããããã¯ã®èªã¿åãã®éã«æå³çã«ããããªé 延ãè¿œå ããŸãããå®éãèªã¿åãæäœã®ééãéåžžã«çãããããªã·ãã¹ã³ãŒãã«ã¯ããã衚瀺ãããŸããã
ãã®åçãããããããã«ãã¢ã€ãã¢ã¯æåã§ãããåã®æäœãçµäºãããšããã«ãæ°ããèªã¿åãæäœãéå§ãããŸããèªã¿åãéã®äžæåæ¢ã¯éåžžã«å°ãããäž»ã«ãã¹ãã«ãã£ãŠæ±ºå®ãããŸãïŒãã©ã³ã¶ã¯ã·ã§ã³éã®1ããªç§ã®åãé 延ïŒã倧ããªãã¡ã€ã«ã®å¹³åèªã¿åãé床ã¯400ã440kb / sã«éããéåžžã«è¯å¥œã§ããæåŸã«ãããã»ããµã®è² è·ã¯çŽ2ïŒ ã§ãã
ããããèšé²ã¯ã©ãã§ããïŒ
ã«ãŒãã«èšé²ãããšãã話é¡ãå·§ã¿ã«é¿ããªãããããããçŸåšã§ã¯ãMSCãã©ã€ããŒã®ç¥èãšç解ãããã°ãèšé²æ©èœã®å®è£ ãè€éã«ããå¿ èŠã¯ãããŸããã
å ã®å®è£ ã¯æ¬¡ã®ããã«åäœããŸãã
- SCSIæžã蟌ã¿ãã©ã³ã¶ã¯ã·ã§ã³
- ã³ãã³ãã¯ãäžé£ã®é¢æ°MSC_BOT_DataOutïŒïŒ-> MSC_BOT_CBW_DecodeïŒïŒ-> SCSI_ProcessCmdïŒïŒ-> SCSI_Write10ïŒïŒã«ãã£ãŠåŠçãããŸãã
- hmsc->bot_state == USBD_BOT_IDLE, : ,
- USBD_LL_PrepareReceive() USB .
- hmsc->bot_state = USBD_BOT_DATA_OUT
- SCSI: Data Out
- 64 . USB, MSC
- Data Out SCSI_Write10()
- hmsc->bot_state == USBD_BOT_DATA_OUT, SCSI_ProcessWrite()
- åæã¢ãŒãã§ã«ãŒãã«é²é³ããããŸã
- ãã¹ãŠã®ããŒã¿ããŸã åä¿¡ãããŠããªãå Žåã¯ãUSBD_LL_PrepareReceiveïŒïŒãåŒã³åºããŠåä¿¡ããåå é»ãããŸã
- ãã¹ãŠã®ãããã¯ãæžã蟌ãŸãããšãé¢æ°MSC_BOT_SendCSWïŒïŒãåŒã³åºããããã¹ãã«ç¢ºèªãéä¿¡ããïŒå¶åŸ¡ã¹ããŒã¿ã¹ã¯ãŒã-CSWïŒããã©ã€ããŒã¯USBD_BOT_IDLEã«åãæ¿ãããŸãã
- SCSIãã©ã³ã¶ã¯ã·ã§ã³ïŒå¿ç
- ãã®æç¹ã§ãã¹ããŒã¿ã¹ããã±ãŒãžã¯æ¢ã«éä¿¡ãããŠããŸãã察åŠäžèŠ
æåã«ãå ã®å®è£ ãWriteïŒïŒé¢æ°ã®éåæã«é©åãããŸããSCSI_ProcessWriteïŒïŒé¢æ°ãåé¢ããã³ãŒã«ããã¯ã§æ®ãã®ååãåŒã³åºãã ãã§ãã
ã¬ã³ãŒãæ©èœã®å®è£
/** * @brief SCSI_ProcessWrite * Handle Write Process * @param lun: Logical unit number * @retval status */ static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, uint8_t lun) { uint32_t len; USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassDataMSC; len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); if(pdev->pClassSpecificInterfaceMSC->Write(lun , hmsc->bot_data, hmsc->scsi_blk_addr / hmsc->scsi_blk_size, len / hmsc->scsi_blk_size, pdev) < 0) { SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, WRITE_FAULT); return -1; } return 0; } return 0; } void cardWriteCompletedCB(uint8_t res, void * context) { USBD_HandleTypeDef * pdev = (USBD_HandleTypeDef *)context; USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassDataMSC; uint8_t lun = hmsc->cbw.bLUN; uint32_t len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); // Check error code first if(res != 0) { SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, WRITE_FAULT); return; } hmsc->scsi_blk_addr += len; hmsc->scsi_blk_len -= len; /* case 12 : Ho = Do */ hmsc->csw.dDataResidue -= len; if (hmsc->scsi_blk_len == 0) { MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED); } else { /* Prepare EP to Receive next packet */ USBD_LL_PrepareReceive (pdev, MSC_OUT_EP, hmsc->bot_data, MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET)); } }
èªã¿åãã®å Žåãšåæ§ã«ãæåã®é¢æ°ãã2çªç®ã®é¢æ°ã«äœããã®æ¹æ³ã§å€æ°ãæž¡ãå¿ èŠããããŸãããã®ããã«ãã³ã³ããã¹ããã©ã¡ãŒã¿ã䜿çšããŠUSBããã€ã¹ã®ãã³ãã«ãæž¡ããŸãïŒããããå¿ èŠãªããŒã¿ããã¹ãŠååŸã§ããŸãïŒã
ãã®ã¢ãŒãã§ã®èšé²é床ã¯çŽ90kb / sã§ãäž»ã«ã«ãŒããžã®æžã蟌ã¿é床ã«ãã£ãŠå¶éãããŸããããã¯æ³¢åœ¢ã«ãã£ãŠç¢ºèªãããŸã-åããŒã¯ã¯1ãããã¯ã®èšé²ã§ããç»åããå€æãããšã512ãã€ãã®èšé²ã«ã¯3ã6ããªç§ããããŸãïŒæ¯åç°ãªãæ¹æ³ã§ïŒã
ããã«ãã¬ã³ãŒãã¯100msãã0.5sã«åºå®ãããå ŽåããããŸã-æããã«ã«ãŒãã®ã©ããã«ããŸããŸãªå éšã¢ã¯ãã£ããã£ãå¿ èŠã§ã-ãããã¯ã®åãããã³ã°ãããŒãžã®æ¶å»ããŸãã¯ãã®ãããªãã®ã
ãã®ããšããé²ãã§ãããã«ãããã¡ã«ããŒãã³ã°ããŠãç¶æ³ãåçã«æ¹åããããšã¯ã»ãšãã©ãããŸããããããããšã«ãããç§ãã¡ã¯çŽç²ã«ã¹ããŒãã®èå³ãããããããããšããŸãã
ãããã£ãŠããã®æŒç¿ã®æ¬è³ªã¯ãåã®ãããã¯ãã«ãŒãã«æžã蟌ãŸããŠããéã«ãã¹ããã次ã®ãããã¯ãååŸããããšã§ããSCSI_Write10ïŒïŒé¢æ°ã®ã©ããã§èšé²ãšæ¬¡ã®ãããã¯ã®åä¿¡ãåæã«éå§ãããªãã·ã§ã³ãããã«æãæµ®ãã³ãŸããDataOutã€ãã³ãã«ãã£ãŠïŒæ¬¡ã®ãããã¯ã®åä¿¡ãå®äºããŸãïŒãäœãæ©èœããŸããããªããªã åä¿¡ã¯èšé²ãããã¯ããã«é«éã§ãã«ãŒããæžã蟌ã¿ã管çãããããå€ãã®ããŒã¿ãåä¿¡ã§ããŸãã ããªãã¡æ¬¡ã®ããŒã¿ã¯ä»¥åã«åãå ¥ãããããäžæžããããŸããããŸã åŠçãããŠããŸããã
ãã®ã¹ããŒã ã§ã¯ãè€æ°ã®ãã±ãããé£ç¶ããŠåä¿¡ã§ããŸããããã¹ãŠã®ãã±ãããSDã«ãŒãã«èšé²ãããããã§ã¯ãããŸãããã»ãšãã©ã®å ŽåãããŒã¿ã®äžéšã¯æ¬¡ã®ãããã¯ã§æ¶å»ãããŸãã
åæãè¡ãå¿ èŠããããŸããã©ãã ãïŒèªã¿åãæäœã®å Žåãã«ãŒãããã®èªã¿åããçµäºããããŒã¿ãUSBã«è»¢éãããå Žæã§ããã«ãããã¡ãªã³ã°ãšåæãè¡ããŸããããã®å Žæã¯cardReadCompletedCBïŒïŒé¢æ°ã§ãããæžã蟌ã¿æäœã®å ŽåãSCSI_Write10ïŒïŒé¢æ°ã¯ãã®ãããªäžå¿çãªå Žæã«ãªããŸãã次ã®ããŒã¿ãããã¯ãåä¿¡ããããšãã«ããã«ãããããããã«ãŒããžã®æžã蟌ã¿ãéå§ããŸãã
ãã ããcardReadCompletedCBïŒïŒé¢æ°ãšSCSI_Write10ïŒïŒé¢æ°ã«ã¯åºæ¬çãªéãã1ã€ãããŸãã1ã€ç®ã¯SDã«ãŒãã¹ããªãŒã ã§æ©èœãã2ã€ç®ã¯USBå²ã蟌ã¿ã§æ©èœããŸããäœããã®ã€ãã³ããŸãã¯åæãªããžã§ã¯ããåŸ æ©ããŠããéãéåžžã®ã¹ã¬ãããäžæãããå ŽåããããŸããäžæãããšããã®ãããªãã©ãŒã«ã¹ã¯æ©èœããŸãã-FromISRãµãã£ãã¯ã¹ãæã€ãã¹ãŠã®FreeRTOSé¢æ°ã¯éããããã³ã°ã§ãããããã¯ãå¿ èŠã«å¿ããŠæ©èœããŸãïŒç©ºããããå Žåã¯ãªãœãŒã¹ããã£ããã£ããã¹ããŒã¹ãŸãã¯å¿ èŠãªã¡ãã»ãŒãžãããå Žåã¯ãã¥ãŒãä»ããŠã¡ãã»ãŒãžãéåä¿¡ããŸãïŒããŸãã¯ãããã®é¢æ°ã¯ãšã©ãŒãè¿ããŸãããããã圌ãã¯æ±ºããŠåŸ ã¡ãŸããã
ãã ããå²ã蟌ã¿ã§åŸ æ©ãç·šæããããšãäžå¯èœãªå Žåã¯ãå²ã蟌ã¿ãåã³åŒã³åºãããªãããã«ããããšãã§ããŸããããæ£ç¢ºã«ã¯ãããã§ãããäžæãå¿ èŠãªãšãã«æ£ç¢ºã«äœåºŠãçºçãããšããããšã§ãã
åä¿¡/é²é³ããã»ã¹äžã«çºçããå¯èœæ§ã®ããããã€ãã®ã±ãŒã¹ãèŠãŠã¿ãŸãããã
ã±ãŒã¹çªå·1ïŒæåã®ãããã¯ã®åä¿¡ãæåã®ãããã¯ãåä¿¡ããããšããã«ããã®ãããã¯ã®èšé²ãéå§ã§ããŸããåæã«ã2çªç®ã®ãããã¯ã®åä¿¡ãéå§ã§ããŸããããã«ãããåã®ãããã¯ãã«ãŒãã«æžã蟌ãŸããŠããéã«æ¬¡ã®ãããã¯ãåãå ¥ããªãå Žåã«äžæåæ¢ãä¿åãããŸãã
ã±ãŒã¹2ïŒãã©ã³ã¶ã¯ã·ã§ã³ã®éäžã§ãããã¯ãåãåããã»ãšãã©ã®å Žåãäž¡æ¹ã®ãããã¡ããã§ã«ãã£ã±ãã«ãªã£ãŠããŸãã SDã«ãŒãã¹ããªãŒã ã®ã©ããã§ãæåã®ãããã¯ããããŒã¿ãããã¯ãæžã蟌ãŸãã2çªç®ã®ãããã¯ã¯ãã¹ãããåä¿¡ããã°ããã§ããååãšããŠã2çªç®ã®ãããã¯ã®ã¬ã³ãŒããè«æ±ããããšã劚ãããã®ã¯äœããããŸãã-å ¥åã«ãã¥ãŒãããïŒäžèšã®SD_MSC_ReadïŒïŒé¢æ°ãåç §ïŒãå ¥åèŠæ±ã調æŽãããããã¯ãé çªã«æžã蟌ã¿ãŸãããã®ãã¥ãŒã«2ã€ã®ãªã¯ãšã¹ãã®å Žæãããããšã確èªããå¿ èŠããããŸãã
ããããåä¿¡ã調æŽããæ¹æ³ã¯ïŒåä¿¡ãããã¡ãŒã¯2ã€ãããããŸããã 2çªç®ã®ãããã¯ãåä¿¡ããçŽåŸã«æ¬¡ã®ãããã¯ã®åä¿¡ãéå§ãããšãæåã®ãããã¡ãŒã®ããŒã¿ãäžæžããããããããã«ãŒããžã®èšé²ãçŸåšè¡ãããŸãããã®å Žåããããã¡ãŒã解æŸããããšããã€ãŸãèšé²ãçµäºãããšãïŒã€ãŸããæžã蟌ã¿é¢æ°ã®ã³ãŒã«ããã¯ã§ïŒã«ã次ã®ããŒã¿ãããã¯ã®åä¿¡ãéå§ããæ¹ãé©åã§ãã
æåŸã«ãã±ãŒã¹çªå·3ïŒåä¿¡/é²é³æé ãæ£ããå®äºããå¿ èŠããããŸããæåŸã®ãããã¯ã§ã¯ãã¹ãŠãæ確ã§ãã次ã®ãããã¯ãåä¿¡ãã代ããã«ãããŒã¿ãåä¿¡ããããã©ã³ã¶ã¯ã·ã§ã³ãéããããšãã§ããããšãCSWãã¹ãã«éä¿¡ããå¿ èŠããããŸãããã ãããã©ã³ã¶ã¯ã·ã§ã³ã®éå§æã«æ¢ã«è¿œå ã®ã¬ã»ãã·ã§ã³ãç·šæããŠãããããæåŸãã2çªç®ã®ãããã¯ã¯è¿œå ã®ãããã¯ã泚æããªãããšã«æ³šæããŠãã ããã
ãããã®ã±ãŒã¹ã説æããåçã次ã«ç€ºããŸãã
ã±ãŒã¹1ïŒæåã®DataOutã§ãããã«2çªç®ã®ãããã¯ã®åä¿¡ãéå§ããŸããã±ãŒã¹2ïŒèšé²ãçµäºãããããã¡ã解æŸãããåŸã«ã®ã¿ã次ã®ãããã¯ã®åä¿¡ãéå§ããŸããã±ãŒã¹3ïŒæåŸãã2çªç®ã®èšé²ã§åä¿¡ãéå§ãããæåŸã®èšé²ã§CSWãéä¿¡ããŸãã
èå³æ·±ã芳å¯ïŒã«ãŒããžã®èšé²ãæåã®ãããã¡ããæ¥ãå Žåãèšé²ã®çµããã«æ¬¡ã®ãããã¯ãåãæåã®ãããã¡ã§åä¿¡ãããŸããåæ§ã«ã2çªç®ã®ãããã¡ãŒã䜿çšããŸãããã®äºå®ãå®è£ ã«äœ¿çšããããšæããŸãã
èšç»ãå®è¡ããŠã¿ãŸããããæåã®ã±ãŒã¹ïŒè¿œå ã®ãããã¯ãåãåãïŒãå®è£ ããã«ã¯ãç¹å¥ãªç¶æ ãå¿ èŠã§ã
æåã®ãããã¯ãåä¿¡ããããã®æ°ããç¶æ
#define USBD_BOT_DATA_OUT_1ST 6 /* Data Out state for the first receiving block */
ãããŠãã®åŠç
/** * @brief MSC_BOT_DataOut * Process MSC OUT data * @param pdev: device instance * @param epnum: endpoint index * @retval None */ void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum) { USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassDataMSC; switch (hmsc->bot_state) { case USBD_BOT_IDLE: MSC_BOT_CBW_Decode(pdev); break; case USBD_BOT_DATA_OUT: case USBD_BOT_DATA_OUT_1ST: if(SCSI_ProcessCmd(pdev, hmsc->cbw.bLUN, &hmsc->cbw.CB[0]) < 0) { MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED); } break; default: break; } }
2çªç®ã®ã±ãŒã¹ïŒèšé²ã®æåŸã«ãããã¯ãåãåãïŒãå®è£ ããã«ã¯ãäœããã®åœ¢ã§äžå®éã®æ å ±ãã³ãŒã«ããã¯ã«è»¢éããå¿ èŠããããŸãããããè¡ãããã«ãèšé²ã³ã³ããã¹ããæã€æ§é äœãäœæããUSBãã³ãã«ã§ãã®æ§é äœã®2ã€ã®ã€ã³ã¹ã¿ã³ã¹ã宣èšããŸããã
ã¬ã³ãŒãã³ã³ããã¹ã
typedef struct { uint32_t next_write_len; uint8_t * buf; USBD_HandleTypeDef * pdev; } USBD_WriteBlockContext; typedef struct _USBD_MSC_BOT_HandleTypeDef { ⊠USBD_WriteBlockContext write_ctxt[2]; ... } USBD_MSC_BOT_HandleTypeDef;
SDã«ãŒãã¹ããªãŒã ã®èšé²ãã¥ãŒã®ãµã€ãºãå€æŽããããšãå¿ããªãã§ãã ãã
ãã¥ãŒã®åæå
// Initialize thread responsible for communication with SD card bool initSDIOThread() { // Initialize synchronisation sdCmdQueue = xQueueCreate(2, sizeof(IOMsg)); ⊠}
SCSI_Write10ïŒïŒé¢æ°ã¯ã»ãšãã©å€æŽãããŠããŸãããããã«ãããã¡ãŒã€ã³ããã¯ã¹ã®åæåãšUSBD_BOT_DATA_OUT_1STç¶æ ãžã®ç§»è¡ã®ã¿ãè¿œå ãããŠããŸãã
SCSI_Write10ïŒïŒé¢æ°
/** * @brief SCSI_Write10 * Process Write10 command * @param lun: Logical unit number * @param params: Command parameters * @retval status */ static int8_t SCSI_Write10 (USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params) { USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassDataMSC; if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */ { // Checking params ⊠hmsc->scsi_blk_addr = ... hmsc->scsi_blk_len = ... /* Prepare EP to receive first data packet */ hmsc->bot_state = USBD_BOT_DATA_OUT_1ST; hmsc->bot_data_idx = 0; USBD_LL_PrepareReceive (pdev, MSC_OUT_EP, hmsc->bot_data, MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET)); } else /* Write Process ongoing */ { return SCSI_ProcessWrite(pdev, lun); } return 0; }
æãèå³æ·±ãããžãã¯ã¯ãã¹ãŠSCSI_ProcessWriteïŒïŒé¢æ°ã«éäžããŸã-ããã¯ãããã¡ãŒãå²ãåœãŠãããèªã¿åããšã¬ã³ãŒãã®ãã§ãŒã³å šäœãæ§ç¯ãããå Žæã§ãã
SCSI_ProcessWriteïŒïŒé¢æ°
/** * @brief SCSI_ProcessWrite * Handle Write Process * @param lun: Logical unit number * @retval status */ static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, uint8_t lun) { USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassDataMSC; uint32_t len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); USBD_WriteBlockContext * ctxt = hmsc->write_ctxt + hmsc->bot_data_idx; // Figure out what to do after writing the block if(hmsc->scsi_blk_len == len) { ctxt->next_write_len = 0xffffffff; } else if(hmsc->scsi_blk_len == len + MSC_MEDIA_PACKET) { ctxt->next_write_len = 0; } else { ctxt->next_write_len = MIN(hmsc->scsi_blk_len - 2 * MSC_MEDIA_PACKET, MSC_MEDIA_PACKET); } // Prepare other fields of the context ctxt->buf = hmsc->bot_data + hmsc->bot_data_idx * MSC_MEDIA_PACKET; ctxt->pdev = pdev; // Do not allow several receives at a time if(hmsc->bot_state != USBD_BOT_DATA_OUT_1ST) pdev->pClassSpecificInterfaceMSC->OnStartOp(); // Write received data if(pdev->pClassSpecificInterfaceMSC->Write(lun , ctxt->buf, hmsc->scsi_blk_addr / hmsc->scsi_blk_size, len / hmsc->scsi_blk_size, ctxt) < 0) { SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, WRITE_FAULT); return -1; } // Switching blocks hmsc->bot_data_idx ^= 1; hmsc->scsi_blk_addr += len; hmsc->scsi_blk_len -= len; /* case 12 : Ho = Do */ hmsc->csw.dDataResidue -= len; // Performing one extra receive for the first time in order to run receive and write operations in parallel if(hmsc->bot_state == USBD_BOT_DATA_OUT_1ST && hmsc->scsi_blk_len != 0) { hmsc->bot_state = USBD_BOT_DATA_OUT; USBD_LL_PrepareReceive (pdev, MSC_OUT_EP, hmsc->bot_data + hmsc->bot_data_idx * MSC_MEDIA_PACKET, // Second buffer MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET)); } return 0; }
ãŸããããã§èšé²ã³ã³ããã¹ããæºåãããŠããŸã-ã³ãŒã«ããã¯ã«éä¿¡ãããæ å ±ãç¹ã«ããã®ãããã¯ã®èšé²ãçµäºãããšãã®åŠçã決å®ããŸãã
- éåžžã®å Žåãåããããã¡ãžã®æ¬¡ã®ãããã¯ã®åä¿¡ãéå§ããŸãïŒäžèšã®ã±ãŒã¹No. 2ïŒ
- æåŸãã2çªç®ã®ãããã¯ã®å ŽåãäœãããŸããïŒã±ãŒã¹No. 3ïŒ
- æåŸã®ãããã¯ã®å Žåãã³ã³ãããŒã«ã¹ããŒã¿ã¹ã¯ãŒãïŒCSWïŒ-æäœã®ã¹ããŒã¿ã¹ã«é¢ãããã¹ããžã®ã¬ããŒããéä¿¡ããŸã
ããŒã¿ãããã¯ãã«ãŒãã®æžã蟌ã¿ãã¥ãŒã«éä¿¡ãããåŸããããã¡ãŒã€ã³ããã¯ã¹ïŒbot_data_idxïŒã¯ä»£æ¿ã®ã€ã³ããã¯ã¹ã«åãæ¿ãããŸãã ããªãã¡æ¬¡ã®ãã±ããã¯å¥ã®ãããã¡ã§åä¿¡ãããŸãã
æåŸã«ãç¹å¥ãªã±ãŒã¹ïŒã±ãŒã¹No. 1ïŒ-æåã®ãããã¯ïŒUSBD_BOT_DATA_OUT_1STç¶æ ïŒã®å Žåãè¿œå ã®ããŒã¿åä¿¡ãç·šæ
ããŸããã®ã³ãŒãã®å¿çéšåã¯ãã«ãŒããžã®èšé²å®äºæã®ã³ãŒã«ããã¯ã§ããèšé²ããããããã¯ã«å¿ããŠã次ã®ãããã¯ã®åä¿¡ãç·šæãããCSWãéä¿¡ãããããäœãèµ·ãããŸããã
ã³ãŒã«ããã¯é²é³æ©èœ
void cardWriteCompletedCB(uint8_t res, void * context) { USBD_WriteBlockContext * ctxt = (USBD_WriteBlockContext*)context; USBD_HandleTypeDef * pdev = ctxt->pdev; USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassDataMSC; uint8_t lun = hmsc->cbw.bLUN; // Check error code first if(res != 0) { SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, WRITE_FAULT); return; } if (ctxt->next_write_len == 0xffffffff) { MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED); } else { pdev->pClassSpecificInterfaceMSC->OnFinishOp(); if(ctxt->next_write_len != 0) { /* Prepare EP to Receive next packet */ USBD_LL_PrepareReceive (pdev, MSC_OUT_EP, ctxt->buf, ctxt->next_write_len); } } }
æåŸã®åé³ã¯åæã§ããããã®æ¬è³ªã¯åçã«è¡šââ瀺ããããã§ãã
éåžžã«ãŸãã§ãããããã§ãã次ã®ãã±ãããåä¿¡ããåã«ã«ãŒããžã®æžã蟌ã¿ãçµäºããå ŽåããããŸãããã®çµæãã³ãŒãã¯ïŒåæããªãã£ãå ŽåïŒå¥ã®ãã±ãããèŠæ±ã§ããŸãããçŸåšã®ãã±ããã¯ãŸã å®å šã«åä¿¡ãããŠããŸããããããé²ãã«ã¯ãåæãè¿œå ããå¿ èŠããããŸãããããã§ã次ã®ãããã¯ã®åä¿¡ãèŠæ±ããåã«ãã³ãŒãã¯åã®ãããã¯ã®åä¿¡ãçµäºãããŸã§åŸ æ©ããŸããèªã¿åãæã«äœ¿çšãããåæããŒã«ïŒOnStartOpïŒïŒ/ OnFinishOpïŒïŒïŒã¯éåžžã«é©ããŠããŸãã
åæããå¿ èŠãããæ¡ä»¶ã¯éåžžã«æ³šæãå¿ èŠã§ãããã©ã³ã¶ã¯ã·ã§ã³ã®éå§æã«è¿œå ã®ãããã¯ãåä¿¡ãããšã1ãããã¯ã®ã·ããã§åæãè¡ãããŸãããããã£ãŠãNçªç®ã®ãããã¯ã®ã³ãŒã«ããã¯ã¬ã³ãŒãã¯ãN + 1ãããã¯ã®åä¿¡ãåŸ æ©ããŠããŸããããã¯ãæåã®ãããã¯ã®åä¿¡ïŒUSBããã®å²ã蟌ã¿ã®ã³ã³ããã¹ãã§çºçïŒãšæåŸã®èšé²ïŒSDã«ãŒãã¹ããªãŒã ã®ã³ã³ããã¹ãã§çºçïŒãåæãå¿ èŠãšããªãããšãæå³ããŸãã
èµ€ãç¢å°ãé»ãç¢å°ãè€è£œãã次ã®ãããã¯ã®èšé²ãéå§ããããã«èŠããå ŽåããããŸããããããã³ãŒããèŠããšãããã§ã¯ãªãããšãããããŸããèµ€ïŒåæïŒã¯MSCãã©ã€ããŒã®ã³ãŒããåæãïŒéã®ããã¯ã¹ïŒããã¥ãŒã¯ã«ãŒããã©ã€ããŒïŒSDã«ãŒãã¹ããªãŒã ã®ã¡ã€ã³ã«ãŒããããïŒã§åŠçãããŸããããŸããŸãªã³ã³ããŒãã³ãã®ã³ãŒãã«å¹²æžããããããŸããã§ããã
å°ããã°ãèšå®ãããšã4kbã®ããŒã¿ã¬ã³ãŒãã¯æ¬¡ã®ããã«ãªããŸã
4 kbãããã¯èšé²ã®åµåãã°
Starting write operation for LBA=0041C600, len=4096
Receiving first block into buf=1
Writing block of data for LBA=0041C600, len=512, buf=0
This will be regular block
Receiving an extra block into buf=1
Writing block of data for LBA=0041C800, len=512, buf=1
This will be regular block
Write completed callback with status 0 (buf=0)
Preparing next receive into buf=0
Writing block of data for LBA=0041CA00, len=512, buf=0
This will be regular block
Write completed callback with status 0 (buf=1)
Preparing next receive into buf=1
Writing block of data for LBA=0041CC00, len=512, buf=1
This will be regular block
Write completed callback with status 0 (buf=0)
Preparing next receive into buf=0
Writing block of data for LBA=0041CE00, len=512, buf=0
This will be regular block
Write completed callback with status 0 (buf=1)
Preparing next receive into buf=1
Writing block of data for LBA=0041D000, len=512, buf=1
This will be regular block
Write completed callback with status 0 (buf=0)
Preparing next receive into buf=0
Writing block of data for LBA=0041D200, len=512, buf=0
This will be one before the last block
Write completed callback with status 0 (buf=1)
Preparing next receive into buf=1
Writing block of data for LBA=0041D400, len=512, buf=1
This will be the last block
Write completed callback with status 0 (buf=0)
Write completed callback with status 0 (buf=1)
Write finished. Sending CSW
äºæ³ã©ãããããã«ããé床ãå€§å¹ ã«åäžããããšã¯ãããŸããã§ãããå€æŽåŸãé床ã¯95ã100 kb / sã§ãããããããç§ãèšã£ãããã«ãããã¯ãã¹ãŠã¹ããŒãã®é¢å¿ããè¡ãããŸããã
ããã«é«éã§ããïŒ
ãã£ãŠã¿ãŸããããäœæ¥ã®éäžã®ã©ããã§ã1ã€ã®ãããã¯ã®èªã¿åããšäžé£ã®ãããã¯ã®èªã¿åããç°ãªãSDã«ãŒãã³ãã³ãã§ããããšã«èª€ã£ãŠæ°ä»ããŸããããããã¯ãããããã©ã€ããŒã®ç°ãªãã¡ãœãã-readBlockïŒïŒããã³readBlocksïŒïŒã§è¡šãããŸããåæ§ã«ã1ã€ã®ãããã¯ã«å¯ŸããŠã³ãã³ããæžã蟌ã¿ãäžé£ã®ãããã¯ãæžã蟌ãããšã¯ç°ãªããŸãã
MSCãã©ã€ããŒã¯ããã©ã«ãã§åäœæéããã1ãããã¯ã§åäœããããã«èª¿æŽãããŠãããããreadBlocksïŒïŒãreadBlockïŒïŒã«çœ®ãæããããšã¯çã«ããªã£ãŠããŸããé©ããããšã«ãèªã¿åãé床ã¯ããã«å¢å ãââã480-500kb / sã®ã¬ãã«ã«ãªããŸããïŒæ®å¿µãªãããé²é³æ©èœã䜿çšããåæ§ã®ããªãã¯ã§ã¯ãé床ã¯åäžããŸããã§ããã
ããããæåãã1ã€ã®è³ªåã«æ©ãŸãããŸãããèªæžã®åçãããäžåºŠèŠãŠã¿ãŸãããããããéïŒ1ãããã¯ã®èªã¿åãïŒ-çŽ2msã
SPIã¯ããã¯ã18MHzã«èšå®ãããŠããŸãïŒã³ã¢ã®ååšåšã¯72MHzã§4ã§ãïŒãçè«çã«ã¯ã512ãã€ãã®éä¿¡ã¯512ãã€ã* 8ããã/ 18 MHz = 228ÎŒsãå ããå¿ èŠããããŸããã¯ããããã€ãã®ã¹ã¬ããã®åæããã¥ãŒã€ã³ã°ãªã©ã«äžå®ã®ãªãŒããŒããããçºçããŸãããããã§ã¯10åè¿ãéãã説æã§ããŸããã
ãªã·ãã¹ã³ãŒãã䜿çšããŠãèªã¿åãæäœã®ããŸããŸãªéšåã«ãããæéã枬å®ããŸããã
éå¶ | æé |
MSCãã©ã€ããŒããã«ãŒããã©ã€ããŒãžã®ãªã¯ãšã¹ã転éïŒãªã¯ãšã¹ããã¥ãŒã䜿çšïŒ | <100ÎŒs |
èªã¿åãã³ãã³ãããããã«éä¿¡ãã | 70mks |
ã«ãŒãåŸ ã¡ | 500-1000ÎŒs |
ã«ãŒããã1ãããã¯ãèªã¿åã | 280ÎŒs |
å¿çãMSCãã©ã€ããŒã«æ»ã | <100ÎŒs |
é©ããããšã«ãæãé·ãæäœã¯ããŒã¿ã®èªã¿åãã§ã¯ãªããèªã¿åãã³ãã³ããšãã«ãŒãã®æºåãã§ããŠããŒã¿ãèªã¿åãããšãã§ãããšããã«ãŒãããã®ç¢ºèªã®ééã§ãããããã«ããã®ééã¯ãããŸããŸãªãã©ã¡ãŒã¿ãŒïŒèŠæ±ã®é »åºŠãèªã¿åãããããŒã¿ã®ãµã€ãºãèªã¿åããããããã¯ã®ã¢ãã¬ã¹ïŒã«å¿ããŠå€§ããå€åããŸããæåŸã®ãã€ã³ãã¯éåžžã«èå³æ·±ãã§ã-ãããã®å é ããé ãã«èªã¿åããããã¯ããããšãèªã¿åããéããªããŸãïŒãããã«ãããããã¯ç§ã®å®éšãããã®å Žåã§ãïŒããã
ã«æžã蟌ããšãã«ãåæ§ã®ïŒãããæ²ããïŒç»åã芳å¯ãããŸãããã¹ãŠã®ã¿ã€ãã³ã°ãååã«æž¬å®ããããšãã§ããŸããã§ãããããªãåºãç¯å²ã§æ³³ããŸãããããã®ããã«èŠããŸãã
éå¶ | æé |
ã¬ã³ãŒããžã®ãããã³ãã³ãã®éä¿¡ | 70mks |
ã«ãŒãåŸ ã¡ | 1ã5ããªç§ |
1ãããã¯ãã«ãŒãã«æžã蟌ã | 0.4-1.2ms |
ããã¯ãã¹ãŠãããªã倧ããªCPUè² è·ïŒçŽ75ïŒ ïŒã«ãã£ãŠããã«æªåããŸããèšé²èªäœã¯ãçè«çã«ã¯èªã¿åããšåã228ÎŒsãå æããå¿ èŠããããŸãããããã¯åã18 MHzã§ã¯ããã¯ãããŸãããã®å Žåã«ã®ã¿ãFreeRTOSã¹ããªãŒã ã®åæãåŒãç¶ã衚瀺ãããŸããæããã«ã倧ããªCPUè² è·ãšä»ã®ïŒåªå 床ã®é«ãïŒã¹ã¬ããã«åãæ¿ããå¿ èŠããããããåèšæéã¯ã¯ããã«é·ããªããŸãã
ããããæ倧ã®æ²ãã¿ã¯ãã«ãŒãã®æºåãæŽãã®ãåŸ ã£ãŠããããšã§ããèªæžã®å Žåãããäœåã倧ãããããã«ãããã§ã«ãŒãã¯100ããªç§ãŸãã¯500ããªç§ã貌ãä»ããããšãã§ããŸããããã«ãã«ãŒããã©ã€ããŒã§ã¯ããã®éšåã¯ã¢ã¯ãã£ããªåŸ æ©ã«ãã£ãŠå®è£ ãããåãé«ããã»ããµè² è·ã«ã€ãªãããŸãã
ã«ãŒãã®æºåãç©æ¥µçã«åŸ
ã£ãŠããŸã
// wait for card to go not busy bool SdSpiCard::waitNotBusy(uint16_t timeoutMS) { uint16_t t0 = curTimeMS(); while (spiReceive() != 0XFF) { if (isTimedOut(t0, timeoutMS)) { return false; } } return true; }
ã«ãŒãå ã«SysCall :: yieldïŒïŒãžã®åŒã³åºããè¿œå ããã³ãŒãã«åå²ããããŸãããç¶æ³ã解決ããªãã®ã§ã¯ãªãããšæããŸãããã®åŒã³åºãã¯ãã¿ã¹ã¯ã¹ã±ãžã¥ãŒã©ãå¥ã®ã¹ã¬ããã«åãæ¿ããããšã®ã¿ãæšå¥šããŠããŸããããããä»ã®ãããŒã¯ã»ãšãã©ç§ãšäžç·ã«å¯ãŠããã®ã§ãããã¯ç¶æ³ãæ ¹æ¬çã«æ¹åããããšã¯ãããŸãã-ãããã¯æããªããšãæ¢ããŸããã
å¥ã®é¢çœãç¬éãFreeRTOSã§ã¯ãã³ã³ããã¹ãã¯SysTickå²ã蟌ã¿ã«ãã£ãŠåãæ¿ããããŸããããã¯ããã©ã«ãã§1msã«èšå®ãããŠããŸãããã®ããããªã·ãã¹ã³ãŒãã®å€ãã®æäœã¯ãã°ãªããäžã§1ããªç§åäœã§èª¿æŽãããŸããã«ãŒãããã«ã§ã¯ãªããåŸ æ©ã§1ãããã¯ãèªã¿åãã®ã«1ããªç§æªæºããããããªãå Žåããã¹ãŠã®ã¹ã¬ãããåæããã¥ãŒãå«ããŠã1ãã£ãã¯ã§æ¹åãå€ããããšãã§ããŸãããããã£ãŠããã®ã¢ãã«ã®çè«äžã®æ倧èªã¿åãé床ã¯ãæ£ç¢ºã«500 kb / sïŒ1ããªç§ã§0.5 kbïŒã§ããäœãå¬ãã-ããã¯éæãããŸããïŒ
ãããããã®ããšã¯åé¿ã§ããŸãã 1msã§ã®æŽåã¯ã次ã®çç±ã§çºçããŸãã USBãŸãã¯DMAããã®å²ã蟌ã¿ã¯äœã«ãçµã³ä»ããããŠãããããã£ãã¯ã®éäžã§çºçããå¯èœæ§ããããŸããå²ã蟌ã¿ãåæãªããžã§ã¯ãã®ç¶æ ãå€æŽããå ŽåïŒããšãã°ãã»ããã©ã®ããã¯ã解é€ãããããã¥ãŒã«ã¡ãã»ãŒãžãè¿œå ããå ŽåïŒãFreeRTOSã¯ããã«ãããèªèããŸãããå²ã蟌ã¿ããžã§ããå®è¡ãããšãå¶åŸ¡ã¯å²ã蟌ã¿åã«åäœããŠããã¹ã¬ããã«è»¢éãããŸãããã£ãã¯ãçµäºãããšãã¹ã±ãžã¥ãŒã©ãåŒã³åºãããåæãªããžã§ã¯ãã®ç¶æ ã«å¿ããŠã察å¿ããã¹ããªãŒã ã«åãæ¿ããããšãã§ããŸãã
ãã ãããã®ãããªå Žåã«ã®ã¿ãFreeRTOSã«ã¯ã¹ã±ãžã¥ãŒã©ã匷å¶ããã¡ã«ããºã ããããŸããå ã»ã©èšã£ãããã«ãå²ã蟌ã¿ãäžæããããšã¯ã§ããŸããããã ããã¹ã±ãžã¥ãŒã©ãŒãåŒã³åºãå¿ èŠãããããšã瀺åããããšãã§ããŸãïŒã¹ã±ãžã¥ãŒã©ãŒãåŒã³åºãã®ã§ã¯ãªããåŒã³åºãå¿ èŠãããããšã瀺åããŸãïŒãããã¯ãŸãã«portYIELD_FROM_ISRïŒïŒé¢æ°ãè¡ãããšã§ãã
äžæåŸããã«ãããŒãåãæ¿ããããã¹ã±ãžã¥ãŒã©ãŒã«äŸé ŒããŸã
void SdFatSPIDriver::dmaTransferCompletedCB() { // Resume SD thread BaseType_t xHigherPriorityTaskWoken; xSemaphoreGiveFromISR(xSema, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); }
å²ã蟌ã¿åŠçïŒDMAãªã©ããïŒãçµäºãããšãã¹ã±ãžã¥ãŒã©ãåŒã³åºããããã³ãã©ãŒã§PendSVå²ã蟌ã¿ãèªåçã«åŒã³åºãããŸãã次ã«ãã³ã³ããã¹ãã匷å¶çã«åãæ¿ããã»ããã©ãåŸ æ©ããŠããã¹ã¬ããã«å¶åŸ¡ã移ããŸãã T.O.äžæã«å¯Ÿããå¿çæéãå€§å¹ ã«ççž®ã§ããããããã®ããªãã¯ã«ããããã¹ãã«ãŒãã§ã®èªã¿åããæ倧600kb / sãŸã§é«éåã§ããŸãã
ããããããã¯ã«ãŒãã®æºåãã§ããã®ãé·ãåŸ ããªãå Žåã§ããæ®å¿µãªãããã«ãŒããé·ãéèããŠããå Žåãèªã¿åãã¯2ãã£ãã¯ïŒããã³4ã6æžã蟌ã¿ïŒã¹ãã¬ãããããé床ã¯å€§å¹ ã«äœäžããŸããããã«ãã¢ã¯ãã£ããªåŸ æ©ã³ãŒãã絶ããã«ãŒãã«äŸµå ¥ããã«ãŒããé·æéå¿çããªãå Žåããã£ãã¯å šäœãééããå¯èœæ§ããããŸãããã®å ŽåãOSã¹ã±ãžã¥ãŒã©ã¯ããã®ã¹ã¬ããã®å®è¡æéãé·ããããšå€æããéåžžã¯ä»ã®ã¹ã¬ããã«å¶åŸ¡ãåãæ¿ããŸãããã®ãããè¿œå ã®é 延ãçºçããå ŽåããããŸãã
ã¡ãªã¿ã«ãç§ã¯ããããã¹ãŠã8GBã¯ã©ã¹6ã«ãŒãã§ãã¹ãããæå ã«ããä»ã®ã«ãŒããããã€ãè©ŠããŸãããå¥ã®ã«ãŒãã8GBã§ãããäœããã®çç±ã§ã¯ã©ã¹10ã¯èªã¿åãçšã«300ã350 kb / sã ãããæžã蟌ã¿çšã«120 kb / sãæäŸããŸãããç§ãæã£ãŠããæ倧ãã€æéã®ã«ãŒã-32GBãå ¥ããããšæããŸãããããã§æ倧é床ãéæããããšãå¯èœã§ãã-èªã¿åãã®ããã®650kb / sãšæžã蟌ã¿ã®ããã®120kb / sããšããã§ãç§ãåŒçšããé床ã¯å¹³åã§ããç¬éé床ã枬å®ãããã®ã¯äœããããŸããã§ããã
ãã®åæããã©ã®ãããªçµè«ãå°ãåºãããšãã§ããŸããïŒ
- ãŸããSPIã¯æããã«SDã«ãŒãã®ãã€ãã£ãã€ã³ã¿ãŒãã§ã€ã¹ã§ã¯ãããŸãããæãäžè¬çãªæäœã§ã¯ãã¯ãŒã«ãªã«ãŒãã§ããæãã§ããSDIOã«ç®ãåããã®ã¯çã«ããªã£ãŠããŸãïŒæ¢ã«ã¡ãŒã«ã§STM32F103RCT6ã®ããã°ãæã«å ¥ããŸãã-ããã«äœ¿ããSDIOãµããŒãããããŸãïŒ
- -, . . SDIO
- -, ( 4). / . 20 (STM32F103C8T6) 512
ãããã«
ãã®èšäºã§ã¯ãUSB MSCå®è£ ãSTMicroelectronicsããã¢ããã°ã¬ãŒãããæ¹æ³ã«ã€ããŠèª¬æããŸãããä»ã®STM32ã·ãªãŒãºãã€ã¯ãã³ã³ãããŒã©ãŒãšã¯ç°ãªããF103ã·ãªãŒãºã«ã¯USBçšã®DMAãµããŒããçµã¿èŸŒãŸããŠããŸãããããããFreeRTOSã®å©ããåããŠãDMAçµç±ã§SDã«ãŒãã®èªã¿åã/æžã蟌ã¿ãåºå®ããããšãã§ããŸããããŸããUSBãã¹åž¯åå¹ ã®äœ¿çšãæ倧åããããã«ãããã«ãããã¡ãªã³ã°ã匷åããããšãã§ããŸããã
çµæã¯ç§ã®æåŸ ãè¶ ããŸãããæåã¯ãçŽ400kb / sã®é床ãç®æããŸãããããªããšã650kb / sãçµãããšãã§ããŸãããããããç§ã«ãšã£ãŠéèŠãªã®ã¯ã絶察çãªé床ã€ã³ãžã±ãŒã¿ã§ãããªãããã®é床ãæå°éã®ããã»ããµã®ä»å ¥ã§éæããããšããäºå®ã§ãããããã£ãŠãããŒã¿ã¯DMAããã³USBåšèŸºæ©åšã䜿çšããŠéä¿¡ãããããã»ããµã¯æ¬¡ã®æäœãå é»ããããã«ã®ã¿æ¥ç¶ãããŸãã
確ãã«ãèšé²ã§ã¯æé«é床ãåŸãããšãã§ããŸããã§ãã-ããã100-120kb / sã SDã«ãŒãèªäœã®å·šå€§ãªã¿ã€ã ã¢ãŠãã®åå ãã«ãŒãã¯SPIçµç±ã§æ¥ç¶ãããŠãããããã«ãŒãã®æºåç¶æ³ã確èªããæ¹æ³ã¯ä»ã«ãããŸããïŒåžžã«ããŒãªã³ã°ããæ¹æ³ãé€ãïŒããã®ãããæžã蟌ã¿æäœã§ããªãé«ãããã»ããµè² è·ã芳å¯ãããŸãã SDIOãä»ããŠã«ãŒããæ¥ç¶ãããšãã¯ããã«é«ãé床ãå®çŸã§ããããšãç§ã¯ç§å¯ã«æãã§ããŸãã
ã³ãŒããæäŸããã ãã§ãªããã³ãŒããã©ã®ããã«æ§æãããŠããã®ãããªããã®ããã«æ§ç¯ãããŠããã®ãã説æããããšããŸããããããããããã¯ä»ã®ã³ã³ãããŒã©ãŒãŸãã¯ã©ã€ãã©ãªãŒã«å¯ŸããŠåæ§ã®ããšãè¡ãã®ã«åœ¹ç«ã¡ãŸããç§ã¯ãããå¥ã®ã©ã€ãã©ãªã«å²ãåœãŠãŸããã§ããããã®ã³ãŒãã¯ãç§ã®ãããžã§ã¯ãã®ä»ã®éšåãšFreeRTOSã©ã€ãã©ãªã«äŸåããŠããŸããããã«ãããããé©çšããMSCã®å®è£ ã«åºã¥ããŠã³ãŒããæ§ç¯ããŸããããããã£ãŠãç§ã®ããŒãžã§ã³ã䜿çšããå Žåã¯ãå ã®ã©ã€ãã©ãªã«ããã¯ããŒãããå¿ èŠããããŸãã
ãªããžããªãžã®ãªã³ã¯ïŒgithub.com/grafalex82/GPSLogger
SDã«ãŒãã§ã®äœæ¥ãé«éåããæ¹æ³ã«é¢ãã建èšçãªã³ã¡ã³ãããã®ä»ã®ã¢ã€ãã¢ãåãã§ããŸãã