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.
Your GPIO initialisation is incomplete. Nothing enables the GPIOA peripheral clock:
[...]
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.