This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] AM2432:OSPI 序列读取操作、以增加吞吐量

Guru**** 2322270 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1477706/am2432-ospi-sequence-read-operation-to-increase-throughput

器件型号:AM2432

工具/软件:

您好:

以该 OSPI 闪存为例。 在读取时序图中、命令、地址、虚拟周期之后有几个序列数据周期。 这样可以以突发方式自动读入多个数据。  

https://www.infineon.com/dgdl/Infineon-S28HS512T_S28HS01GT_S28HL512T_S28HL01GT_512MB_1GB_SEMPER_TM_FLASH_OCTAL_INTERFACE_1_8V_3-DataSheet-v68_00-EN.pdf?fileId=8ac78c8c7d0d8da4017d0ee6bca96f97

也在电路板上捕获了类似的波形。

但似乎软件不使用突发读取。  

在软件中读取10字节数据时、OSPI 输出10 CS、每个 CS 周期都有命令、地址、虚拟周期和5个 DQS 周期。  

如果读取8字节数据、则输出8个 CS 周期。  

深入研究代码、软件使用 memcpy 进行读取、OSPI 应已经处于存储器映射模式。

根据波形可以看出、有5个 DQS 信号、闪存已经在一个 CS 周期内输出10字节的数据、但软件不知道、仍逐字节读取。

由于存在这种时序行为、吞吐量非常差、浪费了过多的周期、甚至低于单线 SPI、因为它不需要虚拟周期。  

#1。 如何利用序列读取来提高吞吐量? 只能使用 DMA 来利用连续突发读取?

#2. 5个 DQS 是否可配置? 我们看到无论要读取多少个字节、它始终是5个序列脉冲。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、

    qi yu1 说:
    #1. 如何利用序列读取来提高吞吐量? 只能使用 DMA 使用连续突发读取?

    也可以在我们的设置中看到客户观察到的波形。 这也是我们在 TI EVM 设置中看到的内容。

    此外、当要读取的字节数大于等于1024个字节时、使用 DMA。 我来检查启用 DMA 传输 LET (假设有1KB 数据)时的行为。 我将检查相应的波形、并告知您是否有任何改进。

    qi yu1 说:
    #2. 5个 DQS 是否可配置? 我们看到它始终是5个序列脉冲、无论要读取多少个字节。

    我没有配置探测 DQS 线路、因此无法看到此行为。

    请告诉我客户是否期待 INDAC 读取? INDAC 读取时、我们看到整个操作(例如256字节的传输)发生在1个片选下。

    此致、

    Vaibhav

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、

    qi yu1 说:
    在软件中读取10字节数据时、OSPI 输出10 CS

    在 DMA 读取的情况下不会出现这种情况、例如、我降低了 DMA 复制的限制、并测试了256字节数据的读取、而 CS 的数量远少于我在波形中看到的数量。 它不是256 CS、而是大约8-9 CS。

    更改 DMA 副本下限的方法只是转到名为 ospi_v0.c 的文件、并更改宏的值:

    #define OSPI_DMA_COPY_LOWER_LIMIT  (128U)// 1024
    我将其更改为128字节、这意味着传输大小必须大于128字节才能启动 DMA 传输。
    只需重新构建库、然后查看相同的波形。
    此致、
    Vaibhav
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Vaibhav:

    在 DMA 读取的情况下不会出现这种情况

    我同意 DMA 将对突发进行流水线处理。  

    CPU 访问是否可以利用接口的突发特性?

    我将其更改为128字节、这意味着传输大小必须大于128字节才能启动 DMA 传输。

    是否有理由选择1024来分隔 DMA 和 CPU 访问? 如果 size<1024、DMA 的表现不如 CPU? 或只留下一个可配置的大小选项?

    INDAC 读出、我们看到整个操作(即256字节传输)发生在1个芯片选择下。

    是否有有助于理解的波形?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、

    如果 size<1024?
    、DMA 的性能不如 CPU

    正确理解、但您也可以使用可配置的尺寸进行实验。

    是否有波形有助于理解?

    我可以分享128字节数据的波形。  

    您可以:  

    不同协议的波形: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1450567/am6421-ospi-frame-is-split/5683140#5683140

    协议8D-8D-8D 的波形: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1450567/am6421-ospi-frame-is-split/5683367#5683367

    此致、

    Vaibhav

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    客户验证=<256字节 将仅是一个带 INDAC 的 CS、由于来自代码的 FIFO、>256将拆分为多个 CS、但没有找到有关 OSPI 接口 FIFO 大小的太多详细信息。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Tony:

    我知道客户看到了这种行为。

    您是否建议客户继续并按如下方式修改 OSPI_readIndirect API。

    如果客户使用最新的 SDK:

    int32_t OSPI_lld_readIndirect(OSPILLD_Handle hOspi, OSPI_Transaction *trans)
    {
        int32_t status = OSPI_SYSTEM_SUCCESS;
        const CSL_ospi_flash_cfgRegs *pReg;
        uint8_t *pDst;
        uint32_t addrOffset;
        uint32_t remainingSize;
        uint32_t readFlag = 0U;
        uint32_t sramLevel = 0, readBytes = 0;
        OSPILLD_InitHandle hOspiInit;
    
        /* Check if hOspi & OSPI_transactions are NULL */
        if((NULL != hOspi) && (NULL != trans))
        {
            pReg = (const CSL_ospi_flash_cfgRegs *)(hOspi->baseAddr);
            hOspiInit = hOspi->hOspiInit;
            addrOffset = trans->addrOffset;
            pDst = (uint8_t *) trans->buf;
    
            OSPI_disableInterrupt(hOspi);
            OSPI_clearInterrupt(hOspi);
            if(TRUE == hOspi->hOspiInit->intrEnable)
            {
                OSPI_enableInterrupt(hOspi);
                hOspi->currTrans->addrOffset = trans->addrOffset;
                hOspi->currTrans->buf = trans->buf;
                hOspi->currTrans->count = trans->count;
                hOspi->currTrans->dataLen = trans->dataLen;
                hOspi->currTrans->transferOffset = 0U;
                hOspi->currTrans->state = OSPI_TRANS_READ;
                hOspi->currTrans->status = trans->status;
            }
    
            /* Disable DAC Mode */
            CSL_REG32_FINS(&pReg->CONFIG_REG,
                        OSPI_FLASH_CFG_CONFIG_REG_ENB_DIR_ACC_CTLR_FLD,
                        0U);
            CSL_REG32_WR(&pReg->IND_AHB_ADDR_TRIGGER_REG, 0);
    
            /* Config the Indirect Read Transfer Start Address Register */
            CSL_REG32_WR(&pReg->INDIRECT_READ_XFER_START_REG, addrOffset);
    
            /* Set the Indirect Write Transfer Start Address Register */
            CSL_REG32_WR(&pReg->INDIRECT_READ_XFER_NUM_BYTES_REG, trans->count);
    
            /* Set the Indirect Write Transfer Watermark Register */
            CSL_REG32_WR(&pReg->INDIRECT_READ_XFER_WATERMARK_REG,
                        CSL_OSPI_SRAM_WARERMARK_RD_LVL);
    
            // CHANGE INTRODUCED
            /* Set the SRAM Pariticion config reg read partition to fully 255, and write partition becomes 0. Earlier this value was set to 63. */
            CSL_REG32_WR(&pReg->SRAM_PARTITION_CFG_REG,
                        255);
    
            /* Start the indirect read transfer */
            CSL_REG32_FINS(&pReg->INDIRECT_READ_XFER_CTRL_REG,
                        OSPI_FLASH_CFG_INDIRECT_READ_XFER_CTRL_REG_START_FLD,
                        1);
    
            if(OSPI_TRANSFER_MODE_POLLING == hOspi->transferMode)
            {
                remainingSize = trans->count;
    
                while(remainingSize > 0U)
                {
                    if(OSPI_waitReadSRAMLevel(pReg, &sramLevel) != 0)
                    {
                        /* SRAM FIFO has no data, failure */
                        readFlag = 1U;
                        status = OSPI_SYSTEM_FAILURE;
                        trans->status = OSPI_TRANSFER_FAILED;
                        break;
                    }
    
                    readBytes = sramLevel * CSL_OSPI_FIFO_WIDTH;
                    readBytes = (readBytes > remainingSize) ? remainingSize : readBytes;
    
                    /* Read data from FIFO */
                    OSPI_readFifoData(hOspiInit->dataBaseAddr, pDst, readBytes);
    
                    pDst += readBytes;
                    remainingSize -= readBytes;
                }
                /* Wait for completion of INDAC Read */
                if(readFlag == 0U && OSPI_waitIndReadComplete(pReg) != 0)
                {
                    readFlag = 1U;
                    status = OSPI_SYSTEM_FAILURE;
                    trans->status = OSPI_TRANSFER_FAILED;
                }
    
            }
        }
        else
        {
            status = OSPI_LLD_INVALID_PARAM;
        }
        // Reverting back to default value.
        CSL_REG32_WR(&pReg->SRAM_PARTITION_CFG_REG,
                    63);
    
        return status;
    }

    如果客户使用的是较早的 SDK:

    int32_t OSPI_readIndirect(OSPI_Handle handle, OSPI_Transaction *trans)
    {
        int32_t status = SystemP_SUCCESS;
        const OSPI_Attrs *attrs = ((OSPI_Config *)handle)->attrs;
        OSPI_Object *obj = ((OSPI_Config *)handle)->object;
        const CSL_ospi_flash_cfgRegs *pReg = (const CSL_ospi_flash_cfgRegs *)(attrs->baseAddr);
        uint8_t *pDst;
        uint32_t addrOffset;
        uint32_t remainingSize;
        uint32_t readFlag = 0U;
        uint32_t sramLevel = 0, readBytes = 0;
        uint32_t dacState;
    
        addrOffset = trans->addrOffset;
        pDst = (uint8_t *) trans->buf;
    
        /* Disable DAC Mode */
        dacState = obj->isDacEnable;
        if(dacState == TRUE)
        {
            OSPI_disableDacMode(handle);
        }
    
        /* Config the Indirect Read Transfer Start Address Register */
        CSL_REG32_WR(&pReg->INDIRECT_READ_XFER_START_REG, addrOffset);
    
        /* Set the Indirect Write Transfer Start Address Register */
        CSL_REG32_WR(&pReg->INDIRECT_READ_XFER_NUM_BYTES_REG, trans->count);
    
        /* Set the Indirect Write Transfer Watermark Register */
        CSL_REG32_WR(&pReg->INDIRECT_READ_XFER_WATERMARK_REG,
                     CSL_OSPI_SRAM_WARERMARK_RD_LVL);
    
        // CHANGE INTRODUCED
        /* Set the SRAM Pariticion config reg read partition to fully 255, and write partition becomes 0. Earlier this value was set to 63. */
        CSL_REG32_WR(&pReg->SRAM_PARTITION_CFG_REG,
                    255);
    
        /* Start the indirect read transfer */
        CSL_REG32_FINS(&pReg->INDIRECT_READ_XFER_CTRL_REG,
                       OSPI_FLASH_CFG_INDIRECT_READ_XFER_CTRL_REG_START_FLD,
                       1);
    
        if(OSPI_TRANSFER_MODE_POLLING == obj->transferMode)
        {
            remainingSize = trans->count;
    
            while(remainingSize > 0U)
            {
                if(OSPI_waitReadSRAMLevel(pReg, &sramLevel) != 0)
                {
                    /* SRAM FIFO has no data, failure */
                    readFlag = 1U;
                    status = SystemP_FAILURE;
                    trans->status = OSPI_TRANSFER_FAILED;
                    break;
                }
    
                readBytes = sramLevel * CSL_OSPI_FIFO_WIDTH;
                readBytes = (readBytes > remainingSize) ? remainingSize : readBytes;
    
                /* Read data from FIFO */
                OSPI_readFifoData(attrs->dataBaseAddr, pDst, readBytes);
    
                pDst += readBytes;
                remainingSize -= readBytes;
            }
            /* Wait for completion of INDAC Read */
            if(readFlag == 0U && OSPI_waitIndReadComplete(pReg) != 0)
            {
                readFlag = 1U;
                status = SystemP_FAILURE;
                trans->status = OSPI_TRANSFER_FAILED;
            }
    
        }
    
        // Reverting back to default value.
        CSL_REG32_WR(&pReg->SRAM_PARTITION_CFG_REG,
                    63);
    
        /* Return to DAC mode if it was initially in enabled state */
        if(dacState == TRUE)
        {
            OSPI_enableDacMode(handle);
        }
    
        return status;
    }

    这将确保事务(我测试了最多512字节)发生在1个芯片选择下。

    简而言之、我要修改 SRAM 分区配置寄存器、在这里、我们为读取分区分配了更多空间、然后复位回默认值63。

    请阅读适用于客户当前开发环境的代码中的注释。

    此致、

    Vaibhav

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Vaibhav:

    什么时候会更新到 AM64x、AM62x、AM24x MCU SDK?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Tony、

    很高兴再次回到这个主题。

    [报价 userid="35100" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1477706/am2432-ospi-sequence-read-operation-to-increase-throughput/5865735 #5865735"]

    尊敬的 Vaibhav:

    什么时候会更新到 AM64x、AM62x、AM24x MCU SDK?

    [/报价]

    我的逻辑是否适用于客户选择的1个芯片? 比如事务在1个片选下发生了什么? 如果是、我想通知您、这更多是修改、具体取决于特定客户的各种要求。

    内部代码更改:

    这本质上是一种指示必须为 OSPI 间接写入 VS 读取操作保留多少空间的方法。 这可以根据要求进行配置。

    例如,如果我不应该写很多,读取很少的字节数,那么我会分配更多的写入和较少的读取来固定东西,或者至少确保事务发生在1芯片选择下。

    请告诉我您对此的看法。

    结语:

    这不能进入 SDK ,因为它只是一个小黑客,可以从客户的末端,以及测试了一堆循环后.

    此致、

    Vaibhav