- #define CMD_WRITE 0x02
- #define CMD_READ 0x03
- #define CMD_FAST_READ 0x0b
- #define CMD_RESET_EN 0x66
- #define CMD_RESET 0x99
- #define CMD_READ_ID 0x9f
- static int psram_send_cmd(const uint8_t cmd)
- {
- fsp_err_t err;
- g_transfer_complete = false;
- err = R_SPI_Write(&g_spi0_ctrl, &cmd, 1, SPI_BIT_WIDTH_8_BITS);
- if (FSP_SUCCESS != err) {
- SEGGER_RTT_printf(0, "psram_read_id write cmd failed\n");
- R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_05_PIN_00, BSP_IO_LEVEL_HIGH);
- return -1;
- }
- /* Wait for SPI_EVENT_TRANSFER_COMPLETE callback event. */
- while (g_transfer_complete == false) {;}
- return 0;
- }
读取psram id
- static int psram_read_id(uint8_t *buf)
- {
- uint8_t cmd[4];
- fsp_err_t err;
- cmd[0] = CMD_READ_ID;
- /* cmd[1], cmd[2] and cmd[3] are dummy address */
- g_transfer_complete = false;
- err = R_SPI_Write(&g_spi0_ctrl, cmd, 4, SPI_BIT_WIDTH_8_BITS);
- if (FSP_SUCCESS != err) {
- SEGGER_RTT_printf(0, "psram_read_id write cmd failed\n");
- R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_05_PIN_00, BSP_IO_LEVEL_HIGH);
- return -1;
- }
- /* Wait for SPI_EVENT_TRANSFER_COMPLETE callback event. */
- while (g_transfer_complete == false) {;}
- g_transfer_complete = false;
- err = R_SPI_Read(&g_spi0_ctrl, buf, 6, SPI_BIT_WIDTH_8_BITS);
- if (FSP_SUCCESS != err) {
- SEGGER_RTT_printf(0, "psram_read_id read ID failed\n");
- R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_05_PIN_00, BSP_IO_LEVEL_HIGH);
- return -1;
- }
- /* Wait for SPI_EVENT_TRANSFER_COMPLETE callback event. */
- while (g_transfer_complete == false) {;}
- return 0;
- }
实现psram的读取
- int psram_read(uint32_t addr, void *buf, int len)
- {
- uint8_t cmd[5];
- fsp_err_t err;
- cmd[0] = CMD_FAST_READ;
- cmd[1] = (uint8_t)(addr >> 16);
- cmd[2] = (uint8_t)(addr >> 8);
- cmd[3] = (uint8_t)(addr);
- /* cmd[4] is dummy */
- R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_05_PIN_00, BSP_IO_LEVEL_LOW);
- g_transfer_complete = false;
- err = R_SPI_Write(&g_spi0_ctrl, cmd, 5, SPI_BIT_WIDTH_8_BITS);
- if (FSP_SUCCESS != err) {
- SEGGER_RTT_printf(0, "psram_read write cmd failed\n");
- R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_05_PIN_00, BSP_IO_LEVEL_HIGH);
- return -1;
- }
- /* Wait for SPI_EVENT_TRANSFER_COMPLETE callback event. */
- while (g_transfer_complete == false) {;}
- g_transfer_complete = false;
- err = R_SPI_Read(&g_spi0_ctrl, buf, len, SPI_BIT_WIDTH_8_BITS);
- if (FSP_SUCCESS != err) {
- SEGGER_RTT_printf(0, "psram_read read data failed %lx %d\n", addr, len);
- R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_05_PIN_00, BSP_IO_LEVEL_HIGH);
- return -1;
- }
- /* Wait for SPI_EVENT_TRANSFER_COMPLETE callback event. */
- while (g_transfer_complete == false) {;}
- R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_05_PIN_00, BSP_IO_LEVEL_HIGH);
- return len;
- }
实现psram的写入
- int psram_write(uint32_t addr, void *buf, int len)
- {
- uint8_t cmd[4];
- fsp_err_t err;
- cmd[0] = CMD_WRITE;
- cmd[1] = (uint8_t)(addr >> 16);
- cmd[2] = (uint8_t)(addr >> 8);
- cmd[3] = (uint8_t)(addr);
- R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_05_PIN_00, BSP_IO_LEVEL_LOW);
- g_transfer_complete = false;
- err = R_SPI_Write(&g_spi0_ctrl, cmd, 4, SPI_BIT_WIDTH_8_BITS);
- if (FSP_SUCCESS != err) {
- SEGGER_RTT_printf(0, "psram_write write cmd failed\n");
- R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_05_PIN_00, BSP_IO_LEVEL_HIGH);
- return -1;
- }
- /* Wait for SPI_EVENT_TRANSFER_COMPLETE callback event. */
- while (g_transfer_complete == false) {;}
- g_transfer_complete = false;
- err = R_SPI_Write(&g_spi0_ctrl, buf, len, SPI_BIT_WIDTH_8_BITS);
- if (FSP_SUCCESS != err) {
- SEGGER_RTT_printf(0, "psram_write write data failed %lx %d\n", addr, len);
- R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_05_PIN_00, BSP_IO_LEVEL_HIGH);
- return -1;
- }
- /* Wait for SPI_EVENT_TRANSFER_COMPLETE callback event. */
- while (g_transfer_complete == false) {;}
- R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_05_PIN_00, BSP_IO_LEVEL_HIGH);
- return len;
- }
测试代码
- void psram_test(void)
- {
- unsigned int i;
- uint32_t addr;
- uint32_t t1;
- uint8_t testbuf[64];
- psram_init();
- memset(testbuf, 0x5a, sizeof(testbuf));
- t1 = get_us();
- for (i = 0; i < 10000; ++i) {
- psram_write(i * 64, &testbuf, 64);
- }
- t1 = get_us() - t1;
- t1 /= 1000;
- SEGGER_RTT_printf(0, "PSRAM write speed: %lld B/s.\n", 64 * 10000 * 1000 / t1);
- t1 = get_us();
- for (i = 0; i < 10000; ++i) {
- psram_read(i * 64, &testbuf, 64);
- }
- t1 = get_us() - t1;
- t1 /= 1000;
- SEGGER_RTT_printf(0, "PSRAM read speed: %lld B/s.\n", 64 * 10000 * 1000 / t1);
- SEGGER_RTT_printf(0, "PSRAM test done\n");
- }
编译
- cmake -B /tmp/build
- cmake --build /tmp/build -j8
在/tmp/build目录下有ra2e1.elf和ra2e1.srec文件生成
烧录
- pyocd load -e sector -t R7FA2E1A7 /tmp/build/ra2e1.elf
pyocd获取rtt打印信息
- pyocd rtt -t r7fa2e1a7 -a 0x20004a04
其中0x20004a04是_SEGGER_RTT符号地址,在编译结果的ra2e1.map中搜索即可获得
初步数据解析
烧录后板子重启,运行截图如下:
由此可见,写入速度是549828 Byte/s,读取速度是545144 Byte/s。因PCLKB是24MHZ,那么理论上最大Bit Rate按上文公式可达12Mbps,所以SPI总线理论速度传输速度大概能到1.5MB/s,实际速度大概只有理论速度的三分之一。下文做一些实验尝试提升SPI传输速度。
尝试提升PCLKB的频率
按官方手册,PCLKB的频率最高可到32MHZ,咱们在RASC配置试试。为了让PCLKB达32MHZ,可让HOCO频率升到64MHZ,然后2分频即可。但此时cpu最高只能48MHZ,所以只能两分频给ICLK,故cpu频率此时到32MHZ。编译烧录测试截图如下:
由此可见,读写速度反而下降了,猜测SPI传输瓶颈不在SPI总线上而在CPU上(毕竟现在的测试代码中是由CPU搬运数据),可能是CPU(只有32MHZ)来不及搬运导致。
尝试关闭param_checking
这个选项在RASC中可配置,测试结果基本不变。
尝试开启rxi_transmit
这个选项同样在RASC中可配置,测试截图如下:
由此可见在未使用dma引擎时rxi_transmit可提升SPI传输速度大概1个百分点。
思考与总结
其实如果由DMA引擎来搬运SPI数据,效率最高、速度最快。笔者搜索官方文档发现RA2E1集成了一个名叫DTC(data transfer controller)模块,但目前不太清楚这个DTC是否可以用来搬运SPI数据。所以如果DTC可用于搬运SPI数据,建议官方增加这样使用样例代码。