ESP32 HAL: Fix random pauses during prints (#16548)

This commit is contained in:
felixstorm 2020-01-16 12:57:14 +01:00 committed by Scott Lahteine
parent 5bd66241df
commit 2b9eb4437b
3 changed files with 43 additions and 16 deletions

View File

@ -137,3 +137,44 @@ void HAL_adc_start_conversion(uint8_t adc_pin);
void HAL_idletask(); void HAL_idletask();
void HAL_init(); void HAL_init();
void HAL_init_board(); void HAL_init_board();
//
// Delay in cycles (used by DELAY_NS / DELAY_US)
//
FORCE_INLINE static void DELAY_CYCLES(uint32_t x) {
unsigned long start, ccount, stop;
/**
* It's important to care for race conditions (and overflows) here.
* Race condition example: If `stop` calculates to being close to the upper boundary of
* `uint32_t` and if at the same time a longer loop interruption kicks in (e.g. due to other
* FreeRTOS tasks or interrupts), `ccount` might overflow (and therefore be below `stop` again)
* without the loop ever being able to notice that `ccount` had already been above `stop` once
* (and that therefore the number of cycles to delay has already passed).
* As DELAY_CYCLES (through DELAY_NS / DELAY_US) is used by software SPI bit banging to drive
* LCDs and therefore might be called very, very often, this seemingly improbable situation did
* actually happen in reality. It resulted in apparently random print pauses of ~17.9 seconds
* (0x100000000 / 240 MHz) or multiples thereof, essentially ruining the current print by causing
* large blobs of filament.
*/
__asm__ __volatile__ ( "rsr %0, ccount" : "=a" (start) );
stop = start + x;
ccount = start;
if (stop >= start) {
// no overflow, so only loop while in between start and stop:
// 0x00000000 -----------------start****stop-- 0xffffffff
while (ccount >= start && ccount < stop) {
__asm__ __volatile__ ( "rsr %0, ccount" : "=a" (ccount) );
}
}
else {
// stop did overflow, so only loop while outside of stop and start:
// 0x00000000 **stop-------------------start** 0xffffffff
while (ccount >= start || ccount < stop) {
__asm__ __volatile__ ( "rsr %0, ccount" : "=a" (ccount) );
}
}
}

View File

@ -37,7 +37,7 @@ Servo::Servo() {
int8_t Servo::attach(const int inPin) { int8_t Servo::attach(const int inPin) {
if (channel >= CHANNEL_MAX_NUM) return -1; if (channel >= CHANNEL_MAX_NUM) return -1;
if (pin > 0) pin = inPin; if (inPin > 0) pin = inPin;
ledcSetup(channel, 50, 16); // channel X, 50 Hz, 16-bit depth ledcSetup(channel, 50, 16); // channel X, 50 Hz, 16-bit depth
ledcAttachPin(pin, channel); ledcAttachPin(pin, channel);

View File

@ -145,21 +145,7 @@
} }
#undef nop #undef nop
#elif defined(ESP32) #elif defined(__PLAT_LINUX__) || defined(ESP32)
FORCE_INLINE static void DELAY_CYCLES(uint32_t x) {
unsigned long ccount, stop;
__asm__ __volatile__ ( "rsr %0, ccount" : "=a" (ccount) );
stop = ccount + x; // This can overflow
while (ccount < stop) { // This doesn't deal with overflows
__asm__ __volatile__ ( "rsr %0, ccount" : "=a" (ccount) );
}
}
#elif defined(__PLAT_LINUX__)
// specified inside platform // specified inside platform