1 /*
2  * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 /*
7 This code tests the interaction between PSRAM and SPI flash routines.
8 */
9 
10 #include <esp_types.h>
11 #include <stdio.h>
12 #include "freertos/FreeRTOS.h"
13 #include "freertos/task.h"
14 #include "freertos/semphr.h"
15 #include "freertos/queue.h"
16 #include "unity.h"
17 #include <stdint.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include "esp_heap_caps.h"
22 #include "esp_spi_flash.h"
23 #include "esp_partition.h"
24 #include "test_utils.h"
25 #include "soc/soc.h"
26 
27 #if CONFIG_SPIRAM
28 
29 #if CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC
30 #define USE_CAPS_ALLOC 1
31 #endif // CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC
32 
33 #define TSTSZ (16*1024)
34 
35 #if !CONFIG_FREERTOS_UNICORE
36 
37 volatile static int res[2], err[2];
38 
tstMem(void * arg)39 void tstMem(void *arg) {
40     volatile unsigned char *mem=(volatile unsigned char*)arg;
41     int p=0;
42     while(1) {
43         for (int i=0; i<TSTSZ; i++) {
44             mem[i]=(i^p);
45         }
46         for (int i=0; i<TSTSZ; i++) {
47             if (mem[i]!=((i^p)&0xff)) {
48                 printf("Core %d mem err! Got %x espected %x at addr %p\n", xPortGetCoreID(), mem[i], (i^p)&0xff, &mem[i]);
49                 err[xPortGetCoreID()]++;
50             }
51         }
52         p++;
53         res[xPortGetCoreID()]++;
54     }
55 }
56 
57 
58 TEST_CASE("Spiram cache flush on mmap", "[spiram]")
59 {
60     void *mem[2];
61     res[0]=0; res[1]=0;
62 #if USE_CAPS_ALLOC
63     printf("Allocating SPI RAM chunk...\n");
64     mem[0]=heap_caps_malloc(TSTSZ, MALLOC_CAP_SPIRAM);
65     mem[1]=heap_caps_malloc(TSTSZ, MALLOC_CAP_SPIRAM);
66 #else
67     mem[0]=(void*)SOC_EXTRAM_DATA_LOW;
68     mem[1]=(void*)SOC_EXTRAM_DATA_LOW+TSTSZ;
69 #endif
70     assert(mem[0]);
71     assert(mem[1]);
72     TaskHandle_t th[2];
73     err[0]=0; err[1]=0;
74     printf("Creating tasks\n");
75     xTaskCreatePinnedToCore(tstMem  , "tskone"  , 2048, mem[0], 3, &th[0], 0);
76     xTaskCreatePinnedToCore(tstMem  , "tsktwo"  , 2048, mem[1], 3, &th[1], 1);
77 
78     for (int l=0; l<10; l++) {
79         for (int p=0; p<4096*1024; p+=65536) {
80             const void *out;
81             spi_flash_mmap_handle_t h;
82             spi_flash_mmap(p, 65536, SPI_FLASH_MMAP_DATA, &out, &h);
83             spi_flash_munmap(h);
84         }
85     }
86 
87     printf("Checked memory %d and %d times. Errors: %d and %d\n", res[0], res[1], err[0], err[1]);
88 
89     vTaskDelete(th[0]);
90     vTaskDelete(th[1]);
91 #if USE_CAPS_ALLOC
92     free(mem[0]);
93     free(mem[1]);
94 #endif
95     TEST_ASSERT(err[0]==0);
96     TEST_ASSERT(err[1]==0);
97 }
98 
99 
100 #define CYCLES 1024
101 
102 TEST_CASE("Spiram cache flush on write/read", "[spiram]")
103 {
104     void *mem[2];
105     res[0]=0; res[1]=0;
106 #if USE_CAPS_ALLOC
107     printf("Allocating SPI RAM chunk...\n");
108     mem[0]=heap_caps_malloc(TSTSZ, MALLOC_CAP_SPIRAM);
109     mem[1]=heap_caps_malloc(TSTSZ, MALLOC_CAP_SPIRAM);
110 #else
111     mem[0]=(void*)SOC_EXTRAM_DATA_LOW;
112     mem[1]=(void*)SOC_EXTRAM_DATA_LOW+TSTSZ;
113 #endif
114     assert(mem[0]);
115     assert(mem[1]);
116     TaskHandle_t th[2];
117     const esp_partition_t* part = get_test_data_partition();
118     assert(part!=NULL);
119 
120     printf("Erasing sector...\n");
121     esp_partition_erase_range(part, 0, 64*1024);
122     printf("Erased.\n");
123     printf("Creating tasks\n");
124     xTaskCreatePinnedToCore(tstMem  , "tskone"  , 2048, mem[0], 3, &th[0], 0);
125     xTaskCreatePinnedToCore(tstMem  , "tsktwo"  , 2048, mem[1], 3, &th[1], 1);
126     char buf[512];
127 
128     const void *out;
129     spi_flash_mmap_handle_t handle;
130     esp_partition_mmap(part, 0, 512, SPI_FLASH_MMAP_DATA, &out, &handle);
131     for (int i=0; i<CYCLES; i++) {
132         esp_partition_write(part, 0, buf, 512);
133         esp_partition_read(part, 0, buf, 512);
134         vTaskDelay(1);
135     }
136     spi_flash_munmap(handle);
137 
138     printf("Checked memory %d and %d times.\n", res[0], res[1]);
139 
140     vTaskDelete(th[0]);
141     vTaskDelete(th[1]);
142 #if USE_CAPS_ALLOC
143     free(mem[0]);
144     free(mem[1]);
145 #endif
146 }
147 #endif // !CONFIG_FREERTOS_UNICORE
148 
149 IRAM_ATTR TEST_CASE("Spiram memcmp weirdness at 80MHz", "[spiram]") {
150     char *mem1=malloc(0x10000);
151 #if USE_CAPS_ALLOC
152     char *mem2=heap_caps_malloc(0x10000, MALLOC_CAP_SPIRAM);
153 #else
154     char *mem2=(void*)SOC_EXTRAM_DATA_LOW;
155 #endif
156 
157 #if !CONFIG_SPIRAM_SPEED_80M
158     printf("**** WARNING **** Spi memory isn't running at 80MHz, so this test is somewhat meaningless.\n");
159 #endif
160 
161     printf("RAM: Got %p and %p\n", mem1, mem2);
162     assert(mem1);
163     assert(mem2);
164     for (int i=0; i<0x10000; i++) mem1[i]=i^0xAAAAAAAA;
165 
166     for (int cycle=1; cycle<100; cycle++) {
167         memcpy(mem2, mem1, 0x10000);
168         if (memcmp(mem1, mem2, 0x10000)!=0) {
169             printf("Memcmp failed! Cycle %d\n", cycle);
170             for (int i=0; i<0x10000; i++) {
171                 if (mem1[i]!=mem2[i]) {
172                     printf("Found real difference at index %d: 0x%x vs 0x%x\n", i, mem1[i], mem2[i]);
173                     break;
174                 }
175             }
176         }
177     }
178 
179     free(mem1);
180 #if USE_CAPS_ALLOC
181     free(mem2);
182 #endif
183 }
184 
185 #endif // CONFIG_SPIRAM
186