cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H730 HyperRam issue

Roba
Associate

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?

1 ACCEPTED SOLUTION

Accepted Solutions
Roba
Associate

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;
View more

 

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.

 

View solution in original post

2 REPLIES 2

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.

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

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;
View more

 

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.