test_intr_alloc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. Tests for the interrupt allocator.
  3. */
  4. #include <stdio.h>
  5. #include "esp_types.h"
  6. #include "esp_rom_sys.h"
  7. #include "freertos/FreeRTOS.h"
  8. #include "freertos/task.h"
  9. #include "freertos/semphr.h"
  10. #include "freertos/queue.h"
  11. #include "unity.h"
  12. #include "esp_intr_alloc.h"
  13. #include "driver/periph_ctrl.h"
  14. #include "driver/timer.h"
  15. #include "soc/soc_caps.h"
  16. #include "soc/spi_periph.h"
  17. #include "hal/spi_ll.h"
  18. #include "sdkconfig.h"
  19. #define TIMER_DIVIDER (16) /*!< Hardware timer clock divider */
  20. #define TIMER_SCALE (APB_CLK_FREQ / TIMER_DIVIDER) /*!< used to calculate counter value */
  21. #define TIMER_INTERVAL0_SEC (3) /*!< test interval for timer 0 */
  22. #define TIMER_INTERVAL1_SEC (5) /*!< test interval for timer 1 */
  23. static void my_timer_init(int timer_group, int timer_idx, uint64_t alarm_value)
  24. {
  25. timer_config_t config = {
  26. .alarm_en = 1,
  27. .auto_reload = 1,
  28. .counter_dir = TIMER_COUNT_UP,
  29. .divider = TIMER_DIVIDER,
  30. };
  31. /*Configure timer*/
  32. timer_init(timer_group, timer_idx, &config);
  33. /*Stop timer counter*/
  34. timer_pause(timer_group, timer_idx);
  35. /*Load counter value */
  36. timer_set_counter_value(timer_group, timer_idx, 0);
  37. /*Set alarm value*/
  38. timer_set_alarm_value(timer_group, timer_idx, alarm_value);
  39. /*Enable timer interrupt*/
  40. timer_enable_intr(timer_group, timer_idx);
  41. }
  42. static volatile int count[SOC_TIMER_GROUP_TOTAL_TIMERS] = {0};
  43. static void timer_isr(void *arg)
  44. {
  45. int timer_idx = (int)arg;
  46. int group_id = timer_idx / SOC_TIMER_GROUP_TIMERS_PER_GROUP;
  47. int timer_id = timer_idx % SOC_TIMER_GROUP_TIMERS_PER_GROUP;
  48. count[timer_idx]++;
  49. timer_group_clr_intr_status_in_isr(group_id, timer_id);
  50. timer_group_enable_alarm_in_isr(group_id, timer_id);
  51. }
  52. static void timer_test(int flags)
  53. {
  54. timer_isr_handle_t inth[SOC_TIMER_GROUP_TOTAL_TIMERS];
  55. for (int i = 0; i < SOC_TIMER_GROUPS; i++) {
  56. for (int j = 0; j < SOC_TIMER_GROUP_TIMERS_PER_GROUP; j++) {
  57. my_timer_init(i, j, 100000 + 10000 * (i * SOC_TIMER_GROUP_TIMERS_PER_GROUP + j + 1));
  58. }
  59. }
  60. timer_isr_register(0, 0, timer_isr, (void *)0, flags | ESP_INTR_FLAG_INTRDISABLED, &inth[0]);
  61. printf("Interrupts allocated: %d (dis)\r\n", esp_intr_get_intno(inth[0]));
  62. for (int j = 1; j < SOC_TIMER_GROUP_TIMERS_PER_GROUP; j++) {
  63. timer_isr_register(0, j, timer_isr, (void *)1, flags, &inth[j]);
  64. printf("Interrupts allocated: %d\r\n", esp_intr_get_intno(inth[j]));
  65. }
  66. for (int i = 1; i < SOC_TIMER_GROUPS; i++) {
  67. for (int j = 0; j < SOC_TIMER_GROUP_TIMERS_PER_GROUP; j++) {
  68. timer_isr_register(i, j, timer_isr, (void *)(i * SOC_TIMER_GROUP_TIMERS_PER_GROUP + j), flags, &inth[i * SOC_TIMER_GROUP_TIMERS_PER_GROUP + j]);
  69. printf("Interrupts allocated: %d\r\n", esp_intr_get_intno(inth[i * SOC_TIMER_GROUP_TIMERS_PER_GROUP + j]));
  70. }
  71. }
  72. for (int i = 0; i < SOC_TIMER_GROUPS; i++) {
  73. for (int j = 0; j < SOC_TIMER_GROUP_TIMERS_PER_GROUP; j++) {
  74. timer_start(i, j);
  75. }
  76. }
  77. printf("Timer values on start:");
  78. for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
  79. count[i] = 0;
  80. printf(" %d", count[i]);
  81. }
  82. printf("\r\n");
  83. vTaskDelay(1000 / portTICK_PERIOD_MS);
  84. printf("Timer values after 1 sec:");
  85. for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
  86. printf(" %d", count[i]);
  87. }
  88. printf("\r\n");
  89. TEST_ASSERT(count[0] == 0);
  90. for (int i = 1; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
  91. TEST_ASSERT(count[i] != 0);
  92. }
  93. printf("Disabling half of timers' interrupt...\r\n");
  94. for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS / 2; i++) {
  95. esp_intr_disable(inth[i]);
  96. }
  97. for (int i = SOC_TIMER_GROUP_TOTAL_TIMERS / 2; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
  98. esp_intr_enable(inth[i]);
  99. }
  100. for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
  101. count[i] = 0;
  102. }
  103. vTaskDelay(1000 / portTICK_PERIOD_MS);
  104. printf("Timer values after 1 sec:");
  105. for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
  106. printf(" %d", count[i]);
  107. }
  108. printf("\r\n");
  109. for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS / 2; i++) {
  110. TEST_ASSERT(count[i] == 0);
  111. }
  112. for (int i = SOC_TIMER_GROUP_TOTAL_TIMERS / 2; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
  113. TEST_ASSERT(count[i] != 0);
  114. }
  115. printf("Disabling another half...\r\n");
  116. for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS / 2; i++) {
  117. esp_intr_enable(inth[i]);
  118. }
  119. for (int i = SOC_TIMER_GROUP_TOTAL_TIMERS / 2; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
  120. esp_intr_disable(inth[i]);
  121. }
  122. for (int x = 0; x < SOC_TIMER_GROUP_TOTAL_TIMERS; x++) {
  123. count[x] = 0;
  124. }
  125. vTaskDelay(1000 / portTICK_PERIOD_MS);
  126. printf("Timer values after 1 sec:");
  127. for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
  128. printf(" %d", count[i]);
  129. }
  130. printf("\r\n");
  131. for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS / 2; i++) {
  132. TEST_ASSERT(count[i] != 0);
  133. }
  134. for (int i = SOC_TIMER_GROUP_TOTAL_TIMERS / 2; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
  135. TEST_ASSERT(count[i] == 0);
  136. }
  137. printf("Done.\n");
  138. for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
  139. esp_intr_free(inth[i]);
  140. }
  141. }
  142. TEST_CASE("Intr_alloc test, private ints", "[intr_alloc]")
  143. {
  144. timer_test(0);
  145. }
  146. TEST_CASE("Intr_alloc test, shared ints", "[intr_alloc]")
  147. {
  148. timer_test(ESP_INTR_FLAG_SHARED);
  149. }
  150. typedef struct {
  151. bool flag1;
  152. bool flag2;
  153. bool flag3;
  154. bool flag4;
  155. } intr_alloc_test_ctx_t;
  156. void IRAM_ATTR int_handler1(void *arg)
  157. {
  158. intr_alloc_test_ctx_t *ctx = (intr_alloc_test_ctx_t *)arg;
  159. esp_rom_printf("handler 1 called.\n");
  160. if ( ctx->flag1 ) {
  161. ctx->flag3 = true;
  162. } else {
  163. ctx->flag1 = true;
  164. }
  165. #ifdef CONFIG_IDF_TARGET_ESP32
  166. spi_ll_clear_int_stat(&SPI2);
  167. #else
  168. spi_ll_clear_int_stat(&GPSPI2);
  169. #endif
  170. }
  171. void IRAM_ATTR int_handler2(void *arg)
  172. {
  173. intr_alloc_test_ctx_t *ctx = (intr_alloc_test_ctx_t *)arg;
  174. esp_rom_printf("handler 2 called.\n");
  175. if ( ctx->flag2 ) {
  176. ctx->flag4 = true;
  177. } else {
  178. ctx->flag2 = true;
  179. }
  180. }
  181. TEST_CASE("allocate 2 handlers for a same source and remove the later one", "[intr_alloc]")
  182. {
  183. intr_alloc_test_ctx_t ctx = {false, false, false, false };
  184. intr_handle_t handle1, handle2;
  185. // enable SPI2
  186. periph_module_enable(spi_periph_signal[1].module);
  187. esp_err_t r;
  188. r = esp_intr_alloc(spi_periph_signal[1].irq, ESP_INTR_FLAG_SHARED, int_handler1, &ctx, &handle1);
  189. TEST_ESP_OK(r);
  190. //try an invalid assign first
  191. r = esp_intr_alloc(spi_periph_signal[1].irq, 0, int_handler2, NULL, &handle2);
  192. TEST_ASSERT_EQUAL_INT(ESP_ERR_NOT_FOUND, r);
  193. //assign shared then
  194. r = esp_intr_alloc(spi_periph_signal[1].irq, ESP_INTR_FLAG_SHARED, int_handler2, &ctx, &handle2);
  195. TEST_ESP_OK(r);
  196. #ifdef CONFIG_IDF_TARGET_ESP32
  197. spi_ll_enable_int(&SPI2);
  198. #else
  199. spi_ll_enable_int(&GPSPI2);
  200. #endif
  201. printf("trigger first time.\n");
  202. #ifdef CONFIG_IDF_TARGET_ESP32
  203. spi_ll_set_int_stat(&SPI2);
  204. #else
  205. spi_ll_set_int_stat(&GPSPI2);
  206. #endif
  207. vTaskDelay(100);
  208. TEST_ASSERT( ctx.flag1 && ctx.flag2 );
  209. printf("remove intr 1.\n");
  210. r = esp_intr_free(handle2);
  211. printf("trigger second time.\n");
  212. #ifdef CONFIG_IDF_TARGET_ESP32
  213. spi_ll_set_int_stat(&SPI2);
  214. #else
  215. spi_ll_set_int_stat(&GPSPI2);
  216. #endif
  217. vTaskDelay(500);
  218. TEST_ASSERT( ctx.flag3 && !ctx.flag4 );
  219. printf("test passed.\n");
  220. esp_intr_free(handle1);
  221. }
  222. static void dummy(void *arg)
  223. {
  224. }
  225. static IRAM_ATTR void dummy_iram(void *arg)
  226. {
  227. }
  228. static RTC_IRAM_ATTR void dummy_rtc(void *arg)
  229. {
  230. }
  231. TEST_CASE("Can allocate IRAM int only with an IRAM handler", "[intr_alloc]")
  232. {
  233. intr_handle_t ih;
  234. esp_err_t err = esp_intr_alloc(spi_periph_signal[1].irq,
  235. ESP_INTR_FLAG_IRAM, &dummy, NULL, &ih);
  236. TEST_ASSERT_EQUAL_INT(ESP_ERR_INVALID_ARG, err);
  237. err = esp_intr_alloc(spi_periph_signal[1].irq,
  238. ESP_INTR_FLAG_IRAM, &dummy_iram, NULL, &ih);
  239. TEST_ESP_OK(err);
  240. err = esp_intr_free(ih);
  241. TEST_ESP_OK(err);
  242. err = esp_intr_alloc(spi_periph_signal[1].irq,
  243. ESP_INTR_FLAG_IRAM, &dummy_rtc, NULL, &ih);
  244. TEST_ESP_OK(err);
  245. err = esp_intr_free(ih);
  246. TEST_ESP_OK(err);
  247. }
  248. #ifndef CONFIG_FREERTOS_UNICORE
  249. void isr_free_task(void *param)
  250. {
  251. esp_err_t ret = ESP_FAIL;
  252. intr_handle_t *test_handle = (intr_handle_t *)param;
  253. if (*test_handle != NULL) {
  254. ret = esp_intr_free(*test_handle);
  255. if (ret == ESP_OK) {
  256. *test_handle = NULL;
  257. }
  258. }
  259. vTaskDelete(NULL);
  260. }
  261. void isr_alloc_free_test(void)
  262. {
  263. intr_handle_t test_handle = NULL;
  264. esp_err_t ret = esp_intr_alloc(spi_periph_signal[1].irq, 0, int_handler1, NULL, &test_handle);
  265. if (ret != ESP_OK) {
  266. printf("alloc isr handle fail\n");
  267. } else {
  268. printf("alloc isr handle on core %d\n", esp_intr_get_cpu(test_handle));
  269. }
  270. TEST_ASSERT(ret == ESP_OK);
  271. xTaskCreatePinnedToCore(isr_free_task, "isr_free_task", 1024 * 2, (void *)&test_handle, 10, NULL, !xPortGetCoreID());
  272. vTaskDelay(1000 / portTICK_RATE_MS);
  273. TEST_ASSERT(test_handle == NULL);
  274. printf("test passed\n");
  275. }
  276. TEST_CASE("alloc and free isr handle on different core", "[intr_alloc]")
  277. {
  278. isr_alloc_free_test();
  279. }
  280. #endif
  281. #if __XTENSA__
  282. static volatile int int_timer_ctr;
  283. void int_timer_handler(void *arg)
  284. {
  285. xthal_set_ccompare(1, xthal_get_ccount() + 8000000);
  286. int_timer_ctr++;
  287. }
  288. static void local_timer_test(void)
  289. {
  290. intr_handle_t ih;
  291. esp_err_t r;
  292. r = esp_intr_alloc(ETS_INTERNAL_TIMER1_INTR_SOURCE, 0, int_timer_handler, NULL, &ih);
  293. TEST_ASSERT(r == ESP_OK);
  294. printf("Int timer 1 intno %d\n", esp_intr_get_intno(ih));
  295. xthal_set_ccompare(1, xthal_get_ccount() + 8000000);
  296. int_timer_ctr = 0;
  297. vTaskDelay(1000 / portTICK_PERIOD_MS);
  298. printf("Timer val after 1 sec: %d\n", int_timer_ctr);
  299. TEST_ASSERT(int_timer_ctr != 0);
  300. printf("Disabling int\n");
  301. esp_intr_disable(ih);
  302. int_timer_ctr = 0;
  303. vTaskDelay(1000 / portTICK_PERIOD_MS);
  304. printf("Timer val after 1 sec: %d\n", int_timer_ctr);
  305. TEST_ASSERT(int_timer_ctr == 0);
  306. printf("Re-enabling\n");
  307. esp_intr_enable(ih);
  308. vTaskDelay(1000 / portTICK_PERIOD_MS);
  309. printf("Timer val after 1 sec: %d\n", int_timer_ctr);
  310. TEST_ASSERT(int_timer_ctr != 0);
  311. printf("Free int, re-alloc disabled\n");
  312. r = esp_intr_free(ih);
  313. TEST_ASSERT(r == ESP_OK);
  314. r = esp_intr_alloc(ETS_INTERNAL_TIMER1_INTR_SOURCE, ESP_INTR_FLAG_INTRDISABLED, int_timer_handler, NULL, &ih);
  315. TEST_ASSERT(r == ESP_OK);
  316. int_timer_ctr = 0;
  317. vTaskDelay(1000 / portTICK_PERIOD_MS);
  318. printf("Timer val after 1 sec: %d\n", int_timer_ctr);
  319. TEST_ASSERT(int_timer_ctr == 0);
  320. printf("Re-enabling\n");
  321. esp_intr_enable(ih);
  322. vTaskDelay(1000 / portTICK_PERIOD_MS);
  323. printf("Timer val after 1 sec: %d\n", int_timer_ctr);
  324. TEST_ASSERT(int_timer_ctr != 0);
  325. r = esp_intr_free(ih);
  326. TEST_ASSERT(r == ESP_OK);
  327. printf("Done.\n");
  328. }
  329. TEST_CASE("Intr_alloc test, CPU-local int source", "[intr_alloc]")
  330. {
  331. local_timer_test();
  332. }
  333. #endif // #if __XTENSA__