Writing to OctaSPI via FlexSPI

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

Writing to OctaSPI via FlexSPI

2,036 Views
Masmiseim
Senior Contributor I

Hello Together,

 

 I have another question regarding the FlexSPI interface.

We use the Interface to boot from an Adesto Octa-SPI Flash. This is working fine; we can boot from the Flash and can run our code from it. Reading from the related Memory-mapped data via the Debugger is also working well.

Now we like to write to the flash. Therefore, I’ve extended the command set in the LUT included in the configuration section of the flash with commands for reading JEDEC-ID, Enable write access, reading the status register and the actual write command.

After booting – when entering the code – the interface should be initialized by the Hardware-Bootloader. I can run my code from the flash and I can read the related memory-Areas so it should be fine. However, I can’t access the FlexSPI registers via the debugger. When trying to check them in debug view, the controller gets stuck and the only way to get control over it is to do a power cycle. SO, I can’t check if the LUT is loaded as intended. What is the reason for this?

In Addition, I cannot execute one of the additional commands I’ve added to the LUT, like reading the JEDEC IDs.

Do I have to initialize some additional Stuff? It looks like only the AHB-Bus is initialized to get access via memory mapping. The access over the IP Bus seems not to work.

 

I know that I could do a complete reinitialization. However, I like to understand what is going on there in first place. In addition, I don’t like a complete reinitialization of an interface which is already initialized especially on a complex one like this where I fear to break something else.

 

Best regards

Labels (1)
0 Kudos
11 Replies

1,715 Views
Masmiseim
Senior Contributor I

Hello Mark,

Hello Eyal,

 

thank you for your feedback.

We use our self-designed board, not the Embedded Artist's Board.

You can compare my LUT from the configuration section: https://github.com/Masmiseim36/iMXRT/blob/master/samples/iMXRT/flexspi_flash_OSPI_Adesto.c

 

Mark you wrote “maximum number of entries is a bit limited”. Up to now I didn’t reach any limit. The LUT is 256 Byte in Size and is spitted up in 16 chucks with 16 Byte each. One chunk is sufficient for one command-sequence (with the exception of the Cypress Hyperflash). So, you can use sixteen command-sequences. Your two LUT tables could be merged to one and will fit in one LUT if I’m correct

 

In the mean time I found the reason why the controller got stuck when accessing the FlexSPI registers. The Address of the FlexSPI was wrong in the CMSIS-SVD File. So, the debugger accessed an invalid address which lead to a not responding controller. The Address in the CMSIS Peripheral Access Layer was correct.

With the correct Address I can check the registers now. It looks like the HW-Bootloader is only initializing the first 32 Byte of the LUT. This explains why I ‘can’t read the JEDEC-ID. The related command-sequence in the LUT is not loaded. Which means I have to load at least all command-sequences beyond the first 32 Bytes.

This seems to be the same procedure you have done Eyal.

 

Bye the way, I was not talking about a JEDEC-Reset, but reading the JEDEC-ID. We use a generic Flash Library which first reads the Information of a Flash memory: The JEDEC ID and the SFDP Data.

 

Best regards

0 Kudos

1,715 Views
mjbcswitzerland
Specialist V

Markus

The LUT is limited to 16 entries which is Ok in most cases. The QSPI flash devices however usually support a lot of potential commands and I thus have a "setup set" and a "working set" in case I want to experiment with more.
If one has a fixed requirement where 16 would be adequate only one would be needed but it is very simple to swap out these so I am keeping the flexibility for now.
Note also that Hyper Flash devices often use multiple LUT entries for a single command (for example a sector erase on a Cypress S26KS512SDPBHI02 occupies already 4 LUTs!), meaning that 16 LUTs don't always go that far.

Regards

Mark
[uTasker project developer for Kinetis and i.MX RT]

0 Kudos

1,715 Views
Masmiseim
Senior Contributor I

Hello Mark,

 

I’ve also mentioned the exception with the Cypress Flash. For this Flash I fully agree.

I think a flash memory which is double the price of the controller is also a rather unusual choice. That is the reason why we have chosen the Adesto Flash. It is quite fast and relatively cheap. I wonder why this Flash Type is not used on any Evaluation Board, for me it is the obvious choice.

 

Best regards

0 Kudos

1,715 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi Markus Klein,

  Which Adesto Flash you are using? In fact, Adesto also has cooperation with NXP.

  Please check adesto's application note, whether it is useful to you or not:

https://www.adestotech.com/wp-content/uploads/AN106A1.pdf 

  If you have any question about adesto flash, you also can let the adesto side know it.

Kerry

 

-------------------------------------------------------------------------------
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.
-----------------------------------------------------------------------------

0 Kudos

1,715 Views
eyal_barzilay
Contributor II

Hi Markus,

Yes, that is exactly my experience. After boot the i.MXRT boot loader leaves two command sequence entries in the LUT even if I originally specified several other entries in the flash configuration block. I think it is doing it to be on the safe side (avoid accidental triggering of command which might change the state of the flash or perform program/erase). And so you have to modify the LUT and add your custom sequences.

Regards,

Eyal

1,715 Views
Masmiseim
Senior Contributor I

Hello Eyal,

 

I would agree if the other command sequences would be set to zero by the HW-Bootloader. But they seem to have random values which make it even more dangerous when commands are accidental triggered.

Best Regards

0 Kudos

1,715 Views
eyal_barzilay
Contributor II

One more thing: are you trying to implement code for the EcoXiP (ATXPxxx) read-while-write (RWW) feature? I have implemented it on i.MXRT1050 so I may be able to help you. This feature allows executing in place from flash (XiP) and at the same time writing to another area (memory bank) of the flash.

0 Kudos

1,715 Views
mjbcswitzerland
Specialist V

Eyal

The Embedded Artist boards presently us the ATXP032 which doesn't support RWW. I understand that they may upgrade at some point to the ATXP032R which does and I have code references ready for when this becomes possible.

Regards

Mark
[uTasker project developer for Kinetis and i.MX RT]

0 Kudos

1,715 Views
eyal_barzilay
Contributor II

Thanks, Mark. I think I know this customer/project and in this case it's not associated with Embedded Artists. Adesto currently supports RWW on the ATXP064 and eventually will on the entire ATXPxxx family. Great to know that you've implemented RWW as well. On my side there were a couple of challenges on the FlexSPI side but overall it wasn't too bad. It did require me to slightly tweak the SDK FlexSPI driver but really no big deal. Perhaps at some point we can compare notes.

0 Kudos

1,715 Views
eyal_barzilay
Contributor II

I have done something similar and did not need a re-initialization of the FlexSPI host controller. Like you I had to "patch" the LUT to add additional entries of my own as the i.MXRT boot loader doesn't leave much the LUT. I can't remember if I could view FlexSPI registers from the debugger but I do remember adding my own function to print the entire LUT so I know its contents are what I expect. It worked. BTW to patch the LUT I used the MCUXpresso SDK driver function FLEXSPI_UpdateLUT.

One thing to remember is to make sure the LUT  entries you add are compatible with the flash mode you use for boot. For example, if you boot in octal-DDR mode make sure those LUT entries are for octal-DDR.

Applying JEDEC reset to the flash is a separate issue. It is recommended to keep the host and the flash in sync. However the i.MXRT boot loader can perform it automatically if you set a certain fuse. I have tested it and the i.MXRT1050/60. It works.

1,715 Views
mjbcswitzerland
Specialist V

Hi Markus

Are you using the adesto ATXP as on the Embedded Artist's OEM module?

I have recently ported a flash driver to this part so that it can be used for parameter and file system storage (and also for firmware upgrading): https://www.utasker.com/iMX/iMX_RT1062_OEM.html

If you ask adesto directly they will send you a reference driver - it is not compatible with the latest SDK so either needs to be used an old one or be ported accordingly.

The start with a Jedec reset sequence and you I used that as it is and so don't know whether it is possible to avoid some of the RM code initialisation being repeated, but once working reliably one can progressively try removing such things until it potentially breaks.

When working with the debugger first ensure that the FlexSPI is not gated off otherwise the debugger can't access registers and thus tends to lead to needing to restart the system.

I have posted the LUTs that I use (one is installed during configuration and the other when the main operation starts since the maximum number of entries is a bit limited to have all commands installed at the same time. It is not in the format that the SDK uses because I find my own format better readable and easier to manage but the details are pretty simple to follow.

Note finally that I don't find this particular adesto chip very suitable for file system work due to the fact that it has very long erase time (x10 longer than most other typical devices). It is of course good when you need to run XiP as fast as possible since this operation is quick(er).


Regards

Mark
[uTasker project developer for Kinetis and i.MX RT]

static const FLEXSPI_LUT_ENTRY tableLUT_config[] = {                     // look-up table used only during configuration
    {   // Fast read - SDR
        NOR_CMD_LUT_SEQ_IDX_READ_FAST,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, FAST_READ) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_RADDR_SDR, ADDRESS_LENGTH_32BITS),
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_DUMMY_SDR, ECOXIP_READ_SPI_DUMMY_CYCLES) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_READ_SDR, 0x80),
        },
    },
    {   // Read status
        NOR_CMD_LUT_SEQ_IDX_READSTATUSREG,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, READ_STATUS_REGISTER_1) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_READ_SDR, 0x01),
        0,
        },
    },
    {   // Write enable
        NOR_CMD_LUT_SEQ_IDX_WRITEENABLE,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, WRITE_ENABLE) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_STOP, 0x00),
        0,
        },
    },  
    {   // Read status/control register
        NOR_CMD_LUT_SEQ_IDX_READ_STATUS_CONTROL_REGS,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, READ_STATUS_CONTROL_REGISTERS) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_RADDR_SDR, ADDRESS_LENGTH_8BITS),
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_DUMMY_SDR, 8) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_READ_SDR, 0x80),
        },
    },
    {   // Write status/control register (this specific sequence will write 2 bytes to status/control regs 2-3)
        NOR_CMD_LUT_SEQ_IDX_WRITE_STATUS_CONTROL_REGS,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, WRITE_STATUS_CONTROL_REGISTERS) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_SDR, 0x02),
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_WRITE_SDR, 0x02) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_STOP, 0x00),
        },
    },
    {   // Read ID
        NOR_CMD_LUT_SEQ_IDX_READID,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, READ_JEDEC_ID) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_READ_SDR, 0x0c),
        0,
        },
    },
    {   // Unprotect sectors
        NOR_CMD_LUT_SEQ_IDX_UNPROTECT_SECTORS,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, _UNPROTECT_SECTOR) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_RADDR_SDR, ADDRESS_LENGTH_32BITS),
        0,
        },
    },
    {   // Exit octal mode
        NOR_CMD_LUT_SEQ_IDX_EXITQPI,
        {
        FLEXSPI_LUT_8PAD_SEQ_1(FLEXSPI_Command_SDR, RETURN_TO_SPI_MODE) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_STOP, 0x00),
        0,
        },
    },
    {   // End of LUT
        NOR_CMD_LUT_SEQ_IDX_END_OF_TABLE,
        {
            0,0
        },
    },
};

static const FLEXSPI_LUT_ENTRY tableLUT_main[] = {                       // look-up table used during main operation
    {   // Fast read - SDR
        NOR_CMD_LUT_SEQ_IDX_READ_FAST,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, FAST_READ) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_RADDR_SDR, ADDRESS_LENGTH_32BITS),
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_DUMMY_SDR, ECOXIP_READ_SPI_DUMMY_CYCLES) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_READ_SDR, 0x80),
        },
    },
    {   // Read status
        NOR_CMD_LUT_SEQ_IDX_READSTATUSREG,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, READ_STATUS_REGISTER_1) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_READ_SDR, 0x01),
        0,
        },
    },
    {   // Write enable
        NOR_CMD_LUT_SEQ_IDX_WRITEENABLE,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, WRITE_ENABLE) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_STOP, 0x00),
        0,
        },
    },
    {   // Unprotect sectors
        NOR_CMD_LUT_SEQ_IDX_UNPROTECT_SECTORS,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, _UNPROTECT_SECTOR) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_RADDR_SDR, ADDRESS_LENGTH_32BITS),
        0,
        },
    },
    {   // Write disable
        NOR_CMD_LUT_SEQ_IDX_WRITEDISABLE,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, WRITE_DISABLE) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_STOP, 0x00),
        0,
        },
    },
    {   // Erase sector - 4k
        NOR_CMD_LUT_SEQ_IDX_ERASESECTOR,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, SUB_SECTOR_ERASE) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_RADDR_SDR, ADDRESS_LENGTH_32BITS),
        0,
        },
    },
    {   // Erase half-block - 32k
        NOR_CMD_LUT_SEQ_IDX_ERASE_HALF_BLOCK,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, HALF_BLOCK_ERASE) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_RADDR_SDR, ADDRESS_LENGTH_32BITS),
        0,
        },
    },
    {   // Erase block - 64k
        NOR_CMD_LUT_SEQ_IDX_ERASE_BLOCK,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, BLOCK_ERASE) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_RADDR_SDR, ADDRESS_LENGTH_32BITS),
        0,
        },
    },
    {   // Page program - single mode
        NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE,
        {
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_SDR, PAGE_PROG) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_RADDR_SDR, ADDRESS_LENGTH_32BITS),
        FLEXSPI_LUT_1PAD_SEQ_1(FLEXSPI_Command_WRITE_SDR, 0x04) | FLEXSPI_LUT_1PAD_SEQ_2(FLEXSPI_Command_STOP, 0x00),
        },
    },
    {   // End of LUT
        NOR_CMD_LUT_SEQ_IDX_END_OF_TABLE,
        {
            0,0
        },
    },
};