cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 FLASH CRC

niallp
Associate III

I'm trying to use the internal CRC calculation unit in the STM32H7 FLASH controller via the HAL_FLASHEx_ComputeCRC() api. I've finally started getting crc32 values returned but can't match them against any common algorithms ... reviewing AN5507 implies it is using poly 0x4c11db7 and maybe initial value 0 ?

I had thought it would match the CRC peripheral defaults but this is not the case.

Part of my issue may be address bounds, it seems to be inclusive of the start/end addresses so end address is 1 less (though RM indicates bottom 2 bits can't be set so -1,-2,-3 gives the same results). Finally got consistent return values with different burst lengths but still can't matching other algorithms such as those generated by srec_cat with the -STM32 filter.

I've seen some comments indicating this may not work at all but the latest errata has nothing about it (STM32H725)

It feels like CRC checking of FLASH memory is exactly what this was supposed to be used for but I'm surprised it isn't better documented. Google AI makes comments the parameters are fixed but is mysterious as to what they actually are.

Any pointers appreciated, thanks.

1 ACCEPTED SOLUTION

Accepted Solutions
niallp
Associate III

For now I've just figured out the hack necessary to the -STM32 CRC generator for srec_cat to match the FLASH CRC calculation on the STM32H7xx, it currently replaces the existing calculations so should be better integrated as an option.

For anyone impatient though (unlikely ;)

diff --git a/srecord/stm32.cc b/srecord/stm32.cc
index 46ccdf5..977064d 100644
--- a/srecord/stm32.cc
+++ b/srecord/stm32.cc
@@ -42,7 +42,8 @@ srecord::stm32::~stm32()
 
 
 srecord::stm32::stm32() :
-    state(0xFFFFFFFF),
+//    state(0xFFFFFFFF),
+    state(0),                  // for FLASH CRC
     cnt(0)
 {
 }
@@ -83,7 +84,7 @@ srecord::stm32::operator=(const stm32 &arg)
 // and operates only on words.
 //
 static unsigned long
-stm32_crc(unsigned long crc, unsigned long data)
+stm32_crc(unsigned long crc, unsigned long data, unsigned long xor_out)
 {
     crc ^= data;
     for (int j = 0; j < 32; ++j)
@@ -93,6 +94,7 @@ stm32_crc(unsigned long crc, unsigned long data)
         else
             crc = (crc << 1);
     }
+    crc ^= xor_out;            // for FLASH CRC
     return crc;
 }
 
@@ -103,7 +105,7 @@ srecord::stm32::generator(void)
     unsigned long data = 0;
     for (size_t j = 0; j < wordsize; j++)
         data |= (buf[j] << (8 * j));
-    state = stm32_crc(state, data);
+    state = stm32_crc(state, data, 0x55555555);
     cnt = 0;
 }
 

 The CRC can then be injected into your .hex (extra binary) using 

srec_cat ${ProjName}.hex -Intel -fill 0xFF 0x08000000 0x0803FFFC -STM32 0x0803FFFC -o ${ProjName}-CRC.hex -Intel

I put this as a post-build step in CubeIDE, with CRC at top end of last sector (adjust for your code size).

To check in your code

bool mcu_check_flash_crc(uint32_t *result)
// true if CRC check passes
{
  FLASH_CRCInitTypeDef crc_init;
  HAL_StatusTypeDef status;

  dbgHi;
  if (HAL_FLASHEx_Unlock_Bank1() == HAL_OK) {
      crc_init.TypeCRC = FLASH_CRC_SECTORS;
      crc_init.Sector = FLASH_SECTOR_0;	// needs to be valid for FLASH_CRC_SECTOR (128kB/sector)
      crc_init.NbSectors = 2;		// to 0x08040000
      crc_init.Bank = FLASH_BANK_1;		// need to specify
      crc_init.BurstSize = FLASH_CRC_BURST_SIZE_256;
      crc_init.CRCStartAddr = 0x08000000;	// for earlier tests
      crc_init.CRCEndAddr = 0x0800007f;		// smallest segment possible

      status = HAL_FLASHEx_ComputeCRC(&crc_init,result);
  }
  HAL_FLASHEx_Lock_Bank1();	// always returns HAL_OK
  dbgLo;

  return (status == HAL_OK) && (*result == 0x55555555);
}

 

View solution in original post

7 REPLIES 7
TDK
Super User

Calculate the CRC on 4 bytes. Show your code. Show what you calculated vs what you expected.

This is likely a byte order problem. Words are interpreted in little endian on the device whereas whatever calculation you're doing is probably big endian. Just a guess, as there are no details given.

If you feel a post has answered your question, please click "Accept as Solution".
niallp
Associate III

Thanks for the suggestion, part of the issue is that the internal FLASH CRC generator works on flash words (256 bit, 32 byte) and minimum burst length of 4 for 128 bytes ... the default standard tests are hard to apply.

As simple as I could make it was 128 bytes at start of flash 0x08000000, length 0x80. For that, the hw CRC peripheral used with defaults via HAL_CRC_Calculate(&hcrc, (uint32_t *) 0x08000000, 0x80) gives 0xCF4784FE, which matches with CRC-32/MPEG-2. So far so good ...

Using the FLASH CRC though the result is 0x922D9C56 (which suspiciously is the same value it gives for a length of 0x200) so clearly an issue with setting the address bounds.

bool mcu_check_flash_crc(uint32_t *result)
{
  FLASH_CRCInitTypeDef crc_init;
  HAL_StatusTypeDef status;

  if (HAL_FLASHEx_Unlock_Bank1() == HAL_OK) {
      crc_init.TypeCRC = FLASH_CRC_ADDR;
      crc_init.Sector = FLASH_SECTOR_0;	// needs to be valid for FLASH_CRC_SECTOR (128kB/sector)
      crc_init.NbSectors = 2;		// to 0x08040000
      crc_init.Bank = FLASH_BANK_1;		// need to specify
      crc_init.BurstSize = FLASH_CRC_BURST_SIZE_4;
      crc_init.CRCStartAddr = 0x08000000;
      crc_init.CRCEndAddr = 0x0800007C;

      status = HAL_FLASHEx_ComputeCRC(&crc_init,result);
  }
  HAL_FLASHEx_Lock_Bank1();	// always returns HAL_OK

  return (status == HAL_OK) && (*result == 0);
}

Despite the clear intended purpose and value of the FLASH CRC hardware in the STM32H7 there seems to be no working examples I can find and I was hoping someone from ST could comment ... is this hardware immature ? It was my naive assumption that the default HW-CRC would match the FLASH CRC in operation.

 

My sample data below (0x08000000, len 0x80):

0x00 0x00 0x05 0x24 0x41 0x23 0x00 0x08   0x91 0x1A 0x00 0x08 0x99 0x1A 0x00 0x08
0xA1 0x1A 0x00 0x08 0xA9 0x1A 0x00 0x08   0xB1 0x1A 0x00 0x08 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00   0x00 0x00 0x00 0x00 0x61 0x54 0x01 0x08
0xB9 0x1A 0x00 0x08 0x00 0x00 0x00 0x00   0xB1 0x56 0x01 0x08 0x35 0x0F 0x01 0x08
0x95 0x23 0x00 0x08 0x95 0x23 0x00 0x08   0x95 0x23 0x00 0x08 0x95 0x23 0x00 0x08
0x95 0x23 0x00 0x08 0x95 0x23 0x00 0x08   0x95 0x23 0x00 0x08 0x95 0x23 0x00 0x08
0x95 0x23 0x00 0x08 0x95 0x23 0x00 0x08   0x95 0x23 0x00 0x08 0x95 0x23 0x00 0x08
0x95 0x23 0x00 0x08 0x95 0x23 0x00 0x08   0x95 0x23 0x00 0x08 0x95 0x23 0x00 0x08

> crc_init.CRCEndAddr = 0x0800007C

> len 0x80

These don't match. End address should be 0x08000080, no?

 

> I was hoping someone from ST could comment

This is primarily a user forum, not a direct pathway to ST. If you want to file a support ticket you can do so here:

https://ols.st.com/s/

 

Indeed it's too bad there isn't a working example. I will try to get this working.

If you feel a post has answered your question, please click "Accept as Solution".
TDK
Super User

I did spend some time on this. Did not get it working but did notice that the FLASH_CRC_BURST_SIZE_4 is not set correctly due to a bug in HAL. The code only sets bits within the mask, it doesn't reset them, and the default value is not zero.

https://github.com/STMicroelectronics/stm32h7xx-hal-driver/blob/1501be883dae6f202c1d3f856ee6b11407dc257d/Src/stm32h7xx_hal_flash_ex.c#L733

I'll spend some more time on it later.

If you feel a post has answered your question, please click "Accept as Solution".
niallp
Associate III

This is primarily a user forum, not a direct pathway to ST. If you want to file a support ticket you can do so here:

https://ols.st.com/s/

 

Thanks, submitted a ticket, will see what they can provide.

niallp
Associate III

So patching the stm32h7xx_hal_flash_ex.c to clear the bits for default BURST_16 does allow me to select both BURST_4 and BURST_64 and I can generate CRC on as small as 0x80 length memory sections, however the CRC calculated still doesn't match the CRC calculated by the CRC peripheral (either default or with 0 init and played with InRef and OutRef ... maybe still a combination I've missed)

      /* Clear current CRC result, program burst size and define memory area on which CRC has to be computed */
      FLASH->CRCCR1 &= (~FLASH_CRCCR_CRC_BURST_Msk);
      FLASH->CRCCR1 |= FLASH_CRCCR_CLEAN_CRC | pCRCInit->BurstSize | pCRCInit->TypeCRC;



At least now I can get the sw emulator from AN5507 to match the FLASH-CRC so I think I'm going to try to add it to srec_cat so I can generate the CRC at build then let the FLASH-CRC hardware check it while running. I can't really believe I'm the first to get this far but I guess someone has to be the first to use the hardware ? (weird it wasn't an ST app engineer though ...)

On to patch srecord, fingers crossed !

niallp
Associate III

For now I've just figured out the hack necessary to the -STM32 CRC generator for srec_cat to match the FLASH CRC calculation on the STM32H7xx, it currently replaces the existing calculations so should be better integrated as an option.

For anyone impatient though (unlikely ;)

diff --git a/srecord/stm32.cc b/srecord/stm32.cc
index 46ccdf5..977064d 100644
--- a/srecord/stm32.cc
+++ b/srecord/stm32.cc
@@ -42,7 +42,8 @@ srecord::stm32::~stm32()
 
 
 srecord::stm32::stm32() :
-    state(0xFFFFFFFF),
+//    state(0xFFFFFFFF),
+    state(0),                  // for FLASH CRC
     cnt(0)
 {
 }
@@ -83,7 +84,7 @@ srecord::stm32::operator=(const stm32 &arg)
 // and operates only on words.
 //
 static unsigned long
-stm32_crc(unsigned long crc, unsigned long data)
+stm32_crc(unsigned long crc, unsigned long data, unsigned long xor_out)
 {
     crc ^= data;
     for (int j = 0; j < 32; ++j)
@@ -93,6 +94,7 @@ stm32_crc(unsigned long crc, unsigned long data)
         else
             crc = (crc << 1);
     }
+    crc ^= xor_out;            // for FLASH CRC
     return crc;
 }
 
@@ -103,7 +105,7 @@ srecord::stm32::generator(void)
     unsigned long data = 0;
     for (size_t j = 0; j < wordsize; j++)
         data |= (buf[j] << (8 * j));
-    state = stm32_crc(state, data);
+    state = stm32_crc(state, data, 0x55555555);
     cnt = 0;
 }
 

 The CRC can then be injected into your .hex (extra binary) using 

srec_cat ${ProjName}.hex -Intel -fill 0xFF 0x08000000 0x0803FFFC -STM32 0x0803FFFC -o ${ProjName}-CRC.hex -Intel

I put this as a post-build step in CubeIDE, with CRC at top end of last sector (adjust for your code size).

To check in your code

bool mcu_check_flash_crc(uint32_t *result)
// true if CRC check passes
{
  FLASH_CRCInitTypeDef crc_init;
  HAL_StatusTypeDef status;

  dbgHi;
  if (HAL_FLASHEx_Unlock_Bank1() == HAL_OK) {
      crc_init.TypeCRC = FLASH_CRC_SECTORS;
      crc_init.Sector = FLASH_SECTOR_0;	// needs to be valid for FLASH_CRC_SECTOR (128kB/sector)
      crc_init.NbSectors = 2;		// to 0x08040000
      crc_init.Bank = FLASH_BANK_1;		// need to specify
      crc_init.BurstSize = FLASH_CRC_BURST_SIZE_256;
      crc_init.CRCStartAddr = 0x08000000;	// for earlier tests
      crc_init.CRCEndAddr = 0x0800007f;		// smallest segment possible

      status = HAL_FLASHEx_ComputeCRC(&crc_init,result);
  }
  HAL_FLASHEx_Lock_Bank1();	// always returns HAL_OK
  dbgLo;

  return (status == HAL_OK) && (*result == 0x55555555);
}