cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F10x interrupt issues

ivan23
Associate II
Posted on March 14, 2014 at 16:13 I'm using an STMF103RCT MCU in IAR 6.5 for ARM. I'm working from a public institution with a questionable software sourcing policy - don't ask me to install Eclipse/OpenOCD/Zadig - I've spent 3 weeks installing it on my ..ahem.. windows and it failed every single time. I have created a 4x4 interrupt table, for various functions I have to launch. So far I am experiencing random PC jumps and Hard faults for every function call I have within an interrupt handler. I have several questions: - I am assuming that my MCU has 48kBytes RAM and 256 kBytes flash, do I assume correctly when I think that the mapped space in the icf must exceed the physical space, and I've created the following .icf:

/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile=''$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml'' */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x08000000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
define symbol __ICFEDIT_region_ROM_end__ = 0x0803FFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x2001FFFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x4000;
define symbol __ICFEDIT_size_heap__ = 0x1000;
/**** End of ICF editor section. ###ICF###*/
define memory mem with size = 4G;
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
initialize by copy { readwrite };
do not initialize { section .noinit };
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
place in ROM_region { readonly };
place in RAM_region { readwrite,
block CSTACK, block HEAP };

I'm using a semihosted debug mode, am I correct to assume that it takes some memory and it might influence execution? Where are the statically-initialized arrays placed for STM32F10x? The standard assembler file provided for the chip didn't work (lots of unknown identifiers), so I took the one from the STM Standard peripheral library and modified it as follows:

; Due to a general development environment defect (unlicensed IAR) the vector table
; options are inaccessible from the menus
; This vector table and memory map file is therefore in conflict with the file D:\Program
; Files\IAR Systems\Embedded Workbench 6.5\arm\src\lib\thumb
; Stage 2 fails to run properly with the standard file, even using the usual ''keep section'' flags.
MODULE ?cstartup
;; Forward declaration of sections.
SECTION CSTACK:DATA:NOROOT(3)
SECTION .intvec:CODE:NOROOT(2)
PUBLIC __vector_table
EXTWEAK __iar_init_vfp
EXTWEAK __iar_init_core
EXTERN __iar_program_start
EXTERN __cmain
;; EXTERN __iar_program_start
;; EXTERN SystemInit 
;; PUBLIC __vector_table
....
unchanged assembler afterwards, except removed references to FSMC vectors (as it is said to be absent from my MCU STM32F10C_series - CD00191185)

SPI_MASTER_Buffer_Rx, SPI_MASTER_Buffer_Tx, MAX11040 are extern variables, for every file they are used in, except the header files where they are actually declared What am I doing wrong in my calls to functions from the interrupt processing routines? Any call to a function from here results in random behavior or a hard fault...

/**
* @brief This function handles External line 0 interrupt request.
* from MAX11040 ADC
* @param None
* @retval None
*/
void EXTI0_IRQHandler(void)
{
uint32_t empty[4]={0};
uint8_t dummy=0;
if((NVIC_GetPendingIRQ(EXTI0_IRQn)==1) || EXTI_GetITStatus(EXTI_Line0)!=RESET)
{
/* Clear the EXTI line 0 pending bit */
NVIC_ClearPendingIRQ(EXTI0_IRQn);
EXTI_ClearITPendingBit(EXTI_Line0);
/* Configure the BASEPRI register to 0x40 (Preemption priority = 1).
Only IRQ with higher preemption priority than 1 are permitted. */
__set_BASEPRI(0x40);
/* Read a packet */
MaxAdcManiReg(&MAX11040 , SPI_MASTER_Buffer_Rx, (uint16_t)MAX11040_DATAREG_SIZE_B, SPI_MASTER_Buffer_Tx, MCMD_R_DATAREG);
//uint8_t MaxAdcManiReg(SPI_group* GSPIx, uint8_t *ibuffer, uint16_t len, uint8_t* obuffer, uint8_t command);
/*TODO: optimal PPS - use timer instead of polling(here)*/
Data_Split(empty, SPI_MASTER_Buffer_Rx ,Datalogger_PPSState());
// 
__set_BASEPRI(0x00); // return to pending status
filt_ToBuff(&RBuffer,empty);
}
}

What am I doing wrong with the memory mapping(?) - sometimes my main() starts going into interrupt processing during debug even without interrupts being configured first... #exti #spi #stm32f103 #nvic
5 REPLIES 5
Posted on March 14, 2014 at 16:30

Defining 128KB of RAM is inviting disaster if you only have 48 KB (0xC000, ie 0x20000000..0x2000BFFF)

You touch this wrong and you get a Hard Fault immediately. Use a proper Hard Fault Handler, ie not while(1), but Joseph Yiu style, and understand what the nature of the fault is, and what registers/memory are involved.

To paste code use the Format Code Block tools (Paintbrush[<>] icon, top left of the window)

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
ivan23
Associate II
Posted on March 14, 2014 at 16:47

Clive, thank you for your reply.

I usually end up in unmapped region when analysing the data of HardFault or just by reading the stack. The issue is that - when I define my actual RAM in the ICF, as it says in the spec, it says there is not enough memory to place my file, which is of ~57kbytes.. but all the size optimizations are active in my tool-chain. Isn't all code placed in ROM? Where are the constants placed? By the end of the actual flash programming the total data written it says only 17kBytes were written in the RAM I have quite a lot of constants, but they are all static, I also have two ring buffers of 4 kBytes total size that I absolutely have to have , as those are constantly reprocessed. This is my HardFault handler, which I took from someone more experienced than I am.

void HardFault_Handler(void)
{
static char msg[80];
printErrorMsg(''In Hard Fault Handler
'');
sprintf(msg, ''SCB->HFSR = 0x%08x
'', SCB->HFSR);
printErrorMsg(msg);
if ((SCB->HFSR & (1 << 
30
)) != 0) {
printErrorMsg(''Forced Hard Fault
'');
sprintf(msg, ''SCB->CFSR = 0x%08x
'', SCB->CFSR );
printErrorMsg(msg);
if((SCB->CFSR & 0xFFFF0000) != 0) {
printUsageErrorMsg(SCB->CFSR);
}
}
stackDump((uint32_t *)(__get_PSP()));
__ASM volatile(''BKPT #01'');
/* Go to infinite loop when Hard Fault exception occurs */
while (1) { }
}

Posted on March 14, 2014 at 16:56

You really should review the .MAP file and understand what you have in RAM. If the linker fails it thinks stuff should be in RAM. You've clearly oversubscribed the available RAM

Things which are ''const'' or ''static const'' should get placed in FLASH. Other static variable will either get copied to RAM if they are non-zero, and other variable regions will be zerod, as part of the start up process code for C run time library.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
ivan23
Associate II
Posted on March 14, 2014 at 17:02

Ok, I'll make sure that all the constants are really static consts and check the linker map.

ivan23
Associate II
Posted on March 18, 2014 at 08:09

Well, I did that and reduced some temporary structure sizes, but I still have the Hard Fault upon reading or writing of any global variable from an IRQ handler. Here's an excerpt of the linker map file. Any access here from a function called from within the EXTI0 which I posted earlier, or for that matter any other Data Gb goes to HardFault.

SPI_InitStructure 0x200068ac 0x14 Data Gb main.o [2]
SPI_MASTER_Buffer_Rx 0x200068c0 0xc Data Gb main.o [2]
SPI_MASTER_Buffer_Tx 0x20004bb0 0xc Data Gb main.o [2]

The variables are declared as follows: In the main.

/*ADC and SPI read and write buffers - used in directed transfers */
uint8_t SPI_MASTER_Buffer_Tx[MAX11040_PacketSize]={0};
uint8_t SPI_MASTER_Buffer_Rx[MAX11040_PacketSize]={0};

In the IRQ processor:

/**/
extern uint8_t * SPI_MASTER_Buffer_Rx;
extern uint8_t * SPI_MASTER_Buffer_Tx;

The function where HardFault arises is such that:

uint8_t MaxAdcManiReg(SPI_group* GSPIx, uint8_t *ibuffer, uint16_t len, uint8_t* obuffer, uint8_t command)
{
uint8_t status;
uint16_t i;
/*Select SPI device*/
GPIO_ResetBits(GSPIx->GPIO[0],GSPIx->Pins[S_SS]);
/* Send the command with the address */
status = MaxAdcSendByte(GSPIx->SPIP, command );
/* Read LEN bytes */
if( len!=0 ) 
{for(i=0; i<
len
; i++) 
{ibuffer[i]=MaxAdcSendByte(GSPIx->SPIP, obuffer[i] );}
}
GPIO_SetBits(GSPIx->GPIO[0],GSPIx->Pins[S_SS]);
return status;
}

And the function it uses to read a single byte:

static uint8_t MaxAdcSendByte(SPI_TypeDef* SPIx, uint8_t b)
{
/* Loop while DR register in not empty */
while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
/* Send byte through the SPI peripheral */
SPI_I2S_SendData(SPIx, b);
/* Wait to receive a byte */
while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);
/* Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(SPIx);
}

The code above used to work without hard faults before I moved all the peripheral-specific procedures and inits into separate files and arranged a proper build order. I realize this sounds stupid, but there is strictly no change in the code, compared to when it was in a single file. No warnings on compile time, too. I even passed much of the code though the built-in IAR MISRA-meter and CPPCheck to find problems and there were no significant issues in MISRA and nothing at all in CPPCheck.... The other issue I'm having, appears during debug - that is IAR losing context and going into a call from one function, but returning from a different part of the code. I.e:

void Stage0(void)
{ uint32_t result=0; /*TODO for Unity*/
MaxAdcSetup(&MAX11040, result); // going into the call here
while(GPIO_ReadInputDataBit(SPI_MASTER_GPIO_EXT, SPI_MASTER_PIN_DRDY)!=0) {}
/*Read the first 96-bit set of digitized measures*/ 
MaxAdcManiReg(&MAX11040, SPI_MASTER_Buffer_Tx, (uint16_t)MAX11040_DATAREG_SIZE_B, SPI_MASTER_Buffer_Tx, MCMD_R_DATAREG);
}
....
void Stage2()
{
uint32_t result=0; 
MaxAdcSetup(&MAX11040, result); // coming out of the call here
/* Initialize Leds LD1 and LD2 mounted on Datalogger board */
Datalogger_LEDInit(VD2_PIN);
Datalogger_LEDInit(VD1_PIN);
/* Turn the LED on to check on IRQ*/
Datalogger_LEDOn(VD1_PIN);
Datalogger_LEDOn(VD2_PIN);
/*Configure the EXTI 0 line to become active on the falling MAX11040 DRDY edge*/
EXTI0_Config();
IRQ_Config();
Ringbuf_Init(&(RBuffer.b), MaxData,(MAX11040_CHDEPTH+8)>>3,MAX11040_CHANNEL);
NVIC_SetPendingIRQ(EXTI0_IRQn);
EXTI_GenerateSWInterrupt(SPI_MASTER_IRQ);
while(cycles>0) { /*wait for a minute*/ } 
SD_Fulltest();
//*TODO*//
}

I wonder if it's related to the HardFault or is it a malfunction of my 'special' IAR?