test_sdio.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. // Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "soc/soc_caps.h"
  15. #if SOC_SDMMC_HOST_SUPPORTED
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include "esp_log.h"
  20. #include "esp_heap_caps.h"
  21. #include "freertos/FreeRTOS.h"
  22. #include "freertos/task.h"
  23. #include "driver/gpio.h"
  24. #include "driver/sdmmc_host.h"
  25. #include "driver/sdmmc_defs.h"
  26. #include "sdmmc_cmd.h"
  27. #include "unity.h"
  28. /* Second ESP32 board attached as follows:
  29. * Master Slave
  30. * IO18 EN
  31. * IO19 IO0
  32. * IO14 SD_CLK
  33. * IO15 SD_CMD
  34. * IO2 SD_D0
  35. * IO4 SD_D1
  36. * IO12 SD_D2
  37. * IO13 SD_D3
  38. */
  39. /* TODO: add SDIO slave header files, remove these definitions */
  40. #define DR_REG_SLC_MASK 0xfffffc00
  41. #define SLCCONF1 (DR_REG_SLC_BASE + 0x60)
  42. #define SLC_SLC0_RX_STITCH_EN (BIT(6))
  43. #define SLC_SLC0_TX_STITCH_EN (BIT(5))
  44. #define SLC0TX_LINK (DR_REG_SLC_BASE + 0x40)
  45. #define SLC_SLC0_TXLINK_PARK (BIT(31))
  46. #define SLC_SLC0_TXLINK_RESTART (BIT(30))
  47. #define SLC_SLC0_TXLINK_START (BIT(29))
  48. #define DR_REG_SLCHOST_MASK 0xfffffc00
  49. #define SLCHOST_STATE_W0 (DR_REG_SLCHOST_BASE + 0x64)
  50. #define SLCHOST_CONF_W0 (DR_REG_SLCHOST_BASE + 0x6C)
  51. #define SLCHOST_CONF_W5 (DR_REG_SLCHOST_BASE + 0x80)
  52. #define SLCHOST_WIN_CMD (DR_REG_SLCHOST_BASE + 0x84)
  53. #define SLC_WIN_CMD_READ 0x80
  54. #define SLC_WIN_CMD_WRITE 0xC0
  55. #define SLC_WIN_CMD_S 8
  56. #define SLC_THRESHOLD_ADDR 0x1f800
  57. static const char* TAG = "sdio_test";
  58. static esp_err_t slave_slchost_reg_read(sdmmc_card_t* card, uint32_t addr, uint32_t* out_val)
  59. {
  60. if ((addr & DR_REG_SLCHOST_MASK) != DR_REG_SLCHOST_BASE) {
  61. ESP_LOGW(TAG, "%s: invalid addr 0x%08x\n", __func__, addr);
  62. return ESP_ERR_INVALID_ARG;
  63. }
  64. return sdmmc_io_read_bytes(card, 1, addr & (~DR_REG_SLCHOST_MASK), out_val, sizeof(*out_val));
  65. }
  66. static esp_err_t slave_slchost_reg_write(sdmmc_card_t* card, uint32_t addr, uint32_t val)
  67. {
  68. if ((addr & DR_REG_SLCHOST_MASK) != DR_REG_SLCHOST_BASE) {
  69. ESP_LOGW(TAG, "%s: invalid addr 0x%08x\n", __func__, addr);
  70. return ESP_ERR_INVALID_ARG;
  71. }
  72. return sdmmc_io_write_bytes(card, 1, addr & (~DR_REG_SLCHOST_MASK), &val, sizeof(val));
  73. }
  74. static esp_err_t slave_slc_reg_read(sdmmc_card_t* card, uint32_t addr, uint32_t* val)
  75. {
  76. if ((addr & DR_REG_SLC_MASK) != DR_REG_SLC_BASE) {
  77. ESP_LOGW(TAG, "%s: invalid addr 0x%08x\n", __func__, addr);
  78. return ESP_ERR_INVALID_ARG;
  79. }
  80. uint32_t word = (addr - DR_REG_SLC_BASE) / 4;
  81. if (word > INT8_MAX) {
  82. return ESP_ERR_INVALID_ARG;
  83. }
  84. uint32_t window_command = word | (SLC_WIN_CMD_READ << SLC_WIN_CMD_S);
  85. esp_err_t err = slave_slchost_reg_write(card, SLCHOST_WIN_CMD, window_command);
  86. if (err != ESP_OK) {
  87. return err;
  88. }
  89. return slave_slchost_reg_read(card, SLCHOST_STATE_W0, val);
  90. }
  91. static esp_err_t slave_slc_reg_write(sdmmc_card_t* card, uint32_t addr, uint32_t val)
  92. {
  93. if ((addr & DR_REG_SLC_MASK) != DR_REG_SLC_BASE) {
  94. ESP_LOGW(TAG, "%s: invalid addr 0x%08x\n", __func__, addr);
  95. return ESP_ERR_INVALID_ARG;
  96. }
  97. uint32_t word = (addr - DR_REG_SLC_BASE) / 4;
  98. if (word > INT8_MAX) {
  99. return ESP_ERR_INVALID_ARG;
  100. }
  101. esp_err_t err = slave_slchost_reg_write(card, SLCHOST_CONF_W5, val);
  102. if (err != ESP_OK) {
  103. return err;
  104. }
  105. uint32_t window_command = word | (SLC_WIN_CMD_WRITE << SLC_WIN_CMD_S);
  106. return slave_slchost_reg_write(card, SLCHOST_WIN_CMD, window_command);
  107. }
  108. /** Reset and put slave into download mode */
  109. static void reset_slave(void)
  110. {
  111. const int pin_en = 18;
  112. const int pin_io0 = 19;
  113. gpio_config_t gpio_cfg = {
  114. .pin_bit_mask = BIT64(pin_en) | BIT64(pin_io0),
  115. .mode = GPIO_MODE_OUTPUT_OD,
  116. };
  117. TEST_ESP_OK(gpio_config(&gpio_cfg));
  118. gpio_set_level(pin_en, 0);
  119. gpio_set_level(pin_io0, 0);
  120. vTaskDelay(10 / portTICK_PERIOD_MS);
  121. gpio_set_level(pin_en, 1);
  122. vTaskDelay(10 / portTICK_PERIOD_MS);
  123. gpio_set_level(pin_io0, 1);
  124. }
  125. static void sdio_slave_common_init(sdmmc_card_t* card)
  126. {
  127. uint8_t card_cap;
  128. esp_err_t err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_CARD_CAP, &card_cap);
  129. TEST_ESP_OK(err);
  130. printf("CAP: 0x%02x\n", card_cap);
  131. uint8_t hs;
  132. err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_HIGHSPEED, &hs);
  133. TEST_ESP_OK(err);
  134. printf("HS: 0x%02x\n", hs);
  135. #define FUNC1_EN_MASK (BIT(1))
  136. uint8_t ioe;
  137. err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_ENABLE, &ioe);
  138. TEST_ESP_OK(err);
  139. printf("IOE: 0x%02x\n", ioe);
  140. uint8_t ior = 0;
  141. err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior);
  142. TEST_ESP_OK(err);
  143. printf("IOR: 0x%02x\n", ior);
  144. // enable function 1
  145. ioe |= FUNC1_EN_MASK;
  146. err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_FN_ENABLE, ioe, NULL);
  147. TEST_ESP_OK(err);
  148. err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_ENABLE, &ioe);
  149. TEST_ESP_OK(err);
  150. printf("IOE: 0x%02x\n", ioe);
  151. // wait for the card to become ready
  152. while ( (ior & FUNC1_EN_MASK) == 0 ) {
  153. err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior);
  154. TEST_ESP_OK(err);
  155. printf("IOR: 0x%02x\n", ior);
  156. }
  157. // get interrupt status
  158. uint8_t ie;
  159. err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_INT_ENABLE, &ie);
  160. TEST_ESP_OK(err);
  161. printf("IE: 0x%02x\n", ie);
  162. // enable interrupts for function 1&2 and master enable
  163. ie |= BIT(0) | FUNC1_EN_MASK;
  164. err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_INT_ENABLE, ie, NULL);
  165. TEST_ESP_OK(err);
  166. err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_INT_ENABLE, &ie);
  167. TEST_ESP_OK(err);
  168. printf("IE: 0x%02x\n", ie);
  169. }
  170. /** Common for all SDIO devices, set block size for specific function */
  171. static void sdio_slave_set_blocksize(sdmmc_card_t* card, int function, uint16_t bs)
  172. {
  173. const uint8_t* bs_u8 = (const uint8_t*) &bs;
  174. uint16_t bs_read = 0;
  175. uint8_t* bs_read_u8 = (uint8_t*) &bs_read;
  176. uint32_t offset = SD_IO_FBR_START * function;
  177. TEST_ESP_OK( sdmmc_io_write_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, bs_u8[0], NULL));
  178. TEST_ESP_OK( sdmmc_io_write_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, bs_u8[1], NULL));
  179. TEST_ESP_OK( sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0]));
  180. TEST_ESP_OK( sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1]));
  181. TEST_ASSERT_EQUAL_HEX16(bs, bs_read);
  182. }
  183. /**
  184. * ESP32 ROM code does not set some SDIO slave registers to the defaults
  185. * we need, this function clears/sets some bits.
  186. */
  187. static void esp32_slave_init_extra(sdmmc_card_t* card)
  188. {
  189. printf("Initialize some ESP32 SDIO slave registers\n");
  190. uint32_t reg_val;
  191. TEST_ESP_OK( slave_slc_reg_read(card, SLCCONF1, &reg_val) );
  192. reg_val &= ~(SLC_SLC0_RX_STITCH_EN | SLC_SLC0_TX_STITCH_EN);
  193. TEST_ESP_OK( slave_slc_reg_write(card, SLCCONF1, reg_val) );
  194. TEST_ESP_OK( slave_slc_reg_read(card, SLC0TX_LINK, &reg_val) );
  195. reg_val |= SLC_SLC0_TXLINK_START;
  196. TEST_ESP_OK( slave_slc_reg_write(card, SLC0TX_LINK, reg_val) );
  197. }
  198. /**
  199. * ESP32 bootloader implements "SIP" protocol which can be used to exchange
  200. * some commands, events, and data packets between the host and the slave.
  201. * This function sends a SIP command, testing CMD53 block writes along the way.
  202. */
  203. static void esp32_send_sip_command(sdmmc_card_t* card)
  204. {
  205. printf("Test block write using CMD53\n");
  206. const size_t block_size = 512;
  207. uint8_t* data = heap_caps_calloc(1, block_size, MALLOC_CAP_DMA);
  208. struct sip_cmd_bootup {
  209. uint32_t boot_addr;
  210. uint32_t discard_link;
  211. };
  212. struct sip_cmd_write_reg {
  213. uint32_t addr;
  214. uint32_t val;
  215. };
  216. struct sip_hdr {
  217. uint8_t fc[2];
  218. uint16_t len;
  219. uint32_t cmdid;
  220. uint32_t seq;
  221. };
  222. struct sip_hdr* hdr = (struct sip_hdr*) data;
  223. size_t len;
  224. #define SEND_WRITE_REG_CMD
  225. #ifdef SEND_WRITE_REG_CMD
  226. struct sip_cmd_write_reg *write_reg = (struct sip_cmd_write_reg*) (data + sizeof(*hdr));
  227. len = sizeof(*hdr) + sizeof(*write_reg);
  228. hdr->cmdid = 3; /* SIP_CMD_WRITE_REG */
  229. write_reg->addr = GPIO_ENABLE_W1TS_REG;
  230. write_reg->val = BIT(0) | BIT(2) | BIT(4); /* Turn of RGB LEDs on WROVER-KIT */
  231. #else
  232. struct sip_cmd_bootup *bootup = (struct sip_cmd_bootup*) (data + sizeof(*hdr));
  233. len = sizeof(*hdr) + sizeof(*bootup);
  234. hdr->cmdid = 5; /* SIP_CMD_BOOTUP */
  235. bootup->boot_addr = 0x4005a980; /* start_tb_console function in ROM */
  236. bootup->discard_link = 1;
  237. #endif
  238. hdr->len = len;
  239. TEST_ESP_OK( sdmmc_io_write_blocks(card, 1, SLC_THRESHOLD_ADDR - len, data, block_size) );
  240. free(data);
  241. }
  242. static void test_cmd52_read_write_single_byte(sdmmc_card_t* card)
  243. {
  244. esp_err_t err;
  245. printf("Write bytes to slave's W0_REG using CMD52\n");
  246. const size_t scratch_area_reg = SLCHOST_CONF_W0 - DR_REG_SLCHOST_BASE;
  247. const uint8_t test_byte_1 = 0xa5;
  248. const uint8_t test_byte_2 = 0xb6;
  249. // used to check Read-After-Write
  250. uint8_t test_byte_1_raw;
  251. uint8_t test_byte_2_raw;
  252. uint8_t val = 0;
  253. err = sdmmc_io_write_byte(card, 1, scratch_area_reg, test_byte_1, &test_byte_1_raw);
  254. TEST_ESP_OK(err);
  255. TEST_ASSERT_EQUAL_UINT8(test_byte_1, test_byte_1_raw);
  256. err = sdmmc_io_write_byte(card, 1, scratch_area_reg + 1, test_byte_2, &test_byte_2_raw);
  257. TEST_ESP_OK(err);
  258. TEST_ASSERT_EQUAL_UINT8(test_byte_2, test_byte_2_raw);
  259. printf("Read back bytes using CMD52\n");
  260. TEST_ESP_OK(sdmmc_io_read_byte(card, 1, scratch_area_reg, &val));
  261. TEST_ASSERT_EQUAL_UINT8(test_byte_1, val);
  262. TEST_ESP_OK(sdmmc_io_read_byte(card, 1, scratch_area_reg + 1, &val));
  263. TEST_ASSERT_EQUAL_UINT8(test_byte_2, val);
  264. }
  265. static void test_cmd53_read_write_multiple_bytes(sdmmc_card_t* card, size_t n_bytes)
  266. {
  267. printf("Write multiple bytes using CMD53\n");
  268. const size_t scratch_area_reg = SLCHOST_CONF_W0 - DR_REG_SLCHOST_BASE;
  269. uint8_t* src = heap_caps_malloc(512, MALLOC_CAP_DMA);
  270. uint32_t* src_32 = (uint32_t*) src;
  271. for (size_t i = 0; i < (n_bytes + 3) / 4; ++i) {
  272. src_32[i] = rand();
  273. }
  274. TEST_ESP_OK(sdmmc_io_write_bytes(card, 1, scratch_area_reg, src, n_bytes));
  275. ESP_LOG_BUFFER_HEX(TAG, src, n_bytes);
  276. printf("Read back using CMD52\n");
  277. uint8_t* dst = heap_caps_malloc(512, MALLOC_CAP_DMA);
  278. for (size_t i = 0; i < n_bytes; ++i) {
  279. TEST_ESP_OK(sdmmc_io_read_byte(card, 1, scratch_area_reg + i, &dst[i]));
  280. }
  281. ESP_LOG_BUFFER_HEX(TAG, dst, n_bytes);
  282. TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, n_bytes);
  283. printf("Read back using CMD53\n");
  284. TEST_ESP_OK(sdmmc_io_read_bytes(card, 1, scratch_area_reg, dst, n_bytes));
  285. ESP_LOG_BUFFER_HEX(TAG, dst, n_bytes);
  286. TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, n_bytes);
  287. free(src);
  288. free(dst);
  289. }
  290. TEST_CASE("can probe and talk to ESP32 SDIO slave", "[sdio][ignore]")
  291. {
  292. reset_slave();
  293. /* Probe */
  294. sdmmc_host_t config = SDMMC_HOST_DEFAULT();
  295. config.flags = SDMMC_HOST_FLAG_1BIT;
  296. config.max_freq_khz = SDMMC_FREQ_PROBING;
  297. sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
  298. (sdmmc_host_init());
  299. (sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config));
  300. sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t));
  301. TEST_ASSERT_NOT_NULL(card);
  302. TEST_ESP_OK(sdmmc_card_init(&config, card));
  303. sdmmc_card_print_info(stdout, card);
  304. /* Set up standard SDIO registers */
  305. sdio_slave_common_init(card);
  306. srand(0);
  307. for (int repeat = 0; repeat < 4; ++repeat) {
  308. test_cmd52_read_write_single_byte(card);
  309. test_cmd53_read_write_multiple_bytes(card, 1);
  310. test_cmd53_read_write_multiple_bytes(card, 2);
  311. test_cmd53_read_write_multiple_bytes(card, 3);
  312. test_cmd53_read_write_multiple_bytes(card, 4);
  313. test_cmd53_read_write_multiple_bytes(card, 5);
  314. test_cmd53_read_write_multiple_bytes(card, 23);
  315. test_cmd53_read_write_multiple_bytes(card, 24);
  316. }
  317. sdio_slave_set_blocksize(card, 0, 512);
  318. sdio_slave_set_blocksize(card, 1, 512);
  319. esp32_slave_init_extra(card);
  320. esp32_send_sip_command(card);
  321. TEST_ESP_OK(sdmmc_host_deinit());
  322. free(card);
  323. }
  324. #endif //SOC_SDMMC_HOST_SUPPORTED