cancel
Showing results for 
Search instead for 
Did you mean: 

My STM32H743VI Application Runs to a debug instruction in the start-up code

Garnett.Robert
Senior III

When I start my program from the uVision debugger the code runs to a debug instruction in the start-up code.

It requires three run push buttons to get it past the debug instruction. The program then works perfectly.

This problem only happens when I include a large AXI ram buffer for sqLite which I use for storing real-time data.

The variable is defined thus

/* Define Heap for sqlite */
#define SIZE_SQL_BUFF 0x00067000 /* 421,888 */
#define MIN_REQ_SQL_BUFF 1024
ALIGN_32BYTES(char sqlBuffArray[SIZE_SQL_BUFF] __attribute__((section("SQLITE_HEAP_MEM"))));

The scatter file is:

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
 
LR_IROM1 0x08000000 0x001E0000  {    ; load region size_region
  ER_IROM1 0x08000000 0x001E0000 {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
 
  ;************************************************************
  EXEC_REGION_ITCM 0x00000000 0x10000  
  { 
    stm32h7xx_it.o (+RO)  
	realTimeProcessing.o  (+RO)
	PLLControl.o (+RO)
	compthresholdcontrol.o (+RO)
	powerProc.o (+RO)
	tasks.o (+RO)
;	stats5MinRMS.o (+RO)
	powerLog.o (+RO)	
  }
 
  ;************************************************************
  CONST_ROM 0x081E0000 0x00020000
  {
	writeFlashConst.o (*)
  }
 
  ;************************************************************  
  DTCM_RAM_STACK 	0x20000000 0x00001000 
  {
	.ANY (STACK)
  }
 
  ;************************************************************
  DTCM_MAIN  		0x20001000 0x0001F000
  {
;	freertos.o  (+RW +ZI)
	realTimeProcessing.o  (+RW +ZI)
	powerProc.o (+RW +ZI)
;	PLLControl.o (+RW +ZI)
	compthresholdcontrol.o (+RW +ZI)
	dac.o (+RW +ZI)
	getgpssentencestr.o (+RW +ZI)
	comp.o (+RW +ZI)
	write_flash.o (+RW +ZI)
	sqlite3.o (+RW +ZI)
;	fatfs.o   (+RW +ZI)
	pllcontrol.o (+RW +ZI)	 
	rtcclockcaltask.o (+RW +ZI)
	calibrationtask.o (+RW +ZI)
	trcstreamingrecorder.o (+RW +ZI)
	
	stm32h7xx_hal_flash.o (+RW +ZI)	
 
	.ANY (+RW +ZI)
  }  
 
  ;*******************************************************************************************************************
  ;SRAM1	131,072 0x20000
  RW_SPI2_DMA 0x30000000 0x00002000   ; 
  {
;	 spiCommsHandler.o (PMON_BOARD_SPI2_RX)
;	 spiCommsHandler.o (PMON_BOARD_SPI2_TX)
	 uartWiFi.o		   (WIFI_UART_RX)
	 uartWiFi.o		   (WIFI_UART_TX)	 
  } 
 
 
  ;************************************************************
  ;SRAM2 	131,072 0x20000   0x30020000 to 0x30028000
  ADC1_DMA_BUFF_1_SR2 0x30020000 0x0005DC0
  {
	 realTimeProcessing.o (ADC1_DMA_1) ;3000 * 4 * 2 = 24000 => 0x5DC0
  }
  
  
  ;************************************************************  
  ;SRAM3 	32,000 0x20000   0x30040000 to 0x30028000
  ADC1_DMA_BUFF_2_SR3 0x30040000 0x00008000
  {
	 realTimeProcessing.o (ADC1_DMA_2) ;3000 * 4 * 2 = 24000 => 0x5DC0
  }
  
 
  ;************************************************************ 
  RW_SRAM4_ADC3_DMA 0x38000000 0x00010000 ;
  {
  	main.o (+RW +ZI)	
	main.o (ADC3_DMA)
	rtcSyncPrepTask.o (UART2_RX_BUFF)
  }  
 
 
  ;************************************************************
  ;AXI SRAM 524,288  0x80000	
 
  RW_AXI_1	0x24000000 UNINIT 0x00067000  
  {
	freertos.o 		(SQLITE_HEAP_MEM)
  }	
  
  RW_AXI_2	0x24067000 0x00019000 
  {
	powerLog.o		(POWER_LOG)
	.ANY (+RW +ZI)
  }
 
  
  ;************************************************************
  ;SRAMBACKUP	4096 0x1000
  BACKUP_SRAM  0x38800000 UNINIT 0x00001000 ; 4096
  {
	calibrationTask.o (ADC_CAL_BACKUPS)
  }  
}
 
;*************** EOF Copywrite C 2019 R J Garnett *************

I have used scatter files like this in most of my projects and never have come across this problem.

As soon as I comment out the code that calls up the variable the thing works. Minus sqLite of course.

Any ideas?

I was going to publich this project on this site as it uses sqLite really well and I know a lot of people want to use sqLite, but are intimidated by the need to write the VFS to talk to fatFS and to get the whole thing to compile. The sqLite DB works really well with write ahead logging. It's robust against power failures causing data corruption and for simply saving data without running large select queries it is very fast.

0690X00000BvsH9QAJ.png

Any hep on this would be greatly appresiated as I have spend a day and a half trying to unravel it.

8 REPLIES 8

This BKPT is because there is a printf or puts in the code somewhere. If you have a debugger UART, or want to use the SWV channel you will need some fputc() code.

Also you should enable SRAM clocks.

I will post some code fragments later when I'm at a computer.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
; Reset handler
Reset_Handler   PROC
                EXPORT  Reset_Handler                    [WEAK]
                IMPORT  SystemInit
                IMPORT  __main
 
                LDR     R0, =0x580244DC ; Enable D2SRAM clocks in RCC_AHB2ENR
                LDR     R1, [R0]
                ORR     R1, #0xE0000000
                STR     R1, [R0]
 
                LDR     R0, =SystemInit
                BLX     R0
                LDR     R0, =__main
                BX      R0
 
                ENDP ; Reset_Handler
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler
 
                ; Determine correct stack
 
                TST     lr, #4
                ITE     EQ
                MRSEQ   R0, MSP         ; Read MSP (Main)
                MRSNE   R0, PSP         ; Read PSP (Process)
 
                MOV     R1, R4
                MOV     R2, R5
                MOV     R3, R6
 
                EXTERN  hard_fault_handler_c
                B       hard_fault_handler_c
                ENDP ; sourcer32@gmail.com
void hard_fault_handler_c(unsigned int * hardfault_args, unsigned int r4, unsigned int r5, unsigned int r6)
{
  printf ("[Hard Fault]\n"); // After Joseph Yiu
 
  printf ("r0 = %08X, r1 = %08X, r2 = %08X, r3 = %08X\n",
    hardfault_args[0], hardfault_args[1], hardfault_args[2], hardfault_args[3]);
  printf ("r4 = %08X, r5 = %08X, r6 = %08X, sp = %08X\n",
    r4, r5, r6, (unsigned int)&hardfault_args[8]);
  printf ("r12= %08X, lr = %08X, pc = %08X, psr= %08X\n",
    hardfault_args[4], hardfault_args[5], hardfault_args[6], hardfault_args[7]);
 
  printf ("bfar=%08X, cfsr=%08X, hfsr=%08X, dfsr=%08X, afsr=%08X\n",
    *((volatile unsigned int *)(0xE000ED38)),
    *((volatile unsigned int *)(0xE000ED28)),
    *((volatile unsigned int *)(0xE000ED2C)),
    *((volatile unsigned int *)(0xE000ED30)),
    *((volatile unsigned int *)(0xE000ED3C)) );
 
extern void *__initial_sp;
{ // Stack Dump
  int i = 0;
  uint32_t *p = (uint32_t *)&hardfault_args[8];
  uint32_t *q = (uint32_t *)&__initial_sp;
  while((p < q) && (i < 32))
  {
    if ((i++ & 7) == 0) putchar('\n');
    printf(" %08X", *p++);
  }
  putchar('\n');
}
 
  while(1);
} // sourcer32@gmail.com
//****************************************************************************
// Hosting of stdio functionality through USART/SWV
//****************************************************************************
 
/* Implementation of putchar (also used by printf function to output data)    */
int SendChar(int ch)                    /* Write character to Serial Port     */
{
  ITM_SendChar(ch); // SWV From core_cm4.c
  OutChar((char)ch); // UART
 
  return(ch);
}
 
//****************************************************************************
 
#include <stdio.h>
#include <rt_misc.h>
 
//Removed these for 6.xx Compiler, uncomment if still using 5.xx
//#pragma import(__use_no_semihosting_swi)
//struct __FILE { int handle; /* Add whatever you need here */ };
//FILE __stdout;
//FILE __stdin;
 
int fputc(int ch, FILE *f) { return (SendChar(ch)); }
 
int ferror(FILE *f)
{
  /* Your implementation of ferror */
  return EOF;
}
 
void _ttywrch(int ch) { SendChar(ch); }
 
void _sys_exit(int return_code)
{
label:  goto label;  /* endless loop */
}
 
//*****************************************************************************

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Garnett.Robert
Senior III

Hi Clive

Yehh! I figured it out.

I start the RAM Clocks in the Main program.

To fix it i did what this link advised:

https://mklimenko.github.io/english/2018/11/02/disable-semihosting/

It' was the semihosting capability built into the compiler. (I am not using microlib can't remember why)

You turn semi hosting off with some macros:

/**
  ******************************************************************************
  * @file    system_stm32h7xx.c
  * @author  MCD Application Team
  * @brief   CMSIS Cortex-Mx Device Peripheral Access Layer System Source File.
  *
  *   This file provides two functions and one global variable to be called from
  *   user application:
  *      - SystemInit(): This function is called at startup just after reset and
  *                      before branch to main program. This call is made inside
  *                      the "startup_stm32h7xx.s" file.
  *
  *      - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
  *                                  by the user application to setup the SysTick
  *                                  timer or configure other parameters.
  *
  *      - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
  *                                 be called whenever the core clock is changed
  *                                 during program execution.
  *
  *
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
  *
  * 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.
  *
  ******************************************************************************
  */
 
/** @addtogroup CMSIS
  * @{
  */
 
/** @addtogroup stm32h7xx_system
  * @{
  */
 
/** @addtogroup STM32H7xx_System_Private_Includes
  * @{
  */
 
#include "stm32h7xx.h"
 
 
#if __ARMCC_VERSION >= 6000000
    __asm(".global __use_no_semihosting");
#elif __ARMCC_VERSION >= 5000000
    #pragma import(__use_no_semihosting)
#else
    #error Unsupported compiler
#endif
 
....

You then create a c and h file to replace the functions excluded by the macro Viz:

#include <rt_sys.h>
#include <rt_misc.h>
#include <time.h>
 
 
const char __stdin_name[] =  ":tt";
const char __stdout_name[] =  ":tt";
const char __stderr_name[] =  ":tt";
 
FILEHANDLE _sys_open(const char *name, int openmode){
    return 1;
}
 
int _sys_close(FILEHANDLE fh){
    return 0;
}
 
char *_sys_command_string(char *cmd, int len){
    return NULL;
}
 
int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode){
    return 0;
}
 
int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode){
    return -1;
}
 
void _ttywrch(int ch){
}
 
int _sys_istty(FILEHANDLE fh){
    return 0;
}
 
int _sys_seek(FILEHANDLE fh, long pos){
    return -1;
}
 
long _sys_flen(FILEHANDLE fh){
    return -1;
}
 
void _sys_exit(int return_code) {
    while (1)
        ;
}
 
clock_t clock(void){
    clock_t tmp;
    return tmp;
}
 
void _clock_init(void){
}
 
time_t time(time_t *timer){
    time_t tmp;
    return tmp;
}
 
int system(const char *string){
    return 0;
}
#include <rt_sys.h>
#include <rt_misc.h>
#include <time.h>
 
const char __stdin_name[] =  ":tt";
const char __stdout_name[] =  ":tt";
const char __stderr_name[] =  ":tt";
 
FILEHANDLE _sys_open(const char *name, int openmode);
 
int _sys_close(FILEHANDLE fh);
 
char *_sys_command_string(char *cmd, int len);
 
int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode);
 
int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode);
 
void _ttywrch(int ch);
 
int _sys_istty(FILEHANDLE fh);
 
int _sys_seek(FILEHANDLE fh, long pos);
 
long _sys_flen(FILEHANDLE fh);
 
void _sys_exit(int return_code);
 
clock_t clock(void);
 
void _clock_init(void);
 
time_t time(time_t *timer);
 
int system(const char *string);
 
char *getenv(const char *name);
 
void _getenv_init(void);

Typical Keil. If there's a hard way to do something they'll find it.

The project works fine now. I was really pleased I got sqLite to work as I hate mucking around with files to store realtime data. That's a good thing about the H7 it's got more than enough ram to do this.

I don't use the Keil version of semihosting for debugging. I've got a j-Link pro and use Segger RTT viewer. It works great except that it won't do floating point values in its print statements. This is for speed I guess.

Best regards

Rob

Cortex-M0 variant

HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler
                EXTERN  hard_fault_handler_c
 
                MOV     R1, LR
                LDR     R0, =hard_fault_handler_c
                MOV     LR, R0
                MOVS    R0, #4          ; Determine correct stack
                TST     R0, R1
                MRS     R0, MSP         ; Read MSP (Main)
                BEQ     .+6             ; BEQ 2, MRS R0,PSP 4
                MRS     R0, PSP         ; Read PSP (Process)
 
                MOV     R1, R4          ; Registers R4-R6, as parameters 2-4 of the function called
                MOV     R2, R5
                MOV     R3, R6          ;  sourcer32@gmail.com
 
                BX      LR
                ENDP 
void hard_fault_handler_c(unsigned int * hardfault_args, unsigned int r4, unsigned int r5, unsigned int r6)
{
  printf ("\n[Hard Fault]\n"); // After Joseph Yiu
 
  printf ("r0 = %08X, r1 = %08X, r2 = %08X, r3 = %08X\n",
    hardfault_args[0], hardfault_args[1], hardfault_args[2], hardfault_args[3]);
  printf ("r4 = %08X, r5 = %08X, r6 = %08X, sp = %08X\n",
    r4, r5, r6, (unsigned int)&hardfault_args[8]);
  printf ("r12= %08X, lr = %08X, pc = %08X, psr= %08X\n",
    hardfault_args[4], hardfault_args[5], hardfault_args[6], hardfault_args[7]);
 
  if (__CORTEX_M >= 3)
		printf ("bfar=%08X, cfsr=%08X, hfsr=%08X, dfsr=%08X, afsr=%08X\n",
			*((volatile unsigned int *)(0xE000ED38)),
			*((volatile unsigned int *)(0xE000ED28)),
			*((volatile unsigned int *)(0xE000ED2C)),
			*((volatile unsigned int *)(0xE000ED30)),
			*((volatile unsigned int *)(0xE000ED3C)) );
 
  while(1);
}

https://community.st.com/s/question/0D50X0000Az372YSQQ/stm32l412-hardfault-while-using-minimal-cubeide-example

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Garnett.Robert
Senior III

Additional Info:

The reason this problem occurred is that I switched from armcc V5 compiler to armcc V6

DavidAlfa
Senior II

Thanks for the invaluable help posting those Hard Fault handlers!

However, the Cortex-M0 variant failed for me when enabling -flto optimizations, causing:

"Error: invalid offset, value too big (0x00003B4C)".

 

The solution was to add a literal pool:

 

                BX      LR
                .LTORG                                  ; Add literal pool

 

This was my way to automatically deal with CM0 and CM3 for STM32CubeIDE:

startup_stm32xx.s:

 

g_pfnVectors:
  .word  _estack
  .word  Reset_Handler
  .word  NMI_Handler
  .word  HardFault_Handler_        <---- Modify this 
volatile uint32_t r4, r5, r6, hardFault_args[9];

void HardFault_Handler(void){
    printf("HARD FAULT\r\n");
    printf("r0:%08lX   r1:%08lX\r\n", hardFault_args[0], hardFault_args[1]);
    printf("r2:%08lX   r3:%08lX\r\n", hardFault_args[2], hardFault_args[3]);
    printf("r4:%08lX   r5:%08lX\r\n", r4, r5);
    printf("r6:%08lX   sp:%08lX\r\n", r6, hardFault_args[8]);
    printf("lr:%08lX  r12:%08lX\r\n", hardFault_args[5], hardFault_args[4]);
    printf("pc:%08lX  psr:%08lX\r\n", hardFault_args[6], hardFault_args[7]);
    while(1){
    }
}

/* copy hardfault args to known storage before calling the final handler*/
__attribute__((used)) void HardFault_Handler_cp(unsigned int * hardfault_args, unsigned int _r4, unsigned int _r5, unsigned int _r6){
  for(uint8_t i=0; i<9; i++){
    hardFault_args[i]=hardfault_args[i];
  }
  r4=_r4;
  r5=_r5;
  r6=_r6;
  HardFault_Handler();
}

/* Initial hard fault trap to capture stack data*/
__attribute__((used)) __attribute__((naked)) void HardFault_Handler_(void){
  asm volatile(
#if (__CORTEX_M >=3)                              // https://community.st.com/t5/stm32-mcus-products/my-stm32h743vi-application-runs-to-a-debug-instruction-in-the/m-p/254666/highlight/true#M57916
      "TST     lr, #4                       \n"
      "ITE     EQ                           \n"
      "MRSEQ   R0, MSP                      \n" //Read MSP (Main)
      "MRSNE   R0, PSP                      \n" //Read PSP (Process)
      "MOV     R1, R4                       \n"
      "MOV     R2, R5                       \n"
      "MOV     R3, R6                       \n"
      "B       HardFault_Handler_cp         \n"
#else                                               // https://community.st.com/t5/stm32-mcus-products/my-stm32h743vi-application-runs-to-a-debug-instruction-in-the/m-p/254668/highlight/true#M57918
      "MOV     R1, LR                       \n"
      "LDR     R0, =HardFault_Handler_cp    \n"
      "MOV     LR, R0                       \n"
      "MOVS    R0, #4                       \n"     // Determine correct stack
      "TST     R0, R1                       \n"
      "MRS     R0, MSP                      \n"     // Read MSP (Main)
      "BEQ     .+6                          \n"     // BEQ 2, MRS R0,PSP 4
      "MRS     R0, PSP                      \n"     // Read PSP (Process)
      "MOV     R1, R4                       \n"     // Registers R4-R6, as parameters 2-4 of the function called
      "MOV     R2, R5                       \n"
      "MOV     R3, R6                       \n"     // sourcer32@gmail.com
      "BX      LR                           \n"
      ".LTORG                               \n"     // Add literal pool just in case
#endif
  );
}

 

Pavel A.
Evangelist III

@DavidAlfa Your variant of CM0 handler is incorrect. The correct variant by @Tesla DeLorean is above.

Yep, there was a typo, should be "LDR R0, =hard_fault_handler_c"