#include <stdio.h>
#include <stdlib.h>
+#include "xtensa/core-macros.h"
+#include "xtensa/hal.h"
#include "esp_types.h"
#include "esp_clk.h"
#include "soc/uart_reg.h"
#include "soc/dport_reg.h"
#include "soc/rtc.h"
+#include "esp_intr_alloc.h"
+#include "driver/timer.h"
#define MHZ (1000000)
static volatile bool exit_flag;
static bool dport_test_result;
static bool apb_test_result;
+uint32_t volatile apb_intr_test_result;
static void accessDPORT(void *pvParameters)
{
void run_tasks(const char *task1_description, void (* task1_func)(void *), const char *task2_description, void (* task2_func)(void *), uint32_t delay_ms)
{
+ apb_intr_test_result = 1;
int i;
TaskHandle_t th[2];
xSemaphoreHandle exit_sema[2];
vSemaphoreDelete(exit_sema[i]);
}
}
- TEST_ASSERT(dport_test_result == true && apb_test_result == true);
+ TEST_ASSERT(dport_test_result == true && apb_test_result == true && apb_intr_test_result == 1);
}
TEST_CASE("access DPORT and APB at same time", "[esp32]")
}
BENCHMARK_END("_DPORT_REG_READ");
}
+
+uint32_t xt_highint5_read_apb;
+
+#ifndef CONFIG_FREERTOS_UNICORE
+timer_isr_handle_t inth;
+xSemaphoreHandle sync_sema;
+
+static void init_hi_interrupt(void *arg)
+{
+ printf("init hi_interrupt on CPU%d \n", xPortGetCoreID());
+ TEST_ESP_OK(esp_intr_alloc(ETS_INTERNAL_TIMER2_INTR_SOURCE, ESP_INTR_FLAG_LEVEL5 | ESP_INTR_FLAG_IRAM, NULL, NULL, &inth));
+ while (exit_flag == false);
+ esp_intr_free(inth);
+ printf("disable hi_interrupt on CPU%d \n", xPortGetCoreID());
+ vTaskDelete(NULL);
+}
+
+static void accessDPORT2_stall_other_cpu(void *pvParameters)
+{
+ xSemaphoreHandle *sema = (xSemaphoreHandle *) pvParameters;
+ dport_test_result = true;
+ while (exit_flag == false) {
+ DPORT_STALL_OTHER_CPU_START();
+ XTHAL_SET_CCOMPARE(2, XTHAL_GET_CCOUNT());
+ xt_highint5_read_apb = 1;
+ for (int i = 0; i < 200; ++i) {
+ if (_DPORT_REG_READ(DPORT_DATE_REG) != _DPORT_REG_READ(DPORT_DATE_REG)) {
+ apb_test_result = false;
+ break;
+ }
+ }
+ xt_highint5_read_apb = 0;
+ DPORT_STALL_OTHER_CPU_END();
+ }
+ printf("accessDPORT2_stall_other_cpu finish\n");
+
+ xSemaphoreGive(*sema);
+ vTaskDelete(NULL);
+}
+
+TEST_CASE("Check stall workaround DPORT and Hi-interrupt", "[esp32]")
+{
+ xt_highint5_read_apb = 0;
+ dport_test_result = false;
+ apb_test_result = true;
+ TEST_ASSERT(xTaskCreatePinnedToCore(&init_hi_interrupt, "init_hi_intr", 2048, NULL, 6, NULL, 1) == pdTRUE);
+ // Access DPORT(stall other cpu method) - CPU0
+ // STALL - CPU1
+ // Hi-interrupt - CPU1
+ run_tasks("accessDPORT2_stall_other_cpu", accessDPORT2_stall_other_cpu, " - ", NULL, 10000);
+}
+
+static void accessDPORT2(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));
+
+ while (exit_flag == false) {
+ XTHAL_SET_CCOMPARE(2, XTHAL_GET_CCOUNT() + 21);
+ for (int i = 0; i < 200; ++i) {
+ if (DPORT_REG_READ(DPORT_DATE_REG) != DPORT_REG_READ(DPORT_DATE_REG)) {
+ dport_test_result = false;
+ break;
+ }
+ }
+ }
+ esp_intr_free(inth);
+ printf("accessDPORT2 finish\n");
+
+ xSemaphoreGive(*sema);
+ vTaskDelete(NULL);
+}
+
+TEST_CASE("Check pre-read workaround DPORT and Hi-interrupt", "[esp32]")
+{
+ 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, "accessDPORT2", accessDPORT2, 10000);
+}
+#endif // CONFIG_FREERTOS_UNICORE
--- /dev/null
+#include <xtensa/coreasm.h>
+#include <xtensa/corebits.h>
+#include <xtensa/config/system.h>
+#include "freertos/xtensa_context.h"
+
+#include "sdkconfig.h"
+#include "soc/soc.h"
+#include "soc/dport_reg.h"
+
+#ifndef CONFIG_FREERTOS_UNICORE
+
+#define L5_INTR_STACK_SIZE 12
+#define L5_INTR_A2_OFFSET 0
+#define L5_INTR_A3_OFFSET 4
+#define L5_INTR_A4_OFFSET 8
+ .data
+_l5_intr_stack:
+ .space L5_INTR_STACK_SIZE
+
+ .section .iram1,"ax"
+ .global xt_highint5
+ .type xt_highint5,@function
+ .align 4
+xt_highint5:
+
+ movi a0, xt_highint5_read_apb
+ l32i a0, a0, 0
+ bnez a0, .read_apb_reg
+
+// Short interrupt
+ esync
+ rsr a0, CCOUNT
+ addi a0, a0, 27
+ wsr a0, CCOMPARE2
+ esync
+
+ rsr a0, EXCSAVE_5 // restore a0
+ rfi 5
+
+
+
+// read APB reg 10 time.
+.read_apb_reg:
+ movi a0, _l5_intr_stack
+ s32i a2, a0, L5_INTR_A2_OFFSET
+ s32i a3, a0, L5_INTR_A3_OFFSET
+ s32i a4, a0, L5_INTR_A4_OFFSET
+
+ movi a4, 10 // count of reading
+ movi a0, 0x3ff40078 // read APB reg
+ l32i a2, a0, 0
+.loop_read_apb_reg:
+ l32i a3, a0, 0
+ bne a3, a2, .need_set_apb_test_result
+ addi a4, a4, -1
+ l32i a2, a0, 0
+ bnez a4, .loop_read_apb_reg
+ j 1f
+.need_set_apb_test_result:
+ movi a0, apb_intr_test_result // set fail
+ movi a2, 0
+ s32i a2, a0, 0
+ memw
+1:
+ movi a0, _l5_intr_stack
+ l32i a2, a0, L5_INTR_A2_OFFSET
+ l32i a3, a0, L5_INTR_A3_OFFSET
+ l32i a4, a0, L5_INTR_A4_OFFSET
+ rsync
+.L_xt_highint5_exit:
+ rsr a0, EXCSAVE_5 // restore a0
+ rfi 5
+
+/* The linker has no reason to link in this file; all symbols it exports are already defined
+ (weakly!) in the default int handler. Define a symbol here so we can use it to have the
+ linker inspect this anyway. */
+
+ .global ld_include_test_dport_xt_highint5
+ld_include_test_dport_xt_highint5:
+#endif // CONFIG_FREERTOS_UNICORE