1
2 #include <esp_types.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include "esp32/rom/lldesc.h"
6 #include "driver/periph_ctrl.h"
7 #include "hal/gpio_hal.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
14 #include "unity.h"
15
16 #include "soc/uart_periph.h"
17 #include "soc/dport_reg.h"
18 #include "soc/gpio_periph.h"
19 #include "soc/i2s_periph.h"
20
21
22
23 #define DPORT_I2S0_CLK_EN (BIT(4))
24 #define DPORT_I2S0_RST (BIT(4))
25
26
27 /*
28 This test tests the s32c1i instruction when the AHB bus is also used. To create some AHB traffic, we use the I2S interface
29 to copy bytes over from one memory location to another. DO NOT USE the i2s routines inhere, they've been trial-and-error'ed until
30 the point where they happened to do what I want.
31 */
32
lcdIfaceInit(void)33 static void lcdIfaceInit(void)
34 {
35 periph_module_enable(PERIPH_I2S0_MODULE);
36
37 //Init pins to i2s functions
38 SET_PERI_REG_MASK(GPIO_ENABLE_W1TS_REG, (1 << 11) | (1 << 3) | (1 << 0) | (1 << 2) | (1 << 5) | (1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20)); //ENABLE GPIO oe_enable
39
40 gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, 0);
41 gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO2_U, 0);
42 gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO5_U, 0);
43 gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO16_U, 0);
44 gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO17_U, 0);
45 gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO18_U, 0);
46 gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO19_U, 0);
47 gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO20_U, 0);
48 gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CMD_U, 2); //11
49 gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO26_U, 0); //RS
50
51 WRITE_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG, (148 << GPIO_FUNC0_OUT_SEL_S));
52 WRITE_PERI_REG(GPIO_FUNC2_OUT_SEL_CFG_REG, (149 << GPIO_FUNC0_OUT_SEL_S));
53 WRITE_PERI_REG(GPIO_FUNC5_OUT_SEL_CFG_REG, (150 << GPIO_FUNC0_OUT_SEL_S));
54 WRITE_PERI_REG(GPIO_FUNC16_OUT_SEL_CFG_REG, (151 << GPIO_FUNC0_OUT_SEL_S));
55 WRITE_PERI_REG(GPIO_FUNC17_OUT_SEL_CFG_REG, (152 << GPIO_FUNC0_OUT_SEL_S));
56 WRITE_PERI_REG(GPIO_FUNC18_OUT_SEL_CFG_REG, (153 << GPIO_FUNC0_OUT_SEL_S));
57 WRITE_PERI_REG(GPIO_FUNC19_OUT_SEL_CFG_REG, (154 << GPIO_FUNC0_OUT_SEL_S));
58 WRITE_PERI_REG(GPIO_FUNC20_OUT_SEL_CFG_REG, (155 << GPIO_FUNC0_OUT_SEL_S));
59 WRITE_PERI_REG(GPIO_FUNC26_OUT_SEL_CFG_REG, (156 << GPIO_FUNC0_OUT_SEL_S)); //RS
60 WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, (I2S0O_WS_OUT_IDX << GPIO_FUNC0_OUT_SEL_S));
61 // WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG, (I2S0O_BCK_OUT_IDX<<GPIO_GPIO_FUNC0_OUT_SEL_S));
62
63 //GPIO_SET_GPIO_FUNC11_OUT_INV_SEL(1); //old
64 WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, READ_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG) | GPIO_FUNC11_OUT_INV_SEL);
65
66 //Reset I2S subsystem
67 CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
68 SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
69 CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
70
71 WRITE_PERI_REG(I2S_CONF_REG(0), 0);//I2S_SIG_LOOPBACK);
72 WRITE_PERI_REG(I2S_CONF2_REG(0), 0);
73
74 WRITE_PERI_REG(I2S_SAMPLE_RATE_CONF_REG(0),
75 (16 << I2S_RX_BITS_MOD_S) |
76 (16 << I2S_TX_BITS_MOD_S) |
77 (1 << I2S_RX_BCK_DIV_NUM_S) |
78 (1 << I2S_TX_BCK_DIV_NUM_S));
79 WRITE_PERI_REG(I2S_CLKM_CONF_REG(0),
80 I2S_CLKA_ENA | I2S_CLK_EN |
81 (1 << I2S_CLKM_DIV_A_S) |
82 (1 << I2S_CLKM_DIV_B_S) |
83 (1 << I2S_CLKM_DIV_NUM_S));
84 WRITE_PERI_REG(I2S_FIFO_CONF_REG(0),
85 (32 << I2S_TX_DATA_NUM_S) | //Low watermark for IRQ
86 (32 << I2S_RX_DATA_NUM_S));
87
88 WRITE_PERI_REG(I2S_CONF1_REG(0), I2S_RX_PCM_BYPASS | I2S_TX_PCM_BYPASS);
89
90 WRITE_PERI_REG(I2S_CONF_CHAN_REG(0), (2 << I2S_TX_CHAN_MOD_S) | (2 << I2S_RX_CHAN_MOD_S));
91
92 //Invert WS to active-low
93 SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RIGHT_FIRST | I2S_RX_RIGHT_FIRST);
94 WRITE_PERI_REG(I2S_TIMING_REG(0), 0);
95 }
96
97
98 static volatile lldesc_t dmaDesc[2];
99
finishDma(void)100 static void finishDma(void)
101 {
102 //No need to finish if no DMA transfer going on
103 if (!(READ_PERI_REG(I2S_FIFO_CONF_REG(0))&I2S_DSCR_EN)) {
104 return;
105 }
106
107 //Wait till fifo done
108 while (!(READ_PERI_REG(I2S_INT_RAW_REG(0))&I2S_TX_REMPTY_INT_RAW)) ;
109 //Wait for last bytes to leave i2s xmit thing
110 //ToDo: poll bit in next hw
111 // for (i=0; i<(1<<8); i++);
112 while (!(READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_IDLE));
113
114 //Reset I2S for next transfer
115 CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
116 CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START | I2S_INLINK_START);
117
118 SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
119 CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
120
121 // for (i=0; i<(1<<8); i++);
122 while ((READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_FIFO_RESET_BACK));
123 }
124
125
126 /*
127 This is a very, very, very hacked up LCD routine which ends up basically doing a memcpy from sbuf to rbuf.
128 */
sendRecvBufDma(uint16_t * sbuf,uint16_t * rbuf,int len)129 static void sendRecvBufDma(uint16_t *sbuf, uint16_t *rbuf, int len)
130 {
131 //Fill DMA descriptor
132 dmaDesc[0].length = len * 2;
133 dmaDesc[0].size = len * 2;
134 dmaDesc[0].owner = 1;
135 dmaDesc[0].sosf = 0;
136 dmaDesc[0].buf = (uint8_t *)sbuf;
137 dmaDesc[0].offset = 0; //unused in hw
138 dmaDesc[0].empty = 0;
139 dmaDesc[0].eof = 1;
140 dmaDesc[1].length = len * 2;
141 dmaDesc[1].size = len * 2;
142 dmaDesc[1].owner = 1;
143 dmaDesc[1].sosf = 0;
144 dmaDesc[1].buf = (uint8_t *)rbuf;
145 dmaDesc[1].offset = 0; //unused in hw
146 dmaDesc[1].empty = 0;
147 dmaDesc[1].eof = 1;
148
149 //Reset DMA
150 SET_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
151 CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
152
153 //Reset I2S FIFO
154 SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
155 CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
156
157 //Set desc addr
158 CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_ADDR);
159 SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), ((uint32_t)(&dmaDesc[0]))&I2S_OUTLINK_ADDR);
160 CLEAR_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_ADDR);
161 SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), ((uint32_t)(&dmaDesc[1]))&I2S_INLINK_ADDR);
162
163 SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(0), I2S_DSCR_EN); //Enable DMA mode
164
165 WRITE_PERI_REG(I2S_RXEOF_NUM_REG(0), len);
166
167 //Enable and configure DMA
168 WRITE_PERI_REG(I2S_LC_CONF_REG(0), I2S_OUT_DATA_BURST_EN |
169 I2S_OUT_EOF_MODE | I2S_OUTDSCR_BURST_EN | I2S_OUT_DATA_BURST_EN |
170 I2S_INDSCR_BURST_EN | I2S_MEM_TRANS_EN);
171
172 //Start transmission
173 SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START);
174 SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_START);
175
176 SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
177 //Clear int flags
178 WRITE_PERI_REG(I2S_INT_CLR_REG(0), 0xFFFFFFFF);
179 }
180
181
182 #define DMALEN (2048-2)
183
tskLcd(void * pvParameters)184 static void tskLcd(void *pvParameters)
185 {
186 uint16_t *sbuf = malloc(DMALEN * 2);
187 uint16_t *rbuf = malloc(DMALEN * 2);
188 uint16_t xorval = 0;
189 int x;
190 lcdIfaceInit();
191 // lcdFlush();
192 while (1) {
193 for (x = 0; x < DMALEN; x++) {
194 sbuf[x] = x ^ xorval;
195 }
196 for (x = 0; x < DMALEN; x++) {
197 rbuf[x] = 0; //clear rbuf
198 }
199 sendRecvBufDma(sbuf, rbuf, DMALEN);
200 vTaskDelay(20 / portTICK_PERIOD_MS);
201 finishDma();
202 for (x = 0; x < DMALEN; x++) if (rbuf[x] != (x ^ xorval)) {
203 printf("Rxbuf err! pos %d val %x xor %x", x, (int)rbuf[x], (int)xorval);
204 }
205 printf(".");
206 fflush(stdout);
207 xorval++;
208 }
209 }
210
211
212
213 void test_s32c1i_lock(volatile int *lockvar, int lockval, int unlockval, volatile int *ctr);
214
215 static volatile int ctr = 0, state = 0;
216 static volatile int lock = 0;
217
tskOne(void * pvParameters)218 static void tskOne(void *pvParameters)
219 {
220 int x;
221 int err = 0, run = 0;
222 while (1) {
223 ctr = 0; lock = 0;
224 state = 1;
225 for (x = 0; x < 16 * 1024; x++) {
226 test_s32c1i_lock(&lock, 1, 0, &ctr);
227 }
228 vTaskDelay(60 / portTICK_PERIOD_MS);
229 state = 2;
230 if (ctr != 16 * 1024 * 2) {
231 printf("Lock malfunction detected! Ctr=0x%x instead of %x\n", ctr, 16 * 1024 * 2);
232 err++;
233 }
234 run++;
235 printf("Run %d err %d\n", run, err);
236 vTaskDelay(20 / portTICK_PERIOD_MS);
237 }
238 }
239
240 #define FB2ADDR 0x40098000
241
tskTwo(void * pvParameters)242 static void tskTwo(void *pvParameters)
243 {
244 int x;
245 int *p = (int *)FB2ADDR;
246 int *s = (int *)test_s32c1i_lock;
247 void (*test_s32c1i_lock2)(volatile int * lockvar, int lockval, int unlockval, volatile int * ctr) = (void *)FB2ADDR;
248 volatile int w;
249 int delay;
250 for (x = 0; x < 100; x++) {
251 *p++ = *s++; //copy routine to different pool
252 }
253
254 while (1) {
255 while (state != 1) ;
256 for (x = 0; x < 16 * 1024; x++) {
257 test_s32c1i_lock2(&lock, 2, 0, &ctr);
258 //Some random delay to increase chance of weirdness
259 if ((x & 0x1f) == 0) {
260 delay = rand() & 0x1f;
261 for (w = 0; w < delay; w++);
262 }
263 }
264 while (state != 2);
265 }
266 }
267
268
269 TEST_CASE("S32C1I vs AHB test (needs I2S)", "[hw][ignore]")
270 {
271 int i;
272 TaskHandle_t th[3];
273 state = 0;
274
275 printf("Creating tasks\n");
276 xTaskCreatePinnedToCore(tskTwo , "tsktwo" , 2048, NULL, 3, &th[1], 1);
277 xTaskCreatePinnedToCore(tskOne , "tskone" , 2048, NULL, 3, &th[0], 0);
278 xTaskCreatePinnedToCore(tskLcd , "tsklcd" , 2048, NULL, 3, &th[2], 0);
279
280 // Let stuff run for 20s
281 while (1) {
282 vTaskDelay(20000 / portTICK_PERIOD_MS);
283 }
284
285 //Shut down all the tasks
286 for (i = 0; i < 3; i++) {
287 vTaskDelete(th[i]);
288 }
289 }
290