Skip to main content
Southbranch
Senior
March 17, 2023
Solved

How to program simple data to OCTOSPI external flash?

  • March 17, 2023
  • 2 replies
  • 4524 views

Hi!

I have a custom board with a STM32H725. The board has an external OCTOSPI flash memory from Infineon's S26KL/S26KS-series. I can read/write data back and fourth in memory-mapped-mode and now I want to be able to program persistent data using the indirect mode.

I am not sure I got the pointers right, but the prgramming sequence is given from Infineo's memory docmentation as below.

After the programming, I switch to memory-mapped-mode and use the memory debugger to read data at 0x70000000, but there is no data there...

0693W00000aJD6YQAW.png 

My implementation of above sequence:

char* Buffer = "Data to be programmed into flash";
uint32_t Size = 32;
uint32_t base_addr = 0x70000000;
uint32_t sector_addr = 0x00000000;
 
ProgramFlashWithBuffer(base_addr, sector_addr, Size, (uint8_t*)Buffer);
EnableMemMapped();
 
 
void ProgramFlashWithBuffer(uint32_t base_addr, uint32_t sector_addr, uint32_t buf_size, uint8_t* buffer)
{
	// Programming sequence for S26KL/S26KS
	// -------------------------------------
	WriteCommand(0x555, 1,(uint8_t*)0xAA); // Write unlock cycle 1
	WriteCommand(0x2AA, 1, (uint8_t*)0x55); // Write unlock cycle 2
	WriteCommand(sector_addr, 1, (uint8_t*)0x55); // Write buffer load command
	WriteCommand(sector_addr, buf_size-1, buffer); // Transfer the actual buffer (count -1)
	WriteCommand(sector_addr,1, (uint8_t*)0x29); // Finally, send write confirm command
}
 
void WriteCommand(uint32_t addr, uint32_t size, uint8_t* data)
{
	OSPI_HyperbusCmdTypeDef sCommand;
 
	// Memory command config
	sCommand.AddressSpace =HAL_OSPI_MEMORY_ADDRESS_SPACE;
	sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
	sCommand.DQSMode = HAL_OSPI_DQS_ENABLE;
	sCommand.NbData = size;
	sCommand.Address = addr;
 
	// Send command and data in indirect mode
	if (HAL_OSPI_HyperbusCmd(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
	if (HAL_OSPI_Transmit(&hospi2, (uint8_t*)&data, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
}

Please, I am really stuck here and any help would be highly appreciated

Thanks in advance

This topic has been closed for replies.
Best answer by Tesla DeLorean

I don't think you implement the pseudo-code / documentation correctly

Try

void ProgramFlashWithBuffer(uint32_t base_addr, uint32_t sector_addr, uint32_t buf_size, uint8_t* buffer)
{
 buf_size = ((buf_size + 1) & ~1); // Ensure byte count rounded to whole words
 
	// Programming sequence for S26KL/S26KS
	// -------------------------------------
	WriteCommandWord(0x555, 0x00AA); 	 // Write unlock cycle 1
	WriteCommandWord(0x2AA, 0x0055); 	 // Write unlock cycle 2
	
	// Could this really be correct, writing commands to
	// the same sectors address as we want to write the
	// actual payload data to?
 // That's how these NOR devices have classically worked
 // Might need to spin on status waiting for process to complete.
 // Area should have been erased
	WriteCommandWord(sector_addr, 0x0025); 	 // Write buffer load command
	WriteCommandWord(sector_addr, (buf_size / 2) - 1); // Write word count minus one
	WriteBuffer(sector_addr, buf_size, buffer); // Transfer the actual buffer
	WriteCommandWord(sector_addr, 0x0029); 	 // Finally, send write confirm command
}
 
void WriteCommandWord(uint32_t addr, uint16_t dataword)
{
	OSPI_HyperbusCmdTypeDef sCommand = {0}; // ensure cleared of stack junk
 
	// Memory command config
	sCommand.AddressSpace =HAL_OSPI_MEMORY_ADDRESS_SPACE;
	sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
	sCommand.DQSMode = HAL_OSPI_DQS_ENABLE;
	sCommand.NbData = sizeof(uint16_t);
	sCommand.Address = addr & 0x0FFFFFFF; // Mask in case passed STM32 memory address
 
	// Send command and data in indirect mode
	if (HAL_OSPI_HyperbusCmd(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
 
	// Address of the word passed by value
	if (HAL_OSPI_Transmit(&hospi2,(uint8_t*)&dataword, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
}
 
// Buffer/Size should be whole word multiple
 
void WriteBuffer(uint32_t addr, uint32_t buf_size, uint8_t* buffer)
{
	OSPI_HyperbusCmdTypeDef sCommand = {0}; // ensure cleared of stack junk
 
	// Memory command config
	sCommand.AddressSpace =HAL_OSPI_MEMORY_ADDRESS_SPACE;
	sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
	sCommand.DQSMode = HAL_OSPI_DQS_ENABLE;
	sCommand.NbData = buf_size & ~1; // Byte count, whole words 
	sCommand.Address = addr & 0x0FFFFFFF; // Mask in case passed STM32 memory address
 
	// Send command and data in indirect mode
	if (HAL_OSPI_HyperbusCmd(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
 
	// Transfer the buffer data
	if (HAL_OSPI_Transmit(&hospi2, buffer, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
}

2 replies

Tesla DeLorean
Guru
March 17, 2023

Also your casting is entirely wrong, you've got situations where you want to send a constant, and instead use cast an illegal/usuable address

WriteCommand(0x555, 1,(uint8_t*)0xAA);

if (HAL_OSPI_Transmit(&hospi2, (uint8_t*)&data, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Tesla DeLorean
Guru
March 17, 2023

f (HAL_OSPI_Transmit(&hospi2, (uint8_t*)&data, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

 This is already a pointer, lose the &

To pass a word, as a value, directly

void WriteCommandWord(uint32_t addr, uint16_t dataword) // passing by value
{
	OSPI_HyperbusCmdTypeDef sCommand;
 
	// Memory command config
	sCommand.AddressSpace =HAL_OSPI_MEMORY_ADDRESS_SPACE;
	sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
	sCommand.DQSMode = HAL_OSPI_DQS_ENABLE;
	sCommand.NbData = sizeof(uint16_t); // 2-byte / 16-bit words
	sCommand.Address = addr;
 
	// Send command and data in indirect mode
	if (HAL_OSPI_HyperbusCmd(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
	if (HAL_OSPI_Transmit(&hospi2, (uint8_t*)&dataword, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) // address of the word passed by value
	{
		Error_Handler();
	}
}

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Southbranch
Senior
March 18, 2023

Many, many thanks for picking this up!

I made changes from your suggestions and also added a third function WriteBuffer in order to send the payload data. But still no data shows up after I switch to memory-mapped mode.

Since we are in indirect memory mode I take it for granted we could only send data and commands to sector based addresses? But it makes me confused to send commands to the same address that we want to send the payload data to...

Please, do you see anything I have mixed up?

void ProgramFlashWithBuffer(uint32_t base_addr, uint32_t sector_addr, uint32_t buf_size, uint8_t* buffer)
{
	// Programming sequence for S26KL/S26KS
	// -------------------------------------
	WriteCommandWord(0x555, 0x00AA); 	 // Write unlock cycle 1
	WriteCommandWord(0x2AA, 0x0055); 	 // Write unlock cycle 2
	
	// Could this really be correct, writing commands to
	// the same sectors address as we want to write the
	// actual payload data to?
	WriteCommandWord(sector_addr, 0x0025); 	 // Write buffer load command
	WriteBuffer(sector_addr, buf_size-1, buffer); // Transfer the actual buffer (count -1)
	WriteCommandWord(sector_addr, 0x0029); 	 // Finally, send write confirm command
}
 
void WriteCommandWord(uint32_t addr, uint16_t dataword)
{
	OSPI_HyperbusCmdTypeDef sCommand;
 
	// Memory command config
	sCommand.AddressSpace =HAL_OSPI_MEMORY_ADDRESS_SPACE;
	sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
	sCommand.DQSMode = HAL_OSPI_DQS_ENABLE;
	sCommand.NbData = sizeof(uint16_t);
	sCommand.Address = addr;
 
	// Send command and data in indirect mode
	if (HAL_OSPI_HyperbusCmd(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
 
	// Address of the word passed by value
	if (HAL_OSPI_Transmit(&hospi2,(uint8_t*)&dataword, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
}
 
void WriteBuffer(uint32_t addr, uint32_t buf_size, uint8_t* buffer)
{
	OSPI_HyperbusCmdTypeDef sCommand;
 
	// Memory command config
	sCommand.AddressSpace =HAL_OSPI_MEMORY_ADDRESS_SPACE;
	sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
	sCommand.DQSMode = HAL_OSPI_DQS_ENABLE;
	sCommand.NbData = buf_size;
	sCommand.Address = addr;
 
	// Send command and data in indirect mode
	if (HAL_OSPI_HyperbusCmd(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
 
	// Transfer the buffer data
	if (HAL_OSPI_Transmit(&hospi2, buffer, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
}