ccmakeembeddedstm32st-link

Why when flashing my stm32f411re Nucleo board does nothing happen even if I get no errors


I am trying to design my own build system for STM32f411re Cortex-M MCU using a Nucleo board with a ST-Link onboard and CMake.

Together with this I want to write my own HAL library, I know all of this is technically just me reinventing the wheel, but I am primarily doing all of this for leaning purposes. Because constantly using vendor IDEs has made me lazy and also reliant on them to get anything done.

I did however borrow the following resources from the IDE to help get me started:

All code in these files will be provided below, and I did not make any modifications to them.

Note the cmake file in the list above is invoked from my custom cmake file in the later provided code.

The compiler I am using is gcc-arm-none-eabi, and the cli tool I use to flash my target is openocd.

When I Flash my device using only the generated code (Both source and CMake code) from STMCubeIDE, I get no errors and my led blinking application works just fine, so I presume there is nothing wrong with how I flash the device. But when I use my custom Cmake and source code, it builds (CMake and make) and flashes with no issues, bot my code that should turn the led (LD2 connected to PA5) on does not work.

I am unsure if the issue lies with my build system or my source code.

My Cmake File:

cmake_minimum_required(VERSION 3.22)

# Set the project name
set(CMAKE_PROJECT_NAME stm32_base)

# Include toolchain file
include("./gcc-arm-none-eabi.cmake")

# Set the compilers
set(ENV{CC} arm-none-eabi-gcc)
set(ENV{CXX} arm-none-eabi-g++)

# Setup compiler settings
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)

# Enable CMake support for ASM and C languages
enable_language(C ASM)

# Set compiler flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")

# # Set output directory
# set(OUTPUT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/out)

# Add the startup file to the project
set(STARTUP_FILE ./startup_stm32f411xe.s)

# Add source directories
set(SOURCE_DIRS
    # User code
    ../code/source
    )

# Add header directories
set(HEADER_DIRS 
    # User code
    ../code/includes
    )

# Add library directories
set(LIBRARY_DIRS
    # User code
    ../code/libraries/f411re_hal/boot
    ../code/libraries/f411re_hal/clock
    ../code/libraries/f411re_hal/gpio
    ../code/libraries/f411re_hal/i2c
    ../code/libraries/f411re_hal/spi
    ../code/libraries/f411re_hal/timers
    ../code/libraries/f411re_hal/uart)

# Collect source files
foreach(SOURCE_DIR ${SOURCE_DIRS})
    file(GLOB_RECURSE SOURCE_FILES_TMP "${SOURCE_DIR}/*.c")
    list(APPEND SOURCE_FILES ${SOURCE_FILES_TMP})
endforeach()

# Collect header files
foreach(HEADER_DIR ${HEADER_DIRS})
    file(GLOB_RECURSE HEADER_FILES_TMP "${HEADER_DIR}/*.h")
    list(APPEND HEADER_FILES ${HEADER_FILES_TMP})
endforeach()

# Collect library (h) files
foreach(LIBRARY_DIR_H ${LIBRARY_DIRS})
    file(GLOB_RECURSE LIBRARY_FILES_TMP "${LIBRARY_DIR_H}/*.h")
    list(APPEND LIBRARY_FILES ${LIBRARY_FILES_TMP})
endforeach()

# Collect library (c) files
foreach(LIBRARY_DIR_C ${LIBRARY_DIRS})
    file(GLOB_RECURSE LIBRARY_FILES_TMP "${LIBRARY_DIR_C}/*.c")
    list(APPEND LIBRARY_FILES ${LIBRARY_FILES_TMP})
endforeach()

# Include directories
include_directories(${HEADER_DIRS})
include_directories(${LIBRARY_DIRS})

project(${CMAKE_PROJECT_NAME})

# Add an executable target
add_executable(
    ${PROJECT_NAME} 
    ${STARTUP_FILE}
    ${SOURCE_FILES} 
    ${HEADER_FILES}
    ${LIBRARY_FILES})

gcc-arm-none-eabi.cmake cmake file:

set(CMAKE_SYSTEM_NAME               Generic)
set(CMAKE_SYSTEM_PROCESSOR          arm)

set(CMAKE_C_COMPILER_FORCED TRUE)
set(CMAKE_CXX_COMPILER_FORCED TRUE)
set(CMAKE_C_COMPILER_ID GNU)
set(CMAKE_CXX_COMPILER_ID GNU)

# Some default GCC settings
# arm-none-eabi- must be part of path environment
set(TOOLCHAIN_PREFIX                arm-none-eabi-)

set(CMAKE_C_COMPILER                ${TOOLCHAIN_PREFIX}gcc)
set(CMAKE_ASM_COMPILER              ${CMAKE_C_COMPILER})
set(CMAKE_CXX_COMPILER              ${TOOLCHAIN_PREFIX}g++)
set(CMAKE_LINKER                    ${TOOLCHAIN_PREFIX}g++)
set(CMAKE_OBJCOPY                   ${TOOLCHAIN_PREFIX}objcopy)
set(CMAKE_SIZE                      ${TOOLCHAIN_PREFIX}size)

set(CMAKE_EXECUTABLE_SUFFIX_ASM     ".elf")
set(CMAKE_EXECUTABLE_SUFFIX_C       ".elf")
set(CMAKE_EXECUTABLE_SUFFIX_CXX     ".elf")

set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

# MCU specific flags
set(TARGET_FLAGS "-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard ")

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${TARGET_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wpedantic -fdata-sections -ffunction-sections")
if(CMAKE_BUILD_TYPE MATCHES Debug)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -g3")
endif()
if(CMAKE_BUILD_TYPE MATCHES Release)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Os -g0")
endif()

set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp -MMD -MP")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -fno-threadsafe-statics")

set(CMAKE_C_LINK_FLAGS "${TARGET_FLAGS}")
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -T \"${CMAKE_SOURCE_DIR}/STM32F411RETx_FLASH.ld\"")
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} --specs=nano.specs")
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Wl,--gc-sections")
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group -lc -lm -Wl,--end-group")
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--print-memory-usage")

set(CMAKE_CXX_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group -lstdc++ -lsupc++ -Wl,--end-group")

startup_stm32f411xe.s startup file:

/**
  ******************************************************************************
  * @file      startup_stm32f411xe.s
  * @author    MCD Application Team
  * @brief     STM32F411xExx Devices vector table for GCC based toolchains. 
  *            This module performs:
  *                - Set the initial SP
  *                - Set the initial PC == Reset_Handler,
  *                - Set the vector table entries with the exceptions ISR address
  *                - Branches to main in the C library (which eventually
  *                  calls main()).
  *            After Reset the Cortex-M4 processor is in Thread mode,
  *            priority is Privileged, and the Stack is set to Main.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2017 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
    
  .syntax unified
  .cpu cortex-m4
  .fpu softvfp
  .thumb

.global  g_pfnVectors
.global  Default_Handler

/* start address for the initialization values of the .data section. 
defined in linker script */
.word  _sidata
/* start address for the .data section. defined in linker script */  
.word  _sdata
/* end address for the .data section. defined in linker script */
.word  _edata
/* start address for the .bss section. defined in linker script */
.word  _sbss
/* end address for the .bss section. defined in linker script */
.word  _ebss
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */

/**
 * @brief  This is the code that gets called when the processor first
 *          starts execution following a reset event. Only the absolutely
 *          necessary set is performed, after which the application
 *          supplied main() routine is called. 
 * @param  None
 * @retval : None
*/

    .section  .text.Reset_Handler
  .weak  Reset_Handler
  .type  Reset_Handler, %function
Reset_Handler:  
  ldr   sp, =_estack             /* set stack pointer */

/* Call the clock system initialization function.*/
  bl  SystemInit   

/* Copy the data segment initializers from flash to SRAM */  
  ldr r0, =_sdata
  ldr r1, =_edata
  ldr r2, =_sidata
  movs r3, #0
  b LoopCopyDataInit

CopyDataInit:
  ldr r4, [r2, r3]
  str r4, [r0, r3]
  adds r3, r3, #4

LoopCopyDataInit:
  adds r4, r0, r3
  cmp r4, r1
  bcc CopyDataInit
  
/* Zero fill the bss segment. */
  ldr r2, =_sbss
  ldr r4, =_ebss
  movs r3, #0
  b LoopFillZerobss

FillZerobss:
  str  r3, [r2]
  adds r2, r2, #4

LoopFillZerobss:
  cmp r2, r4
  bcc FillZerobss

/* Call static constructors */
    bl __libc_init_array
/* Call the application's entry point.*/
  bl  main
  bx  lr    
.size  Reset_Handler, .-Reset_Handler

/**
 * @brief  This is the code that gets called when the processor receives an 
 *         unexpected interrupt.  This simply enters an infinite loop, preserving
 *         the system state for examination by a debugger.
 * @param  None     
 * @retval None       
*/
    .section  .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
  b  Infinite_Loop
  .size  Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex M3. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
* 
*******************************************************************************/
   .section  .isr_vector,"a",%progbits
  .type  g_pfnVectors, %object
    
g_pfnVectors:
  
  **Note some .word declarations were removed to meat the maximum word count.
                   
  .word     USART2_IRQHandler                 /* USART2                       */                   
  .word     0                                 /* Reserved                       */                   
  .word     EXTI15_10_IRQHandler              /* External Line[15:10]s        */                          
  .word     RTC_Alarm_IRQHandler              /* RTC Alarm (A and B) through EXTI Line */                 
  .word     OTG_FS_WKUP_IRQHandler            /* USB OTG FS Wakeup through EXTI line */                       
  .word     0                                 /* Reserved                     */         
  .word     0                                 /* Reserved                     */         
  .word     0                                 /* Reserved                     */
  .word     0                                 /* Reserved                     */                          
  .word     DMA1_Stream7_IRQHandler           /* DMA1 Stream7                 */                          
  .word     0                                 /* Reserved                     */                   
  .word     SDIO_IRQHandler                   /* SDIO                         */                   
  .word     TIM5_IRQHandler                   /* TIM5                         */                   
  .word     SPI3_IRQHandler                   /* SPI3                         */                   
  .word     0                                 /* Reserved                     */                   
  .word     0                                 /* Reserved                     */                   
  .word     0                                 /* Reserved                     */                   
  .word     0                                 /* Reserved                     */
  .word     DMA2_Stream0_IRQHandler           /* DMA2 Stream 0                */                   
  .word     DMA2_Stream1_IRQHandler           /* DMA2 Stream 1                */                   
  .word     DMA2_Stream2_IRQHandler           /* DMA2 Stream 2                */                   
  .word     DMA2_Stream3_IRQHandler           /* DMA2 Stream 3                */                   
  .word     DMA2_Stream4_IRQHandler           /* DMA2 Stream 4                */                   
  .word     0                                 /* Reserved                     */                   
  .word     0                                 /* Reserved                     */                     
  .word     0                                 /* Reserved                     */                          
  .word     0                                 /* Reserved                     */                          
  .word     0                                 /* Reserved                     */                          
  .word     0                                 /* Reserved                     */                          
  .word     OTG_FS_IRQHandler                 /* USB OTG FS                   */                   
  .word     DMA2_Stream5_IRQHandler           /* DMA2 Stream 5                */                   
  .word     DMA2_Stream6_IRQHandler           /* DMA2 Stream 6                */                   
  .word     DMA2_Stream7_IRQHandler           /* DMA2 Stream 7                */                   
  .word     USART6_IRQHandler                 /* USART6                       */                    
  .word     I2C3_EV_IRQHandler                /* I2C3 event                   */                          
  .word     I2C3_ER_IRQHandler                /* I2C3 error                   */                          
  .word     0                                 /* Reserved                     */                   
  .word     0                                 /* Reserved                     */                   
  .word     0                                 /* Reserved                     */                         
  .word     0                                 /* Reserved                     */                   
  .word     0                                 /* Reserved                     */                   
  .word     0                                 /* Reserved                     */                   
  .word     0                                 /* Reserved                     */
  .word     FPU_IRQHandler                    /* FPU                          */
  .word     0                                 /* Reserved                     */                   
  .word     0                                 /* Reserved                     */
  .word     SPI4_IRQHandler                   /* SPI4                         */
  .word     SPI5_IRQHandler                   /* SPI5                         */  
                    

  .size  g_pfnVectors, .-g_pfnVectors

/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler. 
* As they are weak aliases, any function with the same name will override 
* this definition.
* 
*******************************************************************************/
   .weak      NMI_Handler
   .thumb_set NMI_Handler,Default_Handler
  
   .weak      HardFault_Handler
   .thumb_set HardFault_Handler,Default_Handler
  
   .weak      MemManage_Handler
   .thumb_set MemManage_Handler,Default_Handler
  
   .weak      BusFault_Handler
   .thumb_set BusFault_Handler,Default_Handler

   .weak      UsageFault_Handler
   .thumb_set UsageFault_Handler,Default_Handler

   .weak      SVC_Handler
   .thumb_set SVC_Handler,Default_Handler

   .weak      DebugMon_Handler
   .thumb_set DebugMon_Handler,Default_Handler

   .weak      PendSV_Handler
   .thumb_set PendSV_Handler,Default_Handler

   .weak      SysTick_Handler
   .thumb_set SysTick_Handler,Default_Handler              
  
   .weak      WWDG_IRQHandler                   
   .thumb_set WWDG_IRQHandler,Default_Handler      
                  
   .weak      PVD_IRQHandler      
   .thumb_set PVD_IRQHandler,Default_Handler
               
   .weak      TAMP_STAMP_IRQHandler            
   .thumb_set TAMP_STAMP_IRQHandler,Default_Handler
            
   .weak      RTC_WKUP_IRQHandler                  
   .thumb_set RTC_WKUP_IRQHandler,Default_Handler
            
   .weak      FLASH_IRQHandler         
   .thumb_set FLASH_IRQHandler,Default_Handler
                  
   .weak      RCC_IRQHandler      
   .thumb_set RCC_IRQHandler,Default_Handler
                  
   .weak      EXTI0_IRQHandler         
   .thumb_set EXTI0_IRQHandler,Default_Handler
                  
   .weak      EXTI1_IRQHandler         
   .thumb_set EXTI1_IRQHandler,Default_Handler
                     
   .weak      EXTI2_IRQHandler         
   .thumb_set EXTI2_IRQHandler,Default_Handler 
                 
   .weak      EXTI3_IRQHandler         
   .thumb_set EXTI3_IRQHandler,Default_Handler
                        
   .weak      EXTI4_IRQHandler         
   .thumb_set EXTI4_IRQHandler,Default_Handler
                  
   .weak      DMA1_Stream0_IRQHandler               
   .thumb_set DMA1_Stream0_IRQHandler,Default_Handler
         
   .weak      DMA1_Stream1_IRQHandler               
   .thumb_set DMA1_Stream1_IRQHandler,Default_Handler
                  
   .weak      DMA1_Stream2_IRQHandler               
   .thumb_set DMA1_Stream2_IRQHandler,Default_Handler
                  
   .weak      DMA1_Stream3_IRQHandler               
   .thumb_set DMA1_Stream3_IRQHandler,Default_Handler 
                 
   .weak      DMA1_Stream4_IRQHandler              
   .thumb_set DMA1_Stream4_IRQHandler,Default_Handler
                  
   .weak      DMA1_Stream5_IRQHandler               
   .thumb_set DMA1_Stream5_IRQHandler,Default_Handler
                  
   .weak      DMA1_Stream6_IRQHandler               
   .thumb_set DMA1_Stream6_IRQHandler,Default_Handler
                  
   .weak      ADC_IRQHandler      
   .thumb_set ADC_IRQHandler,Default_Handler
            
   .weak      EXTI9_5_IRQHandler   
   .thumb_set EXTI9_5_IRQHandler,Default_Handler
            
   .weak      TIM1_BRK_TIM9_IRQHandler            
   .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler
            
   .weak      TIM1_UP_TIM10_IRQHandler            
   .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
      
   .weak      TIM1_TRG_COM_TIM11_IRQHandler      
   .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler
      
   .weak      TIM1_CC_IRQHandler   
   .thumb_set TIM1_CC_IRQHandler,Default_Handler
                  
   .weak      TIM2_IRQHandler            
   .thumb_set TIM2_IRQHandler,Default_Handler
                  
   .weak      TIM3_IRQHandler            
   .thumb_set TIM3_IRQHandler,Default_Handler
                  
   .weak      TIM4_IRQHandler            
   .thumb_set TIM4_IRQHandler,Default_Handler
                  
   .weak      I2C1_EV_IRQHandler   
   .thumb_set I2C1_EV_IRQHandler,Default_Handler
                     
   .weak      I2C1_ER_IRQHandler   
   .thumb_set I2C1_ER_IRQHandler,Default_Handler
                     
   .weak      I2C2_EV_IRQHandler   
   .thumb_set I2C2_EV_IRQHandler,Default_Handler
                  
   .weak      I2C2_ER_IRQHandler   
   .thumb_set I2C2_ER_IRQHandler,Default_Handler
                           
   .weak      SPI1_IRQHandler            
   .thumb_set SPI1_IRQHandler,Default_Handler
                        
   .weak      SPI2_IRQHandler            
   .thumb_set SPI2_IRQHandler,Default_Handler
                  
   .weak      USART1_IRQHandler      
   .thumb_set USART1_IRQHandler,Default_Handler
                     
   .weak      USART2_IRQHandler      
   .thumb_set USART2_IRQHandler,Default_Handler
                                  
   .weak      EXTI15_10_IRQHandler               
   .thumb_set EXTI15_10_IRQHandler,Default_Handler
               
   .weak      RTC_Alarm_IRQHandler               
   .thumb_set RTC_Alarm_IRQHandler,Default_Handler
            
   .weak      OTG_FS_WKUP_IRQHandler         
   .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
            
   .weak      DMA1_Stream7_IRQHandler               
   .thumb_set DMA1_Stream7_IRQHandler,Default_Handler
                     
   .weak      SDIO_IRQHandler            
   .thumb_set SDIO_IRQHandler,Default_Handler
                     
   .weak      TIM5_IRQHandler            
   .thumb_set TIM5_IRQHandler,Default_Handler
                     
   .weak      SPI3_IRQHandler            
   .thumb_set SPI3_IRQHandler,Default_Handler
                     
   .weak      DMA2_Stream0_IRQHandler               
   .thumb_set DMA2_Stream0_IRQHandler,Default_Handler
               
   .weak      DMA2_Stream1_IRQHandler               
   .thumb_set DMA2_Stream1_IRQHandler,Default_Handler
                  
   .weak      DMA2_Stream2_IRQHandler               
   .thumb_set DMA2_Stream2_IRQHandler,Default_Handler
            
   .weak      DMA2_Stream3_IRQHandler               
   .thumb_set DMA2_Stream3_IRQHandler,Default_Handler
            
   .weak      DMA2_Stream4_IRQHandler               
   .thumb_set DMA2_Stream4_IRQHandler,Default_Handler
            
   .weak      OTG_FS_IRQHandler      
   .thumb_set OTG_FS_IRQHandler,Default_Handler
                     
   .weak      DMA2_Stream5_IRQHandler               
   .thumb_set DMA2_Stream5_IRQHandler,Default_Handler
                  
   .weak      DMA2_Stream6_IRQHandler               
   .thumb_set DMA2_Stream6_IRQHandler,Default_Handler
                  
   .weak      DMA2_Stream7_IRQHandler               
   .thumb_set DMA2_Stream7_IRQHandler,Default_Handler
                  
   .weak      USART6_IRQHandler      
   .thumb_set USART6_IRQHandler,Default_Handler
                        
   .weak      I2C3_EV_IRQHandler   
   .thumb_set I2C3_EV_IRQHandler,Default_Handler
                        
   .weak      I2C3_ER_IRQHandler   
   .thumb_set I2C3_ER_IRQHandler,Default_Handler
                        
   .weak      FPU_IRQHandler                  
   .thumb_set FPU_IRQHandler,Default_Handler  

   .weak      SPI4_IRQHandler                  
   .thumb_set SPI4_IRQHandler,Default_Handler

   .weak      SPI5_IRQHandler                  
   .thumb_set SPI5_IRQHandler,Default_Handler    

my main.c file:

#include <stdint.h>

// Start address in memory for each GPIO registers
//------------------------------------------------
#define GPIO_PORT_A             0x40020000
#define GPIO_PORT_B             0x40020400
#define GPIO_PORT_C             0x40020800
#define GPIO_PORT_D             0x40020C00
#define GPIO_PORT_E             0x40021000
#define GPIO_PORT_H             0x40021400


// Offset for each GPIO set-up register
//-------------------------------------
#define GPIOx_MODER_OFFSET      0x00
#define GPIOx_OTYPER_OFFSET     0x04
#define GPIOx_OSPEEDR_OFFSET    0x08
#define GPIOx_PUPDR_OFFSET      0x0C
#define GPIOx_IDR_OFFSET        0x10
#define GPIOx_ODR_OFFSET        0x14
#define GPIOx_BSRR_OFFSET       0x18
#define GPIOx_LCKR_OFFSET       0x1C
#define GPIOx_AFRL_OFFSET       0x20
#define GPIOx_AFRH_OFFSET       0x24


// Pin numbers that can be used
//-----------------------------
#define PIN_0                   0x00
#define PIN_1                   0x01
#define PIN_2                   0x02
#define PIN_3                   0x03
#define PIN_4                   0x04
#define PIN_5                   0x05
#define PIN_6                   0x06
#define PIN_7                   0x07
#define PIN_8                   0x08
#define PIN_9                   0x09
#define PIN_10                  0x0A
#define PIN_11                  0x0B
#define PIN_12                  0x0C
#define PIN_13                  0x0D
#define PIN_14                  0x0E
#define PIN_15                  0x0F


// Different pin modes to select
//------------------------------
#define OUT_OPEN_DRAIN          0x0 // Digital output with open drain
#define OUT_PUSH_PULL           0x1 // Digital output with push-pull 
#define IN_PULL_UP              0x2 // Digital input with pull up resistor
#define IN_PULL_DOWN            0x3 // Digital input with pull down resistor
#define IN_R_NONE               0x4 // Digital input without pull up or down resistor


void GPIOx_SETUP (uint32_t, uint8_t, uint8_t);
void Drive_Pin_High(uint32_t, uint8_t);

// Set pin as push-pull output
void __Set_Out_Push_Pull (uint32_t port, uint8_t pin) {
    *(volatile unsigned int *)(port + GPIOx_MODER_OFFSET)   |=  (1UL << (pin * 2));
    *(volatile unsigned int *)(port + GPIOx_OTYPER_OFFSET)  |=  (0UL << pin);
    *(volatile unsigned int *)(port + GPIOx_OSPEEDR_OFFSET) |=  (1UL << (pin * 2));
    *(volatile unsigned int *)(port + GPIOx_PUPDR_OFFSET)   &=  ~(3UL << (pin * 2));
}

// Drive output pin high
void Drive_Pin_High(uint32_t port, uint8_t pin) {
    *(volatile unsigned int *)(port + GPIOx_ODR_OFFSET) |= (1UL << pin);
}

// Setup induvidual pin
void GPIOx_SETUP (uint32_t port, uint8_t pin, uint8_t mode) {
    switch (mode) {
        case OUT_PUSH_PULL:
            __Set_Out_Push_Pull (port, pin);
            break;
    }
}

/** @note:
 * This function us used to initiate certain system parameters
 * such as the system clock and certain other perepherals
 * */
void SystemInit (void) { // This funtion had te be added because the startup file required it
   // For now use startup clock settings
}

int main (void) {  
    SystemInit();  
    GPIOx_SETUP(GPIO_PORT_A, PIN_5, OUT_PUSH_PULL);
    Drive_Pin_High(GPIO_PORT_A, PIN_5);
    
    while (1) {
        // NOP for now
    }

    return 0;
}

Note, all the c code was added into a single file to make it easier to read.

Unfortunately, I have no erros to show, because I do not get any during any of the above mentioned steps.


Solution

  • Your GPIO initialisation is incomplete. Nothing enables the GPIOA peripheral clock:

    enter image description here

    [...]

    enter image description here

    You need to do that before you can access any of the GPIOA registers.

    While there are many reasons to avoid ST's HAL and STM32Cube ecosystem in general, I would suggest that you at least use the vendor provided processor register header (not strictly part of the HAL). Defining your own is laborious and error prone.

    In this case stm32f4xx.h, but to ensure that works with your specific part you need a global definition of STM32F411xE so modify your target flags thus:

    set(TARGET_FLAGS "-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -DSTM32F411xE ")
    

    Then setting the GPIOAEN bit is done thus:

    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN ;
    

    and where you have:

    void __Set_Out_Push_Pull (uint32_t port, uint8_t pin) {
        *(volatile unsigned int *)(port + GPIOx_MODER_OFFSET)   |=  (1UL << (pin * 2));
        *(volatile unsigned int *)(port + GPIOx_OTYPER_OFFSET)  |=  (0UL << pin);
        *(volatile unsigned int *)(port + GPIOx_OSPEEDR_OFFSET) |=  (1UL << (pin * 2));
        *(volatile unsigned int *)(port + GPIOx_PUPDR_OFFSET)   &=  ~(3UL << (pin * 2));
    }
    

    for example; you could write:

    void Set_Out_Push_Pull( GPIO_TypeDef* port, uint8_t pin) 
    {
        port->MODER |= (1UL << (pin * 2)) ;
        port->OTYPER |=  (0UL << pin);
        port->OSPEEDR |=  (1UL << (pin * 2));
        port->PUPDR  &=  ~(3UL << (pin * 2));
    }
    

    replacing GPIO_PORT_A with the vendor defined PORTA or changing your GPIO_PORT_A definition to:

    #define GPIO_PORT_A             PORTA
    

    if you prefer your more verbose naming as an alias.

    You'll get further, faster with fewer errors that way. Otherwise every time you post a question to SO, anybody answering will have to spend time trying to determine whether your register definitions are correct.