diff options
author | David Crocker <dcrocker@eschertech.com> | 2019-12-09 22:47:33 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2019-12-09 22:47:33 +0300 |
commit | 14db90f06f74494ee811cf1ae4f12190756ed2ca (patch) | |
tree | c5c8332e39db09a5df8c4475cfc03e184ed46016 | |
parent | bf7be88b40ee5b48aacd4d78917cfaa94f7aa3d2 (diff) |
Support loading IAP in RAM
Support loading IAP in RAM instead of flash, to make more flash memory available for the main firmware
-rw-r--r-- | src/Duet3_V06/Pins_Duet3_V06.h | 23 | ||||
-rw-r--r-- | src/DuetM/Pins_DuetM.h | 20 | ||||
-rw-r--r-- | src/DuetNG/Pins_DuetNG.h | 25 | ||||
-rw-r--r-- | src/GCodes/GCodes3.cpp | 2 | ||||
-rw-r--r-- | src/GCodes/GCodes4.cpp | 2 | ||||
-rw-r--r-- | src/Linux/LinuxInterface.cpp | 27 | ||||
-rw-r--r-- | src/Movement/Move.cpp | 4 | ||||
-rw-r--r-- | src/Movement/StepperDrivers/TMC22xx.cpp | 15 | ||||
-rw-r--r-- | src/Movement/StepperDrivers/TMC22xx.h | 1 | ||||
-rw-r--r-- | src/Movement/StepperDrivers/TMC2660.cpp | 8 | ||||
-rw-r--r-- | src/Movement/StepperDrivers/TMC2660.h | 1 | ||||
-rw-r--r-- | src/Movement/StepperDrivers/TMC51xx.cpp | 9 | ||||
-rw-r--r-- | src/Movement/StepperDrivers/TMC51xx.h | 1 | ||||
-rw-r--r-- | src/Networking/LwipEthernet/GMAC/ethernet_sam.h | 3 | ||||
-rw-r--r-- | src/Networking/LwipEthernet/GMAC/same70_gmac.cpp | 13 | ||||
-rw-r--r-- | src/Networking/LwipEthernet/GMAC/same70_gmac.h | 12 | ||||
-rw-r--r-- | src/Networking/LwipEthernet/LwipEthernetInterface.cpp | 1 | ||||
-rw-r--r-- | src/Networking/Network.cpp | 6 | ||||
-rw-r--r-- | src/Platform.cpp | 283 | ||||
-rw-r--r-- | src/Platform.h | 6 | ||||
-rw-r--r-- | src/RepRap.cpp | 314 | ||||
-rw-r--r-- | src/RepRap.h | 8 | ||||
-rw-r--r-- | src/Version.h | 2 |
23 files changed, 444 insertions, 342 deletions
diff --git a/src/Duet3_V06/Pins_Duet3_V06.h b/src/Duet3_V06/Pins_Duet3_V06.h index 668cfd6e..3a95749d 100644 --- a/src/Duet3_V06/Pins_Duet3_V06.h +++ b/src/Duet3_V06/Pins_Duet3_V06.h @@ -7,7 +7,22 @@ const size_t NumFirmwareUpdateModules = 1; #define IAP_FIRMWARE_FILE "Duet3Firmware_" BOARD_SHORT_NAME ".bin" -#define IAP_UPDATE_FILE "Duet3iap_sd_" BOARD_SHORT_NAME ".bin" + +#define IAP_IN_RAM 0 + +#if IAP_IN_RAM +# define IAP_UPDATE_FILE "Duet3iap_sd_ram_" BOARD_SHORT_NAME ".bin" +constexpr uint32_t IAP_IMAGE_START = 0x20450000; // last 64kb of RAM +#else +# define IAP_UPDATE_FILE "Duet3iap_sd_" BOARD_SHORT_NAME ".bin" + +// SAME70 Flash locations +// These are designed to work with 1Mbyte flash processors as well as 2Mbyte +// We can only erase complete 128kb sectors on the SAME70, so we allow 128Kb for IAP +constexpr uint32_t IAP_IMAGE_START = 0x004E0000; +constexpr uint32_t IAP_IMAGE_END = 0x004FFFFF; +#endif + // Features definition #define HAS_LWIP_NETWORKING 1 @@ -262,12 +277,6 @@ constexpr unsigned int NumNamedPins = ARRAY_SIZE(PinTable); // Function to look up a pin name pass back the corresponding index into the pin table bool LookupPinName(const char *pn, LogicalPin& lpin, bool& hardwareInverted); -// SAME70 Flash locations -// These are designed to work with 1Mbyte flash processors as well as 2Mbyte -// We can only erase complete 128kb sectors on the SAME70, so we allow 128Kb for IAP -constexpr uint32_t IAP_FLASH_START = 0x004E0000; -constexpr uint32_t IAP_FLASH_END = 0x004FFFFF; - // Duet pin numbers for the Linux interface constexpr Pin LinuxTfrReadyPin = PortEPin(2); Spi * const LinuxSpi = SPI1; diff --git a/src/DuetM/Pins_DuetM.h b/src/DuetM/Pins_DuetM.h index 234d761f..8215914e 100644 --- a/src/DuetM/Pins_DuetM.h +++ b/src/DuetM/Pins_DuetM.h @@ -12,7 +12,21 @@ #define DEFAULT_BOARD_TYPE BoardType::DuetM_10 constexpr size_t NumFirmwareUpdateModules = 1; // 1 module #define IAP_FIRMWARE_FILE "DuetMaestroFirmware.bin" -#define IAP_UPDATE_FILE "iap4s.bin" + +#define IAP_IN_RAM 1 + +#if IAP_IN_RAM + +# define IAP_UPDATE_FILE "DuetMaestroIAP.bin" +constexpr uint32_t IAP_IMAGE_START = 0x20010000; + +#else + +# define IAP_UPDATE_FILE "iap4s.bin" +constexpr uint32_t IAP_IMAGE_START = 0x00470000; +constexpr uint32_t IAP_IMAGE_END = 0x0047FFFF; // we allow a full 64K on the SAM4 + +#endif // Features definition #define HAS_LWIP_NETWORKING 0 @@ -259,10 +273,6 @@ constexpr const char *DefaultZProbePinNames = "^zprobe.in+zprobe.mod"; constexpr const char *DefaultFanPinNames[] = { "fan0", "fan1", "fan2" }; constexpr PwmFrequency DefaultFanPwmFrequencies[] = { DefaultFanPwmFreq }; -// SAM4S Flash locations (may be expanded in the future) -constexpr uint32_t IAP_FLASH_START = 0x00470000; -constexpr uint32_t IAP_FLASH_END = 0x0047FFFF; // we allow a full 64K on the SAM4 - // Duet pin numbers to control the W5500 interface constexpr Pin W5500ResetPin = PortCPin(13); // Low on this in holds the W5500 in reset constexpr Pin W5500SsPin = PortAPin(11); // SPI NPCS pin to W5500 diff --git a/src/DuetNG/Pins_DuetNG.h b/src/DuetNG/Pins_DuetNG.h index 8a34a5ef..f183001d 100644 --- a/src/DuetNG/Pins_DuetNG.h +++ b/src/DuetNG/Pins_DuetNG.h @@ -4,11 +4,22 @@ // Pins definition file for Duet 2 WiFi/Ethernet // This file is normally #included by #including RepRapFirmware.h, which includes this file -#define FIRMWARE_NAME "RepRapFirmware for Duet 2 WiFi/Ethernet" -#define DEFAULT_BOARD_TYPE BoardType::DuetWiFi_10 -#define IAP_FIRMWARE_FILE "Duet2CombinedFirmware.bin" -#define IAP_UPDATE_FILE "iap4e.bin" // using the same IAP file for both Duet WiFi and Duet Ethernet -#define WIFI_FIRMWARE_FILE "DuetWiFiServer.bin" +#define FIRMWARE_NAME "RepRapFirmware for Duet 2 WiFi/Ethernet" +#define DEFAULT_BOARD_TYPE BoardType::DuetWiFi_10 +#define IAP_FIRMWARE_FILE "Duet2CombinedFirmware.bin" + +#define IAP_IN_RAM 1 + +#if IAP_IN_RAM +constexpr uint32_t IAP_IMAGE_START = 0x20010000; // IAP is loaded into the second 64kb of RAM +# define IAP_UPDATE_FILE "Duet2CombinedIAP.bin" // using the same IAP file for both Duet WiFi and Duet Ethernet +#else +constexpr uint32_t IAP_IMAGE_START = 0x00470000; +constexpr uint32_t IAP_IMAGE_END = 0x0047FFFF; // we allow a full 64K on the SAM4 +# define IAP_UPDATE_FILE "iap4e.bin" // using the same IAP file for both Duet WiFi and Duet Ethernet +#endif + +#define WIFI_FIRMWARE_FILE "DuetWiFiServer.bin" constexpr size_t NumFirmwareUpdateModules = 4; // 3 modules, plus one for manual upload to WiFi module (module 2 is now unused) @@ -315,10 +326,6 @@ constexpr const char *DefaultZProbePinNames = "^zprobe.in+zprobe.mod"; constexpr const char *DefaultFanPinNames[] = { "fan0", "fan1", "fan2" }; constexpr PwmFrequency DefaultFanPwmFrequencies[] = { DefaultFanPwmFreq }; -// SAM4E Flash locations (may be expanded in the future) -constexpr uint32_t IAP_FLASH_START = 0x00470000; -constexpr uint32_t IAP_FLASH_END = 0x0047FFFF; // we allow a full 64K on the SAM4 - // Duet pin numbers to control the WiFi interface on the Duet WiFi constexpr Pin EspResetPin = PortEPin(4); // Low on this in holds the WiFi module in reset (ESP_RESET) constexpr Pin EspEnablePin = PortEPin(5); // High to enable the WiFi module, low to power it down (ESP_CH_PD) diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp index 1ee06696..43e52665 100644 --- a/src/GCodes/GCodes3.cpp +++ b/src/GCodes/GCodes3.cpp @@ -1059,7 +1059,7 @@ GCodeResult GCodes::UpdateFirmware(GCodeBuffer& gb, const StringRef &reply) return GCodeResult::error; } #endif - if ((firmwareUpdateModuleMap & 1) != 0 && !platform.CheckFirmwareUpdatePrerequisites(reply)) + if ((firmwareUpdateModuleMap & 1) != 0 && !reprap.CheckFirmwareUpdatePrerequisites(reply)) { firmwareUpdateModuleMap = 0; return GCodeResult::error; diff --git a/src/GCodes/GCodes4.cpp b/src/GCodes/GCodes4.cpp index 11fab53a..1e16be06 100644 --- a/src/GCodes/GCodes4.cpp +++ b/src/GCodes/GCodes4.cpp @@ -439,7 +439,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) { // Update main firmware firmwareUpdateModuleMap = 0; - platform.UpdateFirmware(); + reprap.UpdateFirmware(); // The above call does not return unless an error occurred } isFlashing = false; diff --git a/src/Linux/LinuxInterface.cpp b/src/Linux/LinuxInterface.cpp index 9b8ae2ef..fb11db57 100644 --- a/src/Linux/LinuxInterface.cpp +++ b/src/Linux/LinuxInterface.cpp @@ -20,7 +20,7 @@ LinuxInterface::LinuxInterface() : transfer(new DataTransfer()), wasConnected(false), numDisconnects(0), reportPause(false), rxPointer(0), txPointer(0), txLength(0), sendBufferUpdate(true), - iapWritePointer(IAP_FLASH_START), gcodeReply(new OutputStack()) + iapWritePointer(IAP_IMAGE_START), gcodeReply(new OutputStack()) { } @@ -213,17 +213,22 @@ void LinuxInterface::Spin() // Write another chunk of the IAP binary to the designated Flash area case LinuxRequest::WriteIap: { - if (iapWritePointer == IAP_FLASH_START) +#if !IAP_IN_RAM + if (iapWritePointer == IAP_IMAGE_START) { // The EWP command is not supported for non-8KByte sectors in the SAM4 and SAME70 series. // So we have to unlock and erase the complete 64Kb or 128kb sector first. One sector is always enough to contain the IAP. - flash_unlock(IAP_FLASH_START, IAP_FLASH_END, nullptr, nullptr); - flash_erase_sector(IAP_FLASH_START); + flash_unlock(IAP_IMAGE_START, IAP_IMAGE_END, nullptr, nullptr); + flash_erase_sector(IAP_IMAGE_START); } - +#endif const char *dataToWrite = transfer->ReadData(packet->length); - size_t bytesWritten = 0; +#if IAP_IN_RAM + memcpy(reinterpret_cast<char *>(iapWritePointer), dataToWrite, packet->length); + iapWritePointer += packet->length; +#else + size_t bytesWritten = 0; do { size_t bytesToWrite = min<size_t>(IFLASH_PAGE_SIZE, packet->length - bytesWritten), retry = 0; @@ -259,15 +264,17 @@ void LinuxInterface::Spin() dataToWrite += bytesToWrite; iapWritePointer += bytesToWrite; } while (bytesWritten != packet->length); - +#endif break; } // Launch the IAP binary case LinuxRequest::StartIap: +#if !IAP_IN_RAM // Lock the whole IAP flash area again and start the IAP binary - flash_lock(IAP_FLASH_START, IAP_FLASH_END, nullptr, nullptr); - reprap.GetPlatform().StartIap(); + flash_lock(IAP_IMAGE_START, IAP_IMAGE_END, nullptr, nullptr); +#endif + reprap.StartIap(); break; // Assign filament @@ -410,7 +417,7 @@ void LinuxInterface::Spin() rxPointer = txPointer = txLength = 0; sendBufferUpdate = true; - iapWritePointer = IAP_FLASH_START; + iapWritePointer = IAP_IMAGE_START; if (!requestedFileName.IsEmpty()) { diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp index f63afc54..b73ba602 100644 --- a/src/Movement/Move.cpp +++ b/src/Movement/Move.cpp @@ -119,6 +119,10 @@ void Move::Exit() { StepTimer::DisableTimerInterrupt(); mainDDARing.Exit(); +#if SUPPORT_LASER || SUPPORT_IOBITS + delete laserTask; + laserTask = nullptr; +#endif active = false; // don't accept any more moves } diff --git a/src/Movement/StepperDrivers/TMC22xx.cpp b/src/Movement/StepperDrivers/TMC22xx.cpp index 4c0ccda4..f14cd25c 100644 --- a/src/Movement/StepperDrivers/TMC22xx.cpp +++ b/src/Movement/StepperDrivers/TMC22xx.cpp @@ -1033,6 +1033,21 @@ namespace SmartDrivers } } + // Shut down the drivers and stop any related interrupts. Don't call Spin() again after calling this as it may re-enable them. + void Exit() + { + pinMode(GlobalTmc22xxEnablePin, OUTPUT_HIGH); +#if TMC22xx_HAS_MUX + NVIC_DisableIRQ(TMC22xx_UART_IRQn); +#else + for (size_t drive = 0; drive < numTmc22xxDrivers; ++drive) + { + NVIC_DisableIRQ(TMC22xxUartIRQns[drive]); + } +#endif + driversState = DriversState::noPower; + } + void SetAxisNumber(size_t drive, uint32_t axisNumber) { if (drive < numTmc22xxDrivers) diff --git a/src/Movement/StepperDrivers/TMC22xx.h b/src/Movement/StepperDrivers/TMC22xx.h index 08e49cc4..566c5806 100644 --- a/src/Movement/StepperDrivers/TMC22xx.h +++ b/src/Movement/StepperDrivers/TMC22xx.h @@ -38,6 +38,7 @@ namespace SmartDrivers { void Init(const Pin[NumDirectDrivers], size_t numTmcDrivers) pre(numTmcDrivers <= NumDirectDrivers); + void Exit(); void SetAxisNumber(size_t drive, uint32_t axisNumber); uint32_t GetAxisNumber(size_t drive); void SetCurrent(size_t drive, float current); diff --git a/src/Movement/StepperDrivers/TMC2660.cpp b/src/Movement/StepperDrivers/TMC2660.cpp index 45ae10d1..53907a7e 100644 --- a/src/Movement/StepperDrivers/TMC2660.cpp +++ b/src/Movement/StepperDrivers/TMC2660.cpp @@ -929,6 +929,14 @@ namespace SmartDrivers #endif } + // Shut down the drivers and stop any related interrupts. Don't call Spin() again after calling this as it may re-enable them. + void Exit() + { + digitalWrite(GlobalTmc2660EnablePin, HIGH); + NVIC_DisableIRQ(TMC2660_SPI_IRQn); + driversPowered = false; + } + void SetAxisNumber(size_t driver, uint32_t axisNumber) { if (driver < numTmc2660Drivers) diff --git a/src/Movement/StepperDrivers/TMC2660.h b/src/Movement/StepperDrivers/TMC2660.h index 90336c7f..4878aa2d 100644 --- a/src/Movement/StepperDrivers/TMC2660.h +++ b/src/Movement/StepperDrivers/TMC2660.h @@ -28,6 +28,7 @@ namespace SmartDrivers { void Init(const Pin[NumDirectDrivers], size_t numTmcDrivers) pre(numTmcDrivers <= NumDirectDrivers); + void Exit(); void Spin(bool powered); void TurnDriversOff(); diff --git a/src/Movement/StepperDrivers/TMC51xx.cpp b/src/Movement/StepperDrivers/TMC51xx.cpp index ec595407..60e0a30c 100644 --- a/src/Movement/StepperDrivers/TMC51xx.cpp +++ b/src/Movement/StepperDrivers/TMC51xx.cpp @@ -1322,6 +1322,15 @@ void SmartDrivers::Init() tmcTask.Create(TmcLoop, "TMC", nullptr, TaskPriority::TmcPriority); } +// Shut down the drivers and stop any related interrupts. Don't call Spin() again after calling this as it may re-enable them. +void SmartDrivers::Exit() +{ + digitalWrite(GlobalTmc51xxEnablePin, HIGH); + NVIC_DisableIRQ(TMC51xx_SPI_IRQn); + tmcTask.TerminateAndUnlink(); + driversState = DriversState::noPower; +} + void SmartDrivers::SetAxisNumber(size_t driver, uint32_t axisNumber) { if (driver < numTmc51xxDrivers) diff --git a/src/Movement/StepperDrivers/TMC51xx.h b/src/Movement/StepperDrivers/TMC51xx.h index a919026d..cc2c454e 100644 --- a/src/Movement/StepperDrivers/TMC51xx.h +++ b/src/Movement/StepperDrivers/TMC51xx.h @@ -27,6 +27,7 @@ const uint32_t TMC_RR_SGRESULT = 0x3FF; // 10-bit stallGuard2 result namespace SmartDrivers { void Init(); + void Exit(); void Spin(bool powered); void TurnDriversOff(); diff --git a/src/Networking/LwipEthernet/GMAC/ethernet_sam.h b/src/Networking/LwipEthernet/GMAC/ethernet_sam.h index 23266cf3..06516e19 100644 --- a/src/Networking/LwipEthernet/GMAC/ethernet_sam.h +++ b/src/Networking/LwipEthernet/GMAC/ethernet_sam.h @@ -54,6 +54,9 @@ // Perform low-level initialisation of the network interface void init_ethernet(IPAddress ipAddress, IPAddress netMask, IPAddress gateWay); +// Terminate Ethernet and stop any interrupts, tasks etc. Used when shutting down the whole system. +inline void ethernet_terminate() { ethernetif_terminate(); } + // Configure the ethernet interface void ethernet_configure_interface(const uint8_t macAddress[], const char *hostname); diff --git a/src/Networking/LwipEthernet/GMAC/same70_gmac.cpp b/src/Networking/LwipEthernet/GMAC/same70_gmac.cpp index 895f7d22..863f4018 100644 --- a/src/Networking/LwipEthernet/GMAC/same70_gmac.cpp +++ b/src/Networking/LwipEthernet/GMAC/same70_gmac.cpp @@ -683,8 +683,6 @@ err_t ethernetif_init(struct netif *netif) return ERR_OK; } -#if 1 // chrishamm - void ethernetif_hardware_init(void) { /* Enable GMAC clock. */ @@ -828,6 +826,15 @@ void ethernetif_set_mac_address(const uint8_t macAddress[]) } } +// This is called when we shut down +void ethernetif_terminate() +{ + NVIC_DisableIRQ(GMAC_IRQn); +#if LWIP_GMAC_TASK + ethernetTask.TerminateAndUnlink(); +#endif +} + extern "C" u32_t millis(); extern "C" u32_t sys_now(void) @@ -835,4 +842,4 @@ extern "C" u32_t sys_now(void) return millis(); } -#endif +// End diff --git a/src/Networking/LwipEthernet/GMAC/same70_gmac.h b/src/Networking/LwipEthernet/GMAC/same70_gmac.h index 7c676ff7..6d494faf 100644 --- a/src/Networking/LwipEthernet/GMAC/same70_gmac.h +++ b/src/Networking/LwipEthernet/GMAC/same70_gmac.h @@ -54,12 +54,14 @@ extern "C" { #include "lwip/netif.h" #include "netif/etharp.h" -err_t ethernetif_init(struct netif *netif); // called by LwIP to initialise the interface +#ifdef __cplusplus +} -bool ethernetif_input(struct netif *netif); // checks for a new packet and returns true if one was processed +err_t ethernetif_init(struct netif *netif); // called by LwIP to initialise the interface +void ethernetif_terminate(); // called when we shut down -#if 1 // chrishamm +bool ethernetif_input(struct netif *netif); // checks for a new packet and returns true if one was processed void ethernetif_hardware_init(void); // initialises the low-level hardware interface @@ -76,10 +78,6 @@ void ethernetif_set_mac_address(const uint8_t macAddress[]); #endif -#ifdef __cplusplus -} -#endif - // Error counters extern unsigned int rxErrorCount; extern unsigned int rxBuffersNotFullyPopulatedCount; diff --git a/src/Networking/LwipEthernet/LwipEthernetInterface.cpp b/src/Networking/LwipEthernet/LwipEthernetInterface.cpp index f32bf251..79378030 100644 --- a/src/Networking/LwipEthernet/LwipEthernetInterface.cpp +++ b/src/Networking/LwipEthernet/LwipEthernetInterface.cpp @@ -360,6 +360,7 @@ void LwipEthernetInterface::Activate() void LwipEthernetInterface::Exit() { Stop(); + ethernet_terminate(); } // Get the network state into the reply buffer, returning true if there is some sort of error diff --git a/src/Networking/Network.cpp b/src/Networking/Network.cpp index 038078a4..cdd26ed3 100644 --- a/src/Networking/Network.cpp +++ b/src/Networking/Network.cpp @@ -345,7 +345,11 @@ void Network::Exit() TelnetResponder::Disable(); #endif - // TODO: close down the network and suspend the network task. Not trivial because currently, the caller may be the network task. + if (TaskBase::GetCallerTaskHandle() != networkTask.GetHandle()) + { + // Terminate the network task. Not trivial because currently, the caller may be the network task. + networkTask.TerminateAndUnlink(); + } } // Get the network state into the reply buffer, returning true if there is some sort of error diff --git a/src/Platform.cpp b/src/Platform.cpp index 221b914a..38320b1c 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -575,7 +575,7 @@ void Platform::Init() for (size_t i = 0; i < ARRAY_SIZE(DefaultGpioPinNames); ++i) { String<1> dummy; - gpioPorts[i].AssignPort(DefaultGpioPinNames[i], dummy.GetRef(), PinUsedBy::gpio, PinAccess::pwm); + gpioPorts[i].port.AssignPort(DefaultGpioPinNames[i], dummy.GetRef(), PinUsedBy::gpio, PinAccess::pwm); } #endif @@ -645,276 +645,6 @@ void Platform::Init() active = true; } -// Check the prerequisites for updating the main firmware. Return True if satisfied, else print a message to 'reply' and return false. -bool Platform::CheckFirmwareUpdatePrerequisites(const StringRef& reply) -{ -#if HAS_MASS_STORAGE - FileStore * const firmwareFile = OpenFile(DEFAULT_SYS_DIR, IAP_FIRMWARE_FILE, OpenMode::read); - if (firmwareFile == nullptr) - { - reply.printf("Firmware binary \"%s\" not found", IAP_FIRMWARE_FILE); - return false; - } - - // Check that the binary looks sensible. The first word is the initial stack pointer, which should be the top of RAM. - uint32_t firstDword; - bool ok = firmwareFile->Read(reinterpret_cast<char*>(&firstDword), sizeof(firstDword)) == (int)sizeof(firstDword); - firmwareFile->Close(); - if (!ok || firstDword != -#if SAM3XA - IRAM1_ADDR + IRAM1_SIZE -#else - IRAM_ADDR + IRAM_SIZE -#endif - ) - { - reply.printf("Firmware binary \"%s\" is not valid for this electronics", IAP_FIRMWARE_FILE); - return false; - } - - if (!FileExists(DEFAULT_SYS_DIR, IAP_UPDATE_FILE)) - { - reply.printf("In-application programming binary \"%s\" not found", IAP_UPDATE_FILE); - return false; - } -#endif - - return true; -} - -// Update the firmware. Prerequisites should be checked before calling this. -void Platform::UpdateFirmware() -{ -#if HAS_MASS_STORAGE - FileStore * const iapFile = OpenFile(DEFAULT_SYS_DIR, IAP_UPDATE_FILE, OpenMode::read); - if (iapFile == nullptr) - { - MessageF(FirmwareUpdateMessage, "IAP file '" IAP_UPDATE_FILE "' not found\n"); - return; - } - -#if SUPPORT_12864_LCD - reprap.GetDisplay().UpdatingFirmware(); // put the firmware update message on the display -#endif - - // The machine will be unresponsive for a few seconds, don't risk damaging the heaters... - reprap.EmergencyStop(); - - // Step 0 - disable the cache because it interferes with flash memory access - Cache::Disable(); - -#if USE_MPU - //TODO consider setting flash memory to strongly-ordered instead - ARM_MPU_Disable(); -#endif - - // Step 1 - Write update binary to Flash and overwrite the remaining space with zeros - // On the SAM3X, leave the last 1KB of Flash memory untouched, so we can reuse the NvData after this update - -#if !defined(IFLASH_PAGE_SIZE) && defined(IFLASH0_PAGE_SIZE) -# define IFLASH_PAGE_SIZE IFLASH0_PAGE_SIZE -#endif - - // Use a 32-bit aligned buffer. This gives us the option of calling the EFC functions directly in future. - uint32_t data32[IFLASH_PAGE_SIZE/4]; - char* const data = reinterpret_cast<char *>(data32); - -#if SAM4E || SAM4S || SAME70 - // The EWP command is not supported for non-8KByte sectors in the SAM4 and SAME70 series. - // So we have to unlock and erase the complete 64Kb or 128kb sector first. One sector is always enough to contain the IAP. - flash_unlock(IAP_FLASH_START, IAP_FLASH_END, nullptr, nullptr); - flash_erase_sector(IAP_FLASH_START); - - for (uint32_t flashAddr = IAP_FLASH_START; flashAddr < IAP_FLASH_END; flashAddr += IFLASH_PAGE_SIZE) - { - const int bytesRead = iapFile->Read(data, IFLASH_PAGE_SIZE); - - if (bytesRead > 0) - { - // Do we have to fill up the remaining buffer with zeros? - if (bytesRead != IFLASH_PAGE_SIZE) - { - memset(data + bytesRead, 0, sizeof(data[0]) * (IFLASH_PAGE_SIZE - bytesRead)); - } - - // Write one page at a time - cpu_irq_disable(); - const uint32_t rc = flash_write(flashAddr, data, IFLASH_PAGE_SIZE, 0); - cpu_irq_enable(); - - if (rc != FLASH_RC_OK) - { - MessageF(FirmwareUpdateErrorMessage, "flash write failed, code=%" PRIu32 ", address=0x%08" PRIx32 "\n", rc, flashAddr); - return; - } - - // Verify written data - if (memcmp(reinterpret_cast<void *>(flashAddr), data, bytesRead) != 0) - { - MessageF(FirmwareUpdateErrorMessage, "verify during flash write failed, address=0x%08" PRIx32 "\n", flashAddr); - return; - } - } - else - { - // Fill up the remaining space with zeros - memset(data, 0, sizeof(data[0]) * sizeof(data)); - cpu_irq_disable(); - flash_write(flashAddr, data, IFLASH_PAGE_SIZE, 0); - cpu_irq_enable(); - } - } - - // Re-lock the whole area - flash_lock(IAP_FLASH_START, IAP_FLASH_END, nullptr, nullptr); - -#else // SAM3X code - - for (uint32_t flashAddr = IAP_FLASH_START; flashAddr < IAP_FLASH_END; flashAddr += IFLASH_PAGE_SIZE) - { - const int bytesRead = iapFile->Read(data, IFLASH_PAGE_SIZE); - - if (bytesRead > 0) - { - // Do we have to fill up the remaining buffer with zeros? - if (bytesRead != IFLASH_PAGE_SIZE) - { - memset(data + bytesRead, 0, sizeof(data[0]) * (IFLASH_PAGE_SIZE - bytesRead)); - } - - // Write one page at a time - cpu_irq_disable(); - - const char* op = "unlock"; - uint32_t rc = flash_unlock(flashAddr, flashAddr + IFLASH_PAGE_SIZE - 1, nullptr, nullptr); - - if (rc == FLASH_RC_OK) - { - op = "write"; - rc = flash_write(flashAddr, data, IFLASH_PAGE_SIZE, 1); - } - if (rc == FLASH_RC_OK) - { - op = "lock"; - rc = flash_lock(flashAddr, flashAddr + IFLASH_PAGE_SIZE - 1, nullptr, nullptr); - } - cpu_irq_enable(); - - if (rc != FLASH_RC_OK) - { - MessageF(FirmwareUpdateErrorMessage, "flash %s failed, code=%" PRIu32 ", address=0x%08" PRIx32 "\n", op, rc, flashAddr); - return; - } - // Verify written data - if (memcmp(reinterpret_cast<void *>(flashAddr), data, bytesRead) != 0) - { - MessageF(FirmwareUpdateErrorMessage, "verify during flash write failed, address=0x%08" PRIx32 "\n", flashAddr); - return; - } - } - else - { - // Fill up the remaining space - memset(data, 0, sizeof(data[0]) * sizeof(data)); - cpu_irq_disable(); - flash_unlock(flashAddr, flashAddr + IFLASH_PAGE_SIZE - 1, nullptr, nullptr); - flash_write(flashAddr, data, IFLASH_PAGE_SIZE, 1); - flash_lock(flashAddr, flashAddr + IFLASH_PAGE_SIZE - 1, nullptr, nullptr); - cpu_irq_enable(); - } - } -#endif - - iapFile->Close(); - - StartIap(); -#endif -} - -void Platform::StartIap() -{ - Message(AuxMessage, "Updating main firmware\n"); - Message(UsbMessage, "Shutting down USB interface to update main firmware. Try reconnecting after 30 seconds.\n"); - - // Allow time for the firmware update message to be sent - const uint32_t now = millis(); - while (FlushMessages() && millis() - now < 2000) { } - - // Step 2 - Let the firmware do whatever is necessary before we exit this program - reprap.Exit(); - - // Step 3 - Reallocate the vector table and program entry point to the new IAP binary - // This does essentially what the Atmel AT02333 paper suggests (see 3.2.2 ff) - - // Disable all IRQs - SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk; // disable the system tick exception - cpu_irq_disable(); - for (size_t i = 0; i < 8; i++) - { - NVIC->ICER[i] = 0xFFFFFFFF; // Disable IRQs - NVIC->ICPR[i] = 0xFFFFFFFF; // Clear pending IRQs - } - - // Disable all PIO IRQs, because the core assumes they are all disabled when setting them up - PIOA->PIO_IDR = 0xFFFFFFFF; - PIOB->PIO_IDR = 0xFFFFFFFF; - PIOC->PIO_IDR = 0xFFFFFFFF; -#ifdef PIOD - PIOD->PIO_IDR = 0xFFFFFFFF; -#endif -#ifdef ID_PIOE - PIOE->PIO_IDR = 0xFFFFFFFF; -#endif - -#if HAS_MASS_STORAGE - // Newer versions of iap4e.bin reserve space above the stack for us to pass the firmware filename - static const char filename[] = DEFAULT_SYS_DIR IAP_FIRMWARE_FILE; - const uint32_t topOfStack = *reinterpret_cast<uint32_t *>(IAP_FLASH_START); - if (topOfStack + sizeof(filename) <= -# if SAM3XA - IRAM1_ADDR + IRAM1_SIZE -# else - IRAM_ADDR + IRAM_SIZE -# endif - ) - { - memcpy(reinterpret_cast<char*>(topOfStack), filename, sizeof(filename)); - } -#endif - -#if defined(DUET_NG) || defined(DUET_M) - IoPort::WriteDigital(DiagPin, false); // turn the DIAG LED off -#endif - - wdt_restart(WDT); // kick the watchdog one last time - -#if SAM4E || SAME70 - rswdt_restart(RSWDT); // kick the secondary watchdog -#endif - - // Modify vector table location - __DSB(); - __ISB(); - SCB->VTOR = ((uint32_t)IAP_FLASH_START & SCB_VTOR_TBLOFF_Msk); - __DSB(); - __ISB(); - - cpu_irq_enable(); - - __asm volatile ("mov r3, %0" : : "r" (IAP_FLASH_START) : "r3"); - - // We are using separate process and handler stacks. Put the process stack 1K bytes below the handler stack. - __asm volatile ("ldr r1, [r3]"); - __asm volatile ("msr msp, r1"); - __asm volatile ("sub r1, #1024"); - __asm volatile ("mov sp, r1"); - - __asm volatile ("isb"); - __asm volatile ("ldr r1, [r3, #4]"); - __asm volatile ("orr r1, r1, #1"); - __asm volatile ("bx r1"); -} - // Send the beep command to the aux channel. There is no flow control on this port, so it can't block for long. void Platform::Beep(int freq, int ms) { @@ -943,6 +673,9 @@ void Platform::Exit() #if HAS_MASS_STORAGE MassStorage::CloseAllFiles(); #endif +#if HAS_SMART_DRIVERS + SmartDrivers::Exit(); +#endif // Release the aux output stack (should release the others too!) while (auxGCodeReply != nullptr) @@ -2392,6 +2125,14 @@ GCodeResult Platform::DiagnosticTest(GCodeBuffer& gb, const StringRef& reply, un ); break; + case (unsigned int)DiagnosticTestType::PrintObjectAddresses: + reply.printf + ("Platform %08" PRIx32 "-%08" PRIx32 "\nGCodes %08" PRIx32 "-%08" PRIx32, + reinterpret_cast<uint32_t>(this), reinterpret_cast<uint32_t>(this) + sizeof(Platform) - 1, + reinterpret_cast<uint32_t>(&reprap.GetGCodes()), reinterpret_cast<uint32_t>(&reprap.GetGCodes()) + sizeof(GCodes) - 1 + ); + break; + #ifdef DUET_NG case (unsigned int)DiagnosticTestType::PrintExpanderStatus: reply.printf("Expander status %04X\n", DuetExpansion::DiagnosticRead()); diff --git a/src/Platform.h b/src/Platform.h index e75170fa..8fd11bfb 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -147,6 +147,7 @@ enum class DiagnosticTestType : unsigned int TimeSinCos = 103, // do a timing test on the trig functions TimeSDWrite = 104, // do a write timing test on the SD card PrintObjectSizes = 105, // print the sizes of various objects + PrintObjectAddresses = 106, // print the addresses and sizes of various objects TestWatchdog = 1001, // test that we get a watchdog reset if the tick interrupt stops TestSpinLockup = 1002, // test that we get a software reset if a Spin() function takes too long @@ -456,11 +457,6 @@ public: void UpdateConfiguredHeaters(); - // Flash operations - void UpdateFirmware(); - void StartIap(); - bool CheckFirmwareUpdatePrerequisites(const StringRef& reply); - // AUX device void Beep(int freq, int ms); void SendAuxMessage(const char* msg); diff --git a/src/RepRap.cpp b/src/RepRap.cpp index 299bab24..3fd4d22d 100644 --- a/src/RepRap.cpp +++ b/src/RepRap.cpp @@ -14,6 +14,7 @@ #include "Tools/Filament.h" #include "Endstops/ZProbe.h" #include "Tasks.h" +#include "Hardware/Cache.h" #include "Version.h" #ifdef DUET_NG @@ -152,7 +153,7 @@ RepRap::RepRap() : toolList(nullptr), currentTool(nullptr), lastWarningMillis(0) debug(0), beepFrequency(0), beepDuration(0), diagnosticsDestination(MessageType::NoDestinationMessage), justSentDiagnostics(false), - spinningModule(noModule), stopped(false), active(false), resetting(false), processingConfig(true) + spinningModule(noModule), stopped(false), active(false), processingConfig(true) #if HAS_LINUX_INTERFACE , usingLinuxInterface(true) #endif @@ -508,7 +509,7 @@ void RepRap::Diagnostics(MessageType mtype) // Turn off the heaters, disable the motors, and deactivate the Heat and Move classes. Leave everything else working. void RepRap::EmergencyStop() { - stopped = true; + stopped = true; // a useful side effect of setting this is that it prevents Platform::Tick being called, which is needed when loading IAP into RAM // Do not turn off ATX power here. If the nozzles are still hot, don't risk melting any surrounding parts by turning fans off. //platform->SetAtxPower(false); @@ -530,23 +531,8 @@ void RepRap::EmergencyStop() break; } - // Deselect all tools (is this necessary?) - { - MutexLocker lock(toolListMutex); - for (Tool* tool = toolList; tool != nullptr; tool = tool->Next()) - { - tool->Standby(); - } - } - heat->Exit(); // this also turns off all heaters - - // We do this twice, to avoid an interrupt switching a drive back on. move->Exit() should prevent interrupts doing this. - for (int i = 0; i < 2; i++) - { - move->Exit(); - platform->EmergencyDisableDrivers(); - } + move->Exit(); gCodes->EmergencyStop(); platform->StopLogging(); @@ -772,7 +758,7 @@ void RepRap::Tick() rswdt_restart(RSWDT); // kick the secondary watchdog #endif - if (!resetting) + if (!stopped) { platform->Tick(); ++ticksInSpinState; @@ -780,7 +766,7 @@ void RepRap::Tick() const bool heatTaskStuck = (heatTaskIdleTicks >= MaxTicksInSpinState); if (heatTaskStuck || ticksInSpinState >= MaxTicksInSpinState) // if we stall for 20 seconds, save diagnostic data and reset { - resetting = true; + stopped = true; heat->SwitchOffAll(true); platform->EmergencyDisableDrivers(); @@ -2340,6 +2326,294 @@ bool RepRap::WriteToolParameters(FileStore *f, const bool forceWriteOffsets) con #endif +// Firmware update operations + +// Check the prerequisites for updating the main firmware. Return True if satisfied, else print a message to 'reply' and return false. +bool RepRap::CheckFirmwareUpdatePrerequisites(const StringRef& reply) +{ +#if HAS_MASS_STORAGE + FileStore * const firmwareFile = platform->OpenFile(DEFAULT_SYS_DIR, IAP_FIRMWARE_FILE, OpenMode::read); + if (firmwareFile == nullptr) + { + reply.printf("Firmware binary \"%s\" not found", IAP_FIRMWARE_FILE); + return false; + } + + // Check that the binary looks sensible. The first word is the initial stack pointer, which should be the top of RAM. + uint32_t firstDword; + bool ok = firmwareFile->Read(reinterpret_cast<char*>(&firstDword), sizeof(firstDword)) == (int)sizeof(firstDword); + firmwareFile->Close(); + if (!ok || firstDword != +#if SAM3XA + IRAM1_ADDR + IRAM1_SIZE +#else + IRAM_ADDR + IRAM_SIZE +#endif + ) + { + reply.printf("Firmware binary \"%s\" is not valid for this electronics", IAP_FIRMWARE_FILE); + return false; + } + + if (!platform->FileExists(DEFAULT_SYS_DIR, IAP_UPDATE_FILE)) + { + reply.printf("In-application programming binary \"%s\" not found", IAP_UPDATE_FILE); + return false; + } +#endif + + return true; +} + +// Update the firmware. Prerequisites should be checked before calling this. +void RepRap::UpdateFirmware() +{ +#if HAS_MASS_STORAGE + FileStore * const iapFile = platform->OpenFile(DEFAULT_SYS_DIR, IAP_UPDATE_FILE, OpenMode::read); + if (iapFile == nullptr) + { + platform->MessageF(FirmwareUpdateMessage, "IAP file '" IAP_UPDATE_FILE "' not found\n"); + return; + } + +#if SUPPORT_12864_LCD + display->UpdatingFirmware(); // put the firmware update message on the display +#endif + +#if IAP_IN_RAM + // Send this message before we start using RAM that may contain message buffers + platform->Message(AuxMessage, "Updating main firmware\n"); + platform->Message(UsbMessage, "Shutting down USB interface to update main firmware. Try reconnecting after 30 seconds.\n"); + + // Allow time for the firmware update message to be sent + const uint32_t now = millis(); + while (platform->FlushMessages() && millis() - now < 2000) { } +#endif + + // The machine will be unresponsive for a few seconds, don't risk damaging the heaters. + // This also shuts down tasks and interrupts that might make use of the RAM that we are about to load the IAP binary into. + EmergencyStop(); // this also stops Platform::Tick being called, which is necessary because it access Z probe object in RAM used by IAP + network->Exit(); // kill the network task to stop it overwriting RAM that we use to hold the IAP + + // Step 0 - disable the cache because it interferes with flash memory access + Cache::Disable(); + +#if USE_MPU + //TODO consider setting flash memory to strongly-ordered instead + ARM_MPU_Disable(); +#endif + +#if IAP_IN_RAM + // Use RAM-based IAP + iapFile->Read(reinterpret_cast<char *>(IAP_IMAGE_START), iapFile->Length()); +#else + // Step 1 - Write update binary to Flash and overwrite the remaining space with zeros + // On the SAM3X, leave the last 1KB of Flash memory untouched, so we can reuse the NvData after this update + +# if !defined(IFLASH_PAGE_SIZE) && defined(IFLASH0_PAGE_SIZE) +# define IFLASH_PAGE_SIZE IFLASH0_PAGE_SIZE +# endif + + // Use a 32-bit aligned buffer. This gives us the option of calling the EFC functions directly in future. + uint32_t data32[IFLASH_PAGE_SIZE/4]; + char* const data = reinterpret_cast<char *>(data32); + +# if SAM4E || SAM4S || SAME70 + // The EWP command is not supported for non-8KByte sectors in the SAM4 and SAME70 series. + // So we have to unlock and erase the complete 64Kb or 128kb sector first. One sector is always enough to contain the IAP. + flash_unlock(IAP_IMAGE_START, IAP_IMAGE_END, nullptr, nullptr); + flash_erase_sector(IAP_IMAGE_START); + + for (uint32_t flashAddr = IAP_IMAGE_START; flashAddr < IAP_IMAGE_END; flashAddr += IFLASH_PAGE_SIZE) + { + const int bytesRead = iapFile->Read(data, IFLASH_PAGE_SIZE); + + if (bytesRead > 0) + { + // Do we have to fill up the remaining buffer with zeros? + if (bytesRead != IFLASH_PAGE_SIZE) + { + memset(data + bytesRead, 0, sizeof(data[0]) * (IFLASH_PAGE_SIZE - bytesRead)); + } + + // Write one page at a time + cpu_irq_disable(); + const uint32_t rc = flash_write(flashAddr, data, IFLASH_PAGE_SIZE, 0); + cpu_irq_enable(); + + if (rc != FLASH_RC_OK) + { + platform->MessageF(FirmwareUpdateErrorMessage, "flash write failed, code=%" PRIu32 ", address=0x%08" PRIx32 "\n", rc, flashAddr); + return; + } + + // Verify written data + if (memcmp(reinterpret_cast<void *>(flashAddr), data, bytesRead) != 0) + { + platform->MessageF(FirmwareUpdateErrorMessage, "verify during flash write failed, address=0x%08" PRIx32 "\n", flashAddr); + return; + } + } + else + { + // Fill up the remaining space with zeros + memset(data, 0, sizeof(data[0]) * sizeof(data)); + cpu_irq_disable(); + flash_write(flashAddr, data, IFLASH_PAGE_SIZE, 0); + cpu_irq_enable(); + } + } + + // Re-lock the whole area + flash_lock(IAP_IMAGE_START, IAP_IMAGE_END, nullptr, nullptr); + +# else // SAM3X code + + for (uint32_t flashAddr = IAP_FLASH_START; flashAddr < IAP_FLASH_END; flashAddr += IFLASH_PAGE_SIZE) + { + const int bytesRead = iapFile->Read(data, IFLASH_PAGE_SIZE); + + if (bytesRead > 0) + { + // Do we have to fill up the remaining buffer with zeros? + if (bytesRead != IFLASH_PAGE_SIZE) + { + memset(data + bytesRead, 0, sizeof(data[0]) * (IFLASH_PAGE_SIZE - bytesRead)); + } + + // Write one page at a time + cpu_irq_disable(); + + const char* op = "unlock"; + uint32_t rc = flash_unlock(flashAddr, flashAddr + IFLASH_PAGE_SIZE - 1, nullptr, nullptr); + + if (rc == FLASH_RC_OK) + { + op = "write"; + rc = flash_write(flashAddr, data, IFLASH_PAGE_SIZE, 1); + } + if (rc == FLASH_RC_OK) + { + op = "lock"; + rc = flash_lock(flashAddr, flashAddr + IFLASH_PAGE_SIZE - 1, nullptr, nullptr); + } + cpu_irq_enable(); + + if (rc != FLASH_RC_OK) + { + MessageF(FirmwareUpdateErrorMessage, "flash %s failed, code=%" PRIu32 ", address=0x%08" PRIx32 "\n", op, rc, flashAddr); + return; + } + // Verify written data + if (memcmp(reinterpret_cast<void *>(flashAddr), data, bytesRead) != 0) + { + MessageF(FirmwareUpdateErrorMessage, "verify during flash write failed, address=0x%08" PRIx32 "\n", flashAddr); + return; + } + } + else + { + // Fill up the remaining space + memset(data, 0, sizeof(data[0]) * sizeof(data)); + cpu_irq_disable(); + flash_unlock(flashAddr, flashAddr + IFLASH_PAGE_SIZE - 1, nullptr, nullptr); + flash_write(flashAddr, data, IFLASH_PAGE_SIZE, 1); + flash_lock(flashAddr, flashAddr + IFLASH_PAGE_SIZE - 1, nullptr, nullptr); + cpu_irq_enable(); + } + } +# endif +#endif + + iapFile->Close(); + + StartIap(); +#endif +} + +void RepRap::StartIap() +{ +#if !IAP_IN_RAM + platform->Message(AuxMessage, "Updating main firmware\n"); + platform->Message(UsbMessage, "Shutting down USB interface to update main firmware. Try reconnecting after 30 seconds.\n"); + + // Allow time for the firmware update message to be sent + const uint32_t now = millis(); + while (platform->FlushMessages() && millis() - now < 2000) { } +#endif + + // Disable all interrupts, then reallocate the vector table and program entry point to the new IAP binary + // This does essentially what the Atmel AT02333 paper suggests (see 3.2.2 ff) + + // Disable all IRQs + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk; // disable the system tick exception + cpu_irq_disable(); + for (size_t i = 0; i < 8; i++) + { + NVIC->ICER[i] = 0xFFFFFFFF; // Disable IRQs + NVIC->ICPR[i] = 0xFFFFFFFF; // Clear pending IRQs + } + + // Disable all PIO IRQs, because the core assumes they are all disabled when setting them up + PIOA->PIO_IDR = 0xFFFFFFFF; + PIOB->PIO_IDR = 0xFFFFFFFF; + PIOC->PIO_IDR = 0xFFFFFFFF; +#ifdef PIOD + PIOD->PIO_IDR = 0xFFFFFFFF; +#endif +#ifdef ID_PIOE + PIOE->PIO_IDR = 0xFFFFFFFF; +#endif + +#if HAS_MASS_STORAGE + // Newer versions of iap4e.bin reserve space above the stack for us to pass the firmware filename + static const char filename[] = DEFAULT_SYS_DIR IAP_FIRMWARE_FILE; + const uint32_t topOfStack = *reinterpret_cast<uint32_t *>(IAP_IMAGE_START); + if (topOfStack + sizeof(filename) <= +# if SAM3XA + IRAM1_ADDR + IRAM1_SIZE +# else + IRAM_ADDR + IRAM_SIZE +# endif + ) + { + memcpy(reinterpret_cast<char*>(topOfStack), filename, sizeof(filename)); + } +#endif + +#if defined(DUET_NG) || defined(DUET_M) + IoPort::WriteDigital(DiagPin, false); // turn the DIAG LED off +#endif + + wdt_restart(WDT); // kick the watchdog one last time + +#if SAM4E || SAME70 + rswdt_restart(RSWDT); // kick the secondary watchdog +#endif + + // Modify vector table location + __DSB(); + __ISB(); + SCB->VTOR = ((uint32_t)IAP_IMAGE_START & SCB_VTOR_TBLOFF_Msk); + __DSB(); + __ISB(); + + cpu_irq_enable(); + + __asm volatile ("mov r3, %0" : : "r" (IAP_IMAGE_START) : "r3"); + + // We are using separate process and handler stacks. Put the process stack 1K bytes below the handler stack. + __asm volatile ("ldr r1, [r3]"); + __asm volatile ("msr msp, r1"); + __asm volatile ("sub r1, #1024"); + __asm volatile ("mov sp, r1"); + + __asm volatile ("isb"); + __asm volatile ("ldr r1, [r3, #4]"); + __asm volatile ("orr r1, r1, #1"); + __asm volatile ("bx r1"); +} + // Helper function for diagnostic tests in Platform.cpp, to cause a deliberate divide-by-zero /*static*/ uint32_t RepRap::DoDivide(uint32_t a, uint32_t b) { diff --git a/src/RepRap.h b/src/RepRap.h index 6fd8a4fa..9e176402 100644 --- a/src/RepRap.h +++ b/src/RepRap.h @@ -146,6 +146,11 @@ public: bool WriteToolParameters(FileStore *f, const bool forceWriteOffsets) const; // save some information in config-override.g #endif + // Firmware update operations + bool CheckFirmwareUpdatePrerequisites(const StringRef& reply); + void UpdateFirmware(); + void StartIap(); + void ReportInternalError(const char *file, const char *func, int line) const; // Report an internal error static uint32_t DoDivide(uint32_t a, uint32_t b); // helper function for diagnostic tests @@ -221,7 +226,6 @@ private: Module spinningModule; bool stopped; bool active; - bool resetting; bool processingConfig; #if HAS_LINUX_INTERFACE bool usingLinuxInterface; @@ -239,7 +243,9 @@ inline uint16_t RepRap::GetExtrudersInUse() const { return activeExtruders; } inline uint16_t RepRap::GetToolHeatersInUse() const { return activeToolHeaters; } inline bool RepRap::IsStopped() const { return stopped; } +#define STRINGIZE(s) #s #define INTERNAL_ERROR do { reprap.ReportInternalError((__FILE__), (__func__), (__LINE__)); } while(0) +#define INTERNAL_ERROR_MESSAGE "Internal error at " __FILE__ "(" STRINGIZE(__LINE__) ")" #endif diff --git a/src/Version.h b/src/Version.h index bca8b555..8921d2fa 100644 --- a/src/Version.h +++ b/src/Version.h @@ -20,7 +20,7 @@ #endif #ifndef DATE -# define DATE "2019-12-05b2" +# define DATE "2019-12-09b3" #endif #define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman, printm3d" |