element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Embedded and Microcontrollers
  • Technologies
  • More
Embedded and Microcontrollers
Blog STM32H7B3I - Write a CubeMX application: Hardware Cryptography with DMA
  • Blog
  • Forum
  • Documents
  • Quiz
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Embedded and Microcontrollers to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 29 Aug 2020 5:31 PM Date Created
  • Views 3612 views
  • Likes 4 likes
  • Comments 2 comments
  • cryptography
  • security
  • stm32h7b3i
  • rt
  • iot
  • encryption
  • stm32h7b3i-dk
Related
Recommended

STM32H7B3I - Write a CubeMX application: Hardware Cryptography with DMA

Jan Cumps
Jan Cumps
29 Aug 2020

The STM32H7 firmware pack comes with a very nice encrypt / decrypt example.

This example uses the STM32 HAL libraries, and configures all periherals in source code.

I'm going to replicate the exact same example, using the CubeIDE MX STM32 Device Configuration Tool.

 

image

 

The goal is to maximise the use of MX, and to show how such a project is built.

Software versions:

  • CubeIDE 1.4.2
  • STM32CubeH7 Firmware Package V1.8.0
  • STM32CubeMX Version: 6.0.1-RC3

 

 

Example Code

 

The example showcases the hardware cryptography support.

A known set of data is encrypted, and the output  is then compared with the expected encryption result.

Then that encrypted data is decrypted and compared with the original.

Each time, the data should be bit-for-bit exact. If that's true, our test was successful.

 

The encryption and decryption run on the cryptography hardware accelerator, uses DMA to get source and write processed data.

Interrupts are used to flag that the processing is finished and data is ready.

 

If you want to check the original example: it's part of the STM32CubeH7 Firmware Package, called CRYP_AESModes_DMA and can be imported via the CubeIDE Information Center..

 

Start a Fresh Project

 

Enough intro, action now. In CubeIDE, start a new STM32 Project

 

image

 

Select either the controller or the board that we're using.

Selecting the board is easiest. Because then the clock settings will be done for us: STM32H7B3I-DK

 

image

 

Name the project. It's in C, executable, and STM32Cube style for full MX support.

 

image

You can choose your prefered solution here. I use reference because it generates a smaller .zip fil to add to the blog.

image

Let the wizard generate defaults for the drivers.

image

 

That's it. This generated a fresh project. With latest drivers and MX support.

 

Peripheral and Driver Setup with CubeMX

 

CubeIDE automatically loads the MX screen when the project is generated. Time to set up the modules.

All setup I show here is exactly mimicking what the original STM32 example does.

 

 

CPU Cache

Enable both ICache and DCache.

image

Here's the original code from the example. MX will generate compatible code for us.

static void CPU_CACHE_Enable(void)
{
  /* Enable I-Cache */
  SCB_EnableICache();


  /* Enable D-Cache */
  SCB_EnableDCache();
}

 

Cryptography Configuration

This is the main focus of the project.

Enable the module and set the attributes as in the picture below.

Check the original code extract at the end of this subsection for reference.

 

Set method, keys:

image

The DMA pipelines for reading and writing memory:

image

image

Interrupt settings:

 

image

 

Again the original example's code, for comparison:

 

CRYP_HandleTypeDef hcryp;

/* AES Key  */
uint32_t AESKey128[4] = {0x2B7E1516 ,0x28AED2A6 ,0xABF71588 ,0x09CF4F3C};

  /* Set the CRYP parameters */
  hcryp.Instance        = CRYP;
  hcryp.Init.DataType   = CRYP_DATATYPE_32B;
  hcryp.Init.KeySize    = CRYP_KEYSIZE_128B;
  hcryp.Init.pKey       = AESKey128; 
  hcryp.Init.Algorithm  = CRYP_AES_ECB; 
  
  /* Configure the CRYP  */
  HAL_CRYP_Init(&hcryp);

  HAL_NVIC_SetPriority(CRYP_IRQn, 4, 0);
  HAL_NVIC_EnableIRQ(CRYP_IRQn);
  
  /* Enable DMA2 clocks */
  __HAL_RCC_DMA2_CLK_ENABLE();
  __HAL_RCC_DMA2_FORCE_RESET();
  __HAL_RCC_DMA2_RELEASE_RESET();
  
  /***************** Configure common DMA In parameters ***********************/
  hdmaIn.Init.Request             = DMA_REQUEST_CRYP_IN;
  hdmaIn.Init.Direction           = DMA_MEMORY_TO_PERIPH;
  hdmaIn.Init.PeriphInc           = DMA_PINC_DISABLE;
  hdmaIn.Init.MemInc              = DMA_MINC_ENABLE;
  hdmaIn.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  hdmaIn.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;
  hdmaIn.Init.Mode                = DMA_NORMAL;
  hdmaIn.Init.Priority            = DMA_PRIORITY_HIGH;
  hdmaIn.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
  hdmaIn.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  hdmaIn.Init.MemBurst            = DMA_MBURST_SINGLE;
  hdmaIn.Init.PeriphBurst         = DMA_PBURST_SINGLE;
  hdmaIn.Instance = DMA2_Stream6;
  
  /* Associate the DMA handle */
  __HAL_LINKDMA(hcryp, hdmain, hdmaIn);
  
  /* De-initialize the Stream for new transfer */
  HAL_DMA_DeInit(hcryp->hdmain);
  
  /* Configure the DMA Stream */
  HAL_DMA_Init(hcryp->hdmain);      
  
  /* NVIC configuration for DMA Input data interrupt */
  HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
  
  /***************** Configure common DMA Out parameters **********************/
  hdmaOut.Init.Request             = DMA_REQUEST_CRYP_OUT;
  hdmaOut.Init.Direction           = DMA_PERIPH_TO_MEMORY;
  hdmaOut.Init.PeriphInc           = DMA_PINC_DISABLE;
  hdmaOut.Init.MemInc              = DMA_MINC_ENABLE;
  hdmaOut.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  hdmaOut.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;
  hdmaOut.Init.Mode                = DMA_NORMAL;
  hdmaOut.Init.Priority            = DMA_PRIORITY_VERY_HIGH;
  hdmaOut.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
  hdmaOut.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  hdmaOut.Init.MemBurst            = DMA_MBURST_SINGLE;
  hdmaOut.Init.PeriphBurst         = DMA_PBURST_SINGLE;
  hdmaOut.Instance = DMA2_Stream5;
  
  /* Associate the DMA handle */
  __HAL_LINKDMA(hcryp, hdmaout, hdmaOut);
  
  /* De-initialize the Stream for new processing */
  HAL_DMA_DeInit(&hdmaOut);
  
  /* Configure the DMA Stream */
  HAL_DMA_Init(&hdmaOut);
  
  /* NVIC configuration for DMA output data interrupt */
  HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn); 

 

DMA configuration

Nothing to do here. Our Crypto settings are automatically reflected in the DAM module.

You can click on the module and verify. No changes needed.

 

Interrupt Configuration

In this module, the priority and order are set ...

image

... and you flag what interrupt functions MX should pre-generate.

image

 

That's it. Save the configuration file and generate the code.

image

 

Source Code: the Encryption and Decryption Logic

 

This is exactly the main file of the original example, except the things that were auto-generated by MX.

I have used the same variable names, function names and look-and feel. To make comparison easier.

 

CrypCompleteDetected is a variable that is set high in the Crypt interrupt handler, when the work is done.

It is set to 0 before we perform a cryptographic function. The Crypt module and DMA will invoke the interrupt handler when the results are in memory.

__IO is STM32's way to flag it volatile.

 

// for memory comparison function memcmp()
#include "string.h"

/* USER CODE BEGIN PV */
__IO uint32_t CrypCompleteDetected = 0;

/* Plaintext */
uint32_t Plaintext[16]  =    {0x6BC1BEE2 ,0x2E409F96 ,0xE93D7E11 ,0x7393172A ,
                              0xAE2D8A57 ,0x1E03AC9C ,0x9EB76FAC ,0x45AF8E51 ,
                              0x30C81C46 ,0xA35CE411 ,0xE5FBC119 ,0x1A0A52EF ,
                              0xF69F2445 ,0xDF4F9B17 ,0xAD2B417B ,0xE66C3710};

/* Expected ECB Ciphertext with DataType 32 ( no swapping)*/
uint32_t Ciphertext[16] =    {0x3AD77BB4 ,0x0D7A3660 ,0xA89ECAF3 ,0x2466EF97 ,
                              0xF5D3D585 ,0x03B9699D ,0xE785895A ,0x96FDBAAF ,
                              0x43B1CD7F ,0x598ECE23 ,0x881B00E3 ,0xED030688 ,
                              0x7B0C785E ,0x27E8AD3F ,0x82232071 ,0x04725DD4};

/* Plaintext byte swapping (DataType 8)*/
uint32_t Plaintext_8[16] =   {0xE2BEC16B ,0x969F402E ,0x117E3DE9 ,0x2A179373 ,
                              0x578A2DAE ,0x9CAC031E ,0xAC6FB79E ,0x518EAF45 ,
                              0x461CC830 ,0x11E45CA3 ,0x19C1FBE5 ,0xEF520A1A ,
                              0x45249FF6 ,0x179B4FDF ,0x7B412BAD ,0x10376CE6};

/* Expected ECB Ciphertext with DataType 8 */
uint32_t Ciphertext_8[16] =  {0xB47BD73A ,0x60367A0D ,0xF3CA9EA8 ,0x97EF6624 ,
                              0x85D5D3F5 ,0x9D69B903 ,0x5A8985E7 ,0xAFBAFD96 ,
                              0x7FCDB143 ,0x23CE8E59 ,0xE3001B88 ,0x880603ED ,
                              0x5E780C7B ,0x3FADE827 ,0x71202382 ,0xD45D7204};

/* Plaintext  half-word swapping (DataType 16) */
uint32_t Plaintext_16[16] =  {0xBEE26BC1 ,0x9F962E40 ,0x7E11E93D ,0x172A7393 ,
                              0x8A57AE2D ,0xAC9C1E03 ,0x6FAC9EB7 ,0x8E5145AF ,
                              0x1C4630C8 ,0xE411A35C ,0xC119E5FB ,0x52EF1A0A ,
                              0x2445F69F ,0x9B17DF4F ,0x417BAD2B ,0x3710E66C};

/* Expected ECB Ciphertext with DataType 16 */
uint32_t Ciphertext_16[16] = {0x7BB43AD7 ,0x36600D7A ,0xCAF3A89E ,0xEF972466 ,
                              0xD585F5D3 ,0x699D03B9 ,0x895AE785 ,0xBAAF96FD ,
                              0xCD7F43B1 ,0xCE23598E ,0x00E3881B ,0x0688ED03 ,
                              0x785E7B0C ,0xAD3F27E8 ,0x20718223 ,0x5DD40472};
/* Plaintext  bit swapping (DataType 1) */
uint32_t Plaintext_1[16] =   {0x477D83D6 ,0x69F90274 ,0x887EBC97 ,0x54E8C9CE ,
                              0xEA51B475 ,0x3935C078 ,0x35F6ED79 ,0x8A71F5A2 ,
                              0x6238130C ,0x88273AC5 ,0x9883DFA7 ,0xF74A5058,
                              0xA224F96F ,0xE8D9F2FB ,0xDE82D4B5 ,0x08EC3667};

/* Expected ECB Ciphertext with DataType 1 */
uint32_t Ciphertext_1[16] =  {0x2DDEEB5C, 0x066C5EB0, 0xCF537915 ,0xE9F76624  ,
                              0xA1ABCBAF,  0xB9969DC0 ,0x5A91A1E7 ,0xF55DBF69 ,
                              0xFEB38DC2 , 0xC473719A ,0xC700D811 ,0x1160C0B7 ,
                              0x7A1E30DE , 0xFCB517E4 ,0x8E04C441 ,0x2BBA4E20};



/* Used for storing Encrypted text */
ALIGN_32BYTES (static uint32_t Encryptedtext[16])={0};

/* Used for storing Decrypted text */
ALIGN_32BYTES (static uint32_t Decryptedtext[16])={0};

/* USER CODE END PV */

 

Here is that interrupt handler. The name is critical, because if you have this wrong, the default handler will be called. Without compile or runtime errors.

Be careful.

 

void HAL_CRYP_OutCpltCallback(CRYP_HandleTypeDef *hcryp)
 {
     CrypCompleteDetected = 1;
 }

 

And this is the custom part of the main code. Our logic, where we let the Crypt module encrypt and decrypt data.

It's very small. That's because all the big work was generated by MX.

The code is exactly the same as in the original example.

 

int main(void)
{
  // ...
  /* USER CODE BEGIN 2 */

  /* Encryption, result in  Encryptedtext buffer */
  HAL_CRYP_Encrypt_DMA(&hcryp, Plaintext, 16, Encryptedtext);

  /*Wait until output transfer complete*/
  while(CrypCompleteDetected == 0)
  {  }

  /*Compare with expected result */
  if(memcmp(Encryptedtext, Ciphertext, 64) != 0)
  {
    /* Not expected result, wrong on Encryptedtext buffer: Turn LED3 on */
    Error_Handler();
  }

  /* Reset Output Transfer Complete Detect */
  CrypCompleteDetected = 0;

  /* Decryption, result in  Decryptedtext buffer */
  HAL_CRYP_Decrypt_DMA(&hcryp, Ciphertext , 16, Decryptedtext);

  /*Wait until output transfer complete*/
  while(CrypCompleteDetected == 0)
  {  }

  /*Compare with expected result */
  if(memcmp(Decryptedtext, Plaintext, 64) != 0)
  {
    /* Not expected result, wrong on Decryptedtext buffer: Turn LED3 on */
    Error_Handler();
  }
  /* Reset Output Transfer Complete Detect */
  CrypCompleteDetected = 0;

  // original code repeats this a few time, for other crypto algorithms

  /* USER CODE END 2 */
  // ...
}

 

Compile and Run

 

image

 

Set the dedicated load script for this board.

 

image

 

Optimisation

 

When I opted to let MX generate a project for this board, it configured and enabled a number of peripherals that aren't needed for this project.

I selected those and set them to disabled. In the end, these essential resources were kept active:

image

If you see more resources in this tab in your project, go to the unneeded resources and disable them.

This does not change the logic. It gives smaller code and less init time. I have not checked if power consumption is affected.

 

 

 

I hope that this post explains how to set up peripherals, drivers and APIs with the CubeIDE MX STM32 Device Configuration Tool.

Enjoy.

 

Related Posts
First Experience with CubeIDE
Create a TouchGFX Project with support for the Designer, CubeIDE and Debugger - Pt 1: Screen Works
Create a TouchGFX Project with support for the Designer, CubeIDE and Debugger - Pt 2: Touch Works
TouchGFX Simple Example: react on a button click
USB, freeRTOS ,Task Notifications and Interrupts
the Development Kit STMod+ Connector and Using UART2
TouchGFX Application Framework: Model, View, Presentation, Message Queue
TouchGFX Application Framework: A Mock GUI - Show Statuses, Switch Screens
TouchGFX Application Framework: MVP and the ModelListener
Write a CubeIDE MX application: Hardware Cryptography with DMA
Attachments:
MX_CRYP_AESModes_DMA_20200829.zip
  • Sign in to reply

Top Comments

  • DAB
    DAB over 4 years ago +2
    You made it look easy Jan. DAB
  • Jan Cumps
    Jan Cumps over 4 years ago in reply to DAB +2
    That was the goal. Setting up DMA to work with a peripheral, and getting the interrupts to fire when encyption is done, is not straightforward. You need to first understand what DMA hooks are available…
Parents
  • DAB
    DAB over 4 years ago

    You made it look easy Jan.

     

    DAB

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
Comment
  • DAB
    DAB over 4 years ago

    You made it look easy Jan.

     

    DAB

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
Children
  • Jan Cumps
    Jan Cumps over 4 years ago in reply to DAB

    That was the goal. Setting up DMA to work with a peripheral, and getting the interrupts to fire when encyption is done, is not straightforward.

    You need to first understand what DMA hooks are available. Then how to configure peripheral and DMA controller. Define the right channels and modes.

    Change a DMA or Crypto engine setting in the blog post above, and it does not work.

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube