May 10 2025

STM32F411CE Lab 3 – Challenge-Response System (Part 2)


Author: Shafeeque Olassery Kunnikkal | Category: Cyber Security, IoT, Penetration Testing, STM32F411 | Leave a Comment

Welcome back! In this follow-up, we continue developing the STM32F411CE Lab 3 Challenge-Response system.

Today we’ll cover:
✅ Setting up STM32CubeIDE
✅ Configuring JTAG, UART, GPIO
✅ Adding challenge-response logic
✅ Preparing for build, flash, and testing


Step 1: Create the STM32CubeIDE Project

Open STM32CubeIDE → File → New → STM32 Project


Step 2: Select the MCU

In the Target Selection window, enter:
STM32F411CEU6

Select the STM32F411CEU6 device and click Next.

Figure 1 – Selecting Project type
Figure 2 – Selecting MCU type

Step 3: Set Project Name and Options

  • Project Name: STM32f411CE-Lab3-Challenge_response
  • Language: C
  • Binary type: Executable

Accept the firmware package defaults and click Finish.

Figure 3 – Setting Project Name and Options
Figure 4 – Setting Firmware Package and Versions

Step 4: Configure Pinout and Peripherals

In the configuration screen, set up:

  • LED GPIO (PC13) → for blinking
  • USART2 (TX/RX) → for UART
  • JTAG pins → for debug
  • RCC settings → adjust clocks
Figure 5 – Initial Screen for Various configuration Such as PIN and Clock
Figure 6 – Enable LED PIN
Figure 7 – Enabling USART2 (RX/TX)
Figure 8 – Enabling TX
Figure 9 – Enabling RX
Figure 10 – JTAG PINS
Figure 11 – Debug Port pin assignment
Figure 12 – RCC Settings
Figure 13 – clock configuration

Step 5: Generate Code

Go to → Project → Generate Code. This produces the initial project structure, main application file, and HAL drivers.

Figure 14 – Generate Initial Code Base

Step 6: Review Generated Files

Open the generated files in your project, especially the main application file, to check the structure and ready it for customization.


Step 7: Enable Binary Output

✅ Right-click the project → Properties → Configure output settings to also generate .bin files.

Figure 15 -selecting Project Properties
Figure 16 – configure output settings

Why We Refined the LED Code

In embedded development, using blocking code (such as delays) causes the microcontroller to halt while waiting.
For example, if the LED blinking logic uses a blocking delay, the system can’t process UART input or perform other tasks.

To improve responsiveness, we implemented a non-blocking LED control module.
Instead of delays, it uses time comparisons, allowing the system to keep running while the LED blinks in the background — critical for multitasking and system responsiveness.


Why We Insert Code Only in IDE-Provided Sections

STM32CubeIDE automatically generates key project files when you click Project → Generate Code.
If you add custom code outside the provided USER CODE sections, it can be overwritten or deleted during regeneration or when opening the project in a new workspace.

To prevent this, always place your custom code inside the protected areas marked:

  • USER CODE BEGIN Includes → USER CODE END Includes
  • USER CODE BEGIN PV → USER CODE END PV
  • USER CODE BEGIN 2 → USER CODE END 2
  • USER CODE BEGIN 3 → USER CODE END 3

Double-check: When modifying IDE-generated files, ensure all changes are inside these sections.
This protects your work during future regenerations or IDE transitions.


Custom .c and .h Files We Added

challenge.h

#ifndef CHALLENGE_H
#define CHALLENGE_H

#include "stm32f4xx_hal.h"

uint32_t GenerateChallenge(void);
uint8_t ValidateResponse(uint32_t challenge, uint32_t response);

#endif

challenge.c

#include "challenge.h"
#include <stdlib.h>
#include <time.h>

#define CHALLENGE_CONSTANT 3

uint32_t GenerateChallenge(void) {
    srand(HAL_GetTick());
    return (rand() % 100) + 1;
}

uint8_t ValidateResponse(uint32_t challenge, uint32_t response) {
    return (response == challenge * CHALLENGE_CONSTANT);
}

led_control.h

#ifndef INC_LED_CONTROL_H_
#define INC_LED_CONTROL_H_

#include "stm32f4xx_hal.h"

typedef struct {
    GPIO_TypeDef *port;
    uint16_t pin;
    uint8_t count;
    uint32_t interval;
    uint32_t last_toggle;
    uint8_t is_active;
} LedBlinkController;

void LED_StartBlinking(LedBlinkController *controller, GPIO_TypeDef *port, uint16_t pin, uint8_t count);
void LED_Update(LedBlinkController *controller);

#endif

led_control.c

#include "led_control.h"

void LED_StartBlinking(LedBlinkController *controller, GPIO_TypeDef *port, uint16_t pin, uint8_t count) {
    controller->port = port;
    controller->pin = pin;
    controller->count = count * 2;
    controller->interval = 200;
    controller->last_toggle = HAL_GetTick();
    controller->is_active = 1;
}

void LED_Update(LedBlinkController *controller) {
    if (!controller->is_active) return;

    uint32_t now = HAL_GetTick();
    if (now - controller->last_toggle >= controller->interval) {
        HAL_GPIO_TogglePin(controller->port, controller->pin);
        controller->last_toggle = now;
        controller->count--;

        if (controller->count == 0) {
            controller->is_active = 0;
            HAL_GPIO_WritePin(controller->port, controller->pin, GPIO_PIN_RESET);
        }
    }
}

uart_interface.h

#ifndef INC_UART_INTERFACE_H_
#define INC_UART_INTERFACE_H_

#include "stm32f4xx_hal.h"

void UART_SendString(const char *str);
void UART_ReadString(char *buffer, uint16_t size);
void UART_ClearScreen(void);

#endif

uart_interface.c

#include "uart_interface.h"
#include <string.h>
#include <stdio.h>

extern UART_HandleTypeDef huart2;

void UART_SendString(const char *str) {
    HAL_UART_Transmit(&huart2, (uint8_t *)str, strlen(str), HAL_MAX_DELAY);
}

void UART_ReadString(char *buffer, uint16_t size) {
    uint16_t i = 0;
    char ch;
    while (i < size - 1) {
        HAL_UART_Receive(&huart2, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
        if (ch == '\r' || ch == '\n') break;
        buffer[i++] = ch;
    }
    buffer[i] = '\0';
}

void UART_ClearScreen(void) {
    char clear[] = "\033[2J\033[H";
    UART_SendString(clear);
}

Modified main Application Snippets

Includes Section

/* USER CODE BEGIN Includes */
#include "challenge.h"
#include "led_control.h"
#include "uart_interface.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/* USER CODE END Includes */

Private Typedef Section

/* USER CODE BEGIN PTD */
LedBlinkController ledController;
/* USER CODE END PTD */

Private Variables Section

/* USER CODE BEGIN PV */
uint8_t challengeCount = 0;
/* USER CODE END PV */

Initialization Section

/* USER CODE BEGIN 2 */
UART_SendString("Booting up... Blinking LED.\r\n");
LED_StartBlinking(&ledController, LD1_GPIO_Port, LD1_Pin, 5);

while (ledController.is_active) {
    LED_Update(&ledController);
}
/* USER CODE END 2 */

Main Loop Section – inside While(1)

/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_RESET);
UART_SendString("Welcome to Challenge-Response System!\r\n");

uint32_t challenge = GenerateChallenge();
char maskedChallenge[50];
snprintf(maskedChallenge, sizeof(maskedChallenge), "Challenge #%d: ****\r\n", ++challengeCount);
UART_SendString(maskedChallenge);

UART_SendString("Enter your response: ");
char responseBuffer[20] = {0};
UART_ReadString(responseBuffer, sizeof(responseBuffer));

uint32_t userResponse = (uint32_t)atoi(responseBuffer);
if (ValidateResponse(challenge, userResponse)) {
    UART_SendString("\r\n✔️ Correct! Blinking LED.\r\n");
    LED_StartBlinking(&ledController, LD1_GPIO_Port, LD1_Pin, 10);
} else {
    UART_SendString("\r\n❌ Incorrect. Try again.\r\n");
}

uint8_t blinkDone = 0;
while (ledController.is_active) {
    LED_Update(&ledController);
    blinkDone = 1;
}
if (blinkDone) {
    HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_RESET);
}

if (challengeCount >= 5) {
    UART_ClearScreen();
}
/* USER CODE END 3 */

Key Takeaways

  • Non-blocking LED control improves system responsiveness.
  • Modular design keeps the code maintainable.
  • Always use the IDE’s USER CODE sections to protect your work.

Next Steps

  • Build the project.
  • Flash with STM32CubeProgrammer.
  • Test over UART.
  • Debug over JTAG.
  • In the next Part we will go through flashing the binary using STMCubeProgrammer

Happy hacking, and see you soon!

⚠ Licensing, Warnings, and Credits

MIT License
Permission is granted to use, modify, and distribute this project with credit.

Warning:
This tutorial is for educational purposes only.

Credits:
Author: gr4ytips
Firmware Collaboration: gr4ytips + ChatGPT (OpenAI)
Platform: STM32F411CE, STM32CubeIDE
Screenshots & materials © [gr4ytips]

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Categories

Tags

Archives