test_ulp_riscv.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /*
  2. * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <inttypes.h>
  9. #include "esp_sleep.h"
  10. #include "soc/rtc_cntl_reg.h"
  11. #include "soc/sens_reg.h"
  12. #include "soc/rtc_periph.h"
  13. #include "ulp_riscv.h"
  14. #include "ulp_riscv_lock.h"
  15. #include "ulp_test_app.h"
  16. #include "ulp_test_app2.h"
  17. #include "ulp_test_shared.h"
  18. #include "unity.h"
  19. #include <sys/time.h>
  20. #include "freertos/FreeRTOS.h"
  21. #include "freertos/task.h"
  22. #include "freertos/semphr.h"
  23. #define ULP_WAKEUP_PERIOD 1000000 // 1 second
  24. // First ULP firmware
  25. extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_test_app_bin_start");
  26. extern const size_t ulp_main_bin_length asm("ulp_test_app_bin_length");
  27. static bool firmware_loaded = false;
  28. // Second ULP firmware
  29. extern const uint8_t ulp_test_app2_bin_start[] asm("_binary_ulp_test_app2_bin_start");
  30. extern const size_t ulp_test_app2_bin_length asm("ulp_test_app2_bin_length");
  31. // Faulty ULP firmware
  32. extern const uint8_t ulp_test_app3_bin_start[] asm("_binary_ulp_test_app3_bin_start");
  33. extern const size_t ulp_test_app3_bin_length asm("ulp_test_app3_bin_length");
  34. static void load_and_start_ulp_firmware(const uint8_t* ulp_bin, size_t ulp_bin_len)
  35. {
  36. if (!firmware_loaded) {
  37. TEST_ASSERT(ulp_riscv_load_binary(ulp_bin, ulp_bin_len) == ESP_OK);
  38. TEST_ASSERT(ulp_set_wakeup_period(0, ULP_WAKEUP_PERIOD) == ESP_OK);
  39. TEST_ASSERT(ulp_riscv_run() == ESP_OK);
  40. firmware_loaded = true;
  41. printf("New ULP firmware loaded\n");
  42. }
  43. }
  44. TEST_CASE("ULP-RISC-V and main CPU are able to exchange data", "[ulp]")
  45. {
  46. const uint32_t test_data = 0x12345678;
  47. struct timeval start, end;
  48. /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */
  49. load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length);
  50. /* Setup wakeup triggers */
  51. TEST_ASSERT(esp_sleep_enable_ulp_wakeup() == ESP_OK);
  52. /* Setup test data */
  53. ulp_riscv_test_data_in = test_data ^ XOR_MASK;
  54. ulp_main_cpu_command = RISCV_READ_WRITE_TEST;
  55. /* Enter Light Sleep */
  56. esp_light_sleep_start();
  57. /* Wait till we receive the correct command response */
  58. gettimeofday(&start, NULL);
  59. while (ulp_command_resp != RISCV_READ_WRITE_TEST)
  60. ;
  61. gettimeofday(&end, NULL);
  62. printf("Response time %jd ms\n", ((intmax_t)end.tv_sec - (intmax_t)start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000);
  63. /* Verify test data */
  64. TEST_ASSERT(ulp_command_resp == RISCV_READ_WRITE_TEST);
  65. TEST_ASSERT(ulp_main_cpu_reply == RISCV_COMMAND_OK);
  66. printf("data out: 0x%" PRIx32 ", expected: 0x%" PRIx32 " \n", ulp_riscv_test_data_out, test_data);
  67. TEST_ASSERT(test_data == ulp_riscv_test_data_out);
  68. /* Clear test data */
  69. ulp_main_cpu_command = RISCV_NO_COMMAND;
  70. }
  71. TEST_CASE("ULP-RISC-V is able to wakeup main CPU from light sleep", "[ulp]")
  72. {
  73. struct timeval start, end;
  74. /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */
  75. load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length);
  76. /* Setup wakeup triggers */
  77. TEST_ASSERT(esp_sleep_enable_ulp_wakeup() == ESP_OK);
  78. /* Setup test data */
  79. ulp_main_cpu_command = RISCV_LIGHT_SLEEP_WAKEUP_TEST;
  80. /* Enter Light Sleep */
  81. esp_light_sleep_start();
  82. /* Wait till we receive the correct command response */
  83. gettimeofday(&start, NULL);
  84. while (ulp_command_resp != RISCV_LIGHT_SLEEP_WAKEUP_TEST)
  85. ;
  86. gettimeofday(&end, NULL);
  87. printf("Response time 1st: %jd ms\n", ((intmax_t)end.tv_sec - (intmax_t)start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000);
  88. /* Verify test data */
  89. TEST_ASSERT(ulp_command_resp == RISCV_LIGHT_SLEEP_WAKEUP_TEST);
  90. TEST_ASSERT(ulp_main_cpu_reply == RISCV_COMMAND_OK);
  91. /* Enter Light Sleep again */
  92. esp_light_sleep_start();
  93. /* Wait till we receive the correct command response */
  94. gettimeofday(&start, NULL);
  95. while (ulp_command_resp != RISCV_LIGHT_SLEEP_WAKEUP_TEST)
  96. ;
  97. gettimeofday(&end, NULL);
  98. printf("Response time 2nd: %jd ms\n", ((intmax_t)end.tv_sec - (intmax_t)start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000);
  99. /* Verify test data */
  100. TEST_ASSERT(ulp_command_resp == RISCV_LIGHT_SLEEP_WAKEUP_TEST);
  101. TEST_ASSERT(ulp_main_cpu_reply == RISCV_COMMAND_OK);
  102. /* Clear test data */
  103. ulp_main_cpu_command = RISCV_NO_COMMAND;
  104. }
  105. static bool ulp_riscv_is_running(uint32_t *counter_variable)
  106. {
  107. uint32_t start_cnt = *counter_variable;
  108. /* Wait a few ULP wakeup cycles to ensure ULP has run */
  109. vTaskDelay((5 * ULP_WAKEUP_PERIOD / 1000) / portTICK_PERIOD_MS);
  110. uint32_t end_cnt = *counter_variable;
  111. printf("start run count: %" PRIu32 ", end run count %" PRIu32 "\n", start_cnt, end_cnt);
  112. /* If the ulp is running the counter should have been incremented */
  113. return (start_cnt != end_cnt);
  114. }
  115. TEST_CASE("ULP-RISC-V can be stopped and resumed from main CPU", "[ulp]")
  116. {
  117. /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */
  118. load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length);
  119. TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter));
  120. printf("Stopping the ULP\n");
  121. ulp_riscv_timer_stop();
  122. ulp_riscv_halt();
  123. TEST_ASSERT(!ulp_riscv_is_running(&ulp_riscv_counter));
  124. printf("Resuming the ULP\n");
  125. ulp_riscv_timer_resume();
  126. TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter));
  127. }
  128. TEST_CASE("ULP-RISC-V can be loaded with and run multiple firmwares", "[ulp]")
  129. {
  130. /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */
  131. load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length);
  132. TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter));
  133. printf("Stopping the ULP\n");
  134. ulp_riscv_timer_stop();
  135. ulp_riscv_halt();
  136. TEST_ASSERT(!ulp_riscv_is_running(&ulp_riscv_counter));
  137. printf("Loading second firmware on the ULP\n");
  138. firmware_loaded = false;
  139. load_and_start_ulp_firmware(ulp_test_app2_bin_start, ulp_test_app2_bin_length);
  140. TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter2));
  141. printf("Stopping the ULP\n");
  142. ulp_riscv_timer_stop();
  143. ulp_riscv_halt();
  144. TEST_ASSERT(!ulp_riscv_is_running(&ulp_riscv_counter2));
  145. printf("Loading the first firmware again on the ULP\n");
  146. firmware_loaded = false;
  147. load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length);
  148. TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter));
  149. }
  150. TEST_CASE("ULP-RISC-V can be reloaded with a good fimware after a crash", "[ulp]")
  151. {
  152. /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */
  153. load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length);
  154. TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter));
  155. printf("Stopping the ULP\n");
  156. ulp_riscv_timer_stop();
  157. ulp_riscv_halt();
  158. TEST_ASSERT(!ulp_riscv_is_running(&ulp_riscv_counter));
  159. /* Enable ULP wakeup */
  160. TEST_ASSERT(esp_sleep_enable_ulp_wakeup() == ESP_OK);
  161. printf("Loading faulty firmware on the ULP and go into light sleep\n");
  162. firmware_loaded = false;
  163. load_and_start_ulp_firmware(ulp_test_app3_bin_start, ulp_test_app3_bin_length);
  164. esp_light_sleep_start();
  165. /* Verify that main CPU wakes up by a COCPU trap signal trigger */
  166. esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
  167. TEST_ASSERT(cause != ESP_SLEEP_WAKEUP_COCPU);
  168. printf("Resetting the ULP\n");
  169. ulp_riscv_reset();
  170. esp_rom_delay_us(20);
  171. printf("Loading the good firmware on ULP\n");
  172. firmware_loaded = false;
  173. load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length);
  174. TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter));
  175. }
  176. TEST_CASE("ULP-RISC-V can stop itself and be resumed from the main CPU", "[ulp]")
  177. {
  178. volatile riscv_test_commands_t *command_resp = (riscv_test_commands_t*)&ulp_command_resp;
  179. /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */
  180. load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length);
  181. TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter));
  182. printf("Stopping the ULP\n");
  183. /* Setup test data */
  184. ulp_main_cpu_command = RISCV_STOP_TEST;
  185. while (*command_resp != RISCV_STOP_TEST) {
  186. }
  187. /* Wait a bit to ensure ULP finished shutting down */
  188. vTaskDelay(100 / portTICK_PERIOD_MS);
  189. TEST_ASSERT(!ulp_riscv_is_running(&ulp_riscv_counter));
  190. printf("Resuming the ULP\n");
  191. ulp_main_cpu_command = RISCV_NO_COMMAND;
  192. ulp_riscv_timer_resume();
  193. TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter));
  194. }
  195. TEST_CASE("ULP-RISC-V mutex", "[ulp]")
  196. {
  197. /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */
  198. load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length);
  199. /* Setup test data */
  200. ulp_riscv_incrementer = 0;
  201. ulp_main_cpu_reply = RISCV_NO_COMMAND;
  202. ulp_main_cpu_command = RISCV_MUTEX_TEST;
  203. ulp_riscv_lock_t *lock = (ulp_riscv_lock_t*)&ulp_lock;
  204. for (int i = 0; i < MUTEX_TEST_ITERATIONS; i++) {
  205. ulp_riscv_lock_acquire(lock);
  206. ulp_riscv_incrementer++;
  207. ulp_riscv_lock_release(lock);
  208. }
  209. while(ulp_main_cpu_reply != RISCV_COMMAND_OK) {
  210. // Wait for ULP to finish
  211. }
  212. /* If the variable is protected there should be no race conditions
  213. results should be the sum of increments made by ULP and by main CPU
  214. */
  215. TEST_ASSERT_EQUAL(2*MUTEX_TEST_ITERATIONS, ulp_riscv_incrementer);
  216. }
  217. static void do_ulp_wakeup_deepsleep(riscv_test_commands_t ulp_cmd, bool rtc_periph_pd)
  218. {
  219. if (!rtc_periph_pd) {
  220. // Force RTC peripheral power domain to be on
  221. esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
  222. }
  223. /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */
  224. load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length);
  225. /* Setup wakeup triggers */
  226. TEST_ASSERT(esp_sleep_enable_ulp_wakeup() == ESP_OK);
  227. /* Setup test data */
  228. ulp_main_cpu_command = ulp_cmd;
  229. /* Enter Deep Sleep */
  230. esp_deep_sleep_start();
  231. UNITY_TEST_FAIL(__LINE__, "Should not get here!");
  232. }
  233. static void check_reset_reason_ulp_wakeup(void)
  234. {
  235. TEST_ASSERT_EQUAL(ESP_SLEEP_WAKEUP_ULP, esp_sleep_get_wakeup_cause());
  236. }
  237. static void do_ulp_wakeup_after_long_delay_deepsleep(void)
  238. {
  239. do_ulp_wakeup_deepsleep(RISCV_DEEP_SLEEP_WAKEUP_LONG_DELAY_TEST, true);
  240. }
  241. /* Certain erroneous wake-up triggers happen only after sleeping for a few seconds */
  242. TEST_CASE_MULTIPLE_STAGES("ULP-RISC-V is able to wakeup main CPU from deep sleep after a long delay", "[ulp]",
  243. do_ulp_wakeup_after_long_delay_deepsleep,
  244. check_reset_reason_ulp_wakeup);
  245. static void do_ulp_wakeup_after_long_delay_deepsleep_rtc_perip_on(void)
  246. {
  247. do_ulp_wakeup_deepsleep(RISCV_DEEP_SLEEP_WAKEUP_LONG_DELAY_TEST, false);
  248. }
  249. TEST_CASE_MULTIPLE_STAGES("ULP-RISC-V is able to wakeup main CPU from deep sleep after a long delay, RTC periph powerup", "[ulp]",
  250. do_ulp_wakeup_after_long_delay_deepsleep_rtc_perip_on,
  251. check_reset_reason_ulp_wakeup);
  252. static void do_ulp_wakeup_after_short_delay_deepsleep(void)
  253. {
  254. do_ulp_wakeup_deepsleep(RISCV_DEEP_SLEEP_WAKEUP_SHORT_DELAY_TEST, true);
  255. }
  256. TEST_CASE_MULTIPLE_STAGES("ULP-RISC-V is able to wakeup main CPU from deep sleep after a short delay", "[ulp]",
  257. do_ulp_wakeup_after_short_delay_deepsleep,
  258. check_reset_reason_ulp_wakeup);
  259. static void do_ulp_wakeup_after_short_delay_deepsleep_rtc_perip_on(void)
  260. {
  261. do_ulp_wakeup_deepsleep(RISCV_DEEP_SLEEP_WAKEUP_SHORT_DELAY_TEST, false);
  262. }
  263. TEST_CASE_MULTIPLE_STAGES("ULP-RISC-V is able to wakeup main CPU from deep sleep after a short delay, RTC periph powerup", "[ulp]",
  264. do_ulp_wakeup_after_short_delay_deepsleep_rtc_perip_on,
  265. check_reset_reason_ulp_wakeup);
  266. typedef struct {
  267. SemaphoreHandle_t ulp_isr_sw_sem;
  268. SemaphoreHandle_t ulp_isr_trap_sem;
  269. } TestSemaphore_t;
  270. static void ulp_riscv_isr(void *arg)
  271. {
  272. BaseType_t yield = 0;
  273. TestSemaphore_t *sem = (TestSemaphore_t *)arg;
  274. uint32_t status = READ_PERI_REG(RTC_CNTL_INT_ST_REG);
  275. if (status & ULP_RISCV_SW_INT) {
  276. xSemaphoreGiveFromISR(sem->ulp_isr_sw_sem, &yield);
  277. } else if (status & ULP_RISCV_TRAP_INT) {
  278. xSemaphoreGiveFromISR(sem->ulp_isr_trap_sem, &yield);
  279. }
  280. if (yield) {
  281. portYIELD_FROM_ISR();
  282. }
  283. }
  284. TEST_CASE("ULP-RISC-V interrupt signals can be handled via ISRs on the main core", "[ulp]")
  285. {
  286. /* Create test semaphores */
  287. TestSemaphore_t test_sem_cfg;
  288. test_sem_cfg.ulp_isr_sw_sem = xSemaphoreCreateBinary();
  289. TEST_ASSERT_NOT_NULL(test_sem_cfg.ulp_isr_sw_sem);
  290. test_sem_cfg.ulp_isr_trap_sem = xSemaphoreCreateBinary();
  291. TEST_ASSERT_NOT_NULL(test_sem_cfg.ulp_isr_trap_sem);
  292. /* Register ULP RISC-V signal ISR */
  293. TEST_ASSERT_EQUAL(ESP_OK, ulp_riscv_isr_register(ulp_riscv_isr, (void *)&test_sem_cfg,
  294. (ULP_RISCV_SW_INT | ULP_RISCV_TRAP_INT)));
  295. /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */
  296. printf("Loading good ULP firmware\n");
  297. firmware_loaded = false;
  298. load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length);
  299. /* Setup test data. We only need the ULP to send a wakeup signal to the main CPU. */
  300. ulp_main_cpu_command = RISCV_READ_WRITE_TEST;
  301. /* Wait for the ISR to be called */
  302. printf("Waiting for ULP wakeup signal ...\n");
  303. TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(test_sem_cfg.ulp_isr_sw_sem, portMAX_DELAY));
  304. printf("ULP wakeup signal interrupt triggered\n");
  305. /* Reset the ULP command */
  306. ulp_main_cpu_command = RISCV_NO_COMMAND;
  307. /* Load ULP RISC-V with faulty firmware and restart the ULP RISC-V Coprocessor.
  308. * This should cause a cocpu trap signal interrupt.
  309. */
  310. printf("Loading faulty ULP firmware\n");
  311. firmware_loaded = false;
  312. load_and_start_ulp_firmware(ulp_test_app3_bin_start, ulp_test_app3_bin_length);
  313. /* Wait for the ISR to be called */
  314. printf("Waiting for ULP trap signal ...\n");
  315. TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(test_sem_cfg.ulp_isr_trap_sem, portMAX_DELAY));
  316. printf("ULP trap signal interrupt triggered\n");
  317. /* Deregister the ISR */
  318. TEST_ASSERT_EQUAL(ESP_OK, ulp_riscv_isr_deregister(ulp_riscv_isr, (void *)&test_sem_cfg,
  319. (ULP_RISCV_SW_INT | ULP_RISCV_TRAP_INT)));
  320. /* Delete test semaphores */
  321. vSemaphoreDelete(test_sem_cfg.ulp_isr_sw_sem);
  322. vSemaphoreDelete(test_sem_cfg.ulp_isr_trap_sem);
  323. /* Make sure ULP has a good firmware running before exiting the test */
  324. ulp_riscv_reset();
  325. firmware_loaded = false;
  326. load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length);
  327. }