Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2019-12-09 22:47:33 +0300
committerDavid Crocker <dcrocker@eschertech.com>2019-12-09 22:47:33 +0300
commit14db90f06f74494ee811cf1ae4f12190756ed2ca (patch)
treec5c8332e39db09a5df8c4475cfc03e184ed46016
parentbf7be88b40ee5b48aacd4d78917cfaa94f7aa3d2 (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.h23
-rw-r--r--src/DuetM/Pins_DuetM.h20
-rw-r--r--src/DuetNG/Pins_DuetNG.h25
-rw-r--r--src/GCodes/GCodes3.cpp2
-rw-r--r--src/GCodes/GCodes4.cpp2
-rw-r--r--src/Linux/LinuxInterface.cpp27
-rw-r--r--src/Movement/Move.cpp4
-rw-r--r--src/Movement/StepperDrivers/TMC22xx.cpp15
-rw-r--r--src/Movement/StepperDrivers/TMC22xx.h1
-rw-r--r--src/Movement/StepperDrivers/TMC2660.cpp8
-rw-r--r--src/Movement/StepperDrivers/TMC2660.h1
-rw-r--r--src/Movement/StepperDrivers/TMC51xx.cpp9
-rw-r--r--src/Movement/StepperDrivers/TMC51xx.h1
-rw-r--r--src/Networking/LwipEthernet/GMAC/ethernet_sam.h3
-rw-r--r--src/Networking/LwipEthernet/GMAC/same70_gmac.cpp13
-rw-r--r--src/Networking/LwipEthernet/GMAC/same70_gmac.h12
-rw-r--r--src/Networking/LwipEthernet/LwipEthernetInterface.cpp1
-rw-r--r--src/Networking/Network.cpp6
-rw-r--r--src/Platform.cpp283
-rw-r--r--src/Platform.h6
-rw-r--r--src/RepRap.cpp314
-rw-r--r--src/RepRap.h8
-rw-r--r--src/Version.h2
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"