2023-03-17 05:37 AM
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...
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
Solved! Go to Solution.
2023-03-18 05:51 AM
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();
}
}
2023-03-17 07:07 AM
I think it's writing words, not bytes and that second 0x0055 was supposed to be 0x0025, and closes with a 0x0029
Not sure there's going to be a lot of specific experience on the forum.
Related
2023-03-17 07:11 AM
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)
2023-03-17 09:14 AM
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();
}
}
2023-03-18 03:11 AM
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();
}
}
2023-03-18 05:51 AM
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();
}
}
2023-03-19 04:49 AM
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?
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();
}
}
2023-03-19 05:05 AM
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.
2023-03-19 08:49 AM
I fully understand, you already put in an great effort to help out, THANKS! :smiling_face_with_smiling_eyes:
I'll keep posting any updates.