Access to FLEXSPI1 port B in XIP mode.

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

Access to FLEXSPI1 port B in XIP mode.

Jump to solution
666 Views
MichalKv
Contributor III

Hello,

I'm using MIMXRT1176 where M7 is in XIP mode (on FLEXSPI1 port A) and M4 is running in SDRAM. I'm trying to access FlexSPI1 port B but without any luck. I've already followed some documentation, for example:

In my setup we have flash memory for MCU program on FlexSPI1 port A and then another flash memory for data on FlexSPI1 port B. 

In my actual state I initialize M7 core and jumps into a function that runs in RAM memory until M4 initialization isn't done. That works fine. 

On M4 I'm trying to access FLEXSPI1 port B and read vendors ID from flash memory. However, no matter what I try I always read vendors ID from the MCU flash memory. This is quite an unexpected behaviour because the MCU flash memory is on port A1 and I'm using FLEXSPI_TransferBlocking() for port B1.

When it comes to initialization, my XIP configuration on M7 side looks like this:

const flexspi_nor_config_t qspiflash_config = {
    .memConfig =
        {
            .tag              = FLEXSPI_CFG_BLK_TAG,
            .version          = FLEXSPI_CFG_BLK_VERSION,
            .readSampleClksrc=kFlexSPIReadSampleClk_LoopbackInternally,
            .csHoldTime       = 3u,
            .csSetupTime      = 3u,
            // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
            .controllerMiscOption = 0x10,
            .deviceType           = kFlexSpiDeviceType_SerialNOR,
            .sflashPadType        = kSerialFlash_4Pads,
            .serialClkFreq        = kFlexSpiSerialClk_60MHz,
            .sflashA1Size         = 16u * 1024u * 1024u,
            .sflashB1Size		  = 16u * 1024u * 1024u,
            /* Enable flash configuration feature */
            .configCmdEnable   = 1u,
            .configModeType[0] = kDeviceConfigCmdType_Generic,
            /* Set configuration command sequences */
            .configCmdSeqs[0] =
                {
                    .seqNum   = 1,
                    .seqId    = 12,
                    .reserved = 0,
                },
            /* Prepare setting value for Read Register in flash */
            .configCmdArgs[0] = (FLASH_DUMMY_VALUE << 3),
            .lookupTable = 
				{
					[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD + 0] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xEB, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 0x18),
					[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD + 1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, FLASH_DUMMY_CYCLES, kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04),
					
					[4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x05, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
					
					[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_4BYTE + 0] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x12, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x20),
					[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_4BYTE + 1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
					
					[4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x06, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
					
					[4 * NOR_CMD_LUT_SEQ_IDX_READID] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x9F, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
					
					[4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR_4kB] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x20, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
					
					[4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 0] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x13, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x20),
					[4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
					
					[4 * NOR_CMD_LUT_SEQ_IDX_ERASEBLOCK_64kB] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xD8, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
					
					[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_3BYTE + 0] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x02, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
					[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_3BYTE + 1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
					
					[4 * NOR_CMD_LUT_SEQ_IDX_CHIPERASE] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x60, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
					
					[4 * NOR_CMD_LUT_SEQ_IDX_SETREADPARAMS + 0] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xC0, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x01),
					[4 * NOR_CMD_LUT_SEQ_IDX_SETREADPARAMS + 1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00, 0, 0, 0),
				},
        },
    .pageSize           = 256u,
    .sectorSize         = 4u * 1024u,
    .ipcmdSerialClkFreq = 0x1,
    .blockSize          = 64u * 1024u,
    .isUniformBlockSize = false,
};

I've made sure that I tell the XIP that there's another flash on FlexSPI1 (through the sflashB1Size). The internal loopback is there for a reason.
When it comes to the M4 side, I'm trying to initialize the port B as follows:

status_t flexspi1b_Init(FLEXSPI_Type *base) {
	if(!base) {
		return kStatus_Fail;
	}
	
	flexspi_cache_status_t cacheStatus = {0};
	_flexspi1b_CacheEnable(&cacheStatus, false);
    FLEXSPI_SetFlashConfig(base, &flexspi1bDeviceCfg, FLEXSPI1B_FLASH_PORT);
    uint32_t tmpLUT[FLEXSPI1B_LUT_LENGTH] = {0};
    memcpy(tmpLUT, flexspi1bLUT, sizeof(tmpLUT));
    FLEXSPI_UpdateLUT(base, 1, &tmpLUT[1], FLEXSPI1B_LUT_LENGTH - 1);
    FLEXSPI_SoftwareReset(base);
	_flexspi1b_CacheEnable(&cacheStatus, true);
    
    return kStatus_Success;
}

But this doesn't look to have any effect on the behaviour of FlexSPI1 port B. I've tried using FLEXSPI_Init() function, however when I use it, it crashes the whole MCU. I thought it might be because of the native initialization of clock but even after commenting that section, it still crashes the whole MCU. I thought maybe the init function isn't needed since the initialization of FlexSPI1 block is through the XIP but it doesn't seem like it. 

My function for reading vendors ID looks like this:

status_t flexspi1b_GetVendorId(FLEXSPI_Type *base, uint32_t *vendorId) {
	if(!base || !vendorId) {
		return kStatus_Fail;
	}
	
	flexspi_transfer_t flashXfer = {
		.deviceAddress 	= 0,
		.port 			= kFLEXSPI_PortB1,
		.cmdType 		= kFLEXSPI_Read,
	    .SeqNumber     	= 1,
	    .seqIndex      	= NOR_CMD_LUT_SEQ_IDX_READID,
	    .data          	= vendorId,
	    .dataSize      	= 3,
	};
	
	status_t sts = FLEXSPI_TransferBlocking(base, &flashXfer);
	
	return sts;
}

 

What is quite mindblowing to me is the fact that when I use FLEXSPI_Init() function and debug only the M4 core alone, everything works pefectly, I'm even able to write data etc. to the flash memory that is located at FlexSPI1 port B1. 

I'm sure M7 core is not doing anything with FlexSPI1 because I have oscilloscope connected to it the whole time and there's nothing happening there after I enter the RAM function so that shouldn't make any problem. 

Does anyone have any idea what am I doing wrong or what information am I completely missing? 

Thank you in advance for any tip or documentation that describes such issue.

Tags (3)
0 Kudos
Reply
1 Solution
468 Views
MichalKv
Contributor III

It seems like I figured out what was the problem and now I'm able to read vendors ID from both flash memories.

I accidentally came across this thread:

where even if the solution isn't very mentioned, but the "now it works my mistake was that I took the wrong device address" at least gave me a clue that there must be something about device address.

So I've tried to play with it around and found out, even when I was not able to find any mention of this behaviour in any API documentation/reference manual I was able to find about the FlexSPI peripheral for MIXMRT1176, that the FlexSPI uses FLASH memories on both port as one big continuous FLASH memory.

That means that when you call 'FLEXSPI_TransferBlocking()' with your parameter 'flexspi_transfer_t flashXfer', the '.deviceAddress' means memory address. It's better shown on the picture below.

MichalKv_0-1767950249631.png

So in my case if '.deviceAddress = <0x0000000; 0x0FFFFFF>' I read from port A, if the '.deviceAddress = <0x1000000; 0x1FFFFFF>' I read from port B.

Fun fact:  In the structure 'flexspi_transfer_t' is a parameter '.port' which you can set to values according to which port you want to use. This does nothing since no matter which port I set there (port A1 or port B1), the only thing that matters is value of '.deviceAddress'.

Even when I solved my problem, I'm still wondering, is there any description of this behaviour somewhere? Because I would still like to know why there is '.port' parameter in the 'flexspi_transfer_t' structure etc. 

 

 

View solution in original post

0 Kudos
Reply
3 Replies
603 Views
Sam_Gao
NXP Employee
NXP Employee

Hi,

It seems there are some crash issues like M4 access failing while M7 is in XIP, please correct me if my understanding is wrong.

If my understanding is correct(The M4 core's call to FLEXSPI_Init() causes a system crash when M7 is in XIP), the cause: FlexSPI is the only hardware resource shared by M7 and M4. M7 is performing XIP (Execute On-Chip) via FlexSPI1 Port A. The FLEXSPI_Init() function typically performs a software reset (setting MCR0[SWRESET]) or disables the module (MCR0[MDIS]) to write the configuration. This instantly cuts off the M7's instruction stream, causing a HardFault on the M7, which in turn crashes the entire MCU.

So, Please never call an initialization function that performs a global reset or clock gating of the FlexSPI module from M4 during M7 XIP execution.

0 Kudos
Reply
588 Views
MichalKv
Contributor III

Hello,
thank you for a fast response.

To clarify the situation, I'm not using FLEXSPI_Init() anywhere in the code right now. I'm calling only FLEXSPI_SetConfig(), which should set some additional configuration, but it does not cause a crash.

To reply for a suggestion to not perform a software reset - the software reset I'm using (FLEXSPI_SoftwareReset()) in the example does not cause any crash. The M7 is executing XIP however any time I try to access FLEXSPI1 port B from the M4 core, I keep the M7 core halted in RAM memory. That indicates that there's some kind of settings that cause the crash when I've tried to use FLEXSPI_Init() function. It is not configuration of the clock since I've commented that section out.

My problem is not exactly that the MCU is crashing, that's only if I try to use FLEXSPI_Init() function, which I'm no longer doing. My problem is that I'm not able to access the FLEXSPI1 port B1. In fact whatever I try, and however I try to set the FLEXSPI_TransferBlocking() function I always read/write only through FLEXSPI1 port A1. No matter the setup the FLEXSPI1 port A1 is always used. 

0 Kudos
Reply
469 Views
MichalKv
Contributor III

It seems like I figured out what was the problem and now I'm able to read vendors ID from both flash memories.

I accidentally came across this thread:

where even if the solution isn't very mentioned, but the "now it works my mistake was that I took the wrong device address" at least gave me a clue that there must be something about device address.

So I've tried to play with it around and found out, even when I was not able to find any mention of this behaviour in any API documentation/reference manual I was able to find about the FlexSPI peripheral for MIXMRT1176, that the FlexSPI uses FLASH memories on both port as one big continuous FLASH memory.

That means that when you call 'FLEXSPI_TransferBlocking()' with your parameter 'flexspi_transfer_t flashXfer', the '.deviceAddress' means memory address. It's better shown on the picture below.

MichalKv_0-1767950249631.png

So in my case if '.deviceAddress = <0x0000000; 0x0FFFFFF>' I read from port A, if the '.deviceAddress = <0x1000000; 0x1FFFFFF>' I read from port B.

Fun fact:  In the structure 'flexspi_transfer_t' is a parameter '.port' which you can set to values according to which port you want to use. This does nothing since no matter which port I set there (port A1 or port B1), the only thing that matters is value of '.deviceAddress'.

Even when I solved my problem, I'm still wondering, is there any description of this behaviour somewhere? Because I would still like to know why there is '.port' parameter in the 'flexspi_transfer_t' structure etc. 

 

 

0 Kudos
Reply