cancel
Showing results for 
Search instead for 
Did you mean: 

QSPI RAM on OSPI Interface of H7A3 MCU issues

CBerg
Senior

Hi Guys,

I need some help / input:

I am trying to get the communication running between my Nucleo H7A3 and a Shield with a ISSI QuadSPI RAM in a SOP-8 Package running.

Scenario:

I am debugging with my Scope, I have a digital Probe on all 6 lines (CSn, Clock and DIO0-3) and I can see the communication.

First issue:

I am sending the command "0x05 - read mode register". I can see the outgoing communication on the scope, I can see the incoming communication on the scope. I can see on the scope that the RAM is sending a response - with the default Mode Register Value. But the Variable I am reading ins, is not updated with that value.

My Code:

 

	OSPI_RegularCmdTypeDef cmd = {0};
	uint8_t buf[4] = {0,};

	cmd.Instruction				= SRAM_CMD_RDMR;							// instruction byte
	cmd.InstructionMode			= HAL_OSPI_INSTRUCTION_1_LINE;				// mode of the instruction
	cmd.InstructionSize			= HAL_OSPI_INSTRUCTION_8_BITS;				// size of the instruction

	cmd.DataMode				= HAL_OSPI_DATA_1_LINE;						// data mode: 1 Line
	cmd.NbData					= 1;										// number of data transfered with the command
	cmd.DummyCycles        		= 0x00;										// number of dummy cycles before data phase

	HAL_StatusTypeDef status;
	status = HAL_OSPI_Command(hSramOSPI, &cmd, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
	if(HAL_OK != status) {
		return(1);
	}

	status = HAL_OSPI_Receive(hSramOSPI, buf, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
	if (HAL_OK != status) {
		return(1);
	} else {
		SRAM_modereg = buf[0];
	}

 

I see literally in the scope 2 Bytes: 0x05 (=read Mode register command) and the response 0x40 - which is the default value of the chip according to its datasheet. But the buf variable, as well as the SRAM_modereg variable, where it is copied to remain 0.

I am using the MCU, the D-Cache and the I-Cache - Am I running in some weird Cache issues here - even if I am using OSPI in Blocking mode? Are there some DMA Transfers in the Background I am not aware of or something similar?

Second Issue:

If I use anything other than

cmd.AddressMode = HAL_OSPI_ADDRESS_NONE;

like 1 Line or 4 Lines for the address Phase, there is no communication at all on the bus. If I disable the Address phase, I can see communication on the both no matter which mode (SPI or QSPI) I am in. My Code:

 

static uint8_t rOS_SRAM_read(uint32_t addr, uint8_t * pData, uint32_t dataSz) {
	// @brief	read from SRAM in Quad-Mode (Blocking)
	// @PAram	u32 addr: address
	// @oaram	u8* data: read buffer pointer
	// @PAram	u32 dataSz: # of data to be read
	// @return	u8 status: 0 = OK (no error)

	if (pData && dataSz) {
		OSPI_RegularCmdTypeDef cmd = {0};
		cmd.Instruction				= SRAM_CMD_READ;							// instruction byte
		cmd.InstructionSize			= HAL_OSPI_INSTRUCTION_8_BITS;				// size of the instruction

		cmd.Address					= addr;										// data address
		cmd.AddressSize				= HAL_OSPI_ADDRESS_24_BITS;					// size of the address (typ. 24 bit)

		cmd.NbData					= dataSz;									// number of data transfered with the command

		if(SRAM_quad) {
			cmd.InstructionMode			= HAL_OSPI_INSTRUCTION_4_LINES;				// mode of the instruction
			#ifndef SRAM_NOADDR
			cmd.AddressMode				= HAL_OSPI_ADDRESS_4_LINES;					// send an address?
			#endif
			cmd.DataMode				= HAL_OSPI_DATA_4_LINES;					// data mode: send data or just command
			cmd.DummyCycles        		= 0x2;										// number of dummy cycles before data phase
		} else {
			cmd.InstructionMode			= HAL_OSPI_INSTRUCTION_1_LINE;				// mode of the instruction
			#ifndef SRAM_NOADDR
			cmd.AddressMode				= HAL_OSPI_ADDRESS_1_LINE;					// send an address?
			#endif
			cmd.DataMode				= HAL_OSPI_DATA_1_LINE;						// data mode: send data or just command
		}

		HAL_StatusTypeDef status;
		status = HAL_OSPI_Command(hSramOSPI, &cmd, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
		if(HAL_OK != status) {
			return(1);
		}

		status = HAL_OSPI_Receive(hSramOSPI, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
		if (HAL_OK != status) {
			return(1);
		}
	}

	return(0);
}

 

 

No communication at all means: No Chip Select, No Clock, all data lines are idle in the Scope. The OSPI peripheral simply does nothing.

I have some experience with QSPI SRAM on an G4, but I am new to the OSPI Peripheral on the H7. Is there any major differences in the behavior of the QSPI functionality I am not aware of and therefore stumbling over? My approach was similar to that what I got successfully running on an G4, but I have absolutely no Idea why the H7 OSPI-Peripheral would simply do nothing at all, when I add an address phase!?

Any Help / input is appreciated! Thanks guys!

1 ACCEPTED SOLUTION

Accepted Solutions
CBerg
Senior

@KDJEM.1 

Nope, that was not yet the solution.

I tested only with address = 0 ... But as soon as I entered an address >113, the Peripheral did not start. As I am writing 16 byte (for testing) my "effective max. address was 112.

I tried to set the the address in the command struct to 0 first and set the Address-Register manually,

hOSPI->Instance->AR = addr;

after calling HAL_OSPI_Command(hSramOSPI, &cmd, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);

but that made no difference.

I first though the addresses had to be 4-byte aligned, because I was testing with address 0 and address 259, but that was not the case. If I replaced 259 by e.g. 35 it still worked.

I tried to __REV(the_address) but that did not work either, and it does not reflect the datasheet. A visual comparison of the bus in the scope also confirms, that the address must not be __REV() ..ed. They come out "un__REV()ed" MSB first, as required by the chip.

This "address barier" existed in SingleSPI Mode as well as in QuadSPI Mode.

This 128 Byte barrier somehow seemed to have to do with the device size in the OCTOSPI_DCR1 Register. There are 5 bits to encode the device size. My initial config was "7", but this was wrong. The SRAM has 256kByte, so I wrote 7 for (7+1) for kByte, but you have to enter the size in Bytes instead, so the right value would be 17:

2^(17 + 1) = 262.144 Bytes - at least I thought.

If I did so, the Peripheral was not started again when I tried to write to / write from the last 16 bytes of the chip. The "17+1" comes from the Manual, that writes the value for "Devicesize" should be set in a way that "2 ^[DEVSIZE + 1]" equals the number of bytes in the device.

This might be eventually a bit misleading. For my device the value needs to be 18, 2^18 = 262.144 Bytes, because I have a 256k SRAM.

With the correct settings (Device-Size = 18), I can now read and write from the first Byte of the SRAM to the last Byte of the SRAM and get the results I expected.

SCR176.PNG

I see an issue in the HAL Driver. It simply does not start the peripheral, when an address > the allowed device size is requested in the command struct. IMHO it should come back with an HAL_ERROR immediately, instead it does nothing until the timeout is over. Which leads you to debug the hardware instead of looking for the error in a wrong configuration.

 

 

 

View solution in original post

7 REPLIES 7
KDJEM.1
ST Employee

Hello @CBerg,

 

Which SRAM memory are you using?  Can you give the reference?

Could you please check the OCTOSPI configuration? May be table 8. in AN5050 can help you. 

Is the DQS enabled? 

Also, I recommend you to take a look at the errata sheet precisely section OCTOSPI and check whether there is an errata that applies to your case.

 

Thank you.

Kaouthar

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

CBerg
Senior

Hello @KDJEM.1 

thank you for your answer!

I am using an an ISSI IS62WVS2568FBLL Quad-SPI SRAM.

The Datasheet is here: https://www.lcsc.com/datasheet/lcsc_datasheet_2410121704_ISSI-Integrated-Silicon-Solution-IS62WVS2568FBLL-20NLI-TR_C2063954.pdf

My OSPI Config is like in the screenshot below:

O9uCYg41.png

I already went through the AN5050 and tried to configure the Peripheral according to table 8. This is where the refresh rate comes from - even if I have no idea, if that applies to my chip or not. I guess not ..

if "DQS" is "Delay Hold Quater Cycle", then it's disabled.

The errata describes the issue "the other way round":

b.png

it says it would not start, when NO adress phase is configured. I have the issue it will not start, when an address phase is configured, I can only start with NO adress phase ...

 

Note: I cross-posted this question on stack overflow. Here is the Link: https://stackoverflow.com/questions/79367484/stm32h7a3-qspi-ram-on-octospi-peripheral-issues-with-hal-functions

but no response so far ...

 

What I did not mention neither here nor on stack overflow is: the memory has a HOLD Pin (Data Line 3), which is controlled by the chip as long it is in the SPI mode. My workaround was to configure the corresponding pin on the H7A3 as GPIO and pull it low while working in SPI mode. As I can see the communication on the Scope I assume this little trick is working ... When you are reading the datasheet of the SRAM you might stumble over that. So this is the info, that I already addressed that potential troublemaker ...

 

Besides that: This is not a high prio problem. I made a test board with this SRAM and obviously it does not work as I wanted it to. The purpose of that board was (it's a shield for a Nucleo 144) to test some components. Looks like that this stuff is not working as intended, and that's also a valuable information ...

KDJEM.1
ST Employee

Hello @CBerg,

 

Thank you for this information. 

The DQS is the data strobe. The DQS signal can be used for data strobing during the read transactions when the device is toggling the DQS aligned with the data.

I recommend you to disable cache to avoid masking issue and to set all GPIOs in a very high-speed configuration. 

 

Thank you.

Kaouthar

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

CBerg
Senior

Hello @KDJEM.1 

thanks for you input.

Ah, Data Strobe. Yes, I read about that. But the device has no data strobe capabilities, it is a 8-pin SOIC-8 package with VSupp, Gnd, Clock, Chip Select and 4 Data Lines. In SPI Mode the 4th Data Line (D3) is used als "Hold" Signal - which I pulled down by configuring the D3 Line as GPIO. But in Quad Mode there is no pin left for Data Strobing.

I will give it a try to disable Caching and the MPU and inform you about the results

CBerg
Senior

I got it working - almost

in Single SPI Mode, as well as in Quad SPI Mode. This means the hardware is working.

Almost working because:

i used "alternate Bytes" instead of "address bytes" to send the address:

 

		if(SRAM_quad) {
			cmd.InstructionMode			= HAL_OSPI_INSTRUCTION_4_LINES;				// mode of the instruction
			#ifdef SRAM_NOADDR
			cmd.AlternateBytesMode		= HAL_OSPI_ALTERNATE_BYTES_4_LINES;
			#else
			cmd.AddressMode				= HAL_OSPI_ADDRESS_4_LINES;					// send an address?
			#endif
			cmd.DataMode				= HAL_OSPI_DATA_4_LINES;					// data mode: send data or just command
		} else {
			cmd.InstructionMode			= HAL_OSPI_INSTRUCTION_1_LINE;				// mode of the instruction
			#ifdef SRAM_NOADDR
			cmd.AlternateBytesMode		= HAL_OSPI_ALTERNATE_BYTES_1_LINE;
			#else
			cmd.AddressMode				= HAL_OSPI_ADDRESS_1_LINE;					// send an address?
			#endif
			cmd.DataMode				= HAL_OSPI_DATA_1_LINE;						// data mode: send data or just command
		}

 

when I do so, the OSPI Peripheral is started. I have a simple function to write 16 bytes and read them back into another buffer, to check if read/write is working. When I do so, I can see the bus activity on the Scope and I can see the data in the buffer . That's the proof the hardware and my PCB are working ...

BTW: one "trick" to get it running was to learn to read the datasheet ;) - the HOLD line of this chip is actually a HOLDn line and must be kept high to communicate with the chip. Until I read the datasheet again, I was pulling it low ...

The only issue now is, that the data in the response buffer are shifted by one byte. e.g. if I write

uint8_t txBuf[] = {1, 2, 3, 4, 5, 6, 7, 8}, the read back rxBuf[8] is {x, 1, 2, 3, 4, 5, ....}. The first byte is dropped, most probably because I use "alternate bytes", which I understand are some "extra bytes" for the command, that are skipped in the response.

So the big question is: is this a bug in the HAL driver or is this a bug in the H7A3? If it would be an issue in the HAL driver, eventually I would go into the efforts to write my own LL driver for that. The errata say something about similar behaviour - but "the other way round". But it's not clear to me, if the root cause for this errata is in the hardware or in the driver?

What I try next is to send a 32 bit command and stuff the address bytes into the "command word ..."

CBerg
Senior

UPDATE: I got it running

the bit shift was solved by (re-)inserting the 2 Dummy Cycles, I somehow must have removed somewhen during my tests

the second issue is solved, but I don't know exactly why. I assume the chip got somehow "confused" by a wrong command. When I changed my code for the reset function to send first the reset on 1 line, then on 4 and then on 1 again, I can be sure the chip is reset. When I do so, it works properly.

My assumption there might be a bug in the HAL Driver was wrong. The best assumption is now that there was a bug in my code I did not see, which "stalled" the chip, which again lead to a "stuck" peripheral, that did not respond and eventually did not release the data lines in to "high Z mode".

Working code - tested in Single SPI and QuadSPI Mode:

static uint8_t rOS_SRAM_read(uint32_t addr, uint8_t * pData, uint32_t dataSz) {
	// @brief	read from SRAM in Quad-Mode (Blocking)
	// @PAram	u32 addr: address
	// @oaram	u8* data: read buffer pointer
	// @PAram	u32 dataSz: # of data to be read
	// @return	u8 status: 0 = OK (no error)

	if (pData && dataSz) {
		OSPI_RegularCmdTypeDef  cmd = {0};
		cmd.Instruction				= SRAM_CMD_READ;							// instruction byte
		cmd.InstructionSize			= HAL_OSPI_INSTRUCTION_8_BITS;				// size of the instruction
		cmd.Address					= addr;
		cmd.AddressSize				= HAL_OSPI_ADDRESS_24_BITS;					// address size
		cmd.NbData					= dataSz;									// number of data transfered with the command
		if(SRAM_quad) {
			cmd.InstructionMode			= HAL_OSPI_INSTRUCTION_4_LINES;				// mode of the instruction
			cmd.AddressMode				= HAL_OSPI_ADDRESS_4_LINES;					// address mode: 4 lines
			cmd.DummyCycles				= 2;
			cmd.DataMode				= HAL_OSPI_DATA_4_LINES;					// data mode: send data or just command
		} else {
			cmd.InstructionMode			= HAL_OSPI_INSTRUCTION_1_LINE;				// mode of the instruction
			cmd.AddressMode				= HAL_OSPI_ADDRESS_1_LINE;					// address mode: 1 Line
			cmd.DataMode				= HAL_OSPI_DATA_1_LINE;						// data mode: send data or just command
		}

		HAL_StatusTypeDef status;
		status = HAL_OSPI_Command(hSramOSPI, &cmd, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
		if(HAL_OK != status) {
			return(1);
		}

		status = HAL_OSPI_Receive(hSramOSPI, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
		if (HAL_OK != status) {
			return(1);
		}
	}

	return(0);
}

and

static uint8_t rOS_SRAM_write(uint32_t addr, uint8_t * pData, uint32_t dataSz) {
	// @brief	write to PSRAM in Quad Mode (blocking)
	// @PAram	u32 addr: address
	// @oaram	u8* pData: pointer to data source buffer
	// @PAram	u32 dataSz: size of write buffer

	if (pData && dataSz) {
		OSPI_RegularCmdTypeDef cmd = {0};
		cmd.Instruction				= SRAM_CMD_WRITE;							// instruction byte
		cmd.InstructionSize			= HAL_OSPI_INSTRUCTION_8_BITS;				// size of the instruction
		cmd.Address					= addr;										// address
		cmd.AddressSize				= HAL_OSPI_ADDRESS_24_BITS;					// address size
		cmd.NbData					= dataSz;									// number of data transfered with the command
		if(SRAM_quad) {
			cmd.InstructionMode			= HAL_OSPI_INSTRUCTION_4_LINES;				// mode of the instruction
			cmd.AddressMode				= HAL_OSPI_ADDRESS_4_LINES;					// address mode: 4 lines
			cmd.DataMode				= HAL_OSPI_DATA_4_LINES;					// data mode: send data or just command
		} else {
			cmd.InstructionMode			= HAL_OSPI_INSTRUCTION_1_LINE;				// mode of the instruction
			cmd.AddressMode				= HAL_OSPI_ADDRESS_1_LINE;					// address mode: 1 Line
			cmd.DataMode				= HAL_OSPI_DATA_1_LINE;						// data mode: send data or just command
		}

		HAL_StatusTypeDef status;
		status = HAL_OSPI_Command(hSramOSPI, &cmd, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
		if(HAL_OK != status) {
			return(1);
		}

		status = HAL_OSPI_Transmit(hSramOSPI, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
		if (HAL_OK != status) {
			return(1);
		}
	}

	return(0);
}

 

CBerg
Senior

@KDJEM.1 

Nope, that was not yet the solution.

I tested only with address = 0 ... But as soon as I entered an address >113, the Peripheral did not start. As I am writing 16 byte (for testing) my "effective max. address was 112.

I tried to set the the address in the command struct to 0 first and set the Address-Register manually,

hOSPI->Instance->AR = addr;

after calling HAL_OSPI_Command(hSramOSPI, &cmd, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);

but that made no difference.

I first though the addresses had to be 4-byte aligned, because I was testing with address 0 and address 259, but that was not the case. If I replaced 259 by e.g. 35 it still worked.

I tried to __REV(the_address) but that did not work either, and it does not reflect the datasheet. A visual comparison of the bus in the scope also confirms, that the address must not be __REV() ..ed. They come out "un__REV()ed" MSB first, as required by the chip.

This "address barier" existed in SingleSPI Mode as well as in QuadSPI Mode.

This 128 Byte barrier somehow seemed to have to do with the device size in the OCTOSPI_DCR1 Register. There are 5 bits to encode the device size. My initial config was "7", but this was wrong. The SRAM has 256kByte, so I wrote 7 for (7+1) for kByte, but you have to enter the size in Bytes instead, so the right value would be 17:

2^(17 + 1) = 262.144 Bytes - at least I thought.

If I did so, the Peripheral was not started again when I tried to write to / write from the last 16 bytes of the chip. The "17+1" comes from the Manual, that writes the value for "Devicesize" should be set in a way that "2 ^[DEVSIZE + 1]" equals the number of bytes in the device.

This might be eventually a bit misleading. For my device the value needs to be 18, 2^18 = 262.144 Bytes, because I have a 256k SRAM.

With the correct settings (Device-Size = 18), I can now read and write from the first Byte of the SRAM to the last Byte of the SRAM and get the results I expected.

SCR176.PNG

I see an issue in the HAL Driver. It simply does not start the peripheral, when an address > the allowed device size is requested in the command struct. IMHO it should come back with an HAL_ERROR immediately, instead it does nothing until the timeout is over. Which leads you to debug the hardware instead of looking for the error in a wrong configuration.