/* * This file is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * */ #include #include "SPIDevice.h" #include "sdcard.h" #include "bouncebuffer.h" #include "CrashDump.h" #include "hwdef/common/spi_hook.h" #include #include #include "stm32_util.h" extern const AP_HAL::HAL& hal; #if HAL_USE_FATFS static FATFS SDC_FS; // FATFS object #ifndef HAL_BOOTLOADER_BUILD static HAL_Semaphore sem; #endif static bool sdcard_running; #endif #if HAL_USE_SDC static SDCConfig sdcconfig = { SDC_MODE_4BIT, 0 }; #elif HAL_USE_MMC_SPI MMCDriver MMCD1; static AP_HAL::SPIDevice *device; static MMCConfig mmcconfig; static SPIConfig lowspeed; static SPIConfig highspeed; #endif // initialise the microSD block device without mounting its filesystem bool sdcard_init_raw(uint8_t sd_slowdown, uint8_t tries) { #if HAL_USE_FATFS #if HAL_USE_SDC #if STM32_SDC_USE_SDMMC2 == TRUE auto &sdcd = SDCD2; #else auto &sdcd = SDCD1; #endif if (sdcd.bouncebuffer == nullptr) { // allocate 4k-32k bouncebuffer for microSD to match size in // AP_Logger #if defined(STM32H7) bouncebuffer_init(&sdcd.bouncebuffer, AP_FATFS_MAX_IO_SIZE, true); // allocation failure, pick a smaller size if (sdcd.bouncebuffer->dma_buf == nullptr) { bouncebuffer_init(&sdcd.bouncebuffer, AP_FATFS_MIN_IO_SIZE, true); #if AP_FILESYSTEM_FATFS_ENABLED AP_Filesystem_FATFS::set_io_size(AP_FATFS_MIN_IO_SIZE); #endif } else { #if AP_FILESYSTEM_FATFS_ENABLED AP_Filesystem_FATFS::set_io_size(AP_FATFS_MAX_IO_SIZE); #endif } #else bouncebuffer_init(&sdcd.bouncebuffer, AP_FATFS_MAX_IO_SIZE, false); #if AP_FILESYSTEM_FATFS_ENABLED AP_Filesystem_FATFS::set_io_size(AP_FATFS_MAX_IO_SIZE); #endif #endif if (sdcd.bouncebuffer->dma_buf == nullptr) { // we are never going to be able to log sdcard_running = false; return false; } } if (sdcard_running) { sdcard_stop(); } for (uint8_t i=0; iget_device_ptr("sdcard"); if (!device) { printf("No sdcard SPI device found\n"); sdcard_running = false; return false; } } device->set_slowdown(sd_slowdown); mmcObjectInit(&MMCD1, MMCD1.buffer); mmcconfig.spip = (static_cast(device))->get_driver(); mmcconfig.hscfg = &highspeed; mmcconfig.lscfg = &lowspeed; // try the requested number of times to initialise the microSD interface for (uint8_t i=0; i(&SDCD2); #else return reinterpret_cast(&SDCD1); #endif #elif HAL_USE_MMC_SPI return reinterpret_cast(&MMCD1); #else return nullptr; #endif } bool sdcard_init() { #if HAL_USE_FATFS #ifndef HAL_BOOTLOADER_BUILD WITH_SEMAPHORE(sem); const uint8_t sd_slowdown = AP_BoardConfig::get_sdcard_slowdown(); #else const uint8_t sd_slowdown = 0; #endif for (uint8_t i = 0; i < 3; i++) { if (!sdcard_init_raw(sd_slowdown, 1)) { continue; } if (f_mount(&SDC_FS, "/", 1) == FR_OK) { printf("Successfully mounted SDCard (slowdown=%u)\n", (unsigned)sd_slowdown); return true; } sdcard_stop(); } #endif return false; } /* stop sdcard interface (for reboot) */ void sdcard_stop(void) { #if AP_CRASHDUMP_FATFS_ENABLED && (HAL_USE_SDC || \ (HAL_USE_MMC_SPI && CRASHDUMP_SD_SPI_SUPPORTED_MCU)) // Do this before unmounting or disabling the peripheral clock. A fault // after this point must not try to use the cached sector map. crashdump_sd_invalidate(); #endif #if HAL_USE_FATFS // unmount f_mount(nullptr, "/", 1); #endif #if HAL_USE_SDC #if STM32_SDC_USE_SDMMC2 == TRUE auto &sdcd = SDCD2; #else auto &sdcd = SDCD1; #endif if (sdcard_running) { sdcDisconnect(&sdcd); sdcStop(&sdcd); sdcard_running = false; } #elif HAL_USE_MMC_SPI if (sdcard_running) { mmcDisconnect(&MMCD1); mmcStop(&MMCD1); sdcard_running = false; } #endif } bool sdcard_retry(void) { #if HAL_USE_FATFS #if AP_CRASHDUMP_FATFS_ENABLED && (HAL_USE_SDC || \ (HAL_USE_MMC_SPI && CRASHDUMP_SD_SPI_SUPPORTED_MCU)) const bool sdcard_was_running = sdcard_running; #endif if (!sdcard_running) { if (sdcard_init()) { #if AP_FILESYSTEM_FILE_WRITING_ENABLED // create APM directory AP::FS().mkdir("/APM"); #endif } } #if AP_CRASHDUMP_FATFS_ENABLED && (HAL_USE_SDC || \ (HAL_USE_MMC_SPI && CRASHDUMP_SD_SPI_SUPPORTED_MCU)) if (sdcard_running && (!sdcard_was_running || !crashdump_sd_ready())) { crashdump_sd_init(); } #endif return sdcard_running; #endif return false; } #if HAL_USE_MMC_SPI AP_HAL::SPIDevice *sdcard_get_spi_device() { return device; } /* hooks to allow hal_mmc_spi.c to work with HAL_ChibiOS SPI layer. This provides bounce buffers for DMA, DMA channel sharing and bus locking */ void spiStartHook(SPIDriver *spip, const SPIConfig *config) { device->set_speed(config == &lowspeed ? AP_HAL::Device::SPEED_LOW : AP_HAL::Device::SPEED_HIGH); } void spiStopHook(SPIDriver *spip) { } __RAMFUNC__ void spiAcquireBusHook(SPIDriver *spip) { if (sdcard_running) { ChibiOS::SPIDevice *devptr = static_cast(device); devptr->acquire_bus(true, true); } } __RAMFUNC__ void spiReleaseBusHook(SPIDriver *spip) { if (sdcard_running) { ChibiOS::SPIDevice *devptr = static_cast(device); devptr->acquire_bus(false, true); } } __RAMFUNC__ void spiSelectHook(SPIDriver *spip) { if (sdcard_running) { device->get_semaphore()->take_blocking(); device->set_chip_select(true); } } __RAMFUNC__ void spiUnselectHook(SPIDriver *spip) { if (sdcard_running) { device->set_chip_select(false); device->get_semaphore()->give(); } } void spiIgnoreHook(SPIDriver *spip, size_t n) { if (sdcard_running) { device->clock_pulse(n); } } __RAMFUNC__ void spiSendHook(SPIDriver *spip, size_t n, const void *txbuf) { if (sdcard_running) { device->transfer((const uint8_t *)txbuf, n, nullptr, 0); } } __RAMFUNC__ void spiReceiveHook(SPIDriver *spip, size_t n, void *rxbuf) { if (sdcard_running) { device->transfer(nullptr, 0, (uint8_t *)rxbuf, n); } } #endif