Place bootloader after the Application in Flash Memory - stm32

I wrote a Bootloader for my STM32F042k6 board that functions pretty well. On System Reset the Bootloader is launched and can later jump to the Application. That was great:). Now I wish to do the opposite in my Flash. I wish Launch my Bootloader at a start address other than 0x08000000 lets say at 0x08007000. When I do the modifications in the Linker Script the Programm cannot be debugged. In simple words I wish to place my bootloader at the end of my Flash. Without forget that the Bootloader is always the first Code to run after Reset. Thanks in advance for your help and comments
Here is my Linker Script:
/* Entry Point */
ENTRY(Boot_Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20001800; /* end of 6K RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0; /* required amount of heap */
_Min_Stack_Size = 0x80; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
BOOTLOADER (rx) : ORIGIN = 0x08007000, LENGTH = 4K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 28K
RAM (xrw) : ORIGIN = 0x200000C0, LENGTH = 6K - 192
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into BOOTLOADER */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >BOOTLOADER
/* The program code and other data goes into BOOTLOADER */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >BOOTLOADER
/* Constant data goes into BOOTLOADER */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >BOOTLOADER
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >BOOTLOADER
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >BOOTLOADER
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >BOOTLOADER
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >BOOTLOADER
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >BOOTLOADER
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> BOOTLOADER
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(4);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >RAM
/* MEMORY_bank1 section, code must be located here explicitly */
/* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */
.memory_b1_text :
{
*(.mb1text) /* .mb1text sections (code) */
*(.mb1text*) /* .mb1text* sections (code) */
*(.mb1rodata) /* read-only data (constants) */
*(.mb1rodata*)
} >MEMORY_B1
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}

You're out of luck I'm afraid, your processor will always start running code from the address 0x00000000 (sort of, it will look at 0x00000004 to see where the reset vector is).
There are a number of boot pins which change whether flash or RAM is aliased at address 0x00000000, but you can't choose which area of flash, it will always be 0x08000000 onwards. If you want to your custom bootloader, and have it be the first thing run, it needs to be at the start of flash.
What is the problem you're trying to solve by moving the bootloader? There is probably another possible solution.

I'm afraid you're looking after a solution for the wrong problem. Programs loaded by a bootloader can be debugged. I'm doing it all the time.
So something goes wrong before your application hits the first breakpoint set by the debugger.
A probably incomplete list of things to check
The bootloader does something that makes debugging impossible
disables the SWD pins
does not jump to the application reset handler
starts a watchdog
does not disable all possible interrupts
does not return to thread mode
wrong value in the stack pointer
loading the application in the debugger damages the bootloader
e.g. erases the wrong flash sectors
the application startup code fails
problem with the application linker script
sets wrong value in the stack pointer
sets wrong value in NVIC->VTOR - check this one first if you're using HAL

Normally, bootloader is the first piece of code that first executed. And with this way, it is not possible to relocate the bootloader to other memory partition.
However, there is another concept that able to relocate the bootloader to any memory address. That is the bootloader is only for update software later. With this approach, your main software will be the boot code. And when there is request to update, you jump to bootloader and do update software then reboot for normal operation. The drawback of this approach is that if the updated software fail, there isn't any recovery mechanism and you need to reflash by flashing tools.

The Microsoft Jacdac project places a bootloader in the last 4K of the STM32G0 flash, which has 32K to start with. I found this out the hard way when I tried to use the last page of flash for persistent storage.
The linker.ld file for the bootloader created during build has the content:
MEMORY {
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
FLASH (rx) : ORIGIN = 0x8000000 + 32K - 4K, LENGTH = 4K
}
INCLUDE jacdac-stm32x0/ld/gcc_arm_bl_at_end.ld
The file jacdac-jacdac-stm32x0/ld/gcc_arm_bl_at_end.ld can be found on GitHub at: https://github.com/microsoft/jacdac-stm32x0/blob/05f7b6913a0f6cfcd7a15252daff773ead2834da/ld/gcc_arm_bl_at_end.ld

Related

What could be the cause of a constant voltage offset on the STM32L041G6 adc

I have been testing the ADC on my STM32L0 with 12-bit resolution and for some reason, every measurement I take has a 0.048 V offset. I've tried a different supply voltage (from 1.8 V to 3.3 V), but the offset stays there.
This offset starts at the first count, when I apply 0 V to the ADC input and read 130 counts (with 1.8 V Vdda) it stays for the whole range.
My voltage source is very stable and I've verified my ADC input voltage and the STM32 supply voltage with 3 different accurate pieces of measuring equipment.
The voltage is applied to the circuit through a bnc connector connected to a signal generator, in my case I use the Dc output option with high impedance on a normal signal generator. As for the code, I used stm32cubemx to generate some of the code but I didn't use any calibration function, so unless it is enabled by default, I dont do any calibration. As for the adc pin, I just used cubemx to set-up IN0 as an adc input and didn't touch anything else. Then to read the adc, I used 2 hal function "HAL_ADC_START()" and "HAL_ADC_PollForConversion()". Then I send the result to be read by uart.
The board I'm using is a custom PCB, but I only placed the STM32 and some passive components to get it to function (coupling capacitors and reset pull-up).
I also tested multiple boards with different configurations and I always get this offset voltage. I outputed Vrefint and measured it, and I got 1.225 V (specified is 1.224 V) so the ADC reference seems fine too.
I was wondering if someone has a suggestion on the possible cause of this offset error? I've been looking for a solution but I'm having no luck so far, so I would really appreciate the input of more experienced developers.
Here is a simplified version of the code I use :
/* USER CODE BEGIN Header */
/**
******************************************************************************
* #file adc.c
* #brief This file provides code for the configuration
* of the ADC instances.
******************************************************************************
* #attention
*
* Copyright (c) 2022 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.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "adc.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
ADC_HandleTypeDef hadc;
/* ADC init function */
void MX_ADC_Init(void)
{
/* USER CODE BEGIN ADC_Init 0 */
/* USER CODE END ADC_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC_Init 1 */
/* USER CODE END ADC_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.OversamplingMode = DISABLE;
hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerFrequencyMode = ENABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC_Init 2 */
/* USER CODE END ADC_Init 2 */
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspInit 0 */
/* USER CODE END ADC1_MspInit 0 */
/* ADC1 clock enable */
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**ADC GPIO Configuration
PA0-CK_IN ------> ADC_IN0
*/
GPIO_InitStruct.Pin = SENSOR_ANALOG_IN_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(SENSOR_ANALOG_IN_GPIO_Port, &GPIO_InitStruct);
/* USER CODE BEGIN ADC1_MspInit 1 */
/* USER CODE END ADC1_MspInit 1 */
}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspDeInit 0 */
/* USER CODE END ADC1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_ADC1_CLK_DISABLE();
/**ADC GPIO Configuration
PA0-CK_IN ------> ADC_IN0
*/
/* USER CODE BEGIN ADC1_MspDeInit 1 */
/* USER CODE END ADC1_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
And here is the main file where I call the function to read the adc and send it to uart to be read :
#include "main.h"
#include "gpio.h"
#include "adc.h"
#include "usart.h"
#include <stdlib.h>
extern "C"
void execute(){
HAL_Delay(10);
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc, HAL_MAX_DELAY);
const auto value = HAL_ADC_GetValue(&hadc);
char buffer [5];
itoa(value, buffer, 10);
HAL_UART_Transmit(&huart2, reinterpret_cast<uint8_t*>(buffer), 5, HAL_MAX_DELAY);
}
Here is the schematic, as I said, the test circuit only had the mcu and some passive components : https://im.ge/i/FbQPIp

STM32H7 bank swap break at address 0x81006fe

I am trying to do a bank swap with the ST32 H743ZI2. I wasted much of time to fix it but I didn't get it. Maybe because I'm new in STM32 controllers.
I copied the bank swap code from STM32CubeH7 Firmware Examples and did a few modifications regarding to gpio configuration in CubeMX. I did them because I want to implicate the code in a existing project without the stm32h7xx_nucleo headers.
Following the Code for Bank1:
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();
while (1)
{
/* Wait for BUTTON_USER is released */
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == 1)
{
while (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == 1);
/* Get the Dual boot configuration status */
HAL_FLASHEx_OBGetConfig(&OBInit);
/* Get FLASH_WRP_SECTORS write protection status */
OBInit.Banks = FLASH_BANK_1;
HAL_FLASHEx_OBGetConfig(&OBInit);
/* Check Swap FLASH banks status */
if ((OBInit.USERConfig & OB_SWAP_BANK_ENABLE) == OB_SWAP_BANK_DISABLE)
{
/*Swap to bank2 */
/*Set OB SWAP_BANK_OPT to swap Bank2*/
OBInit.OptionType = OPTIONBYTE_USER;
OBInit.USERType = OB_USER_SWAP_BANK;
OBInit.USERConfig = OB_SWAP_BANK_ENABLE;
HAL_FLASHEx_OBProgram(&OBInit);
/* Launch Option bytes loading */
HAL_FLASH_OB_Launch();
/*
as the CPU is executing from the FLASH Bank1, and the I-Cache is enabled :
Instruction cache must be invalidated after bank switching to ensure that
CPU will fetch correct instructions from the FLASH.
*/
SCB_InvalidateICache();
HAL_NVIC_SystemReset();
}
else
{
/* Swap to bank1 */
/*Set OB SWAP_BANK_OPT to swap Bank1*/
OBInit.OptionType = OPTIONBYTE_USER;
OBInit.USERType = OB_USER_SWAP_BANK;
OBInit.USERConfig = OB_SWAP_BANK_DISABLE;
HAL_FLASHEx_OBProgram(&OBInit);
/* Launch Option bytes loading */
HAL_FLASH_OB_Launch();
/*
as the CPU is executing from the FLASH Bank1, and the I-Cache is enabled :
Instruction cache must be invalidated after bank switching to ensure that
CPU will fetch correct instructions from the FLASH.
*/
SCB_InvalidateICache();
}
}
else
{
#ifdef FLASH_BANK1
/* Toggle LED1 */
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
/*Turn Off LED2*/
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, 0);
#else
/* Toggle LED2 */
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_1);
/* Turn off LED1 */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, 0);
#endif
/* Insert 100 ms delay */
HAL_Delay(100);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
The code for bank1 and bank2 are equal except linkerscript.
I split Flash in two areas which have 1024kb each. In following you can see the code for bank1.
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}
In linkerscript for bank2 I changed flash start address to 0x08100000.
Now I have following problem. If I load in order code for bank1 and code for bank2 press the Button1 and Press the Resetbutton I get following error message:
Break at address "0x81006fe" with no debug information available, or outside of program code.
I already successfully checked if there is placed some code with STM32 Utility.
If I load the codes in reverse order the banks get swapped once. Independently if Button1 gets pressed before system reset or not..
I already checked some forums without success.
Does anyone know where the problem could be?
There were two problems in code.
Linker script was splited up in two parts. Linker script had to rebuild in original state regarding to flash. The code for bank2(0x081000000) needs to locate with an extern software like stm32 utility now.
Vector table was relocate at wrong address in system_stm32h7xx.c

STM32F103 Protect section of flash memory

I cannot protect the data in USER_FLASH when I disconnect the ST-Link, connect it and then program the microcontroller via OpenOCD.
I test it with the option (NOLOAD) in the linker script but the data always deleted.
STM32F103C8TX_FLASH.ld:
...
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 63K
USER_FLASH (xrw) : ORIGIN = 0x0800FC00, LENGTH = 1K
}
/* Sections */
SECTIONS
{
/* User data to be stored in the flash memory goes into USER_FLASH */
.user_data_flash (NOLOAD):
{
. = ALIGN(4);
*(.user_data_flash) /* .user_data_flash sections */
*(.user_data_flash*) /* .user_data_flash sections */
. = ALIGN(4);
} >USER_FLASH
...
The function works well while not disconnect the programmer:
void testFlash(void){
uint32_t temp = 0;
//writeFlash(test);
//Flash_Read_Data(0x0800FC00, temp);
temp = readFlashTest((uint32_t *)0x0800FC00);
temp = temp + 4;
writeFlash((uint32_t)temp);
}
uint32_t readFlashTest(uint32_t *mem){
uint32_t temp = 0;
HAL_FLASH_Unlock();
temp = *mem;
HAL_FLASH_Lock();
return temp;
} void writeFlash(uint32_t toWrite){
eraseFlash(); // Necesario si o si sino no escribe
HAL_FLASH_Unlock();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, 0x0800FC00, toWrite);
HAL_FLASH_Lock();
}
The solution is to set BOOT0 and BOOT1 to 1. This way, the boot mode is done from the Embedded SRAM, not from the Main Flash memory.

Why does trace_printf("%f",x); trigger a hard fault on an STM32 MCU?

I'm using an STM32 F413ZH microcontroller with HAL libraries (mainly written to be used with C, but can also be used with C++) in Eclipse. Actually I managed to completely configure Eclipse including semihosting and debug mode (OpenOCD), the basic project files and also I managed to manually adapt the basic project files given by STM32CubeMX to work with C++. So... now I can use HAL libraries in a C++ Eclipse environment and test my code via OpenOCD and trace_printf trace_puts using semihosting.
Now, again, after struggling too much setting up an STM32 environment, I find myself stuck, but this time is different.
These last seven days I have been looking for a solution to my problem, and I have tried many suggestions from similar issues online, but none of them has solved my problem.
Well, I'm facing a hard fault when using trace_printf() in semihosting while debugging. If I use this function to print an integer (%d) via semihosting everything is okay, and I can read the printed value in the OpenOCD console, but when I tried to print a value with the %f formatter the supposedly printed data wasn't being shown in the OpenOCD console.
Then I read that in order to enable the printing of floating point values I needed to add -u _printf_float to the linker flags, so after adding the flag I tried to trace_printf() a floating value, an integer value, or whatever data type, but all of them using the %f formatter, but I keep getting a hard fault using %f in trace_printf().
[HardFault]
Stack frame:
R0 = 00666E69
R1 = 2004FE78
R2 = 2004FF00
R3 = 00666E69
R12 = F642D800
LR = 08005DE7
PC = 08006586
PSR = 01000000
FSR/FAR:
CFSR = 00008200
HFSR = 40000000
DFSR = 0000000A
AFSR = 00000000
BFAR = 00666E69
Misc
LR/EXC_RETURN= FFFFFFF9
By debugging step by step, the hard fault handler is triggered after this function is called: vsnprintf()
I'm using these linker flags:
-T mem.ld -T libs.ld -T sections.ld -Xlinker --gc-sections -L"../ldscripts" -Wl,-Map,"ThreePhaseSignals.map" --specs=nano.specs -u _printf_float
My project settings are:
Project toolchains
Target processor settings
C++ preprocessor
Linker settings and flags
My _sbrk.c is:
_sbrk.c
My linker files are:
mem.ld is:
mem.ld
And sections.ld is:
/*
* Default linker script for Cortex-M (it includes specifics for
STM32F[34]xx).
*
* To make use of the multi-region initialisations, define
* OS_INCLUDE_STARTUP_INIT_MULTIPLE_RAM_SECTIONS for the _startup.c file.
*/
/*
* The '__stack' definition is required by crt0, do not remove it.
*/
__stack = ORIGIN(RAM) + LENGTH(RAM);
_estack = __stack; /* STM specific definition */
/*
* Default stack sizes.
* These are used by the startup in order to allocate stacks
* for the different modes.
*/
__Main_Stack_Size = 1024;
PROVIDE ( _Main_Stack_Size = __Main_Stack_Size );
__Main_Stack_Limit = __stack - __Main_Stack_Size;
/* "PROVIDE" allows to easily override these values from an
* object file or the command line. */
PROVIDE(_Main_Stack_Limit = __Main_Stack_Limit);
/*
* There will be a link error if there is not this amount of
* RAM free at the end.
*/
_Minimum_Stack_Size = 256;
/*
* Default heap definitions.
* The heap start immediately after the last statically allocated
* .sbss/.noinit section, and extends up to the main stack limit.
*/
PROVIDE(_Heap_Begin = _end_noinit);
PROVIDE(_Heap_Limit = __stack - __Main_Stack_Size);
/*
* The entry point is informative, for debuggers and simulators,
* since the Cortex-M vector points to it anyway.
*/
ENTRY(_start)
/* Sections Definitions */
SECTIONS
{
/*
* For Cortex-M devices, the beginning of the startup code is stored in
* the .isr_vector section, which goes to FLASH.
*/
.isr_vector : ALIGN(4)
{
FILL(0xFF)
__vectors_start = ABSOLUTE(.);
__vectors_start__ = ABSOLUTE(.); /* STM specific definition */
KEEP(*(.isr_vector)) /* Interrupt vectors */
KEEP(*(.cfmconfig)) /* Freescale configuration words */
/*
* This section is here for convenience, to store the
* startup code at the beginning of the flash area, hoping that
* this will increase the readability of the listing.
*/
*(.after_vectors .after_vectors.*) /* Startup code and ISR */
} >FLASH
.inits : ALIGN(4)
{
/*
* Memory regions initialisation arrays.
*
* Thee are two kinds of arrays for each RAM region, one for
* data and one for bss. Each is iterrated at startup and the
* region initialisation is performed.
*
* The data array includes:
* - from (LOADADDR())
* - region_begin (ADDR())
* - region_end (ADDR()+SIZEOF())
*
* The bss array includes:
* - region_begin (ADDR())
* - region_end (ADDR()+SIZEOF())
*
* WARNING: It is mandatory that the regions are word aligned,
* since the initialisation code works only on words.
*/
__data_regions_array_start = .;
LONG(LOADADDR(.data));
LONG(ADDR(.data));
LONG(ADDR(.data)+SIZEOF(.data));
LONG(LOADADDR(.data_CCMRAM));
LONG(ADDR(.data_CCMRAM));
LONG(ADDR(.data_CCMRAM)+SIZEOF(.data_CCMRAM));
__data_regions_array_end = .;
__bss_regions_array_start = .;
LONG(ADDR(.bss));
LONG(ADDR(.bss)+SIZEOF(.bss));
LONG(ADDR(.bss_CCMRAM));
LONG(ADDR(.bss_CCMRAM)+SIZEOF(.bss_CCMRAM));
__bss_regions_array_end = .;
/* End of memory regions initialisation arrays. */
/*
* These are the old initialisation sections, intended to contain
* naked code, with the prologue/epilogue added by crti.o/crtn.o
* when linking with startup files. The standalone startup code
* currently does not run these, better use the init arrays below.
*/
KEEP(*(.init))
KEEP(*(.fini))
. = ALIGN(4);
/*
* The preinit code, i.e. an array of pointers to initialisation
* functions to be performed before constructors.
*/
PROVIDE_HIDDEN (__preinit_array_start = .);
/*
* Used to run the SystemInit() before anything else.
*/
KEEP(*(.preinit_array_sysinit .preinit_array_sysinit.*))
/*
* Used for other platform inits.
*/
KEEP(*(.preinit_array_platform .preinit_array_platform.*))
/*
* The application inits. If you need to enforce some order in
* execution, create new sections, as before.
*/
KEEP(*(.preinit_array .preinit_array.*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/*
* The init code, i.e. an array of pointers to static constructors.
*/
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/*
* The fini code, i.e. an array of pointers to static destructors.
*/
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/*
* For some STRx devices, the beginning of the startup code
* is stored in the .flashtext section, which goes to FLASH.
*/
.flashtext : ALIGN(4)
{
*(.flashtext .flashtext.*) /* Startup code */
} >FLASH
/*
* The program code is stored in the .text section,
* which goes to FLASH.
*/
.text : ALIGN(4)
{
*(.text .text.*) /* All remaining code */
/* Read-only data (constants) */
*(.rodata .rodata.* .constdata .constdata.*)
*(vtable) /* C++ virtual tables */
KEEP(*(.eh_frame*))
/*
* Stub sections generated by the linker, to glue together
* ARM and Thumb code. .glue_7 is used for ARM code calling
* Thumb code, and .glue_7t is used for Thumb code calling
* ARM code. Apparently always generated by the linker, for some
* architectures, so better leave them here.
*/
*(.glue_7)
*(.glue_7t)
} >FLASH
/* ARM magic sections */
.ARM.extab : ALIGN(4)
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
. = ALIGN(4);
__exidx_start = .;
.ARM.exidx : ALIGN(4)
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
. = ALIGN(4);
_etext = .;
__etext = .;
/* MEMORY_ARRAY */
/*
.ROarraySection :
{
*(.ROarraySection .ROarraySection.*)
} >MEMORY_ARRAY
*/
/*
* The secondary initialised data section.
*/
.data_CCMRAM : ALIGN(4)
{
FILL(0xFF)
*(.data.CCMRAM .data.CCMRAM.*)
. = ALIGN(4) ;
} > CCMRAM AT>FLASH
/*
* This address is used by the startup code to
* initialise the .data section.
*/
_sidata = LOADADDR(.data);
/*
* The initialised data section.
*
* The program executes knowing that the data is in the RAM
* but the loader puts the initial values in the FLASH (inidata).
* It is one task of the startup to copy the initial values from
* FLASH to RAM.
*/
.data : ALIGN(4)
{
FILL(0xFF)
/* This is used by the startup code to initialise the .data section */
_sdata = . ; /* STM specific definition */
__data_start__ = . ;
*(.data_begin .data_begin.*)
*(.data .data.*)
*(.data_end .data_end.*)
. = ALIGN(4);
/* This is used by the startup code to initialise the .data section */
_edata = . ; /* STM specific definition */
__data_end__ = . ;
} >RAM AT>FLASH
/*
* The uninitialised data sections. NOLOAD is used to avoid
* the "section `.bss' type changed to PROGBITS" warning
*/
/* The secondary uninitialised data section. */
.bss_CCMRAM (NOLOAD) : ALIGN(4)
{
*(.bss.CCMRAM .bss.CCMRAM.*)
} > CCMRAM
/* The primary uninitialised data section. */
.bss (NOLOAD) : ALIGN(4)
{
__bss_start__ = .; /* Standard newlib definition */
_sbss = .; /* STM specific definition */
*(.bss_begin .bss_begin.*)
*(.bss .bss.*)
*(COMMON)
*(.bss_end .bss_end.*)
. = ALIGN(4);
__bss_end__ = .; /* Standard newlib definition */
_ebss = . ; /* STM specific definition */
} >RAM
.noinit_CCMRAM (NOLOAD) : ALIGN(4)
{
*(.noinit.CCMRAM .noinit.CCMRAM.*)
} > CCMRAM
.noinit (NOLOAD) : ALIGN(4)
{
_noinit = .;
*(.noinit .noinit.*)
. = ALIGN(4) ;
_end_noinit = .;
} > RAM
/* Mandatory to be word aligned, _sbrk assumes this */
PROVIDE (end = _end_noinit); /* Was _ebss */
PROVIDE (_end = _end_noinit);
PROVIDE (__end = _end_noinit);
PROVIDE (__end__ = _end_noinit);
/*
* Used for validation only, do not allocate anything here!
*
* This is just to check that there is enough RAM left for the Main
* stack. It should generate an error if it's full.
*/
._check_stack : ALIGN(4)
{
. = . + _Minimum_Stack_Size;
} >RAM
/*
* The FLASH Bank1.
* The C or assembly source must explicitly place the code
* or data there using the "section" attribute.
*/
.b1text : ALIGN(4)
{
*(.b1text) /* Remaining code */
*(.b1rodata) /* Read-only data (constants) */
*(.b1rodata.*)
} >FLASHB1
/*
* The EXTMEM.
* The C or assembly source must explicitly place the code or data there
* using the "section" attribute.
*/
/* EXTMEM Bank0 */
.eb0text : ALIGN(4)
{
*(.eb0text) /* Remaining code */
*(.eb0rodata) /* Read-only data (constants) */
*(.eb0rodata.*)
} >EXTMEMB0
/* EXTMEM Bank1 */
.eb1text : ALIGN(4)
{
*(.eb1text) /* Remaining code */
*(.eb1rodata) /* Read-only data (constants) */
*(.eb1rodata.*)
} >EXTMEMB1
/* EXTMEM Bank2 */
.eb2text : ALIGN(4)
{
*(.eb2text) /* Remaining code */
*(.eb2rodata) /* read-only data (constants) */
*(.eb2rodata.*)
} >EXTMEMB2
/* EXTMEM Bank0 */
.eb3text : ALIGN(4)
{
*(.eb3text) /* Remaining code */
*(.eb3rodata) /* Read-only data (constants) */
*(.eb3rodata.*)
} >EXTMEMB3
/* After that there are only debugging sections. */
/* This can remove the debugging information from the standard libraries */
/*
DISCARD :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
*/
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/*
* DWARF debug sections.
* Symbols in the DWARF debugging sections are relative to the beginning
* of the section so we begin them at 0.
*/
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}
On the Internet many people says that this is because printing floats consumes a lot of memory and probable the microcontroller is crashing due to memory overflow, so many suggestions aim to modify the linker script where stack and heap assignations are made, and some others say that this hard fault is related to_sbrk.c in newlib.
I tried to adapt these solutions to my particular case, but till now my problem still is not solved. I don't know if I'm badly implementing the suggestions or simply my problem is different.
How can I fix this problem?
Solved. Follow the following video and if it doesn't work follow the full series of videos.
STM32 with Eclipse, GNU ARM and J-Link. Part 4 - Minimal CMSIS Project - ITM Printf Debugging

STM32F429 is not receiving the CAN Message

I am using STM32F429 Microcontroller and need to implement CAN Bus Communication between CAN2 and PCAN View.I am able to transmit the message from CAN2 but I am not able to receive any message.I am using TJA1041A CAN transreceiver in the microcontroller.The Problem is that during debugging my CAN bus are properly initalized but it doesn't go to the receive command although I have initalized FIFO0.Herewith I am attching the program for further reference.I have used STM32 HAL Cube for programming.
/**
******************************************************************************
* File Name : main.c
* Date : 05/12/2014 09:43:55
* Description : Main program body
******************************************************************************
*
* COPYRIGHT(c) 2014 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
CAN_HandleTypeDef hcan1;
CAN_HandleTypeDef hcan2;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_CAN1_Init(void);
static void MX_CAN2_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_CAN1_Init();
MX_CAN2_Init();
/* USER CODE BEGIN 2 */
__GPIOD_CLK_ENABLE();
GPIO_InitTypeDef GPIO_Initpins;
GPIO_Initpins.Mode = GPIO_MODE_OUTPUT_PP ;
GPIO_Initpins.Pin = GPIO_PIN_5|GPIO_PIN_7;
GPIO_Initpins.Pull = GPIO_NOPULL ;
HAL_GPIO_Init(GPIOD, &GPIO_Initpins);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5|GPIO_PIN_7, GPIO_PIN_SET);
/* USER CODE END 2 */
/* USER CODE BEGIN 3 */
/* Infinite loop */
CanTxMsgTypeDef TxMess;
TxMess.StdId = 0x123;
TxMess.DLC = 0x0;
TxMess.Data[0] = 0x12;
TxMess.IDE = 0;
TxMess.RTR = 0;
hcan2.pTxMsg = &TxMess;
HAL_CAN_Transmit(&hcan2,50);
HAL_Delay(500);
/* USER CODE END 2 */
CanRxMsgTypeDef RMess;
RMess.FIFONumber = CAN_FIFO1;
RMess.FMI = 14;
RMess.StdId = 0x541;
RMess.DLC = 0;
RMess.RTR = 0;
RMess.IDE = CAN_ID_STD;
hcan2.pRxMsg = &RMess;
HAL_CAN_Receive_IT(&hcan2,CAN_FIFO1);
/* USER CODE BEGIN 3 */
/* Infinite loop */
while (1)
{
HAL_CAN_Receive(&hcan2,CAN_FIFO1,0);
}
/* USER CODE END 3 */
}
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
__PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
}
/* CAN1 init function */
void MX_CAN1_Init(void)
{
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 16;
hcan1.Init.Mode = CAN_MODE_NORMAL;
hcan1.Init.SJW = CAN_SJW_1TQ;
hcan1.Init.BS1 = CAN_BS1_1TQ;
hcan1.Init.BS2 = CAN_BS2_1TQ;
hcan1.Init.TTCM = DISABLE;
hcan1.Init.ABOM = DISABLE;
hcan1.Init.AWUM = DISABLE;
hcan1.Init.NART = DISABLE;
hcan1.Init.RFLM = DISABLE;
hcan1.Init.TXFP = DISABLE;
HAL_CAN_Init(&hcan1);
/*CAN_FilterConfTypeDef CAN_Filters;
CAN_Filters.BankNumber = 0;
CAN_Filters.FilterActivation = ENABLE;
CAN_Filters.FilterFIFOAssignment = CAN_FILTER_FIFO0 ;
CAN_Filters.FilterIdHigh = 0x00;
CAN_Filters.FilterIdLow = 0x00;
CAN_Filters.FilterMaskIdHigh = 0x00;
CAN_Filters.FilterMaskIdLow = 0x00;
CAN_Filters.FilterMode = CAN_FILTERMODE_IDMASK;
CAN_Filters.FilterNumber = 0;
CAN_Filters.FilterScale = CAN_FILTERSCALE_32BIT;
HAL_CAN_ConfigFilter(&hcan1, &CAN_Filters);*/
}
/* CAN2 init function */
void MX_CAN2_Init(void)
{
hcan2.Instance = CAN2;
hcan2.Init.Prescaler = 2;
hcan2.Init.Mode = CAN_MODE_NORMAL;
hcan2.Init.SJW = CAN_SJW_1TQ;
hcan2.Init.BS1 = CAN_BS1_5TQ;
hcan2.Init.BS2 = CAN_BS2_2TQ;
hcan2.Init.TTCM = DISABLE;
hcan2.Init.ABOM = DISABLE;
hcan2.Init.AWUM = DISABLE;
hcan2.Init.NART = DISABLE;
hcan2.Init.RFLM = DISABLE;
hcan2.Init.TXFP = DISABLE;
HAL_CAN_Init(&hcan2);
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{
/* GPIO Ports Clock Enable */
__GPIOH_CLK_ENABLE();
__GPIOB_CLK_ENABLE();
__GPIOA_CLK_ENABLE();
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
#ifdef USE_FULL_ASSERT
/**
* #brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* #param file: pointer to the source file name
* #param line: assert_param error line source number
* #retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif
/**
* #}
*/
/**
* #}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
Thanks
If CAN2 can send messages, the clock and master-slave configurations between CAN1 (master) and CAN2 (slave) are ok.
If there are receiving issues these should be related to the FIFO config or the acceptance filter config.
You configured the FIFO, but it looks like you did not configure the "CAN2StartBank".
CAN1 and CAN2 share also the filter banks and by default the banks are divided in half, so the first half is used for CAN1 and the second half for CAN2.
From the reference manual chapter "CAN Filter Registers":
CAN filter master register (CAN_FMR)
Address offset: 0x200 Reset value: 0x2A1C 0E01 All bits of this
register are set and cleared by software.
...
CAN2SB[5:0]: CAN2 start bank These bits are set and cleared by
software. They define the start bank for the CAN2 interface (Slave) in
the range 0 to 27. Note: When CAN2SB[5:0] = 28d, all the filters to
CAN1 can be used. When CAN2SB[5:0] is set to 0,no filters are assigned
to CAN1.
You set the
CAN_Filters.BankNumber = 0;
but you should choose a bank from the second half with default settings or change the CAN2StartBank value to 0 if you don't need CAN1.
You also have to make sure, that the Filters an in initialisation mode during filter configuration.
CAN filter master register (CAN_FMR)
Bit 0 FINIT : Filter init mode Initialization mode for filter banks
0: Active filters mode.
1: Initialization mode for the filters
Sadly I have no hardware right now to test this by my self.
You should take a FilterNumber 14 for the CAN2 interface; by default after RESET the bits CAN2SB[5:0] initilized with 01110 = dec 14 - so the CAN1 interface is supposed to use filters 0..13 and CAN2 14..27. you can change the start bank from 14 to any value within 1..27 by the method CAN_SlaveStartBank(uint_8).
Try to set Filterbank to more than 14 for the CAN2 interface, it seems there is a bug about bank setting.We have the same issue, but after setting 15,it works.
Check CAN FMR register. Value CAN2SB is 0x0E by default in CAN1 and CAN2 peripheral registers. You should set CAN1FMR->CANS2B to 0x00, and CAN2FMR->CANS2B to 0x0E (anythyng but not same numbers). So you split filterbanks in half and it works fine