2020-01-11 12:18 AM
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.
Any hep on this would be greatly appresiated as I have spend a day and a half trying to unravel it.
2020-01-11 04:41 AM
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.
2020-01-11 06:41 AM
; 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 */
}
//*****************************************************************************
2020-01-12 05:57 PM
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>© 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
2020-01-22 09:26 AM
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);
}
2020-01-27 02:09 PM
Additional Info:
The reason this problem occurred is that I switched from armcc V5 compiler to armcc V6
2024-01-07 11:31 AM - edited 2024-01-07 09:07 PM
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
);
}
2024-01-07 12:51 PM
@DavidAlfa Your variant of CM0 handler is incorrect. The correct variant by @Tesla DeLorean is above.
2024-01-07 06:23 PM - edited 2024-01-07 09:04 PM
Yep, there was a typo, should be "LDR R0, =hard_fault_handler_c"