Merge branch 'bugfix/wa_dport_and_intr_v3.3' into 'release/v3.3'

esp32: Fix for DPORT (v3.3)

See merge request espressif/esp-idf!7350
This commit is contained in:
Jiang Jiang Jian 2020-01-21 10:53:15 +08:00
commit 8be372a1fd
3 changed files with 79 additions and 4 deletions

View file

@ -255,8 +255,8 @@ uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg)
uint32_t apb;
unsigned int intLvl;
__asm__ __volatile__ (\
"movi %[APB], "XTSTR(0x3ff40078)"\n"\
"rsil %[LVL], "XTSTR(CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL)"\n"\
"movi %[APB], "XTSTR(0x3ff40078)"\n"\
"l32i %[APB], %[APB], 0\n"\
"l32i %[REG], %[REG], 0\n"\
"wsr %[LVL], "XTSTR(PS)"\n"\

View file

@ -417,4 +417,81 @@ TEST_CASE("Check pre-read workaround DPORT and Hi-interrupt", "[esp32]")
// Hi-interrupt - CPU1
run_tasks("accessAPB", accessAPB, "accessDPORT2", accessDPORT2, 10000);
}
static uint32_t s_shift_counter;
/*
The test_dport_access_reg_read() is similar DPORT_REG_READ() but has differents:
- generate an interrupt by SET_CCOMPARE
- additional branch command helps get good reproducing an issue with breaking the DPORT pre-read workaround
- uncomment (1) and comment (2) it allows seeing the broken pre-read workaround
For pre-reading the workaround, it is important that the two reading commands APB and DPORT
are executed without interruption. For this reason, it disables interrupts and to do reading inside the safe area.
But despite a disabling interrupt it was still possible that these two readings can be interrupted.
The reason is linked with work parallel execution commands in the pipeline (it is not a bug).
To resolve this issue (1) was moved to (2) position into the disabled interrupt part.
When the read command is interrupted after stage E(execute), the result of its execution will be saved in the internal buffer,
and after returning from the interrupt, this command takes this value from the buffer without repeating the reading,
which is critical for the DPORT pre-read workaround. To fix it we added additional command under safe area ((1)->(2)).
*/
static uint32_t IRAM_ATTR test_dport_access_reg_read(uint32_t reg)
{
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
return _DPORT_REG_READ(reg);
#else
uint32_t apb;
unsigned int intLvl;
XTHAL_SET_CCOMPARE(2, XTHAL_GET_CCOUNT() + s_shift_counter);
__asm__ __volatile__ (\
/* "movi %[APB], "XTSTR(0x3ff40078)"\n" */ /* (1) uncomment for reproduce issue */ \
"bnez %[APB], kl1\n" /* this branch command helps get good reproducing */ \
"kl1:\n"\
"rsil %[LVL], "XTSTR(CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL)"\n"\
"movi %[APB], "XTSTR(0x3ff40078)"\n" /* (2) comment for reproduce issue */ \
"l32i %[APB], %[APB], 0\n"\
"l32i %[REG], %[REG], 0\n"\
"wsr %[LVL], "XTSTR(PS)"\n"\
"rsync\n"\
: [APB]"=a"(apb), [REG]"+a"(reg), [LVL]"=a"(intLvl)\
: \
: "memory" \
);
return reg;
#endif
}
// The accessDPORT3 task is similar accessDPORT2 but uses test_dport_access_reg_read() instead of usual DPORT_REG_READ().
static void accessDPORT3(void *pvParameters)
{
xSemaphoreHandle *sema = (xSemaphoreHandle *) pvParameters;
dport_test_result = true;
TEST_ESP_OK(esp_intr_alloc(ETS_INTERNAL_TIMER2_INTR_SOURCE, ESP_INTR_FLAG_LEVEL5 | ESP_INTR_FLAG_IRAM, NULL, NULL, &inth));
int i = 0;
while (exit_flag == false) {
if (test_dport_access_reg_read(DPORT_DATE_REG) != test_dport_access_reg_read(DPORT_DATE_REG)) {
dport_test_result = false;
break;
}
if ((++i % 100) == 0) {
s_shift_counter = (s_shift_counter + 1) % 30;
}
}
esp_intr_free(inth);
printf("accessDPORT3 finish\n");
xSemaphoreGive(*sema);
vTaskDelete(NULL);
}
TEST_CASE("Check pre-read workaround DPORT and Hi-interrupt (2)", "[esp32]")
{
s_shift_counter = 1;
xt_highint5_read_apb = 0;
dport_test_result = false;
apb_test_result = true;
// Access DPORT(pre-read method) - CPU1
// Hi-interrupt - CPU1
run_tasks("accessAPB", accessAPB, "accessDPORT3", accessDPORT3, 10000);
}
#endif // CONFIG_FREERTOS_UNICORE

View file

@ -28,9 +28,7 @@ xt_highint5:
bnez a0, .read_apb_reg
// Short interrupt
esync
rsr a0, CCOUNT
addi a0, a0, 27
movi a0, 0
wsr a0, CCOMPARE2
esync