We probably need more information to fully help. However, ...
The 'reset value' of 0x44444444 is the value the registers are set to when the hardware is reset. It is not necessarily the port configuration value which you need.
See RM008 Reference manual ... STM32F103xx ... advanced ARM-based 32-bit MCUs Section 9.2
The code is setting all of the port pins to:
"CNFy: 01: Floating input (reset state)"
"MODEy: 00: Input mode (reset state)"
So all pins except the bottom three are set for input, with no specific pull-up or pull-down. Hence a pin connected to a signal, or holding a random charge could be at either 0 or 1.
It is normal to mask off the data from unused pins of a port so that only the values needed are used. This helps if, for example, your hardware is changed and new pins become active for some other purpose.
I mask the IDR, so that only the value for pins that are active inputs are used, before using the port-input-data-register value.
You might consider setting the pull-down resistor on all other pins to make it easier to see what is happening to the active ins. However, that has some risk; for example if those input pins get connected to a high-signal or Vcc.
If you look at the source code for the standard peripheral library, it will show a sequence of registers accesses which do correctly initialise it.
That might provide enough insight for you to continue your learning.
Possibly easier to read is the Leaflabs libmaple source for the Maple STM32F103 development board.
Or dig through stm32duino.com, who are working on their update to libmample.
Or look at a port of libmaple by an LeafLabs ex-staffer at rambutan.cc
EDIT:
when you set the CRL bits to '8=1000(input pull-down)' did you also set the ODR register to 0? According to table 20 in section 9.1, the ODR determines whether the resitor is a pull-down or a pull-up.
EDIT2:
Well done! A good piece of detective work.
The JTAG pins (PA13, PA14, PA15, PB3, PB4) can be freed up for normal GPIO use by setting a value in AFIO_MAPR, but I would tend to leave those pins as JTAG/SWJ-DP.
AFAIK PA11 and PA12 are ordinary pins, so if CAN, USB, TIM1 and USART1 are not used, they are available for normal GPIO.
Best Answer
The Datasheet contains the external description of the MCU, i.e. pin mappings, electrical characteristics, package dimensions.
The register descriptions are in the reference manual, that's where the function of each bit in each peripheral register is explained.
Then there is a programming manual where the ARM core is described, including the core peripheral registers like the interrupt controller or the SysTick timer.
Each usable register bit has a definition in the CMSIS header for your controller. They have predictable names, e.g. to set the
PE
bit of theCR1
register on the first I2C controller, you can writeGPIO data register bits have their definitions in the CMSIS header too, using the same convention as above, so it's possible to write
You can of course assume that the layout of the bits are the same across the
IDR
,ODR
andBSRR
registers, and use the simplifiedGPIO_PIN_2
definition from the HAL headers.You can use the
GPIOx->BSRR
register to set and reset some pins without bitwise instructions, e.g. to set PA2, reset PA4, and let the rest of the pins alone, doit comes handy when some pins of a GPIO port are controlled by interrupt handlers, and others by the main code.
Sure, I mix these approaches all the time. Just mind that whenever you re-generate the code from CubeMX, everything outside the
USER CODE BEGIN
/USER CODE END
blocks will be overwritten. Once you got the HAL part right, the code is all yours.The HAL driver for each peripheral is self-contained, you can even use HAL functions for one peripheral, LL for another, StdPeriph for the third, and direct register access for the fourth, or initialize one peripheral with HAL and access it through registers afterwards. (I had an actual project where some peripherals were initialized by HAL, legacy code taken from older code used StdPeriph, and new code accessed the registers directly)