mirror of
https://github.com/ArduPilot/ardupilot.git
synced 2026-10-06 19:00:27 +08:00
Add an early boot service that exports the microSD block device over USB mass storage before the filesystem and normal flight application start. The service retains exclusive ownership until a power cycle and continues servicing the watchdog. Enable the service on supported boards, provide explicit build control, increase the MSD worker stacks for the SD wait path, scope the ChibiOS fixed-width serial warning suppression to the MSD object, and reject explicit enable requests on unsupported boards.
327 lines
8.0 KiB
C++
327 lines
8.0 KiB
C++
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include <hal.h>
|
|
#include "SPIDevice.h"
|
|
#include "sdcard.h"
|
|
#include "bouncebuffer.h"
|
|
#include "CrashDump.h"
|
|
#include "hwdef/common/spi_hook.h"
|
|
#include <AP_BoardConfig/AP_BoardConfig.h>
|
|
#include <AP_Filesystem/AP_Filesystem.h>
|
|
#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; i<tries; i++) {
|
|
sdcconfig.slowdown = sd_slowdown;
|
|
sdcStart(&sdcd, &sdcconfig);
|
|
if(sdcConnect(&sdcd) == HAL_FAILED) {
|
|
sdcStop(&sdcd);
|
|
continue;
|
|
}
|
|
sdcard_running = true;
|
|
return true;
|
|
}
|
|
#elif HAL_USE_MMC_SPI
|
|
if (MMCD1.buffer == nullptr) {
|
|
// allocate 16 byte non-cacheable buffer for microSD
|
|
MMCD1.buffer = (uint8_t*)malloc_axi_sram(MMC_BUFFER_SIZE);
|
|
}
|
|
|
|
if (sdcard_running) {
|
|
sdcard_stop();
|
|
}
|
|
|
|
sdcard_running = true;
|
|
|
|
if (device == nullptr) {
|
|
device = AP_HAL::get_HAL().spi->get_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<ChibiOS::SPIDevice*>(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<tries; i++) {
|
|
mmcStart(&MMCD1, &mmcconfig);
|
|
|
|
if (mmcConnect(&MMCD1) == HAL_FAILED) {
|
|
mmcStop(&MMCD1);
|
|
continue;
|
|
}
|
|
sdcard_running = true;
|
|
return true;
|
|
}
|
|
#endif
|
|
sdcard_running = false;
|
|
#endif // HAL_USE_FATFS
|
|
return false;
|
|
}
|
|
|
|
BaseBlockDevice *sdcard_get_block_device()
|
|
{
|
|
#if HAL_USE_SDC
|
|
#if STM32_SDC_USE_SDMMC2 == TRUE
|
|
return reinterpret_cast<BaseBlockDevice *>(&SDCD2);
|
|
#else
|
|
return reinterpret_cast<BaseBlockDevice *>(&SDCD1);
|
|
#endif
|
|
#elif HAL_USE_MMC_SPI
|
|
return reinterpret_cast<BaseBlockDevice *>(&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<ChibiOS::SPIDevice*>(device);
|
|
devptr->acquire_bus(true, true);
|
|
}
|
|
}
|
|
|
|
__RAMFUNC__ void spiReleaseBusHook(SPIDriver *spip)
|
|
{
|
|
if (sdcard_running) {
|
|
ChibiOS::SPIDevice *devptr = static_cast<ChibiOS::SPIDevice*>(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
|