test_unal_dma.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "sdkconfig.h"
  7. #if CONFIG_IDF_TARGET_ESP32
  8. #include <esp_types.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include "esp32/rom/lldesc.h"
  13. #include "esp_private/periph_ctrl.h"
  14. #include "hal/gpio_hal.h"
  15. #include "freertos/FreeRTOS.h"
  16. #include "freertos/task.h"
  17. #include "freertos/semphr.h"
  18. #include "freertos/queue.h"
  19. #include "freertos/xtensa_api.h"
  20. #include "unity.h"
  21. #include "soc/dport_reg.h"
  22. #include "soc/gpio_periph.h"
  23. #include "soc/i2s_periph.h"
  24. #define DPORT_I2S0_CLK_EN (BIT(4))
  25. #define DPORT_I2S0_RST (BIT(4))
  26. static volatile lldesc_t dmaDesc[2];
  27. //hacked up routine to essentially do a memcpy() using dma. Supports max 4K-1 bytes.
  28. static void dmaMemcpy(void *in, void *out, int len)
  29. {
  30. volatile int i;
  31. periph_module_enable(PERIPH_I2S0_MODULE);
  32. //Init pins to i2s functions
  33. 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
  34. gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, 0);
  35. gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO2_U, 0);
  36. gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO5_U, 0);
  37. gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO16_U, 0);
  38. gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO17_U, 0);
  39. gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO18_U, 0);
  40. gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO19_U, 0);
  41. gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO20_U, 0);
  42. gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CMD_U, 2); //11
  43. gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO26_U, 0); //RS
  44. WRITE_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG, (148 << GPIO_FUNC0_OUT_SEL_S));
  45. WRITE_PERI_REG(GPIO_FUNC2_OUT_SEL_CFG_REG, (149 << GPIO_FUNC0_OUT_SEL_S));
  46. WRITE_PERI_REG(GPIO_FUNC5_OUT_SEL_CFG_REG, (150 << GPIO_FUNC0_OUT_SEL_S));
  47. WRITE_PERI_REG(GPIO_FUNC16_OUT_SEL_CFG_REG, (151 << GPIO_FUNC0_OUT_SEL_S));
  48. WRITE_PERI_REG(GPIO_FUNC17_OUT_SEL_CFG_REG, (152 << GPIO_FUNC0_OUT_SEL_S));
  49. WRITE_PERI_REG(GPIO_FUNC18_OUT_SEL_CFG_REG, (153 << GPIO_FUNC0_OUT_SEL_S));
  50. WRITE_PERI_REG(GPIO_FUNC19_OUT_SEL_CFG_REG, (154 << GPIO_FUNC0_OUT_SEL_S));
  51. WRITE_PERI_REG(GPIO_FUNC20_OUT_SEL_CFG_REG, (155 << GPIO_FUNC0_OUT_SEL_S));
  52. WRITE_PERI_REG(GPIO_FUNC26_OUT_SEL_CFG_REG, (156 << GPIO_FUNC0_OUT_SEL_S)); //RS
  53. WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, (I2S0O_WS_OUT_IDX << GPIO_FUNC0_OUT_SEL_S));
  54. // WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG, (I2S0O_BCK_OUT_IDX<<GPIO_GPIO_FUNC0_OUT_SEL_S));
  55. //GPIO_SET_GPIO_FUNC11_OUT_INV_SEL(1); //old
  56. WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, READ_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG) | GPIO_FUNC11_OUT_INV_SEL);
  57. //Reset I2S subsystem
  58. CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
  59. SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
  60. CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
  61. WRITE_PERI_REG(I2S_CONF_REG(0), 0);//I2S_I2S_SIG_LOOPBACK);
  62. WRITE_PERI_REG(I2S_CONF2_REG(0), 0);
  63. WRITE_PERI_REG(I2S_SAMPLE_RATE_CONF_REG(0),
  64. (16 << I2S_RX_BITS_MOD_S) |
  65. (16 << I2S_TX_BITS_MOD_S) |
  66. (1 << I2S_RX_BCK_DIV_NUM_S) |
  67. (1 << I2S_TX_BCK_DIV_NUM_S));
  68. WRITE_PERI_REG(I2S_CLKM_CONF_REG(0),
  69. I2S_CLKA_ENA | I2S_CLK_EN |
  70. (1 << I2S_CLKM_DIV_A_S) |
  71. (1 << I2S_CLKM_DIV_B_S) |
  72. (1 << I2S_CLKM_DIV_NUM_S));
  73. WRITE_PERI_REG(I2S_FIFO_CONF_REG(0),
  74. (32 << I2S_TX_DATA_NUM_S) | //Low watermark for IRQ
  75. (32 << I2S_RX_DATA_NUM_S));
  76. WRITE_PERI_REG(I2S_CONF1_REG(0), I2S_RX_PCM_BYPASS | I2S_TX_PCM_BYPASS);
  77. WRITE_PERI_REG(I2S_CONF_CHAN_REG(0), (2 << I2S_TX_CHAN_MOD_S) | (2 << I2S_RX_CHAN_MOD_S));
  78. //Invert WS to active-low
  79. SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RIGHT_FIRST | I2S_RX_RIGHT_FIRST);
  80. WRITE_PERI_REG(I2S_TIMING_REG(0), 0);
  81. //--
  82. //Fill DMA descriptor
  83. dmaDesc[0].length = len;
  84. dmaDesc[0].size = len;
  85. dmaDesc[0].owner = 1;
  86. dmaDesc[0].sosf = 0;
  87. dmaDesc[0].buf = (uint8_t *)in;
  88. dmaDesc[0].offset = 0; //unused in hw
  89. dmaDesc[0].empty = 0;
  90. dmaDesc[0].eof = 1;
  91. dmaDesc[1].length = len;
  92. dmaDesc[1].size = len;
  93. dmaDesc[1].owner = 1;
  94. dmaDesc[1].sosf = 0;
  95. dmaDesc[1].buf = (uint8_t *)out;
  96. dmaDesc[1].offset = 0; //unused in hw
  97. dmaDesc[1].empty = 0;
  98. dmaDesc[1].eof = 1;
  99. //Reset DMA
  100. SET_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
  101. CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
  102. //Reset I2S FIFO
  103. SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
  104. CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
  105. //Set desc addr
  106. CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_ADDR);
  107. SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), ((uint32_t)(&dmaDesc[0]))&I2S_OUTLINK_ADDR);
  108. CLEAR_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_ADDR);
  109. SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), ((uint32_t)(&dmaDesc[1]))&I2S_INLINK_ADDR);
  110. SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(0), I2S_DSCR_EN); //Enable DMA mode
  111. WRITE_PERI_REG(I2S_RXEOF_NUM_REG(0), len);
  112. //Enable and configure DMA
  113. WRITE_PERI_REG(I2S_LC_CONF_REG(0), I2S_OUT_DATA_BURST_EN |
  114. I2S_OUT_EOF_MODE | I2S_OUTDSCR_BURST_EN | I2S_OUT_DATA_BURST_EN |
  115. I2S_INDSCR_BURST_EN | I2S_MEM_TRANS_EN);
  116. //Start transmission
  117. SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START);
  118. SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_START);
  119. SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
  120. //Clear int flags
  121. WRITE_PERI_REG(I2S_INT_CLR_REG(0), 0xFFFFFFFF);
  122. //--
  123. //No need to finish if no DMA transfer going on
  124. if (!(READ_PERI_REG(I2S_FIFO_CONF_REG(0))&I2S_DSCR_EN)) {
  125. return;
  126. }
  127. //Wait till fifo done
  128. while (!(READ_PERI_REG(I2S_INT_RAW_REG(0))&I2S_TX_REMPTY_INT_RAW)) ;
  129. //Wait for last bytes to leave i2s xmit thing
  130. //ToDo: poll bit in next hw
  131. for (i = 0; i < (1 << 8); i++);
  132. while (!(READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_IDLE));
  133. //Reset I2S for next transfer
  134. CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
  135. CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START | I2S_INLINK_START);
  136. SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
  137. CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
  138. // for (i=0; i<(1<<8); i++);
  139. while ((READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_FIFO_RESET_BACK));
  140. }
  141. int mymemcmp(char *a, char *b, int len)
  142. {
  143. int x;
  144. for (x = 0; x < len; x++) {
  145. if (a[x] != b[x]) {
  146. printf("Not equal at byte %d. a=%x, b=%x\n", x, (int)a[x], (int)b[x]);
  147. return 1;
  148. }
  149. }
  150. return 0;
  151. }
  152. TEST_CASE("Unaligned DMA test (needs I2S)", "[hw][ignore]")
  153. {
  154. int x;
  155. char src[2049], dest[2049];
  156. for (x = 0; x < sizeof(src); x++) {
  157. src[x] = x & 0xff;
  158. }
  159. printf("Aligned dma\n");
  160. memset(dest, 0, 2049);
  161. dmaMemcpy(src, dest, 2048 + 1);
  162. TEST_ASSERT(mymemcmp(src, dest, 2048) == 0);
  163. printf("Src unaligned\n");
  164. dmaMemcpy(src + 1, dest, 2048 + 1);
  165. TEST_ASSERT(mymemcmp(src + 1, dest, 2048) == 0);
  166. printf("Dst unaligned\n");
  167. dmaMemcpy(src, dest + 1, 2048 + 2);
  168. TEST_ASSERT(mymemcmp(src, dest + 1, 2048) == 0);
  169. }
  170. #endif // CONFIG_IDF_TARGET_ESP32