cancel
Showing results for 
Search instead for 
Did you mean: 

Setting up HyperRAM S70KL1282 with STM32H735 issues

MartinDQ
Associate III

Hi,

I'm trying to setup this new RAM chips on STM32H735 in OSPI/HyperRAM mode. The HW connection is the same as on ST STM32H735 devkit. I found a driver for similar chip S70KL1281 but there are some differences, e.g. in latencies, but generally S70KL1282 is faster. The used driver file identification from header:

******************************************************************************
* @file s70kl1281.c
* @modify MCD Application Team
* @brief This file provides the S70KL1281 OSPI drivers.

...

* Copyright (c) 2020 STMicroelectronics.
******************************************************************************

I configured the Hyperbus in STM32CubeMX but there are no hints how to setup all the options for this memory. So after some messing and trial-error I ended with this partially working init code:

 

 

static void MX_OCTOSPI2_Init(void) { OSPIM_CfgTypeDef sOspiManagerCfg = {0}; OSPI_HyperbusCfgTypeDef sHyperBusCfg = {0}; /* OCTOSPI2 parameter configuration*/ hospi2.Instance = OCTOSPI2; hospi2.Init.FifoThreshold = 1; hospi2.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE; hospi2.Init.MemoryType = HAL_OSPI_MEMTYPE_HYPERBUS; hospi2.Init.DeviceSize = 24; hospi2.Init.ChipSelectHighTime = 1; hospi2.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE; hospi2.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0; hospi2.Init.WrapSize = HAL_OSPI_WRAP_NOT_SUPPORTED; hospi2.Init.ClockPrescaler = 2; // for testing use prescaler 2 at 133MHz, prescaler 1 gets garbage hospi2.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_NONE; hospi2.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_ENABLE; hospi2.Init.ChipSelectBoundary = 0; hospi2.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_USED; hospi2.Init.MaxTran = 0; hospi2.Init.Refresh = 500; if (HAL_OSPI_Init(&hospi2) != HAL_OK) { Error_Handler(); } sOspiManagerCfg.ClkPort = 2; sOspiManagerCfg.DQSPort = 2; sOspiManagerCfg.NCSPort = 2; sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_2_LOW; sOspiManagerCfg.IOHighPort = HAL_OSPIM_IOPORT_2_HIGH; if (HAL_OSPIM_Config(&hospi2, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } sHyperBusCfg.RWRecoveryTime = 3; sHyperBusCfg.AccessTime = 7; sHyperBusCfg.WriteZeroLatency = HAL_OSPI_NO_LATENCY_ON_WRITE; // someone suggested HAL_OSPI_LATENCY_ON_WRITE but doesn't have effect sHyperBusCfg.LatencyMode = HAL_OSPI_FIXED_LATENCY; if (HAL_OSPI_HyperbusCfg(&hospi2, &sHyperBusCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } }
View more

 

 

First time I had a problem that reading from memory was unrealiable and I sometimes getting a different results on every run. Enabling the magic option hospi2.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_USED; solved it but still not at the full clock speed I configured - I have both OSPI clocked at 133MHz. The FlashROM at OSPI1 works fine at 133MHz but for this HyperRAM I have to set prescaler 2. Then I got some consistent result.

But there's another problem that test data pattern I wrote into memory are readed by 8 Bytes shifted further than it should be. Currently for testing I don't use mapping yet but I use driver functions S70KL1281_Write and S70KL1281_Read. A simple piece of code for test write and readbeck:

 

 

{ uint8_t buff[64]={0}; int i; buff[0]=0xab; buff[1]=0xcd; buff[2]=0xef; buff[3]=0xaa; if (S70KL1281_Write(&XRAM, buff, 0, 16)!=S70KL1281_OK) printf("Failed to write to HyperRAM\n"); for (i=0; i<32; i++) printf("%02X ", buff[i]); printf("\n"); if (S70KL1281_Read(&XRAM, buff, 0, 32)!=S70KL1281_OK) printf("Failed to read from HyperRAM\n"); for (i=0; i<32; i++) printf("%02X ", buff[i]); printf("\n"); if (S70KL1281_Read(&XRAM, buff, 0, 32)!=S70KL1281_OK) printf("Failed to read from HyperRAM\n"); for (i=0; i<32; i++) printf("%02X ", buff[i]); printf("\n"); }

 

 

The memory address is 0 but I get this:

Ext. OctoSPI HyperRAM ID: 0C81 0001
Manufacturer: Infineon, HyperRAM 2.0, rowbits: 13, colbits: 9
AB CD EF AA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
57 47 57 5D D5 D7 8C 15 AB CD EF AA 00 00 00 00 00 00 00 00 00 00 00 00 D5 D5 57 5F D5 D5 5F 75
57 47 57 5D D5 D7 8C 15 AB CD EF AA 00 00 00 00 00 00 00 00 00 00 00 00 D5 D5 57 5F D5 D5 5F 75

There's some garbage in first 8 Bytes (57 47 57 5D D5 D7 CC 15 - uninitialized memory?) followed by correct pattern AB CD EF AA and trailing zeros from buffer

22 REPLIES 22

fyi, if any issue to source 128Mb OPI 3V BGA24 due to EOL, you can get APS12808L-3OBM-BA (also tested on STM32H72x/3x Disco, file attached)

Alex

Datasheet : http://www.apmemory.com/wp-content/uploads/APS12808L-3OBM-BA.pdf

Proto: https://www.mouser.com/ProductDetail/AP-Memory/APS12808L-3OBM-BA?qs=IS%252B4QmGtzzrXcGkbuYahqw%3D%3D

 

LCE
Principal II

I got my custom PCB today, including H733 and S70KL1282.

At least the HyperRam worked instantly. 

I check at power up by completely writing the RAM with i = 0, i++, then reading it back. 
I know this test is not perfect, but on my test boards until now, when this test was working, so did the audio / SAI buffers I used in HyperRAM.

I think the only change compared to S70KL1281 was setting the latency to 7.

See init below.

 

/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* OCTOSPIx basic init function * for octal HyperBus / HyperRAM * Infineon S70KL1281 / S70KL1282 * in memory-mapped mode * linear burst read & write => no page wrap (only at end of memory) * input clock is 1/2 HCLK (200 MHz) -> prescaler /2 */ uint8_t OspiHypRam_Init(void) { uint8_t u8RetVal = 0; /* use pointer to simplify OSPI 1 / 2 switching */ #if OSPI_CUSTOM_RAM_OSPI1 // custom: OSPI 1 HyperRAM; OSPI 2 Quad Flash pOspiHypRam = OCTOSPI1; #else // H735D: OSPI 1 Oct Flash; OSPI 2 HyperRAM pOspiHypRam = OCTOSPI2; #endif /* OSPI_CUSTOM_RAM_OSPI1 */ hOspiHypRam.Instance = pOspiHypRam; /* clock & GPIO initialization */ OspiHypRamGpioDmaInit(); /* start OFF */ pOspiHypRam->CR = 0; /* DEVICE configuration registers * DCR1 .. DCR4 */ /* DCR1: * MTYP = 100 Hyperbus memory mode * DEVSIZE * CHST * DLYBYP = 0 delay block is used * FRCK = 0 no free running clock * CKMODE = 0 clock low when idle */ pOspiHypRam->DCR1 = OCTOSPI_DCR1_MTYP_2 | ((OSPI_HYPERRAM_SIZE - 1) << OCTOSPI_DCR1_DEVSIZE_Pos) | ((OSPI_HYPERRAM_NCS_HITIME - 1) << OCTOSPI_DCR1_CSHT_Pos); /* DCR2: * WRAPSIZE = 0 wrapped read OFF * PRESCALER = 1 divide by 2 -> 100 MHz = max at 3.3V */ pOspiHypRam->DCR2 = (OSPI_HYPERRAM_WRAP_ZERO << OCTOSPI_DCR2_WRAPSIZE_Pos) | ((OSPI_HYPERRAM_CLK_DIV - 1) << OCTOSPI_DCR2_PRESCALER_Pos); /* DCR3: * CSBOUND = 23 set to 2^n memory size * MAXTRAN = 0 unused */ pOspiHypRam->DCR3 = (OSPI_HYPERRAM_CSBOUND << OCTOSPI_DCR3_CSBOUND_Pos); /* DCR4: * REFRESH = 400 NCS must be released for PSRAM for internal refresh */ pOspiHypRam->DCR4 = OSPI_HYPERRAM_REFRESH; /* CR: control register * no polling * no interrupts * FMODE = 0 indirect mode, set to memory-mapped mode later * FTTHRES = 4 FIFO threshold * FSEL = 0 nc in octal mode * TCEN = 0 no timeout counter * DMAEN = 0 no DMA * ABORT = 0 no ABORT request * EN = 0 ENable set later */ pOspiHypRam->CR = ((OSPI_HYPERRAM_FTHRES - 1) << OCTOSPI_CR_FTHRES_Pos); /* TCR: timing config * SSHIFT = 0 no read sample shifting * DHQC = 1 delay hold quarter cycle ON * DCYC = 0 dummy cycles between readd addr & data */ pOspiHypRam->TCR = OCTOSPI_TCR_DHQC | (OSPI_HYPERRAM_DCYC << OCTOSPI_TCR_DCYC_Pos); /* Hyperbus configuration * memory-mapped mode configuration * CR, DCR1, CCR, WCCR, DLR, AR */ /* HLCR: HyperBus latency configuration register * TRWR[7:0] = x read write recovery time * TACC[7:0] = y access time * WZL = 0 latency on write access * LM = 1 fixed latency */ pOspiHypRam->HLCR = (OSPI_HYPERRAM_RW_REC_TIME << OCTOSPI_HLCR_TRWR_Pos) | (OSPI_HYPERRAM_LATENCY << OCTOSPI_HLCR_TACC_Pos) | OCTOSPI_HLCR_LM; /* CR: clear FMODE -> exit MM for now */ pOspiHypRam->CR &= ~OCTOSPI_CR_FMODE; /* DCR1: Hyperbus from register access to memory */ pOspiHypRam->DCR1 &= ~OCTOSPI_DCR1_MTYP_0; /* CCR & WCCR: * DQS signal enabled (used as RWDS) * DTR mode enabled on address and data * address and data on 8 lines */ /* READ: CCR */ pOspiHypRam->CCR = OCTOSPI_CCR_DQSE | OCTOSPI_CCR_DDTR | OCTOSPI_CCR_DMODE_2 | OCTOSPI_CCR_ADSIZE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADMODE_2; /* WRITE: WCCR */ pOspiHypRam->WCCR = OCTOSPI_CCR_DQSE | OCTOSPI_WCCR_DDTR | OCTOSPI_WCCR_DMODE_2 | OCTOSPI_WCCR_ADSIZE | OCTOSPI_WCCR_ADDTR | OCTOSPI_WCCR_ADMODE_2; /* DLR: data length = 1 byte */ pOspiHypRam->DLR = 0; /* AR: address reset */ pOspiHypRam->AR = 0; /* update state */ hOspiHypRam.State = HAL_OSPI_STATE_CMD_CFG; /* LPTR: lo-power timeout reset */ pOspiHypRam->LPTR = 0; /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* HW IO MUX setup */ /* MUX OCTOSPIM->PCR[n] */ pOspiHypRam->CR &= ~OCTOSPI_CR_EN; /* NO multiplexed mode */ OCTOSPIM->CR = 0; #if OSPI_CUSTOM_RAM_OSPI1 // custom: OSPI 1 HyperRAM; OSPI 2 Quad Flash /* PORT 1: * select signals & enable * hi port 1 4..7: OCTOSPIM_PCR_IOHsrc=01 + IOHEN * lo port 1 0..3: OCTOSPIM_PCR_IOLsrc=00 + IOLEN * NCS 1: NCSsrc=0 + NCSEN * DQS 1: DQSsrc=0 + DQSEN * CLK 1: CLKsrc=0 + CLKEN */ OCTOSPIM->PCR[0] = ( OCTOSPIM_PCR_IOHSRC_0 | OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOLEN | OCTOSPIM_PCR_NCSEN | OCTOSPIM_PCR_DQSEN | OCTOSPIM_PCR_CLKEN ); /* DELAY block */ /* disable the output clock and enable the access to the phase selection SEL[3:0] */ DLYB_OCTOSPI1->CR = DLYB_CR_SEN; /* set delay */ DLYB_OCTOSPI1->CFGR = (0 & DLYB_CFGR_SEL_Msk); /* disable the access to the phase selection, enable output */ DLYB_OCTOSPI1->CR = DLYB_CR_DEN; #else // H735-DK: OSPI 1 Oct Flash; OSPI 2 HyperRAM /* PORT 2: * select signals & enable * hi port 2 4..7 * lo port 2 0..3 * NCS 2 * DQS 2 * clock 2 */ OCTOSPIM->PCR[1] = ( OCTOSPIM_PCR_IOHSRC_1 | OCTOSPIM_PCR_IOHSRC_0 | OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOLSRC_1 | OCTOSPIM_PCR_IOLEN | OCTOSPIM_PCR_NCSSRC | OCTOSPIM_PCR_NCSEN | OCTOSPIM_PCR_DQSSRC | OCTOSPIM_PCR_DQSEN | OCTOSPIM_PCR_CLKSRC | OCTOSPIM_PCR_CLKEN ); /* DELAY block */ /* disable the output clock and enable the access to the phase selection SEL[3:0] */ DLYB_OCTOSPI2->CR = DLYB_CR_SEN; /* set delay */ DLYB_OCTOSPI2->CFGR = (0 & DLYB_CFGR_SEL_Msk); /* disable the access to the phase selection, enable output */ DLYB_OCTOSPI2->CR = DLYB_CR_DEN; #endif /* OSPI_CUSTOM_RAM_OSPI1 */ /* enable in peripheral -> clear bypass */ pOspiHypRam->DCR1 &= ~OCTOSPI_DCR1_DLYBYP; /* clear all status flags */ pOspiHypRam->FCR = 0xFFFFFFFF; /* CR: memory-mapped, no timeout */ pOspiHypRam->CR &= ~OCTOSPI_CR_TCEN; pOspiHypRam->CR |= OCTOSPI_CR_FMODE; /* CR: enable peripheral */ pOspiHypRam->CR |= OCTOSPI_CR_EN; /* set state (for DMA & HAL stuff) */ hOspiHypRam.State = HAL_OSPI_STATE_BUSY_MEM_MAPPED; return u8RetVal; } /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* basic GPIO & DMA init */ void OspiHypRamGpioDmaInit(void) { GPIO_InitTypeDef GPIO_InitStruct = { 0 }; #if OSPI_CUSTOM_RAM_OSPI1 // custom: OSPI 1 HyperRAM; OSPI 2 Quad Flash /* OCTOSPI1 clock enable */ if( 0 == (RCC->AHB3ENR & RCC_AHB3ENR_IOMNGREN) ) __HAL_RCC_OCTOSPIM_CLK_ENABLE(); if( 0 == (RCC->AHB3ENR & RCC_AHB3ENR_OSPI1EN) ) __HAL_RCC_OSPI1_CLK_ENABLE(); /* reset & release */ __HAL_RCC_OSPI1_FORCE_RESET(); __HAL_RCC_OSPI1_RELEASE_RESET(); #else // H735-DK: OSPI 1 Oct Flash; OSPI 2 HyperRAM /* OCTOSPI2 clock enable */ if( 0 == (RCC->AHB3ENR & RCC_AHB3ENR_IOMNGREN) ) __HAL_RCC_OCTOSPIM_CLK_ENABLE(); if( 0 == (RCC->AHB3ENR & RCC_AHB3ENR_OSPI2EN) ) __HAL_RCC_OSPI2_CLK_ENABLE(); /* reset */ __HAL_RCC_OSPI2_FORCE_RESET(); __HAL_RCC_OSPI2_RELEASE_RESET(); #endif /* OSPI_CUSTOM_RAM_OSPI1 */ /* ATTENTION: very different ALTERNATE function numbers! custom: HyperRAM OCTOSPI 1 GPIO Configuration PA3 ------> OCTOSPIM_P1_CLK PB2 ------> OCTOSPIM_P1_DQS PE11 ------> OCTOSPIM_P1_NCS PB1 ------> OCTOSPIM_P1_IO0 PB0 ------> OCTOSPIM_P1_IO1 PB13 ------> OCTOSPIM_P1_IO2 PA6 ------> OCTOSPIM_P1_IO3 PE7 ------> OCTOSPIM_P1_IO4 PE8 ------> OCTOSPIM_P1_IO5 PE9 ------> OCTOSPIM_P1_IO6 PE10 ------> OCTOSPIM_P1_IO7 H735-DK: HyperRAM OCTOSPI 2 GPIO Configuration PF4 ------> OCTOSPIM_P2_CLK PF12 ------> OCTOSPIM_P2_DQS PG12 ------> OCTOSPIM_P2_NCS PF0 ------> OCTOSPIM_P2_IO0 PF1 ------> OCTOSPIM_P2_IO1 PF2 ------> OCTOSPIM_P2_IO2 PF3 ------> OCTOSPIM_P2_IO3 PG0 ------> OCTOSPIM_P2_IO4 PG1 ------> OCTOSPIM_P2_IO5 PG10 ------> OCTOSPIM_P2_IO6 PG11 ------> OCTOSPIM_P2_IO7 */ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* control signals */ GPIO_InitStruct.Pin = OSPIRAM_CLK_Pin; GPIO_InitStruct.Alternate = OSPIRAM_CLK_AF; HAL_GPIO_Init(OSPIRAM_CLK_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = OSPIRAM_DQS_Pin; GPIO_InitStruct.Alternate = OSPIRAM_DQS_AF; HAL_GPIO_Init(OSPIRAM_DQS_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = OSPIRAM_NCS_Pin; GPIO_InitStruct.Alternate = OSPIRAM_NCS_AF; HAL_GPIO_Init(OSPIRAM_NCS_GPIO_Port, &GPIO_InitStruct); /* data IOs */ GPIO_InitStruct.Pin = OSPIRAM_IO0_Pin; GPIO_InitStruct.Alternate = OSPIRAM_IO0_AF; HAL_GPIO_Init(OSPIRAM_IO0_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = OSPIRAM_IO1_Pin; GPIO_InitStruct.Alternate = OSPIRAM_IO1_AF; HAL_GPIO_Init(OSPIRAM_IO1_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = OSPIRAM_IO2_Pin; GPIO_InitStruct.Alternate = OSPIRAM_IO2_AF; HAL_GPIO_Init(OSPIRAM_IO2_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = OSPIRAM_IO3_Pin; GPIO_InitStruct.Alternate = OSPIRAM_IO3_AF; HAL_GPIO_Init(OSPIRAM_IO3_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = OSPIRAM_IO4_Pin; GPIO_InitStruct.Alternate = OSPIRAM_IO4_AF; HAL_GPIO_Init(OSPIRAM_IO4_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = OSPIRAM_IO5_Pin; GPIO_InitStruct.Alternate = OSPIRAM_IO5_AF; HAL_GPIO_Init(OSPIRAM_IO5_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = OSPIRAM_IO6_Pin; GPIO_InitStruct.Alternate = OSPIRAM_IO6_AF; HAL_GPIO_Init(OSPIRAM_IO6_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = OSPIRAM_IO7_Pin; GPIO_InitStruct.Alternate = OSPIRAM_IO7_AF; HAL_GPIO_Init(OSPIRAM_IO7_GPIO_Port, &GPIO_InitStruct); }
View more

/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* HyperRAM memory: * S70KL1281 on H735-Discovery * S70KL1282 on custom board */ /* size 2^x */ #define OSPI_HYPERRAM_SIZE 24 /* NCS high time between commands */ #define OSPI_HYPERRAM_NCS_HITIME 8 #define OSPI_HYPERRAM_WRAP_ZERO 0 /* clock prescaler */ #define OSPI_HYPERRAM_CLK_DIV 2 #define OSPI_HYPERRAM_CSBOUND (OSPI_HYPERRAM_SIZE - 1) #define OSPI_HYPERRAM_REFRESH 400 #define OSPI_HYPERRAM_FTHRES 4 #define OSPI_HYPERRAM_DCYC 0 /* timing for register HLCR HyperBus latency configuration */ /* clock cycles for read / write recovery time */ #define OSPI_HYPERRAM_RW_REC_TIME 3 /* clock cycles for device access time */ #define OSPI_HYPERRAM_LATENCY_S70KL1281 6 #define OSPI_HYPERRAM_LATENCY_S70KL1282 7 #define OSPI_HYPERRAM_LATENCY OSPI_HYPERRAM_LATENCY_S70KL1282 /* end address */ #define OSPI_HYPERRAM_END_ADDR (1 << OSPI_HYPERRAM_SIZE) /* ++++++++++++++++++++++++++++++++++++++++++++++++ */ /* DCR2 clock prescaler */ /* functional modes of peripheral */ #define OSPI_CR_FM_INDIRECT_WRITE (uint32_t)0 /*!< Indirect write mode */ #define OSPI_CR_FM_INDIRECT_READ (uint32_t)OCTOSPI_CR_FMODE_0 /*!< Indirect read mode */ #define OSPI_CR_FM_AUTO_POLLING (uint32_t)OCTOSPI_CR_FMODE_1 /*!< Automatic polling mode */ #define OSPI_CR_FM_MEMORY_MAPPED (uint32_t)OCTOSPI_CR_FMODE /*!< Memory-mapped mode */
View more

 

Hi, 

Good to hear, I can't comment much about specific for HyperRAM. 

If competiveness is important, I can just advice to look at APMemory products, APS12808L-3OBM-BA, this is compatible device on your BGA24  PCB footprint.

Regards

Alex