test_psram.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /*
  2. * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "sdkconfig.h"
  7. #include <sys/param.h>
  8. #include <string.h>
  9. #include "inttypes.h"
  10. #include "esp_log.h"
  11. #include "esp_attr.h"
  12. #include "freertos/FreeRTOS.h"
  13. #include "freertos/task.h"
  14. #include "unity.h"
  15. #include "esp_heap_caps.h"
  16. #include "esp_private/esp_psram_io.h"
  17. #include "esp_psram.h"
  18. #include "esp_private/esp_psram_extram.h"
  19. #include "esp_flash.h"
  20. #include "esp_partition.h"
  21. __attribute__((unused)) const static char *TAG = "PSRAM";
  22. TEST_CASE("test psram heap allocable", "[psram]")
  23. {
  24. size_t largest_size = heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);
  25. ESP_LOGI(TAG, "largest size is %zu", largest_size);
  26. uint32_t *ext_buffer = (uint32_t *)heap_caps_calloc(largest_size, 1, MALLOC_CAP_SPIRAM);
  27. TEST_ASSERT(ext_buffer);
  28. intptr_t start = (intptr_t)ext_buffer;
  29. intptr_t end = (intptr_t)ext_buffer + largest_size;
  30. ESP_LOGI(TAG, "test ext buffer start addr is 0x%"PRIxPTR", end addr is 0x%"PRIxPTR, start, end);
  31. TEST_ASSERT(esp_psram_check_ptr_addr((void *)start) && esp_psram_check_ptr_addr((void *)end));
  32. for (int i = 0; i < largest_size / sizeof(uint32_t); i++) {
  33. ext_buffer[i] = (i + 1) ^ 0xaaaaaaaa;
  34. }
  35. for (int i = 0; i < largest_size / sizeof(uint32_t); i++) {
  36. TEST_ASSERT(ext_buffer[i] == ((i + 1) ^ 0xaaaaaaaa));
  37. }
  38. free(ext_buffer);
  39. }
  40. #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA
  41. #include "esp_partition.h"
  42. #include "driver/gptimer.h"
  43. #include "esp_rom_spiflash.h"
  44. #define SECTOR_LEN 4096
  45. #define TEST_NUM 10
  46. #define TEST_BUF {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}
  47. static uint32_t s_timer_cb_exe_times;
  48. static const uint8_t s_test_buf[TEST_NUM] = TEST_BUF;
  49. static const esp_partition_t *s_get_partition(void)
  50. {
  51. //Find the "storage1" partition defined in `partitions.csv`
  52. const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage1");
  53. if (!result) {
  54. ESP_LOGE(TAG, "Can't find the partition, please define it correctly in `partitions.csv`");
  55. abort();
  56. }
  57. return result;
  58. }
  59. static bool NOINLINE_ATTR s_test_rodata(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
  60. {
  61. s_timer_cb_exe_times ++;
  62. uint8_t cmp_buf[TEST_NUM] = TEST_BUF;
  63. TEST_ASSERT(memcmp(cmp_buf, s_test_buf, TEST_NUM) == 0);
  64. return false;
  65. }
  66. TEST_CASE("test spi1 flash operation after putting .text and .rodata into psram", "[psram]")
  67. {
  68. //Get the partition used for SPI1 erase operation
  69. const esp_partition_t *part = s_get_partition();
  70. ESP_LOGI(TAG, "found partition '%s' at offset 0x%"PRIx32" with size 0x%"PRIx32, part->label, part->address, part->size);
  71. //Erase whole region
  72. TEST_ESP_OK(esp_flash_erase_region(part->flash_chip, part->address, part->size));
  73. gptimer_handle_t gptimer = NULL;
  74. gptimer_config_t timer_config = {
  75. .resolution_hz = 1 * 1000 * 1000,
  76. .clk_src = GPTIMER_CLK_SRC_DEFAULT,
  77. .direction = GPTIMER_COUNT_UP,
  78. };
  79. TEST_ESP_OK(gptimer_new_timer(&timer_config, &gptimer));
  80. gptimer_alarm_config_t alarm_config = {
  81. .reload_count = 0,
  82. .alarm_count = 10, // 10us
  83. .flags.auto_reload_on_alarm = true,
  84. };
  85. TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
  86. gptimer_event_callbacks_t cbs = {
  87. .on_alarm = s_test_rodata,
  88. };
  89. TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));
  90. esp_rom_spiflash_result_t ret;
  91. uint32_t start = part->address;
  92. ESP_LOGI(TAG, "test data partition: 0x%"PRIx32, start);
  93. uint32_t sector_num = start / SECTOR_LEN;
  94. TEST_ESP_OK(gptimer_enable(gptimer));
  95. TEST_ESP_OK(gptimer_start(gptimer));
  96. ret = esp_rom_spiflash_erase_sector(sector_num);
  97. if (ret != ESP_ROM_SPIFLASH_RESULT_OK) {
  98. ESP_LOGE(TAG, "erase fail!");
  99. TEST_ASSERT(false);
  100. }
  101. TEST_ESP_OK(gptimer_stop(gptimer));
  102. TEST_ASSERT(s_timer_cb_exe_times > 0);
  103. printf("timer callback runs %"PRId32" times\n", s_timer_cb_exe_times);
  104. ESP_LOGI(TAG, "Finish");
  105. TEST_ESP_OK(gptimer_disable(gptimer));
  106. TEST_ESP_OK(gptimer_del_timer(gptimer));
  107. }
  108. #endif //CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA
  109. TEST_CASE("test psram unaligned access", "[psram]")
  110. {
  111. size_t largest_size = heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
  112. ESP_LOGI(TAG, "largest size is %zu", largest_size);
  113. uint8_t *ext_buffer = (uint8_t *)heap_caps_calloc(largest_size, 1, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
  114. for (int i = 0; i < largest_size; i++) {
  115. ext_buffer[i] = i & 0xff;
  116. }
  117. for (int i = 0; i < largest_size - 4; i += 4) {
  118. uint8_t *ptr_base = (uint8_t *)(ext_buffer + i);
  119. for (int j = 1; j < 4; j++) {
  120. uint8_t *unaligned_ptr = (uint8_t *)(ptr_base + j);
  121. ESP_LOGV(TAG, "i is %d, j is %d, unaligned_ptr addr is %p", i, j, unaligned_ptr);
  122. uint8_t val_8bit = *unaligned_ptr;
  123. ESP_LOGV(TAG, "i is %d, j is %d, val_8bit val is 0x%"PRIx8, i, j, val_8bit);
  124. uint8_t first_byte = (i + j) & 0xff;
  125. uint8_t expected_val_8bit = first_byte;
  126. TEST_ASSERT(val_8bit == expected_val_8bit);
  127. /**
  128. * If the vaddr doesn't support unaligned access, below codes will generate `LoadStoreAlignment` error.
  129. *
  130. * This is because below lines includes 16-bit load and 32-bit load:
  131. * - l16ui
  132. * - l32i.n
  133. *
  134. * Whereas we use an `add.n` to adding an offset (from 0 to 3) to the original buffer address.
  135. *
  136. * Therefore we get unaligned access
  137. */
  138. uint16_t val_16bit = *(uint16_t *)unaligned_ptr;
  139. ESP_LOGV(TAG, "i is %d, j is %d, val_16bit val is 0x%"PRIx16, i, j, val_16bit);
  140. uint32_t val_32bit = *(uint32_t *)unaligned_ptr;
  141. ESP_LOGV(TAG, "i is %d, j is %d, val_32bit val is 0x%"PRIx32, i, j, val_32bit);
  142. uint8_t second_byte = ((i + j) & 0xff) + 1;
  143. uint8_t third_byte = ((i + j) & 0xff) + 2;
  144. uint8_t fourth_byte = ((i + j) & 0xff) + 3;
  145. uint16_t expected_val_16bit = (second_byte << 8) | first_byte;
  146. ESP_LOGV(TAG, "i is %d, j is %d, expected_val_16bit val is 0x%"PRIx16, i, j, expected_val_16bit);
  147. TEST_ASSERT(val_16bit == expected_val_16bit);
  148. uint32_t expected_val_32bit = (fourth_byte << 24) | (third_byte << 16) | (second_byte << 8) | first_byte;
  149. ESP_LOGV(TAG, "i is %d, j is %d, expected_val_32bit val is 0x%" PRIx32, i, j, expected_val_32bit);
  150. TEST_ASSERT(val_32bit == expected_val_32bit);
  151. }
  152. }
  153. heap_caps_free(ext_buffer);
  154. }