cancel
Showing results for 
Search instead for 
Did you mean: 

Looking for sample code for Hyperflash erase/programming with OctoSPI

GS1
Senior III

We started a project with Hyperflash and Hyperram (each on a separate OctoSPI port) with STM32H7A3.

I will need to flash the Hyperflash (S26KL512) via

1) Keil ARM Programmer (ULINK Pro) <- Needs a programming algorithm

2) By my own software parts for flashing firmware updates.

Is there meanwhile a sample project which I can refer to for more details?

Any help is very much appreciated.

BR GS

21 REPLIES 21

I fully understand.

I will give it another try within the next weeks. If I fail again (likely..), I will consider sending you my hardware in case you would be interested to help out. Reimbursement of course.

Hi Southbranch,

I got the HyperFlash running:

  • Reading Status,
  • Reading ID
  • Flashing Data in Hyper-Mode
  • Erasing Chip / Sectors
  • Switching to Memory Mapped Mode and back to Hyper Mode.

Now I will adapt the flash downloader for Keil via ULINK Pro ...

The needed fix was: shifting the Address by 1 to the left!

I use the Infineon LLDriver and fixed the following definition:

In lld_target_specific.h:

#define LLD_CONFIGURATION_X8X16_AS_X16  /* no-interleaving, a single x8/x16 device in x16 mode */

#define USER_SPECIFIC_CMD

In S26KSxxxS_S26KLxxxS.h:

     #ifdef USER_SPECIFIC_CMD

       // ########### Shift Offset by 1 to the left !!! ################

        #define FLASH_WR(b,o,d) FlashWriteUserCmd( b,(o<<1),d )

       #define FLASH_RD(b,o) FlashReadUserCmd(b,(o<<1))

FlashWriteUserCmd / FlashReadUserCmd:

void FlashWriteUserCmd(FLASHDATA* addr, ADDRESS offset, FLASHDATA data)

{

   OSPI_HyperbusCmdTypeDef sCommand = { 0 };// ensure cleared of stack junk

   ADDRESS FullAddress;

   uint8_t data_8[2];

   data_8[0] = data & 0xFF;         // Low Byte

   data_8[1] = (data >> 😎 & 0xFF;   // High Byte

   /* OctoSPI Hyperbus command configuration */

   sCommand.AddressSpace = HAL_OSPI_MEMORY_ADDRESS_SPACE;

   sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;

   sCommand.Address = offset;

   sCommand.DQSMode = HAL_OSPI_DQS_ENABLE;    

   sCommand.NbData = 2U;

   halErr = HAL_OSPI_HyperbusCmd(&HandleOspiFlash, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);

   if (halErr != HAL_OK)

   {

      MyErrorHandler(E_SPI_TX, halErr);

   }

   /* Transmission of the data */

   halErr = HAL_OSPI_Transmit(&HandleOspiFlash, (uint8_t*)&(data_8[0]), HAL_OSPI_TIMEOUT_DEFAULT_VALUE);

   if (halErr != HAL_OK)

   {

      MyErrorHandler(E_SPI_TX, halErr);

   }

}

FLASHDATA FlashReadUserCmd(FLASHDATA* addr, ADDRESS offset)

{

   FLASHDATA data = 0x5555;

   OSPI_HyperbusCmdTypeDef sCommand;

   /* Initialize the read command */

   sCommand.AddressSpace = HAL_OSPI_MEMORY_ADDRESS_SPACE;

   sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;

   sCommand.Address = offset;

   sCommand.DQSMode = HAL_OSPI_DQS_ENABLE;

   sCommand.NbData = 2U;

         /* Configure the command */

   halErr = HAL_OSPI_HyperbusCmd(&HandleOspiFlash, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);

   if (halErr != HAL_OK)

   {

       MyErrorHandler(E_SPI_TX, halErr);

      return data;

   }

   /* Reception of the data */

   halErr = HAL_OSPI_Receive(&HandleOspiFlash, (uint8_t*)&data, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);

   if (halErr != HAL_OK)

   {

       MyErrorHandler(E_SPI_RX, halErr);

    }

   return data;

}

octospi.c

 hospi1.Instance = OCTOSPI1;

 hospi1.Init.FifoThreshold = 1;

 hospi1.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;

 hospi1.Init.MemoryType = HAL_OSPI_MEMTYPE_HYPERBUS;

 hospi1.Init.DeviceSize = 26;

 hospi1.Init.ChipSelectHighTime = 1;

 hospi1.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE;

 hospi1.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0;

 hospi1.Init.WrapSize = HAL_OSPI_WRAP_NOT_SUPPORTED;

 hospi1.Init.ClockPrescaler = 10; // currently only 1.4 MHz active for testing

 hospi1.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_NONE;

 hospi1.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_ENABLE;

 hospi1.Init.ChipSelectBoundary = 0;

 hospi1.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED;//HAL_OSPI_DELAY_BLOCK_USED;//

 hospi1.Init.MaxTran = 0;

 hospi1.Init.Refresh = 0;

 if (HAL_OSPI_Init(&hospi1) != HAL_OK)

 {

   Error_Handler();

 }

 sOspiManagerCfg.ClkPort = 1;

 sOspiManagerCfg.DQSPort = 1;

 sOspiManagerCfg.NCSPort = 1;

 sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_1_LOW;

 sOspiManagerCfg.IOHighPort = HAL_OSPIM_IOPORT_1_HIGH;

 if (HAL_OSPIM_Config(&hospi1, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

 {

   Error_Handler();

 }

 sHyperBusCfg.RWRecoveryTime = 3;

 sHyperBusCfg.AccessTime = 7;

 sHyperBusCfg.WriteZeroLatency = HAL_OSPI_NO_LATENCY_ON_WRITE;

 sHyperBusCfg.LatencyMode = HAL_OSPI_VARIABLE_LATENCY;

 if (HAL_OSPI_HyperbusCfg(&hospi1, &sHyperBusCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

 {

   Error_Handler();

 }

How about you? Is yours working as needed? I hope my solution will help you to get yours working too!

BR GS

GS1
Senior III

Hello Southbranch,

In addition to my previous post I detected a wrong handling for the shifting of the adress:

Please take a close look to where the shift is done, because the target adress is not supposed to be shifted when it is used for the programming or read of data.

I therefore implemented a second declaration without the shift as seen below:

In S26KSxxxS_S26KLxxxS.h:

     #ifdef USER_SPECIFIC_CMD

       // ########### Shift Offset by 1 to the left !!! ################

        #define FLASH_WR(b,o,d) FlashWriteUserCmd( b,(o<<1),d )

        #define FLASH_WR_TO_TARGET_ADDRESS(b,o,d) FlashWriteUserCmd( b,(o),d )

       #define FLASH_RD(b,o) FlashReadUserCmd(b,(o<<1))

        #define FLASH_RD_FROM_TARGET_ADDRESS(b,o) FlashReadUserCmd(b,(o))

The FLASH_WR_TO_TARGET_ADDRESS and FLASH_RD_FROM_TARGET_ADDRESS  macros have to be used in lld_WriteBufferProgramOp and lld_ReadOp for the commands for write /read of the data.

Otherwise data is written to / read from the wrong address !

BR GS

Please see my additional post from a minute ago concerning the shifting of the address.

Thanks for posting this!

It seems your function shifts the offset adress and not the base adress, right?

As a concrete example, could you please post the function calls you are doing in order to read the ID/CFI? It would be very helpful if you could include the exact inputs in terms of base adress, offset address and commands.

Many thanks in advacne

Yes, only the offset has to be shifted.

Simply download the cypress LL driver for NOR Flash (Infineon-Low_Level_Driver_for_NOR_Flash-Software-v01_00-EN.zip, can be downloaded from Infineon!). This includes all necessary functions and declarations for calls to write and read.

Then exchange the above mentioned FLASH_WR / RD implementations.

Here an example for status read:

FLASHDATA ReadStatus(void)

{

   FLASHDATA nStatus;

   nStatus = lld_StatusGetReg(HYPER_FLASH_BASE_PTR,0);

return Status;

}

Extract from the LL Driver:

/******************************************************************************

*

* lld_StatusRegReadCmd - Status register read command

*

* This function sends the status register read command before actually reading it.

*

* RETURNS: void

*

*/

void lld_StatusRegReadCmd

(

FLASHDATA * base_addr   /* device base address in system */

)

{        

 FLASH_WR(base_addr, LLD_UNLOCK_ADDR1, NOR_STATUS_REG_READ_CMD);

}

/******************************************************************************

*   

* lld_StatusGetReg - Gets the flash status register bits

*

*

* RETURNS: FLASHDATA

*

*/

FLASHDATA lld_StatusGetReg

(

FLASHDATA * base_addr,     /* device base address in system */

ADDRESS     offset         /* address offset from base address */

)

{

 FLASHDATA status_reg = 0xFFFF;

 lld_StatusRegReadCmd( base_addr );   /* Issue status register read command */

 status_reg = FLASH_RD( base_addr, offset );    /* read the status register */

 return status_reg;

}

I think you have to dig into the driver by yourself and understand how it works and then implement what you need.

BR GS

Thanks I, yes I have that driver.

But I suspect I have mixed up the base adress with the offset somehow.

So when you call the function FLASHDATA lld_StatusGetReg - are you using base adress 0x90000000 (OCSPI1) and offset adress 0x00000000?

Thanks, yes have the driver.

But I suspect I have been mixing up the base address with offset somehow..

For instance, when you read the StatusReg are you then using thease params?

Base adress: 0x90000000

Offset: 0x555 (shifted 1 bit left)

Command: 0x70 (written as a byte and not a word)

Or is it this?

Base adress: 0x90000000 + 0x555

Offset: 0x00000000

Command: 0x70

Thanks

Hi GS@S,

I am using the same functions for read/write as you are but I can only read 0xFF:s when trying to read e.g. StatusReg.

For reading StatusReg I have tried passing in combinations of params:

Addr: 0x00000000

Offset: 0x555

CMD: 0x70 (or 0x0070)

Addr: 0x00000000 + 0x555

Offset: 0x0;

CMD: 0x70 (or 0x0070)

..but the reault is the same when, i.e reading (0xFF:s).

-You don't seem to use the addr param at all in your functions?

-Is there any chance you could provide me with an example of what params you are using in the function calls when reading StatusReg or ID?

Many thanks in advance

GS1
Senior III

Hi,

call to Addr. 0, Offset 0x555 and data 0x0070 is correct. If you still see 0xFF then there is some other issue.

But the 0x555 has to be shifted as recommended in my previous post.

See:

       #define FLASH_WR(b,o,d) FlashWriteUserCmd( b,(o<<1),d )

       #define FLASH_RD(b,o) FlashReadUserCmd(b,(o<<1))

Alternatively you can try to use without shifting:

#define LLD_UNLOCK_ADDR1  0x00000AAA

#define LLD_UNLOCK_ADDR2  0x00000554

And I urgently recommend: use a logic analyzer to see what is actually sent to the bus.

I am also still working on the programming part, because the buffer write mode is not working as needed. Programming data with 1 word at a time works, but needs more than 3 hours to program 32 MByte at 70 MHz clock. This is not what I accept when debugging of software is needed...

But there is two other traps:

1)

When accessing the target address, shifting is not to be used.

The driver needs to be adapted for FLASH_WR accordingly, when reading/writing to the target addresses.

        #define FLASH_WR_TO_TARGET_ADDRESS(b,o,d) FlashWriteUserCmd( b,(o),d )

        #define FLASH_RD_FROM_TARGET_ADDRESS(b,o) FlashReadUserCmd(b,(o))

2)

In the Infinion file the SA_OFFSET_MASK is set to ((FLASHDATA)0xFFFE0000), which is wrong. This ends up in programming only up to adress 0x20000. Therefore the variable should be ADDRESS like this:

#define SA_OFFSET_MASK   ((ADDRESS)0xFFFE0000)  /* mask off the offset */

BR GS