STM32H730 HyperRam issue
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-23 5:16 AM - last edited on ‎2025-05-23 5:53 AM by Andrew Neil
I have a custom board with a STM32H730 and an IS66WVH32M8 HyperRam.
The ram is connected on octospi1 outputs.
I can read and write in indirect mode to the internal registers of the ram.
But in memory mapped mode i read only wrong values.
To test the ram I write alternating 0x5555 5555 and 0xAAAA AAAA.
When I inspect in the memory view I see always the second byte wrong per word.
For example at address 0x7000 0000:
AAFFAAAA 55FF5555 AAFEAAAA 55DD5555
But when I measure the OCTOSPI on a scope, the data is correct (see attachement)
The setup of the OCTOSPI is as follows:
Clock speed of the OCTOSPI is 20Mhz with prescaler.
OCTOSPIM->PCR[0] = 0x07050333;
OCTOSPI2->CR &= ~OCTOSPI_CR_EN;
wait_busy();
OCTOSPI2->CR = 0x30000300;
OCTOSPI2->DCR1 = 0x4170700;
OCTOSPI2->DCR2 = 4;
OCTOSPI2->DCR3 = 0x5003F;
OCTOSPI2->DCR4 = 0xC8;
OCTOSPI2->TCR = 0x10000000;
OCTOSPI2->CCR = 0x2C003C00;
OCTOSPI2->WCCR = 0x2C003C00;
OCTOSPI2->HLCR = 0x010600;
wait_busy();
OCTOSPI2->CR |= OCTOSPI_CR_EN;
When I run the almost identical setup on a STM32H735-DK, everything works as intended. Only the prescaler and OCTOSPIM are different.
How can I make the ram work on my custom board?
Solved! Go to Solution.
- Labels:
-
OctoSPI
-
STM32H7 series
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-28 2:29 AM
After a lot of experimenting I got it finally working.
RCC->AHB3RSTR = RCC_AHB3RSTR_OSPI2RST;
RCC->AHB3RSTR = 0;
auto wait_busy = []()-> void { while(OCTOSPI2->SR & OCTOSPI_SR_BUSY); };
OCTOSPI2->CR &= ~OCTOSPI_CR_EN;
wait_busy();
OCTOSPI2->CR = 3<<OCTOSPI_CR_FMODE_Pos
| 5<<OCTOSPI_CR_FTHRES_Pos
;
OCTOSPI2->DCR1 = 4<<OCTOSPI_DCR1_MTYP_Pos
| 23<<OCTOSPI_DCR1_DEVSIZE_Pos // 16Mbyte
| 1<<OCTOSPI_DCR1_CSHT_Pos
;
OCTOSPI2->DCR2 = 0<<OCTOSPI_DCR2_WRAPSIZE_Pos
| 1<<OCTOSPI_DCR2_PRESCALER_Pos // clk / (prescaler+1)
;
OCTOSPI2->DCR3 = 5<<OCTOSPI_DCR3_CSBOUND_Pos
| 10<<OCTOSPI_DCR3_MAXTRAN_Pos
;
OCTOSPI2->DCR4 = 200; //refresh
if((OCTOSPI2->DCR2 & OCTOSPI_DCR2_PRESCALER_Msk) > 0){
OCTOSPI2->TCR = OCTOSPI_TCR_DHQC; // only when prescaler > 0
}
OCTOSPI2->CCR = OCTOSPI_CCR_DQSE
| OCTOSPI_CCR_DDTR
| 4<<OCTOSPI_CCR_DMODE_Pos
| OCTOSPI_CCR_ADDTR
| 4<<OCTOSPI_CCR_ADMODE_Pos
| 3<<OCTOSPI_CCR_ADSIZE_Pos
;
OCTOSPI2->WCCR = OCTOSPI2->CCR;
OCTOSPI2->HLCR = 4<<OCTOSPI_HLCR_TRWR_Pos
| 6<<OCTOSPI_HLCR_TACC_Pos
//| OCTOSPI_HLCR_LM // 1=fixed latency
;
wait_busy();
// Delay Block
DLYB_OCTOSPI2->CR = DLYB_CR_DEN | DLYB_CR_SEN;
DLYB_OCTOSPI2->CFGR = 1<<DLYB_CFGR_SEL_Pos //0-15
| 36<<DLYB_CFGR_UNIT_Pos //0-127
;
DLYB_OCTOSPI2->CR = DLYB_CR_DEN;
OCTOSPI2->CR |= OCTOSPI_CR_EN;
To make it work, I had to include the delay block. First I started with an example for tuning, but that didn't work. Tuning always ended in a timeout. Then I just changed the values of SEL and UNIT until I no longer had erronous readings. I skipped the tuning.
After this I had a working Hyperbus with 25MHz clock frequeny.
I then increased the frequency to 100MHz with the prescaler=0. And I did experiment with SEL and UNIT to make things work again, but I never succeded.
I guess the prescaler has to be at least 1. So I changed the PWR setting from default VOS to VOS2. Then I could run a higher input clock to the OCTOSPI peripheral and divide it with the prescaler to 100MHz.
Similar to this answer I estimated the values of SEL and UNIT.
And finally I have correct readings of the complete content of the ram.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-23 7:25 AM
Yeah, I'm not going to unpack uncommented register level code.
Try with the HAL, showing the read/write templates. Once it works there you can check the registers and use whatever form you want.
Verify with direct command level interaction, which are just the same, but without the address substitution.
Up vote any posts that you find helpful, it shows what's working..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-28 2:29 AM
After a lot of experimenting I got it finally working.
RCC->AHB3RSTR = RCC_AHB3RSTR_OSPI2RST;
RCC->AHB3RSTR = 0;
auto wait_busy = []()-> void { while(OCTOSPI2->SR & OCTOSPI_SR_BUSY); };
OCTOSPI2->CR &= ~OCTOSPI_CR_EN;
wait_busy();
OCTOSPI2->CR = 3<<OCTOSPI_CR_FMODE_Pos
| 5<<OCTOSPI_CR_FTHRES_Pos
;
OCTOSPI2->DCR1 = 4<<OCTOSPI_DCR1_MTYP_Pos
| 23<<OCTOSPI_DCR1_DEVSIZE_Pos // 16Mbyte
| 1<<OCTOSPI_DCR1_CSHT_Pos
;
OCTOSPI2->DCR2 = 0<<OCTOSPI_DCR2_WRAPSIZE_Pos
| 1<<OCTOSPI_DCR2_PRESCALER_Pos // clk / (prescaler+1)
;
OCTOSPI2->DCR3 = 5<<OCTOSPI_DCR3_CSBOUND_Pos
| 10<<OCTOSPI_DCR3_MAXTRAN_Pos
;
OCTOSPI2->DCR4 = 200; //refresh
if((OCTOSPI2->DCR2 & OCTOSPI_DCR2_PRESCALER_Msk) > 0){
OCTOSPI2->TCR = OCTOSPI_TCR_DHQC; // only when prescaler > 0
}
OCTOSPI2->CCR = OCTOSPI_CCR_DQSE
| OCTOSPI_CCR_DDTR
| 4<<OCTOSPI_CCR_DMODE_Pos
| OCTOSPI_CCR_ADDTR
| 4<<OCTOSPI_CCR_ADMODE_Pos
| 3<<OCTOSPI_CCR_ADSIZE_Pos
;
OCTOSPI2->WCCR = OCTOSPI2->CCR;
OCTOSPI2->HLCR = 4<<OCTOSPI_HLCR_TRWR_Pos
| 6<<OCTOSPI_HLCR_TACC_Pos
//| OCTOSPI_HLCR_LM // 1=fixed latency
;
wait_busy();
// Delay Block
DLYB_OCTOSPI2->CR = DLYB_CR_DEN | DLYB_CR_SEN;
DLYB_OCTOSPI2->CFGR = 1<<DLYB_CFGR_SEL_Pos //0-15
| 36<<DLYB_CFGR_UNIT_Pos //0-127
;
DLYB_OCTOSPI2->CR = DLYB_CR_DEN;
OCTOSPI2->CR |= OCTOSPI_CR_EN;
To make it work, I had to include the delay block. First I started with an example for tuning, but that didn't work. Tuning always ended in a timeout. Then I just changed the values of SEL and UNIT until I no longer had erronous readings. I skipped the tuning.
After this I had a working Hyperbus with 25MHz clock frequeny.
I then increased the frequency to 100MHz with the prescaler=0. And I did experiment with SEL and UNIT to make things work again, but I never succeded.
I guess the prescaler has to be at least 1. So I changed the PWR setting from default VOS to VOS2. Then I could run a higher input clock to the OCTOSPI peripheral and divide it with the prescaler to 100MHz.
Similar to this answer I estimated the values of SEL and UNIT.
And finally I have correct readings of the complete content of the ram.
