cancel
Showing results for 
Search instead for 
Did you mean: 

How to program simple data to OCTOSPI external flash?

Southbranch
Senior II

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

1 ACCEPTED SOLUTION

Accepted Solutions

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();
	}
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

8 REPLIES 8

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 Venmo
Up vote any posts that you find helpful, it shows what's working..

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 Venmo
Up vote any posts that you find helpful, it shows what's working..

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();
	}
}

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();
	}
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Many thanks again!

I implemented all of your adjustments, but still no result..

Reading flash data is working though using the ReadCommand() function below which returns 0xFF on all memory locations. It also reflecs the same result inspection in memory-mapped -mode, assuming this being standard content in a none programmed area.

Then I tried the simplest thing I could figure out, reading the flash’s StatusReg which supposedly needs writing of a single command as below. But the data returned is still returns 0xFF:s.

It seems the problem is that all writing + reading are done in Read Mode i.e. flash memory space, see extract from documentation below. I just can’t figure out how to swap between the different address map modes..

Do you see anything more I might have missed?

0693W00000aJH3JQAW.png0693W00000aJH3OQAW.png 

void ReadStatusReg(uint8_t* data)
{
	WriteCommandWord(0x00000555, 0x0070);  // Status register read command
	ReadCommand(0x00000000, 2, data);      // Use any address to read the actual status register as 16-bit
}
 
void ReadCommand(uint32_t addr, uint32_t buf_size, uint8_t* buf)
{
	OSPI_HyperbusCmdTypeDef sCommand;
 
	// Memory command config
	sCommand.AddressSpace =HAL_OSPI_MEMORY_ADDRESS_SPACE;
	//sCommand.AddressSpace =HAL_OSPI_REGISTER_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();
	}
 
	if (HAL_OSPI_Receive(&hospi2, buf, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
}

Sorry don't have hardware here.

Might be something more fundamentally wrong.

You could try reading the JEDEC ID, see that work.

You could try doing the individual Word Write.

Perhaps I misunderstood the WBL address could be index into buffer, not address in device.​

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

I fully understand, you already put in an great effort to help out, THANKS! 😊

I'll keep posting any updates.