Fix flashing languages with inline wdr instructions

A fairly mysterious situation happened recently in the MK3 branch.
After merging #3033 (change watchdogReset() into a single inline wdr instruction)
we were unable to flash languages.

Since it looked similarly suspicious like issue #2954 we started investigating deeply.
The problem was in the code as described in the comment in this PR.
This commit is contained in:
D.R.racer 2021-03-03 11:19:39 +01:00
parent a5a83038fe
commit 3922bf2877

View File

@ -115,8 +115,6 @@ uint8_t optiboot_w25x20cl_enter()
// If the magic is not received on time, or it is not received correctly, continue to the application. // If the magic is not received on time, or it is not received correctly, continue to the application.
{ {
wdt_reset(); wdt_reset();
unsigned long boot_timeout = 2000000;
unsigned long boot_timer = 0;
const char *ptr = entry_magic_send; const char *ptr = entry_magic_send;
const char *end = strlen_P(entry_magic_send) + ptr; const char *end = strlen_P(entry_magic_send) + ptr;
const uint8_t selectedSerialPort_bak = selectedSerialPort; const uint8_t selectedSerialPort_bak = selectedSerialPort;
@ -128,7 +126,6 @@ uint8_t optiboot_w25x20cl_enter()
} }
selectedSerialPort = 0; //switch to Serial0 selectedSerialPort = 0; //switch to Serial0
MYSERIAL.flush(); //clear RX buffer MYSERIAL.flush(); //clear RX buffer
int SerialHead = rx_buffer.head;
// Send the initial magic string. // Send the initial magic string.
while (ptr != end) while (ptr != end)
putch(pgm_read_byte(ptr ++)); putch(pgm_read_byte(ptr ++));
@ -138,11 +135,18 @@ uint8_t optiboot_w25x20cl_enter()
ptr = entry_magic_receive; ptr = entry_magic_receive;
end = strlen_P(entry_magic_receive) + ptr; end = strlen_P(entry_magic_receive) + ptr;
while (ptr != end) { while (ptr != end) {
while (rx_buffer.head == SerialHead) { unsigned long boot_timer = 2000000;
// Beware of this volatile pointer - it is important since the while-cycle below
// doesn't contain any obvious references to rx_buffer.head
// thus the compiler is allowed to remove the check from the cycle
// i.e. rx_buffer.head == SerialHead would not be checked at all!
// With the volatile keyword the compiler generates exactly the same code as without it with only one difference:
// the last brne instruction jumps onto the (*rx_head == SerialHead) check and NOT onto the wdr instruction bypassing the check.
volatile int *rx_head = &rx_buffer.head;
int SerialHead = rx_buffer.head;
while (*rx_head == SerialHead) {
wdt_reset(); wdt_reset();
delayMicroseconds(1); if ( --boot_timer == 0) {
if (++ boot_timer > boot_timeout)
{
// Timeout expired, continue with the application. // Timeout expired, continue with the application.
selectedSerialPort = selectedSerialPort_bak; //revert Serial setting selectedSerialPort = selectedSerialPort_bak; //revert Serial setting
return 0; return 0;