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