STM32 HardFault_Handler

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Rick81
Inlägg: 755
Blev medlem: 30 december 2005, 13:07:09

STM32 HardFault_Handler

Inlägg av Rick81 »

Har ett problem jag inte förstår i STMF103C8T7

STM32 läser korrupt data i en array för att sedan krascha.


Arrayen ser ut så här:
typedef struct
{
int32_t v1;
int32_t v2;
uint32_t v3;
short v4;
}V_Data;

#define DATA_LENGTH 850
V_Data data[DATA_LENGTH];


Vid läsning från index 670 till 696 så är datat korrupt för att sedan ge en HardFault Exception när STM32 försöker skriva till index 697. Det är inga problem att accessa data efter arrayen.


.map fil ser ut så här:
0x20001268 annan variabel
0x2000126c data
0x2000478c annan variabel, går bra att skriva, läsa
0x20004790 annan variabel, går bra att skriva, läsa
0x20004858 annan variabel, går bra att skriva, läsa
0x2000485c annan variabel, går bra att skriva, läsa

Korrupt address börjar på
0x2000126c + 670 * 16 = 15436 => 0x20003C4C


Krasch adress
0x2000126c + 697 * 16 = 15868 => 0x20003DFC


Processorn har 20 kB SRAM och SRAM börjar på adress 0x20000000 med storlek 0x00005000.


Jag har gått igenom de pekare, arrayer och lagt in skydd för att de inte ska skriva i den aktuella arrayen. Eftersom det även blir ett Hardfault exception misstänker jag att det är något som är fel med minnesmappningen.
gkar
Inlägg: 1585
Blev medlem: 31 oktober 2011, 15:28:29
Ort: Linköping

Re: STM32 HardFault_Handler

Inlägg av gkar »

Det verkar som om det redan ligger något användbart data där.
Var har du lagt stacken?
Senast redigerad av gkar 7 augusti 2014, 19:00:38, redigerad totalt 1 gång.
Rick81
Inlägg: 755
Blev medlem: 30 december 2005, 13:07:09

Re: STM32 HardFault_Handler

Inlägg av Rick81 »

Heap och stack ligger på:

.heap 0x20004a04 0x0
0x20004a04 __end__ = .
0x20004a04 _end = __end__
0x20004a04 end = __end__
*(.heap*)
0x20004a04 __HeapLimit = .

.co_stack 0x20004a04 0x404 load address 0x0801377c
0x20004a08 . = ALIGN (0x8)
*fill* 0x20004a04 0x4
*(.co_stack .co_stack.*)
.co_stack 0x20004a08 0x400 ..\obj\startup_stm32f10x_md.o
0x20004a08 pulStack
0x20005000 __StackTop = (ORIGIN (ram) + 0x5000)
0x20004bfc __StackLimit = (__StackTop - SIZEOF (.co_stack))
0x20005000 PROVIDE (__stack, __StackTop)
0x00000001 ASSERT ((__StackLimit >= __HeapLimit), region ram overflowed with stack)



Så borde inte vara det.

Jag använder GCC 4.8.2 och CooCox 1.7.6
SvenW
Inlägg: 1156
Blev medlem: 24 april 2007, 16:23:10
Ort: Göteborg

Re: STM32 HardFault_Handler

Inlägg av SvenW »

Hade ett liknande fel ett tag sedan med en närbesläktad processor.
Det hade att göra med att bootpinnarna var felsatta, så att
någon pekare, kanske var det SP, blev felsatt vid uppstart.
Det gick bra att köra ändå, men ibland uppträdde felet.

Kolla bootpinnarna och att den kör programmet i rätt minne.
Att GCC och länkaren säger "load address 0x0801377c"
garanterar inte att programmet verkligen körs där!
En debugger borde veta.
gkar
Inlägg: 1585
Blev medlem: 31 oktober 2011, 15:28:29
Ort: Linköping

Re: STM32 HardFault_Handler

Inlägg av gkar »

Antar att du allokerar din struct på heapen?
Det är inte så att du har en massa data på stacken?

Prova detta så vet du var nuvarande stackframe är:

volatile int kaka = 0;
printf ("%lx", (long) &kaka);

"Hardfault exception" behöver inte vara minnesmappningfel, det kan vara ett följdfel på att en adress någonstans blivit fel.
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: STM32 HardFault_Handler

Inlägg av blueint »

Vad var det "volatile" bettyde?
Användarvisningsbild
Icecap
Inlägg: 26650
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: STM32 HardFault_Handler

Inlägg av Icecap »

volatile betyder att variabeln alltid ska kollas enl. programmet, den kan ändras av t.ex. interrupt. Då optimeras den koll inte bort.
Rick81
Inlägg: 755
Blev medlem: 30 december 2005, 13:07:09

Re: STM32 HardFault_Handler

Inlägg av Rick81 »

Bootpinnarna var ett bra tips. Ska kolla dem.

Arrayen definierad utanför funktioner och ligger alltså inte på heapen. Ska kolla stackpekaren.

En sak som förbryllar mig var att om jag satte arrayen till static så blev RAM överskrider med typ 2000 byte. Såg på nätet att nån hade löst liknande problem med detta.

En fundering: structen är inte alignad mot 4 byte. Men blir ändå 16 byte. Kan detta påverka?

Jag kör med egen bootloader. Ska nog testa utan denna och se om felet försvinner.
Rick81
Inlägg: 755
Blev medlem: 30 december 2005, 13:07:09

Re: STM32 HardFault_Handler

Inlägg av Rick81 »

Jag har nu testat att gå till ett debugläge innan huvudprogrammet, som ligger direkt i main loopen där jag kan läsa/skiva till olika delar av arrayen.

Det är samma fenomen med korrupta addresser och krach när man kommer för högt upp.

testade även
volatile int kaka = 0;
printf ("%X\n\r", (long) &kaka);

Vilket gav utskriften
20003EFC

Dvs mitt inne i min array:
0x20001268 annan variabel
0x2000126c data
0x2000478c annan variabel, går bra att skriva, läsa
0x20004790 annan variabel, går bra att skriva, läsa
0x20004858 annan variabel, går bra att skriva, läsa
0x2000485c annan variabel, går bra att skriva, läsa


Så något måste få stackpekaren till fel läge.

Jag har lagt till samma utskrift det första som händer efter att RCC och UART konfiguerats och då hamnar variablen på 20003F24, dvs inne i arrayen.


heap och stack ligger på följande addresser
.heap 0x20004a04 0x0
0x20004a04 __end__ = .
0x20004a04 _end = __end__
0x20004a04 end = __end__
*(.heap*)
0x20004a04 __HeapLimit = .

.co_stack 0x20004a04 0x404 load address 0x08013a1c
0x20004a08 . = ALIGN (0x8)
*fill* 0x20004a04 0x4
*(.co_stack .co_stack.*)
.co_stack 0x20004a08 0x400 ..\obj\startup_stm32f10x_md.o
0x20004a08 pulStack
0x20005000 __StackTop = (ORIGIN (ram) + 0x5000)
0x20004bfc __StackLimit = (__StackTop - SIZEOF (.co_stack))
0x20005000 PROVIDE (__stack, __StackTop)
0x00000001 ASSERT ((__StackLimit >= __HeapLimit), region ram



Jag misstänker att stackpekaren kan bli fel vid hopp från bootloader till applikationen.

Så här ser hoppet
#define BL_FLASH_START 0x08000000
#define BL_FLASH_SIZE 0x3400 // 13 kB
#define FLASH_START BL_FLASH_START + BL_FLASH_SIZE


uint32_t FLASH_SIZE = 0xCC00; // 51 kB



JumpAddress = *(uint32_t*) (FLASH_START + 4);
Jump_To_Application = (pFunction) JumpAddress;

sprintf(string, "Address %X\r\n", *(uint32_t*)JumpAddress);
Print(string);

/* Initialize user application's Stack Pointer */
__set_MSP(*(uint32_t*) FLASH_START);
Jump_To_Application();



I applikationen kan jag endast hitta följande om stack.
/**
*@brief 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
* 0x00000000.
*/
__attribute__ ((used,section(".isr_vector")))
void (* const g_pfnVectors[])(void) =
{
/*----------Core Exceptions-------------------------------------------------*/
(void *)&pulStack[STACK_SIZE], /*!< The initial stack pointer */
Reset_Handler, /*!< Reset Handler */
NMI_Handler, /*!< NMI Handler */
HardFault_Handler, /*!< Hard Fault Handler */
MemManage_Handler, /*!< MPU Fault Handler */
BusFault_Handler, /*!< Bus Fault Handl




Jag kan inte hitta var stackpekaren initieras.
gkar
Inlägg: 1585
Blev medlem: 31 oktober 2011, 15:28:29
Ort: Linköping

Re: STM32 HardFault_Handler

Inlägg av gkar »

Anta att stacken skall ligga på 0x20005000,

0x2000478c annan variabel, går bra att skriva, läsa
0x20004790 annan variabel, går bra att skriva, läsa
0x20004858 annan variabel, går bra att skriva, läsa
0x2000485c annan variabel, går bra att skriva, läsa
då är dessa ok om de ligger på stacken:

Jag tycker det verkar som om du har en massa data på stacken så att stacken krockar med heapen.

Det finns normalt inga checkar i C runtome miljö för att kontrollera hur stor stacken är.
Det är ditt ansvar.
0x20005000 PROVIDE (__stack, __StackTop) säger bara ar stacken börjar, inte var den slutar...


Kolla om du inte har några fler arrayer på stacken?..
SvenW
Inlägg: 1156
Blev medlem: 24 april 2007, 16:23:10
Ort: Göteborg

Re: STM32 HardFault_Handler

Inlägg av SvenW »

Vill minnas att jag heller inte kunde hitta var SP initierades.
Förstod aldrig varför. De kan rimligen inte bara ha glömt detta!
Gick runt problemet genom att lägga in det där , har jag för mig.

Det vore intressant att få veta om och varför i så fall det är gjort så att SP _inte_ initieras i uppstartrutinen.
Någon som har en ide om detta?
Rick81
Inlägg: 755
Blev medlem: 30 december 2005, 13:07:09

Re: STM32 HardFault_Handler

Inlägg av Rick81 »

Jag tror inte stacken är full då det är minimalt med variabler som läggs på stacken, utan att problemet är att stackpekaren initeras fel. Jag kan även accessa variabler senare i arrayen.

Sär ser koden ut:

Kod: Markera allt

int main(void)
{
	char c;
	bool SDactive = false;
	uint32_t i;

	int writeIndex = 697;
	//int counter = 0;

	//RCC_Configuration();
	//NVIC_Configuration();

	HW_UART_Init(LOG, 115200);

	volatile int kaka = 0;
	printf ("Stack = %X\n\r", (long) &kaka);
.....





void HW_UART_Init(USART_TypeDef* USARTx, int baudrate)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	if(USARTx == USART1)
	{
		/* Enable GPIOA and USART1 clock */
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);

		/* Configure USART1 Rx (PA10) as input floating */
		GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10;
		GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;

		GPIO_Init(GPIOA, &GPIO_InitStructure);

		/* Configure USART1 Tx (PA9) as alternate function push-pull */
		GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;

		GPIO_Init(GPIOA, &GPIO_InitStructure);

		// Interrupt för UART
		//USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	}
	else if(USARTx == USART2)
	{

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

		/* Configure USART2 Rx (PA3) as input floating */
		GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3;
		GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;

		GPIO_Init(GPIOA, &GPIO_InitStructure);

		/* Configure USART2 Tx (PA2) as alternate function push-pull */	// Endast lyssna!
		GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;

		GPIO_Init(GPIOA, &GPIO_InitStructure);
	}
	else if(USARTx == USART3)
	{
		/* Enable GPIOA and USART3 clock */
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

		// PC10/USART3_TX
		// PC11/USART3_RX


		// PB10/I2C2_SCL/USART3_TX/TIM2_CH3
		// PB11/I2C2_SDA/USART3_RX/TIM2_CH4

		/* Configure USART3 Rx (PB11) as input floating */
		GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_11;
		GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;

		GPIO_Init(GPIOB, &GPIO_InitStructure);

		/* Configure USAR3 Tx (PB10) as alternate function push-pull */
		GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;

		GPIO_Init(GPIOB, &GPIO_InitStructure);
	}

	/* USART general configuration ------------------------------------------------------*/

	USART_InitStructure.USART_BaudRate = baudrate;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_DeInit(USARTx);
	USART_Init(USARTx, &USART_InitStructure);
	USART_Cmd(USARTx, ENABLE);

}
Rick81
Inlägg: 755
Blev medlem: 30 december 2005, 13:07:09

Re: STM32 HardFault_Handler

Inlägg av Rick81 »

Stack pekaren verkar sättas av första data i flashet så jag testade
for(c = 0; c < 50; c++)
{
sprintf(string, "%X\r\n", (unsigned int)*(uint32_t*)(0x08003400 + c *4));
Print(string);
}


Och jag får följande utskrift
20004E08
800502D
80079AD
80079B9
80079D1
80079E9
8007A01
0
0
0


SP borde bli 20004E08, vilket verkar korrekt
Rick81
Inlägg: 755
Blev medlem: 30 december 2005, 13:07:09

Re: STM32 HardFault_Handler

Inlägg av Rick81 »

Jag har nu lagt in stack debug.



#include "stackdebug.h"
void Default_Reset_Handler(void)
{
/* Initialize data and bss */
unsigned long *pulSrc, *pulDest;


/* Copy the data segment initializers from flash to SRAM */
pulSrc = &_sidata;


for(pulDest = &_sdata; pulDest < &_edata; )
{
*(pulDest++) = *(pulSrc++);
}

/* Zero fill the bss segment. This is done with inline assembly since this
will clear the value of pulDest if it is not kept in a register. */
__asm(" ldr r0, =_sbss\n"
" ldr r1, =_ebss\n"
" mov r2, #0\n"
" .thumb_func\n"
"zero_loop:\n"
" cmp r0, r1\n"
" it lt\n"
" strlt r2, [r0], #4\n"
" blt zero_loop");

ClearStackArray();
SaveStack();
/* Setup the microcontroller system. */
SystemInit();


SaveStack();
/* Call the application's entry point.*/
main();
}




När jag skriver ut sparade stack pekare får jag:
sp[0] = 20003F50
sp[1] = 20003F50
sp[2] = 20003EC8
sp[3] = 20003EC8

Så flash verkar OK men innan System_Init i default handler så blir stack fel. Kan det bli någor fel här?

pulSrc = &_sidata;


for(pulDest = &_sdata; pulDest < &_edata; )
{
*(pulDest++) = *(pulSrc++);
}

/* Zero fill the bss segment. This is done with inline assembly since this
will clear the value of pulDest if it is not kept in a register. */
__asm(" ldr r0, =_sbss\n"
" ldr r1, =_ebss\n"
" mov r2, #0\n"
" .thumb_func\n"
"zero_loop:\n"
" cmp r0, r1\n"
" it lt\n"
" strlt r2, [r0], #4\n"
" blt zero_loop");


Rättelse:
Det funkar om man kör utan bootloader...
Rick81
Inlägg: 755
Blev medlem: 30 december 2005, 13:07:09

Re: STM32 HardFault_Handler

Inlägg av Rick81 »

Tror jag har löst det nu. La in utskrifter i bootloader när den laddar stackpekaren och såg mycket riktigt att den blev fel.

Det jag gjorde var att ändra
__set_MSP(*(uint32_t*) FLASH_START);
till
__set_MSP(*(uint32_t*) (FLASH_START));

Och nu blir stack pekaren rätt.

Kan någon förklara hur detta kan ge skillnad?
Skriv svar