diff options
author | David Crocker <dcrocker@eschertech.com> | 2022-01-10 00:29:47 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2022-01-10 00:29:47 +0300 |
commit | d9ff09f7c9030389c0fa7bb8eb7f85156c9d9045 (patch) | |
tree | 050deb7efa50f9749876532d5f799ae0e08ab388 /src | |
parent | c0356a4933bbbe11af20032ee1965358a29cf4bd (diff) |
Support external SD card on MB6HC
Diffstat (limited to 'src')
-rw-r--r-- | src/Duet3_V06/Pins_Duet3_V06.h | 8 | ||||
-rw-r--r-- | src/Libraries/sd_mmc/sd_mmc.c | 13 | ||||
-rw-r--r-- | src/Libraries/sd_mmc/sd_mmc.h | 3 | ||||
-rw-r--r-- | src/Libraries/sd_mmc/sd_mmc_spi.cpp | 19 | ||||
-rw-r--r-- | src/Libraries/sd_mmc/sd_mmc_spi.h | 3 | ||||
-rw-r--r-- | src/Platform/Platform.cpp | 12 | ||||
-rw-r--r-- | src/Platform/RepRap.cpp | 12 | ||||
-rw-r--r-- | src/RepRapFirmware.h | 3 | ||||
-rw-r--r-- | src/Storage/MassStorage.cpp | 53 | ||||
-rw-r--r-- | src/Storage/MassStorage.h | 12 |
10 files changed, 119 insertions, 19 deletions
diff --git a/src/Duet3_V06/Pins_Duet3_V06.h b/src/Duet3_V06/Pins_Duet3_V06.h index 773b1d09..741df19e 100644 --- a/src/Duet3_V06/Pins_Duet3_V06.h +++ b/src/Duet3_V06/Pins_Duet3_V06.h @@ -151,10 +151,10 @@ constexpr Pin DiagPin = PortCPin(20); constexpr bool DiagOnPolarity = true; // SD cards -constexpr size_t NumSdCards = 1; -constexpr Pin SdCardDetectPins[1] = { PortAPin(29) }; -constexpr Pin SdWriteProtectPins[1] = { NoPin }; -constexpr Pin SdSpiCSPins[1] = { NoPin }; +constexpr size_t NumSdCards = 2; // we now allow one SPI-connected SD card to be configured at boot time +constexpr Pin SdCardDetectPins[NumSdCards] = { PortAPin(29), NoPin }; +constexpr Pin SdWriteProtectPins[NumSdCards] = { NoPin, NoPin }; +constexpr Pin SdSpiCSPins[NumSdCards] = { NoPin, NoPin }; constexpr uint32_t ExpectedSdCardSpeed = 25000000; constexpr IRQn SdhcIRQn = HSMCI_IRQn; diff --git a/src/Libraries/sd_mmc/sd_mmc.c b/src/Libraries/sd_mmc/sd_mmc.c index d05eb40a..11d0cd75 100644 --- a/src/Libraries/sd_mmc/sd_mmc.c +++ b/src/Libraries/sd_mmc/sd_mmc.c @@ -1928,6 +1928,19 @@ uint32_t sd_mmc_get_interface_speed(uint8_t slot) #endif +#if SD_MMC_SPI_MEM_CNT != 0 + +// Change the CS pin used by an SPI-connected card slot. Only used by the Duet 3 MB6HC. Linker garbage collection will eliminate this function in other builds. +void sd_mmc_change_cs_pin(uint8_t slot, Pin csPin) noexcept +{ + if (slot >= SD_MMC_HSMCI_MEM_CNT) + { + sd_mmc_spi_change_cs_pin(slot - SD_MMC_HSMCI_MEM_CNT, csPin); + } +} + +#endif + // Initialise for reading blocks // On entry the card is not selected // If SD_MMC_OK is returned then the card is selected, otherwise it is not selected diff --git a/src/Libraries/sd_mmc/sd_mmc.h b/src/Libraries/sd_mmc/sd_mmc.h index 619bf3a1..b71be5bd 100644 --- a/src/Libraries/sd_mmc/sd_mmc.h +++ b/src/Libraries/sd_mmc/sd_mmc.h @@ -177,6 +177,9 @@ void sd_mmc_unmount(uint8_t slot) noexcept; // Get the interface speed in bytes/sec uint32_t sd_mmc_get_interface_speed(uint8_t slot) noexcept; +// Change the CS pin used by an SPI-connected card slot. Only used by the Duet 3 MB6HC. Linker garbage collection will eliminate this function in other builds. +void sd_mmc_change_cs_pin(uint8_t slot, Pin csPin) noexcept; + #endif /** diff --git a/src/Libraries/sd_mmc/sd_mmc_spi.cpp b/src/Libraries/sd_mmc/sd_mmc_spi.cpp index a32336b9..2df31a90 100644 --- a/src/Libraries/sd_mmc/sd_mmc_spi.cpp +++ b/src/Libraries/sd_mmc/sd_mmc_spi.cpp @@ -70,7 +70,7 @@ extern void debugPrintf(const char* fmt, ...) noexcept; static sd_mmc_spi_errno_t sd_mmc_spi_err; //! Slot array of SPI structures -static SharedSpiClient *sd_mmc_spi_devices[SD_MMC_SPI_MEM_CNT]; +static SharedSpiClient *sd_mmc_spi_devices[SD_MMC_SPI_MEM_CNT] = { 0 }; static SharedSpiClient *currentSpiClient = nullptr; //! 32 bits response of the last command @@ -108,7 +108,11 @@ static uint8_t sd_mmc_spi_crc7(uint8_t * buf, uint8_t size) noexcept value = *buf++; for (i = 0; i < 8; i++) { crc <<= 1; +#if 1 // DC + if ((value ^ crc) & 0x80) +#else if ((value & 0x80) ^ (crc & 0x80)) +#endif { crc ^= 0x09; } @@ -348,6 +352,19 @@ void sd_mmc_spi_init(const Pin csPins[SD_MMC_SPI_MEM_CNT]) noexcept } } +#if 1 + +// This function is used by the Duet 3 MB6HC to enable support for a second SD card +void sd_mmc_spi_change_cs_pin(uint8_t spiSlot, Pin csPin) noexcept +{ + if (spiSlot < SD_MMC_SPI_MEM_CNT) + { + sd_mmc_spi_devices[spiSlot]->SetCsPin(csPin); + } +} + +#endif + // Note, every call to sd_mmc_spi_select_device must be matched to a call to sd_mmc_spi_deselect_device so that the SPI mutex gets released! // Unfortunately, sd_mmc.c calls this more than one without deselecting it in between. So check whether it is already selected. bool sd_mmc_spi_select_device(uint8_t slot, uint32_t clock, uint8_t bus_width, bool high_speed) noexcept diff --git a/src/Libraries/sd_mmc/sd_mmc_spi.h b/src/Libraries/sd_mmc/sd_mmc_spi.h index 164bc625..80be7dd5 100644 --- a/src/Libraries/sd_mmc/sd_mmc_spi.h +++ b/src/Libraries/sd_mmc/sd_mmc_spi.h @@ -243,6 +243,9 @@ typedef void (*spiIdleFunc_t)(uint32_t, uint32_t) noexcept; // Set the idle function and return the old one spiIdleFunc_t sd_mmc_spi_set_idle_func(spiIdleFunc_t) noexcept; +// This function is used by the Duet 3 MB6HC to enable support for a second SD card +void sd_mmc_spi_change_cs_pin(uint8_t spiSlot, Pin csPin) noexcept; + #endif //! @} diff --git a/src/Platform/Platform.cpp b/src/Platform/Platform.cpp index 8e1b12f8..b6a14f48 100644 --- a/src/Platform/Platform.cpp +++ b/src/Platform/Platform.cpp @@ -4404,7 +4404,13 @@ GCodeResult Platform::ConfigurePort(GCodeBuffer& gb, const StringRef& reply) THR { // Exactly one of FHJPSR is allowed unsigned int charsPresent = 0; - for (char c : (const char[]){'R', 'J', 'F', 'H', 'P', 'S'}) + for (char c : +#ifdef DUET3_V06 + (const char[]){'D', 'R', 'J', 'F', 'H', 'P', 'S'} +#else + (const char[]){'R', 'J', 'F', 'H', 'P', 'S'} +#endif + ) { charsPresent <<= 1; if (gb.Seen(c)) @@ -4443,6 +4449,10 @@ GCodeResult Platform::ConfigurePort(GCodeBuffer& gb, const StringRef& reply) THR const uint32_t slot = gb.GetLimitedUIValue('R', MaxSpindles); return spindles[slot].Configure(gb, reply); } +#ifdef DUET3_V06 + case 64: // D + return MassStorage::ConfigureSdCard(gb, reply); +#endif default: reply.copy("exactly one of FHJPSR must be given"); diff --git a/src/Platform/RepRap.cpp b/src/Platform/RepRap.cpp index 035818f0..b2c56027 100644 --- a/src/Platform/RepRap.cpp +++ b/src/Platform/RepRap.cpp @@ -238,7 +238,7 @@ constexpr ObjectModelArrayDescriptor RepRap::volumesArrayDescriptor = constexpr ObjectModelArrayDescriptor RepRap::volChangesArrayDescriptor = { nullptr, - [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return NumSdCards; }, + [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return MassStorage::GetNumVolumes(); }, [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue { return ExpressionValue((int32_t)MassStorage::GetVolumeSeq(context.GetLastIndex())); } }; @@ -314,7 +314,7 @@ constexpr ObjectModelTableEntry RepRap::objectModelTable[] = { "trackedObjects", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxTrackedObjects), ObjectModelEntryFlags::verbose }, { "triggers", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxTriggers), ObjectModelEntryFlags::verbose }, #if HAS_MASS_STORAGE - { "volumes", OBJECT_MODEL_FUNC_NOSELF((int32_t)NumSdCards), ObjectModelEntryFlags::verbose }, + { "volumes", OBJECT_MODEL_FUNC_NOSELF((int32_t)MassStorage::GetNumVolumes()), ObjectModelEntryFlags::verbose }, #else { "volumes", OBJECT_MODEL_FUNC_NOSELF((int32_t)0), ObjectModelEntryFlags::verbose }, #endif @@ -1688,14 +1688,14 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) con #if HAS_MASS_STORAGE // Total and mounted volumes size_t mountedCards = 0; - for (size_t i = 0; i < NumSdCards; i++) + for (size_t i = 0; i < MassStorage::GetNumVolumes(); i++) { if (MassStorage::IsDriveMounted(i)) { - mountedCards |= (1 << i); + mountedCards |= (1u << i); } } - response->catf(",\"volumes\":%u,\"mountedVolumes\":%u", NumSdCards, mountedCards); + response->catf(",\"volumes\":%u,\"mountedVolumes\":%u", MassStorage::GetNumVolumes(), mountedCards); #endif // Machine mode and name @@ -2079,7 +2079,7 @@ OutputBuffer *RepRap::GetLegacyStatusResponse(uint8_t type, int seq) const noexc { // Add the static fields response->catf(",\"geometry\":\"%s\",\"axes\":%u,\"totalAxes\":%u,\"axisNames\":\"%s\",\"volumes\":%u,\"numTools\":%u,\"myName\":\"%.s\",\"firmwareName\":\"%.s\"", - move->GetGeometryString(), numVisibleAxes, gCodes->GetTotalAxes(), gCodes->GetAxisLetters(), NumSdCards, GetNumberOfContiguousTools(), myName.c_str(), FIRMWARE_NAME); + move->GetGeometryString(), numVisibleAxes, gCodes->GetTotalAxes(), gCodes->GetAxisLetters(), MassStorage::GetNumVolumes(), GetNumberOfContiguousTools(), myName.c_str(), FIRMWARE_NAME); } response->cat("}\n"); // include a newline to help PanelDue resync diff --git a/src/RepRapFirmware.h b/src/RepRapFirmware.h index 0351298c..2db51861 100644 --- a/src/RepRapFirmware.h +++ b/src/RepRapFirmware.h @@ -101,7 +101,8 @@ enum class PinUsedBy : uint8_t gpout, filamentMonitor, temporaryInput, - sensor + sensor, + sdCard }; #include "Pins.h" diff --git a/src/Storage/MassStorage.cpp b/src/Storage/MassStorage.cpp index 8e21ad70..dcab61c2 100644 --- a/src/Storage/MassStorage.cpp +++ b/src/Storage/MassStorage.cpp @@ -19,6 +19,10 @@ static_assert(SD_MMC_MEM_CNT == NumSdCards); # include <SBC/SbcInterface.h> #endif +#ifdef DUET3_V06 +# include <GCodes/GCodeBuffer/GCodeBuffer.h> +#endif + // A note on using mutexes: // Each SD card volume has its own mutex. There is also one for the file table, and one for the find first/find next buffer. // The FatFS subsystem locks and releases the appropriate volume mutex when it is called. @@ -93,6 +97,10 @@ static uint64_t GetFreeSpace(size_t slot) static const char * const VolPathNames[] = { "0:/", "1:/" }; static_assert(ARRAY_SIZE(VolPathNames) >= NumSdCards, "Incorrect VolPathNames array"); +#ifdef DUET3_V06 +static IoPort sd1Ports[2]; // first element is CS port, second is CD port +#endif + constexpr ObjectModelTableEntry SdCardInfo::objectModelTable[] = { // Within each group, these entries must be in alphabetical order @@ -173,6 +181,41 @@ static FileStore files[MAX_FILES]; #if HAS_MASS_STORAGE +# ifdef DUET3_V06 + +// Return the number of volumes, which on the 6HC is normally 1 but can be increased to 2 +size_t MassStorage::GetNumVolumes() noexcept +{ + return (sd1Ports[0].IsValid()) ? 2 : 1; // we have 2 slots if the second one has a valid CS pin, else 1 +} + +// Configure additional SD card slots +// The card detect pin may be NoPin if the SD card slot doesn't support card detect +GCodeResult MassStorage::ConfigureSdCard(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException) +{ + (void)gb.GetLimitedUIValue('D', 1, 2); // only slot 1 may be configured + IoPort * const portAddresses[2] = { &sd1Ports[0], &sd1Ports[1] }; + if (gb.Seen('C')) + { + const PinAccess accessNeeded[2] = { PinAccess::write1, PinAccess::read }; + if (IoPort::AssignPorts(gb, reply, PinUsedBy::sdCard, 2, portAddresses, accessNeeded) == 0) + { + return GCodeResult::error; + } + sd_mmc_change_cs_pin(1, sd1Ports[0].GetPin()); + info[1].cdPin = sd1Ports[1].GetPin(); + reprap.VolumesUpdated(); + } + else + { + reply.copy("SD card 1 uses pins "); + IoPort::AppendPinNames(reply, 2, portAddresses); + } + return GCodeResult::ok; +} + +# endif + // Sequence number management uint16_t MassStorage::GetVolumeSeq(unsigned int volume) noexcept { @@ -895,7 +938,7 @@ bool MassStorage::CheckDriveMounted(const char* path) noexcept const size_t card = (strlen(path) >= 2 && path[1] == ':' && isDigit(path[0])) ? path[0] - '0' : 0; - return card < NumSdCards && info[card].isMounted; + return card < GetNumVolumes() && info[card].isMounted; } // Return true if any files are open on the file system @@ -941,7 +984,7 @@ bool MassStorage::IsCardDetected(size_t card) noexcept // This may only be called to mount one card at a time. GCodeResult MassStorage::Mount(size_t card, const StringRef& reply, bool reportSuccess) noexcept { - if (card >= NumSdCards) + if (card >= GetNumVolumes()) { reply.copy("SD card number out of range"); return GCodeResult::error; @@ -1037,7 +1080,7 @@ GCodeResult MassStorage::Mount(size_t card, const StringRef& reply, bool reportS // If an error occurs, return true with the error message in 'reply'. GCodeResult MassStorage::Unmount(size_t card, const StringRef& reply) noexcept { - if (card >= NumSdCards) + if (card >= GetNumVolumes()) { reply.copy("SD card number out of range"); return GCodeResult::error; @@ -1058,7 +1101,7 @@ GCodeResult MassStorage::Unmount(size_t card, const StringRef& reply) noexcept bool MassStorage::IsDriveMounted(size_t drive) noexcept { - return drive < NumSdCards + return drive < GetNumVolumes() #if HAS_MASS_STORAGE && info[drive].isMounted #endif @@ -1166,7 +1209,7 @@ void MassStorage::RecordSimulationTime(const char *printingFilePath, uint32_t si // Get information about the SD card and interface speed MassStorage::InfoResult MassStorage::GetCardInfo(size_t slot, uint64_t& capacity, uint64_t& freeSpace, uint32_t& speed, uint32_t& clSize) noexcept { - if (slot >= NumSdCards) + if (slot >= GetNumVolumes()) { return InfoResult::badSlot; } diff --git a/src/Storage/MassStorage.h b/src/Storage/MassStorage.h index 86b0782f..854d56b4 100644 --- a/src/Storage/MassStorage.h +++ b/src/Storage/MassStorage.h @@ -48,6 +48,12 @@ namespace MassStorage bool FileExists(const char *filePath) noexcept; void CloseAllFiles() noexcept; void Spin() noexcept; + +# ifdef DUET3_V06 + size_t GetNumVolumes() noexcept; // The number of SD slots may be 1 or 2 on the 6HC +# else + inline size_t GetNumVolumes() noexcept { return NumSdCards; } +# endif #endif #if HAS_MASS_STORAGE || HAS_SBC_INTERFACE @@ -99,8 +105,11 @@ namespace MassStorage InfoResult GetCardInfo(size_t slot, uint64_t& capacity, uint64_t& freeSpace, uint32_t& speed, uint32_t& clSize) noexcept; +# ifdef DUET3_V06 + GCodeResult ConfigureSdCard(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException); // Configure additional SD card slots +# endif + # if SUPPORT_OBJECT_MODEL - inline size_t GetNumVolumes() noexcept { return NumSdCards; } const ObjectModel *_ecv_from GetVolume(size_t vol) noexcept; # endif @@ -108,4 +117,5 @@ namespace MassStorage } + #endif |