2016-06-01 07:19 AM
I am working with the STM32F405/STM32F407 microcontrollers.I am trying to understand what's happening inside the microcontroller before main() is called and I would like to get rid of as much as possible to minimize risk that something is happening ''behind my back''.I don't plan to use the HAL-layer much, but I think it's useful for small tasks such as initializing GPIO-pins, timers, UART:s, etc because of the type safeness with struct and enums. I do not plan to use any sort of realtime operating system and I don't want the HAL to keep track of what resources are in use for me, I will do that myself.My HSE_VALUE is defined to 0 and HSI_VALUE is defined to 16000000 and I want to use internal clock.Below I have tried to write down what is being called when the microcontroller is powered-up and I would like to know what is safe to remove. For sure I don't like rows 053-057, I mean is the microcontroller using a timer and ''ticking'' every 1 ms!?!?! Anything else I can rid of?
001 __initialize_hardware_early()
002
003
void
SystemInit(
void
)
004 {
005
/* Reset the RCC clock configuration to the default reset state ------------*/
006
/* Set HSION bit */
007 RCC->CR |= (uint32_t)0x00000001;
008
009
/* Reset CFGR register */
010 RCC->CFGR = 0x00000000;
011
012
/* Reset HSEON, CSSON and PLLON bits */
013 RCC->CR &= (uint32_t)0xFEF6FFFF;
014
015
/* Reset PLLCFGR register */
016 RCC->PLLCFGR = 0x24003010;
017
018
/* Reset HSEBYP bit */
019 RCC->CR &= (uint32_t)0xFFFBFFFF;
020
021
/* Disable all interrupts */
022 RCC->CIR = 0x00000000;
023
024
/* Configure the Vector Table location add offset address ------------------*/
025 SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
/* Vector Table Relocation in Internal FLASH */
026 }
027
028 #
if
defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
029
// Set VTOR to the actual address, provided by the linker script.
030
// Override the manual, possibly wrong, SystemInit() setting.
031 SCB->VTOR = (uint32_t)(&__vectors_start);
032 #endif
033
034
void
__initialize_hardware(
void
)
035 {
036
// Initialise the HAL Library; it must be the first function
037
// to be executed before the call of any HAL function.
038 HAL_StatusTypeDef HAL_Init(
void
)
039 {
040
/* Configure Flash prefetch, Instruction cache, Data cache */
041 #
if
(INSTRUCTION_CACHE_ENABLE != 0U)
042 __HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
043 #endif
/* INSTRUCTION_CACHE_ENABLE */
044
045 #
if
(DATA_CACHE_ENABLE != 0U)
046 __HAL_FLASH_DATA_CACHE_ENABLE();
047 #endif
/* DATA_CACHE_ENABLE */
048
049 #
if
(PREFETCH_ENABLE != 0U)
050 __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
051 #endif
/* PREFETCH_ENABLE */
052
053
/* Set Interrupt Group Priority */
054 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
055
056
/* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
057 HAL_InitTick(TICK_INT_PRIORITY);
058
059
/* Init the low level hardware */
060 HAL_MspInit();
061
062
/* Return function status */
063
return
HAL_OK;
064 }
065
066
// Enable HSE Oscillator and activate PLL with HSE as source
067
void
__attribute__((weak)) SystemClock_Config(
void
)
068 {
069
// Enable Power Control clock
070 __PWR_CLK_ENABLE();
071
072
// The voltage scaling allows optimizing the power consumption when the
073
// device is clocked below the maximum system frequency, to update the
074
// voltage scaling value regarding system frequency refer to product
075
// datasheet.
076 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
077
078 #warning
''Please check if the SystemClock_Config() settings match your board!''
079
// Comment out the warning after checking and updating.
080
081 RCC_OscInitTypeDef RCC_OscInitStruct;
082
083
// Use HSI and activate PLL with HSI as source.
084
// This is tuned for NUCLEO-F411; update it for your board.
085 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
086 RCC_OscInitStruct.HSIState = RCC_HSI_ON;
087
// 16 is the average calibration value, adjust for your own board.
088 RCC_OscInitStruct.HSICalibrationValue = 16;
089 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
090
// This assumes the HSI_VALUE is a multiple of 1 MHz. If this is not
091
// your case, you have to recompute these PLL constants.
092 RCC_OscInitStruct.PLL.PLLM = (HSI_VALUE/1000000u);
093
094 RCC_OscInitStruct.PLL.PLLN = 336;
095 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
/* 168 MHz */
096 RCC_OscInitStruct.PLL.PLLQ = 7;
/* To make USB work. */
097 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
098 HAL_RCC_OscConfig(&RCC_OscInitStruct);
099
100 RCC_ClkInitTypeDef RCC_ClkInitStruct;
101
// Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
102
// clocks dividers
103 RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK
104 | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
105 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
106
// This is expected to work for most large cores.
107
// Check and update it for your own configuration.
108 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
109 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
110 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
111 HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
112
113 HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
114
115 HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
116 }
117
118
119
// Call the CSMSIS system clock routine to store the clock frequency
120
// in the SystemCoreClock global RAM location.
121
void
SystemCoreClockUpdate(
void
)
122 {
123 uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
124
125
/* Get SYSCLK source -------------------------------------------------------*/
126 tmp = RCC->CFGR & RCC_CFGR_SWS;
127
128
switch
(tmp)
129 {
130
case
0x00:
/* HSI used as system clock source */
131 SystemCoreClock = HSI_VALUE;
132
break
;
133
case
0x04:
/* HSE used as system clock source */
134 SystemCoreClock = HSE_VALUE;
135
break
;
136
case
0x08:
/* PLL used as system clock source */
137
138
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
139 SYSCLK = PLL_VCO / PLL_P
140 */
141 pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
142 pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
143
144
if
(pllsource != 0)
145 {
146
/* HSE used as PLL clock source */
147 pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
148 }
149
else
150 {
151
/* HSI used as PLL clock source */
152 pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
153 }
154
155 pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
156 SystemCoreClock = pllvco/pllp;
157
break
;
158
default
:
159 SystemCoreClock = HSI_VALUE;
160
break
;
161 }
162
/* Compute HCLK frequency --------------------------------------------------*/
163
/* Get HCLK prescaler */
164 tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
165
/* HCLK frequency */
166 SystemCoreClock >>= tmp;
167 }
168 }
2016-06-01 08:28 AM
The model is that SystemInit() is called to initialize the clocks to operating speed, and any pins, interfaces, and external memory chips that the C code is going to use. ie what you described as regions and load regions in the scatter file or linker script.
Then prior to calling main() the C runtime code initializes the statics, ie the variables you have created, either with zeros or specific values, int global = 1232016-06-02 12:48 AM
What can I remove from HAL_Init()? I would like to throw it out altogether, but it seems dangerous to fiddle with cache and pre-fetch things. Under all circumstances I must not have a timer waking the microcontroller up ever so often doing ''ticks'' in the background!!!
036
// Initialise the HAL Library; it must be the first function
037
// to be executed before the call of any HAL function.
038 HAL_StatusTypeDef HAL_Init(
void
)
039 {
040
/* Configure Flash prefetch, Instruction cache, Data cache */
041 #
if
(INSTRUCTION_CACHE_ENABLE != 0U)
042 __HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
043 #endif
/* INSTRUCTION_CACHE_ENABLE */
044
045 #
if
(DATA_CACHE_ENABLE != 0U)
046 __HAL_FLASH_DATA_CACHE_ENABLE();
047 #endif
/* DATA_CACHE_ENABLE */
048
049 #
if
(PREFETCH_ENABLE != 0U)
050 __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
051 #endif
/* PREFETCH_ENABLE */
052
053
/* Set Interrupt Group Priority */
054 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
055
056
/* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
057 HAL_InitTick(TICK_INT_PRIORITY);
058
059
/* Init the low level hardware */
060 HAL_MspInit();
061
062
/* Return function status */
063
return
HAL_OK;
064 }
2016-06-02 03:02 AM
> What can I remove from HAL_Init()?
Everything. > I would like to throw it out altogether, but it seems dangerous to fiddle with cache and pre-fetch things. Why? There is no magic in them. Read the user manual.#define XTAL_FREQ 12
int main(void) { RCC->CR |= ((uint32_t)RCC_CR_HSEON); // enable HSE while((RCC->CR & RCC_CR_HSERDY) == 0); // wait until up // before firing up PLL, one word of caution: the VOS bit in PWR_CR register must be 1 for fSYS>144MHz // that's the reset value so there's no need to change it here (VOS=0 brings some 10% reduction in power consumption between 30MHz-144MHz) // if we'd need to change it, the power module's clock would have to be fired up, too - see the STM-supplied ''systemInit'' code RCC->CFGR |= RCC_CFGR_HPRE_DIV1 // AHB prescaler set to 1 -> AHB clock = 160MHz | RCC_CFGR_PPRE1_DIV4 // APB1 prescaler set to 4 -> APB1 clock = 40MHz (required to be < 42MHz) | RCC_CFGR_PPRE2_DIV2; // APB2 prescaler set to 2 -> APB2 clock = 80MHz (required to be < 84MHz) RCC->PLLCFGR = ( XTAL_FREQ * RCC_PLLCFGR_PLLM_0) // M = XTAL divider - the PLL needs 1MHz to 2MHz at its input | (( 160 * 2) * RCC_PLLCFGR_PLLN_0) // N = PLL multiplier (feedback divider) - the VCO's output needs to fall between 64MHz and 432MHz // | (0 * RCC_PLLCFGR_PLLP_0) // P = divider for SYSCLK - 0 = /2, 1 = /4, 2 = /6, 3 = /8 | (1 * RCC_PLLCFGR_PLLP_0) // P = divider for SYSCLK - 0 = /2, 1 = /4, 2 = /6, 3 = /8 | (7 * RCC_PLLCFGR_PLLQ_0) // Q = divider for USB (and SDIO and RNG), should result in 48MHz but that's unattainable with this setup - we won't use it anyway - for SDIO and RNG it should be below 48MHz | (RCC_PLLCFGR_PLLSRC_HSE); // PLL source is HSE RCC->CR |= RCC_CR_PLLON; // fire up PLL while((RCC->CR & RCC_CR_PLLRDY) == 0); // and wait until up FLASH->ACR = 0 | FLASH_ACR_ICEN // meantime, configure flash for maximum performance - enable both caches | FLASH_ACR_DCEN | FLASH_ACR_PRFTEN // errata says this is ''unavailable'' for A-revision devices - should we selectively disable this through reading DBGMCU_IDCODE? | FLASH_ACR_LATENCY_5WS; // for VCC>2.7V and FSYS>144MHz, 5 waitstate is appropriate RCC->CFGR = (RCC->CFGR & (~(RCC_CFGR_SW))) | RCC_CFGR_SW_PLL; // switch clock source to PLL while ((RCC->CFGR & RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); // wait until switches // and that's it. This too was written with the assumption of the registers being at their reset value. JW2016-06-02 03:36 AM
After further investigations it seems (correct me if I'm wrong) the SysTick is needed for the HAL_Delay() function and this function is called in stm32f4xx_hal_eth.c, stm32f4xx_hal_sd.c and stm32f4xx_ll_usb.c. Since I don't use those files, I am very tempted to throw out the HAL altogether (not just the call to HAL_Init(), but all files as well), but the problem is that I am using STSW-STM32066 (EEPROM emulation in STM32F40x/STM32F41x microcontrollers (AN3969)) which is depending on HAL.