Last active
January 2, 2025 03:49
-
-
Save GOROman/9ae00eacc297a8e6676d29a5884ac502 to your computer and use it in GitHub Desktop.
ESP32S3 + esp-idf + ESP PSRAM64H (QPI接続) で読み書きしよう!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ESP-IDF v5.5.0 | |
| // ESP32S3 | |
| // SPI PSRAM (ESP-PSRAM64H) is used. | |
| #include <stdio.h> | |
| #include "driver/spi_master.h" | |
| #include "driver/gpio.h" | |
| #include "freertos/FreeRTOS.h" | |
| #include "freertos/task.h" | |
| #include "esp_log.h" | |
| #include <string.h> | |
| // GPIO Pin Assignments | |
| #define SPI_MOSI 4 // 5:SI/SIO[0] I/O Serial input | |
| #define SPI_MISO 5 // 2:SO/SIO[1] I/O Serial output | |
| #define SPI_QUADWP 6 // 3: SIO[2] | |
| #define SPI_QUADHD 7 // 7: SIO[3] | |
| #define SPI_SCK 8 // 6:CLK Input Clock signa | |
| #define SPI_CS 9 // 1:CS Input Chip select signal(Active low) | |
| // ESP-PSRAM64 Command | |
| #define PSRAM_READ 0x03 | |
| #define PSRAM_FAST_READ 0x0B | |
| #define PSRAM_FAST_READ_QUAD 0xEB | |
| #define PSRAM_WRITE 0x02 | |
| #define PSRAM_QUAD_WRITE 0x38 | |
| #define PSRAM_ENTER_QMODE 0x35 | |
| #define PSRAM_EXIT_QMODE 0xF5 | |
| #define PSRAM_RESET_EN 0x66 | |
| #define PSRAM_RESET 0x99 | |
| #define PSRAM_SET_BURST_LEN 0xC0 | |
| #define PSRAM_DEVICE_ID 0x9F | |
| #define PSRAM_CLOCK 1 | |
| //(10 * 1000 * 1000) // 10MHz | |
| #define SPI_DEF SPI2_HOST | |
| spi_device_handle_t psram_spi; | |
| // PSRAMのリセット | |
| void psram_reset() { | |
| printf("Resetting PSRAM\n"); | |
| spi_transaction_t t = { | |
| .length = 8, | |
| .tx_data = {PSRAM_RESET_EN}, | |
| .flags = SPI_TRANS_USE_TXDATA | |
| }; | |
| ESP_ERROR_CHECK(spi_device_polling_transmit(psram_spi, &t)); | |
| t.tx_data[0] = PSRAM_RESET; | |
| ESP_ERROR_CHECK(spi_device_polling_transmit(psram_spi, &t)); | |
| } | |
| // Quad Mode に入る | |
| void psram_enter_qmode() { | |
| printf("Entering Quad Mode\n"); | |
| uint8_t tx_buffer[1] = {PSRAM_ENTER_QMODE}; | |
| // トランザクション設定 | |
| spi_transaction_t t = { | |
| .length = 8 * sizeof(tx_buffer), // ビット単位で長さを指定 | |
| .tx_buffer = tx_buffer, | |
| }; | |
| // トランザクション送信 | |
| ESP_ERROR_CHECK(spi_device_polling_transmit(psram_spi, &t)); | |
| } | |
| // Quad Mode から出る | |
| void psram_exit_qmode() { | |
| printf("Exit Quad Mode\n"); | |
| //PSRAM_ENTER_QMODE | |
| uint8_t tx_buffer[1] = {PSRAM_EXIT_QMODE}; | |
| spi_transaction_t t = { | |
| .length = 8 * sizeof(tx_buffer), | |
| .tx_buffer = tx_buffer, | |
| .flags = SPI_TRANS_MODE_QIO, | |
| }; | |
| ESP_ERROR_CHECK(spi_device_polling_transmit(psram_spi, &t)); | |
| } | |
| void psram_read_id() { | |
| printf("Reading PSRAM ID\n"); | |
| // 送信用バッファ(コマンドのみ) | |
| uint8_t tx_buffer[4] = {PSRAM_DEVICE_ID, 0x00, 0x00, 0x00}; // コマンド + ダミーバイト | |
| // 受信用バッファ(IDは最大8バイト) | |
| uint8_t rx_buffer[8]; | |
| // トランザクション設定 | |
| spi_transaction_t t = { | |
| .length = 8 * (4 + 8), // コマンド(4バイト) + 受信データ(8バイト) | |
| .tx_buffer = tx_buffer, | |
| .rx_buffer = rx_buffer | |
| }; | |
| // トランザクション送信 | |
| ESP_ERROR_CHECK(spi_device_polling_transmit(psram_spi, &t)); | |
| // 受信データを出力 | |
| printf("PSRAM ID:[ "); | |
| for (int i = 0; i < 8; i++) { | |
| printf("%02X ", rx_buffer[4+i]); | |
| } | |
| printf("]\n"); | |
| } | |
| void psram_write(uint32_t address, const uint8_t *data, size_t size) { | |
| printf("Writing to PSRAM at address 0x%06lx\n", (unsigned long)address); | |
| uint8_t tx_buffer[4 + size]; // コマンド+アドレス(3バイト) + データサイズ | |
| // コマンドとアドレスをバッファにコピー | |
| tx_buffer[0] = PSRAM_WRITE; | |
| tx_buffer[1] = (address >> 16) & 0xFF; // アドレス上位バイト | |
| tx_buffer[2] = (address >> 8) & 0xFF; // アドレス中位バイト | |
| tx_buffer[3] = address & 0xFF; // アドレス下位バイト | |
| // 書き込むデータをバッファにコピー | |
| memcpy(&tx_buffer[4], data, size); | |
| // トランザクションの設定 | |
| spi_transaction_t t = { | |
| .length = 8 * (4 + size), // ビット単位で長さを指定 | |
| .tx_buffer = tx_buffer // データ送信用バッファ | |
| }; | |
| // トランザクション送信 | |
| ESP_ERROR_CHECK(spi_device_polling_transmit(psram_spi, &t)); | |
| for( int i = 0; i < size; i++) { | |
| printf("[SPI] Write : 0x%06lx: [0x%02X]\n", address + i, data[i]); | |
| } | |
| } | |
| void psram_write_quad(uint32_t address, const uint8_t *data, size_t size) { | |
| printf("Writing to PSRAM(Quad) at address 0x%06lx\n", (unsigned long)address); | |
| #if 0 // こっちでも良い | |
| uint8_t tx_buffer[4 + size]; // コマンド+アドレス(3バイト) + データサイズ | |
| // コマンドとアドレスをバッファにコピー | |
| tx_buffer[0] = PSRAM_WRITE; | |
| tx_buffer[1] = (address >> 16) & 0xFF; // アドレス上位バイト | |
| tx_buffer[2] = (address >> 8) & 0xFF; // アドレス中位バイト | |
| tx_buffer[3] = address & 0xFF; // アドレス下位バイト | |
| // 書き込むデータをバッファにコピー | |
| memcpy(&tx_buffer[4], data, size); | |
| // トランザクションの設定 | |
| spi_transaction_t t = { | |
| .length = 8 * (4 + size), // ビット単位で長さを指定 | |
| .tx_buffer = tx_buffer, // データ送信用バッファ | |
| .flags = SPI_TRANS_MODE_QIO | |
| }; | |
| // トランザクション送信 | |
| ESP_ERROR_CHECK(spi_device_polling_transmit(psram_spi, &t)); | |
| #else | |
| spi_transaction_t t = { | |
| .cmd = PSRAM_WRITE, // コマンド | |
| .addr = address, // アドレス | |
| .length = 8 * (size), // ビット単位のデータ長 | |
| .tx_buffer = data, // 送信バッファ | |
| .flags = SPI_TRANS_MODE_QIO | |
| | SPI_TRANS_MULTILINE_CMD // 重要⭐️ | |
| | SPI_TRANS_MULTILINE_ADDR // 重要⭐️ | |
| | SPI_TRANS_VARIABLE_CMD | |
| | SPI_TRANS_VARIABLE_ADDR, | |
| }; | |
| spi_transaction_ext_t ext = { | |
| .base = t, | |
| .command_bits = 8, | |
| .address_bits = 24, | |
| .dummy_bits = 0, | |
| }; | |
| esp_err_t ret = spi_device_polling_transmit(psram_spi, (spi_transaction_t*)&ext); | |
| if (ret != ESP_OK) { | |
| printf("SPI transaction failed: %s\n", esp_err_to_name(ret)); | |
| return; | |
| } | |
| #endif | |
| for( int i = 0; i < size; i++) { | |
| printf("[QPI] Write : 0x%06lx: [0x%02X]\n", address + i, data[i]); | |
| } | |
| } | |
| void psram_read(uint32_t address, uint8_t *data, size_t size) { | |
| printf("Reading from PSRAM at address 0x%06lx\n", (unsigned long)address); | |
| uint8_t rx_buffer[4 + size]; // コマンド+アドレス(3バイト) + データサイズ | |
| uint8_t tx_buffer[4] = { | |
| PSRAM_READ, // コマンド | |
| (address >> 16) & 0xFF, // アドレス上位バイト | |
| (address >> 8) & 0xFF, // アドレス中位バイト | |
| address & 0xFF // アドレス下位バイト | |
| }; | |
| spi_transaction_t t = { | |
| .length = 8 * (4+size), // ビット単位で長さを指定 | |
| .tx_buffer = tx_buffer, // コマンドとアドレス | |
| .rx_buffer = rx_buffer, // 受信データバッファ | |
| }; | |
| // トランザクション送信 | |
| ESP_ERROR_CHECK(spi_device_polling_transmit(psram_spi, &t)); | |
| memcpy(data, &rx_buffer[4], size); | |
| } | |
| void psram_read_quad(uint32_t address, uint8_t *data, size_t size) { | |
| printf("Reading from PSRAM(Quad) at address 0x%06lx size:%d\n", (unsigned long)address, size); | |
| // QPI で読み込む | |
| spi_transaction_ext_t ext = { | |
| .base = { | |
| .cmd = PSRAM_FAST_READ_QUAD, | |
| .addr = address, | |
| .length = 0, | |
| .rxlength = 8 * (size), // 受信データ長(半二重) | |
| .tx_buffer = NULL, // 送信バッファ | |
| .rx_buffer = data, // 受信バッファ | |
| .flags = SPI_TRANS_MODE_QIO // QIOモード | |
| | SPI_DEVICE_HALFDUPLEX // 半二重 | |
| // | SPI_TRANS_MODE_DIOQIO_ADDR // アドレスをDIO/QIOモードで送信 | |
| | SPI_TRANS_MULTILINE_CMD // 重要⭐️ | |
| | SPI_TRANS_MULTILINE_ADDR // 重要⭐️ | |
| | SPI_TRANS_VARIABLE_CMD | |
| | SPI_TRANS_VARIABLE_ADDR // アドレスのビット数を指定 | |
| | SPI_TRANS_VARIABLE_DUMMY, // ダミービット数を指定 | |
| }, | |
| .command_bits = 8, | |
| .address_bits = 24, // 8(data) + 24(address) | |
| .dummy_bits = 6 // PSRAM64H データシートより | |
| }; | |
| esp_err_t ret = spi_device_polling_transmit(psram_spi, (spi_transaction_t *)&ext); | |
| if (ret != ESP_OK) { | |
| printf("SPI transaction failed: %s\n", esp_err_to_name(ret)); | |
| return; | |
| } | |
| } | |
| void app_main(void) { | |
| printf("Initializing SPI for PSRAM\n"); | |
| esp_log_level_set("*", ESP_LOG_DEBUG); | |
| { | |
| spi_bus_config_t buscfg = { | |
| .sclk_io_num = SPI_SCK, | |
| .mosi_io_num = SPI_MOSI, | |
| .miso_io_num = SPI_MISO, | |
| .quadwp_io_num = SPI_QUADWP, | |
| .quadhd_io_num = SPI_QUADHD, | |
| .data0_io_num = SPI_MOSI, | |
| .data1_io_num = SPI_MISO, | |
| .data2_io_num = SPI_QUADWP, | |
| .data3_io_num = SPI_QUADHD, | |
| .max_transfer_sz = 4096, | |
| .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_QUAD, | |
| }; | |
| ESP_ERROR_CHECK(spi_bus_initialize(SPI_DEF, &buscfg, SPI_DMA_CH_AUTO)); | |
| spi_device_interface_config_t devcfg = { | |
| .clock_speed_hz = PSRAM_CLOCK, | |
| .mode = 0, | |
| .spics_io_num = SPI_CS, | |
| .queue_size = 7, | |
| .flags = 0 | |
| }; | |
| ESP_ERROR_CHECK(spi_bus_add_device(SPI_DEF, &devcfg, &psram_spi)); | |
| psram_reset(); | |
| psram_read_id(); | |
| const uint8_t DATA[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xD0, 0xF0, 0x0D}; | |
| uint32_t address = 0x000000; | |
| uint8_t read_buffer[sizeof(DATA)]; | |
| memset(read_buffer, 0x00, sizeof(DATA)); | |
| psram_write(address, DATA, sizeof(DATA)); | |
| vTaskDelay(pdMS_TO_TICKS(100)); | |
| psram_read(address, read_buffer, sizeof(read_buffer)); | |
| for (size_t i = 0; i < sizeof(DATA); i++) { | |
| printf("[SPI] Verify: 0x%06lx: [0x%02X] == [0x%02X] %s\n", address + i, DATA[i], read_buffer[i], DATA[i] == read_buffer[i] ? "😃" : "😖"); | |
| } | |
| psram_read_id(); | |
| psram_enter_qmode(); | |
| } | |
| ESP_ERROR_CHECK(spi_bus_remove_device(psram_spi)); | |
| spi_device_interface_config_t devcfg_quad = { | |
| .clock_speed_hz = PSRAM_CLOCK, | |
| .mode = 0, | |
| .spics_io_num = SPI_CS, // CS ピン | |
| .queue_size = 7, | |
| .flags = SPI_DEVICE_HALFDUPLEX, | |
| }; | |
| ESP_ERROR_CHECK(spi_bus_add_device(SPI_DEF, &devcfg_quad, &psram_spi)); | |
| const uint8_t DATA[] = {0x01, 0x02, 0x03, 0x04 , 0xBA, 0xD0, 0xF0, 0x0D}; | |
| uint32_t address = 0x000000; | |
| uint8_t read_buffer[sizeof(DATA)]; | |
| memset(read_buffer, 0x00, sizeof(DATA)); | |
| psram_write_quad(address, DATA, sizeof(DATA)); | |
| vTaskDelay(pdMS_TO_TICKS(100)); | |
| psram_read_quad(address, read_buffer, sizeof(read_buffer)); | |
| for (size_t i = 0; i < sizeof(DATA); i++) { | |
| printf("[QPI] Verify: 0x%06lx: [0x%02X] == [0x%02X] %s\n", address + i, DATA[i], read_buffer[i], DATA[i] == read_buffer[i] ? "😃" : "😖"); | |
| } | |
| psram_exit_qmode(); | |
| ESP_ERROR_CHECK(spi_bus_remove_device(psram_spi)); | |
| { | |
| spi_device_interface_config_t devcfg = { | |
| .clock_speed_hz = PSRAM_CLOCK, | |
| .mode = 0, | |
| .spics_io_num = SPI_CS, | |
| .queue_size = 7 | |
| }; | |
| ESP_ERROR_CHECK(spi_bus_add_device(SPI_DEF, &devcfg, &psram_spi)); | |
| psram_read_id(); | |
| } | |
| ESP_ERROR_CHECK(spi_bus_remove_device(psram_spi)); | |
| ESP_ERROR_CHECK(spi_bus_free(SPI_DEF)); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment