FlexSPI AHB Write Questions

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

FlexSPI AHB Write Questions

3,892 Views
barrett_lowe
Contributor II

I'm trying to get the FlexSPI to be handled via hardware/AHB on my i.MX RT 1064. I'm using IS25LP064A - same as on the eval board. I'm trying to use it simply as external flash. I don't think this can be done completely in hardware because the chip needs a separate command to enable writing to the part followed by deasserting the CS pin.

I guess my first question is, is this possible? Can I deassert and reassert the CS pin in the same LUT sequence?

My second question is how do manage the amount of data transmitted in 1 write operation? When reading through the manual, it looks like it may be dependent on AHB Burst. Is that correct? How can I configure the AHB Burst size and type? With the default config defined in the SDK, it looks like sometimes 16 bytes are transmitted and sometimes 32 bytes are transmitted.

Ideally I'd like to be able to write a max of 256 bytes but less if less is requested.

Thank you!

EDIT:

Okay I've figured more out. I had to increase the SEQNUM to get the next sequence to execute. The SDK variable name is confusing since it mimics the register name in the RM. But the register value is the number of sequences you want to run -1 while the variable seems to be the actual number of sequences you want to run. Got that part sorted out!

My question about the AHB buffer/burst still stands. How can I control the size of the write? Using IP commands I can make it be 256 bytes but using AHB I can't seem to control it.

Labels (1)
9 Replies

3,693 Views
victorjimenez
NXP TechSupport
NXP TechSupport

Hello Barrett, 

I'm not sure that I understood your question correctly, so please correct me if I'm wrong. In the SDK you will find an example project named flexspi_nor_polling_transfer. This example project demonstrates how to achieve what you are trying to do. The example uses the function flexspi_nor_flash_page_program to write to the flash, however, within the drivers you will find a function called flexspi_nor_flash_program in which you can pass as an argument the length of what you are trying to write. 

Regards,

Victor

-------------------------------------------------------------------------------

Note:

- If this post answers your question, please click the "Mark Correct"button. Thank you!

- We are following threads for 7 weeks after the last post, later replies are ignored

Please open a new thread and refer to the closed one, if you have a related question at a later point in time.

------------------------------------------------------------------------------- 

3,693 Views
barrett_lowe
Contributor II

Hi Victor,

Have you had a chance to look into my question?

Also, am I missing a demo project in the SDK for writing via AHB commands? Thanks

0 Kudos
Reply

3,693 Views
victorjimenez
NXP TechSupport
NXP TechSupport

Hello Barrett, 

Thanks for clarifying the information! So, just to clarify, if you call the function memcpy(FlexSPI_AMBA_BASE, src, size);

And the size is lezz than 32 bytes, you don't see anything on the oscilloscope and hence the data is not written into the memory, but if the size is 32 bytes then you are able to see the signals in the oscilloscope and the writing does occur, correct? Could you please share with me the project that you used to make these tests?

Regarding the demo project for writing via AHB commands, unfortunately, we don't have a demo project that fits these needs. The only example that we have that shows how to write to the external memory is the one I mentioned before but as you mentioned it uses IP commands. 

Regards,

Victor 

0 Kudos
Reply

3,693 Views
barrett_lowe
Contributor II

Hi Victor,

Sorry - let me try to be more clear. If I try sending 32 bytes of data using

    std::vector<uint8_t> nor_program_buffer(320xA5);
    memcpy((uint8_t*)(FlexSPI_AMBA_BASE), nor_program_buffer.data(), nor_program_buffer.size());

On the oscilloscope, I see a read command sequence (not a write sequence) reading the first 32 bytes and that is all. The data never actually makes it into the chip. I never see a write command.

If I write 256 bytes, I get something very different.

Writing 256 bytes yields 5 read command sequences each reading 32 bytes of data at addresses 0x00, 0x20, 0x40, 0x60, 0x80. After those signals, I finally see a write command sequence writing 32 bytes at address 0xA0. In this case, some of my data still did not make it to the chip...

I don't know if I can send my whole project but maybe I can send you my config. Let me know if you need more information. I can try and create an entire separate project if needed. Thanks!

    flexspi_config_t config;

    auto AHBFreq = CLOCK_GetAhbFreq();
    auto ahbCycleNs = 1.0f / AHBFreq;
    ahbCycleNs *= 1.0e9;
    auto totCycles = 800000 / ahbCycleNs;
    auto ahbWriteInterval = totCycles / 512 ;
    // WARNING: somehow the theory on this doesn't work out and we are not sure why.
    // Although we divide by 512 here, it looks like we are actually 4 times too slow
    // according to the oscilloscope. For this reason, we actually use 128 below for
    // the AHBWriteWaitUnit. 

#pragma diag_suppress = Pe2361 //Disable warning about precision loss with the static_casts below
    flexspi_device_config_t deviceconfig = {
        // .flexspiRootClk = 99000000,
        .flexspiRootClk = 18750000,
        .flashSize = FLASH_SIZE,
        .CSIntervalUnit = kFLEXSPI_CsIntervalUnit1SckCycle,
        .CSInterval = static_cast<uint32_t>(7 / ahbCycleNs) + 1,
        .CSHoldTime = static_cast<uint32_t>(6 / ahbCycleNs) + 1,
        .CSSetupTime = static_cast<uint32_t>(6 / ahbCycleNs) + 1,
        .dataValidTime = static_cast<uint32_t>(10 / ahbCycleNs) + 1,
        .columnspace = 8,                                            
        .enableWordAddress = 0,
        .AWRSeqIndex = (uint8_t)(m_quadEnable ? WEL_WRITE_QUAD_IDX : WEL_WRITE_SINGLE_IDX),
        .AWRSeqNumber = 2,
        .ARDSeqIndex = (uint8_t)(m_quadEnable ? READ_QUAD_IDX : READ_SINGLE_IDX),
        .ARDSeqNumber = 1,
        .AHBWriteWaitUnit = kFLEXSPI_AhbWriteWaitUnit128AhbCycle,
        .AHBWriteWaitInterval = static_cast<uint32_t>(ahbWriteInterval),
    };
#pragma diag_default = Pe2361


    FLEXSPI_Type* ptrs[] = FLEXSPI_BASE_PTRS;
    auto base = const_cast<FLEXSPI_Type*>(ptrs[m_flexspiBase]);

#if defined(__DCACHE_PRESENT&& (__DCACHE_PRESENT == 1U)
    bool DCacheEnableFlag = false;
    /* Disable D cache. */
    if (SCB_CCR_DC_Msk == (SCB_CCR_DC_Msk & SCB->CCR))
    {
        SCB_DisableDCache();
        DCacheEnableFlag = true;
    }
#endif /* __DCACHE_PRESENT */

    /*Get FLEXSPI default settings and configure the flexspi. */
    FLEXSPI_GetDefaultConfig(&config);

    // /*Set AHB buffer size for reading data through AHB bus. */
    config.ahbConfig.enableAHBPrefetch = false;
    config.ahbConfig.enableAHBBufferable = false;
    config.ahbConfig.enableReadAddressOpt = false;
    config.ahbConfig.enableAHBCachable = false;

    FLEXSPI_Init(base&config);

    /* Configure flash settings according to serial flash feature. */
    FLEXSPI_SetFlashConfig(base&deviceconfigkFLEXSPI_PortA1);

    /* Update LUT table. */
   
    FLEXSPI_UpdateLUT(base0customLUTCUSTOM_LUT_LENGTH);

    /* Do software reset. */
    FLEXSPI_SoftwareReset(base);

#if defined(__DCACHE_PRESENT&& (__DCACHE_PRESENT == 1U)
    if (DCacheEnableFlag)
    {
        /* Enable D cache. */
        SCB_EnableDCache();
    }
#endif /* __DCACHE_PRESENT */
0 Kudos
Reply

3,693 Views
victorjimenez
NXP TechSupport
NXP TechSupport

Hi Barrett, 

Sorry for the late response. I made several tests and I was able to reproduce the behavior that you mentioned. I will check this internally and I will provide you an update as soon as possible. 

Regards, 

Victor 

3,693 Views
victorjimenez
NXP TechSupport
NXP TechSupport

Hi Barrett,

I confirm with the applications team that you can not use memcpy directly to write NOR flash via FlexSPI, this feature is NOT supported. I apologize for the inconvenience that this might cause you. 

Regards,

Victor

3,693 Views
barrett_lowe
Contributor II

Victor,

Thanks for getting back to me. I am surprised by this answer! The documentation reports that this is possible in multiple locations throughout the FlexSPI section. There are many mentions of the AHB TX buffer and direct memory read/write access. Infact, there is an entire section dedicated to it as well. A few sections from Rev. 1:

Section 27.2.1 (Features)

Section 27.5.8.1 (Instruction execution on SPI interface)

Section 27.5.10.1 (AHB write access to Flash)

As well as various registers

I certainly can work around this but it is documented as an obvious feature. Am I missing something? Are you sure this is not supported? Are there plans to revise the manual? Thank you

0 Kudos
Reply

3,693 Views
victorjimenez
NXP TechSupport
NXP TechSupport

Hi Barrett,

 

I double-check this directly with the design team and they confirmed that this feature is only supported in RAM memories that complete write commands quickly. 

I agree with you that the information in the reference manual is not clear enough to understand that this feature is only supported in RAM memories. They will review this internally to evaluate if some information has to be modified in future releases of the reference manual. 

 

Regards,

Victor

0 Kudos
Reply

3,693 Views
barrett_lowe
Contributor II

Actually no. That demo app writes to flash using IP commands. I am talking about AHB commands. It looks like I can save quite a few clock cycles if I use AHB instead. The example does show reading values via AHB commands but that's NOT what I'm having problems with.

I'd like to be able to write to the flash using the address mapping for the FlexSPI peripheral. This way, the hardware will take care of creating my SPI output signals. For example:

If src is an array [0x0, 0x1, 0x2, 0x3, 0x4] and size is 5, when I run the below code

    memcpy(FlexSPI_AMBA_BASEsrcsize);

I would expect this see this on my osciloscope: (Write Request), (address,data)

Something like this:

MOSI:   <0x06> <0x00,0x00,0x00> <0x0, 0x1, 0x2, 0x3, 0x4>

CS    :   -_____-_____________________________________

Does this make sense?

Right now, I do not get any data out until I try to write 256 bytes. Even when I do that, the behavior is very strange. The first 160 bytes are read in multiple transactions and then address 0xA0-0xFF is written in multiple transactions. This is particularly unexpected behavior. Any ideas?

Thank you

EDIT:

I've made more progress. After setting up my LUT to expect a 16 bit row address and 8 bit column address as well as specifying in the config that I'm using a 8 bit width column address, I'm getting more expected results out on the oscilloscope. However, the data is still only being written in 32 byte chunks. Any idea why this is?

0 Kudos
Reply