cancel
Showing results for 
Search instead for 
Did you mean: 

code crashes and lead to Hardfault when I include I2C1_IRQ_handler.

GR.5
Associate II

Hi guys,

I using 

keil uvisionV5.35.0.0

arm_compiler : V6.16

We are developing a project on STM32L071CZYx MCU. which has 

flash memory: 192kB

RAM: 20KB

I have attached a I2C1_IRQhandler function for your reference.

void I2C1_IRQHandler(void)
{
		I2C1->CR1 &= ~(I2C_CR1_RXIE |I2C_CR1_ADDRIE | I2C_CR1_STOPIE | I2C_CR1_TXIE);
		switch((I2C1->ISR &(I2C_ISR_STOPF | I2C_ISR_ADDR |I2C_ISR_RXNE | I2C_ISR_TXIS)))
		{
			case 0x08: //address match
				dev_addr = ((I2C1->ISR >> 16 ) & 0xFE); // assigning Recieved slave address
				if(I2C1->ISR & I2C_ISR_DIR)
					{
						// Slave address with Read bit
						if(i2c_state == I2C_GOT_CONTROL_WORD_ADDR)
						{
							i2c_state = I2C_REPEATED_START;
						}
						else 
						{
							i2c_state = I2C_RD_STARTED;
						}
						__HAL_I2C_CLEAR_FLAG(&hi2c1,(I2C_FLAG_ADDR ));
						I2C1->CR1 |= (I2C_CR1_TXIE); // enabling Transmitter Interrupt
						//slave Tx
					}
				else
					{
						// Slave address with write bit
						i2c_pkt_length = 0;
						
						i2c_state = I2C_WR_STARTED;
						__HAL_I2C_CLEAR_FLAG(&hi2c1,I2C_FLAG_ADDR);
						I2C1->CR1 |= (I2C_CR1_RXIE); // stopIE is not required
						//slave Rx
						} 
			break;
			case 0x04: //rx data for master
				if(i2c_state == I2C_WR_STARTED)
				{
					CW =I2C1->RXDR;
					word_addr = CW;
					i2c_state = I2C_GOT_CONTROL_WORD_ADDR;
				}
				else
				{
					i2cdatarx[i2c_pkt_length++] = I2C1->RXDR;
					i2c_state = I2C_DATA_STARTED;
				}
				__HAL_I2C_CLEAR_FLAG(&hi2c1,I2C_FLAG_RXNE);
			I2C1->CR1 |= (I2C_CR1_RXIE | I2C_CR1_ADDRIE | I2C_CR1_STOPIE); // enabling Rx address match and Stop interrupt
			break;
			
			case 0x20: // detected a stop
				if (dev_addr == 0xB0 )
				{
					if (i2c_state == I2C_DATA_STARTED || i2c_state == I2C_GOT_CONTROL_WORD_ADDR)
					{
						F0_write(word_addr);
					}
					else 
					{
					I2C1->ISR |= I2C_ISR_TXE;//Setting  flushing the TX buffer for new data transfer
					}
				}
				else
				{
					if (i2c_state == I2C_DATA_STARTED || i2c_state == I2C_WR_STARTED)
					{
						if (mode == mFACTORY)
						{
							A0_write_FM(word_addr); // writting to sram and Eeprom
						}
						else
						{
							A0_write(word_addr);
						}
					}
					else 
					{
					I2C1->ISR |= I2C_ISR_TXE;//Setting  flushing the TX buffer for new data transfer
					}
				}
				i2c_state = I2C_IDLE;
				__HAL_I2C_CLEAR_FLAG(&hi2c1,I2C_FLAG_STOPF);
				I2C1->CR1 |= (I2C_CR1_ADDRIE); // enabling address match 
			break;
			case 0x02: // Transmit has detected
					
					//i2cdatarx = I2C_read_F0(CW);
					if (dev_addr == 0xB0)
					{
						I2C1->TXDR = F0_Read(CW);
					}
					else
					{
						if (mode == 1)
							{
						I2C1->TXDR = A0_read_FM(CW);
							}
						else
							{
							I2C1->TXDR = A0_read(CW);	
							}
					}
				__HAL_I2C_CLEAR_FLAG(&hi2c1,(I2C_FLAG_ADDR));
				I2C1->CR1 |= (I2C_CR1_STOPIE | I2C_CR1_TXIE);
			break;
		}
}

here I2C1 is configured has a slave.

without I2C_IRQ_handler function I2C1 will work well in polling mode.

Code crashes and lead to hardfault at hsc_dev_obj_init when I include I2C1_IRQ_handler function.

0693W00000aIoTnQAK.pngI have tried all the ways like increasing stack memory and reducing global variables but nothing works. please help me to resolve this error.

Regards,

Gopal Gowda

8 REPLIES 8
Foued_KH
ST Employee

Hello @GR.5​ ,

Please check the LR register content (in CPU registers), if :

  • 0xFFFF-FFF1: Handler stack  
  • 0xFFFF-FFF9 : main stack 
  • 0xFFFF-FFFD : process stack 

If main stack => copy the @ in the main stack register and paste it in the memory view .

Copy the PC content and paste it in the disassembly viewer and see the instruction that cause the HardaFault 

Foued

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

GR.5
Associate II

Hi KHALSI_Foued Thanks for your reply,

As we can see above the LR register value is 0xFFFF-FFF9 and call stack local is showing hsc_dev_obj_init lead to the hardfault your suggesting that there is problem in handling main stack (may be stack overflow) so I have tried to increase the stack size and reduce the global variables in the program but still not working.

I don't know how I2C1_IRQ_handler is causing the problem?

Regards,

Gopal Gowda

Have a better routine to display registers at fault, and identify specific instructions involved.​

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
GR.5
Associate II

Hi Tesla thanks for your reply,

I have attached a function at which I am getting Hardfault.

hsc_dev_t* hsc_dev_obj_init(struct hsc_dev_cls *dev, uint32_t asic_id)
{
    /* Initialize */
    HSC_MEMSET(dev, 0x0, sizeof(struct hsc_dev_cls));
    dev->ops = NULL;
    dev->asic_id = asic_id;
    dev->pkg_type = 0;
 
    return (hsc_dev_t*) dev;
}

But there won't be any crash in code if I don't add I2C1_IRQhandler function

only when I include I2C1_IRQhandler function It crashes.

 I don't know How I2C1_IRQhandler function is responsible for crash.

Regards,

Gopal Gowda

GR.5
Associate II

Hi Krani thank you for reply,

can u elaborate please.

do you mean to display all the registers like R0 R1 R2 R3 R12 LR SP PC registers in the hard fault function.?

In Debug mode I executed step by step instructions when I try to execute

dev->ops = NULL of hsc_dev_obj_init function it is leading to hardfault.

Bob S
Principal

Search these forums, or even the Keil website for fault handler code. @Community member​ has posted several (many????) of them here. Not just CPU registers but the memory management/fault registers.

Hmmm... I've never used uVision on ARM chips, but doesn't it have a fault analysis window somewhere in their IDE?

Sanity check the pointer "dev", ie its not NULL, misaligned, pointing outside of RAM

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

It does have something, not sure I've learned how to drive it. I know the MCU, I know my code, and I know what I'm looking for..

But, having useful output to a serial port is a force multiplier, it can be used to diagnose failures in the field, using very simple tools, and on large blocks of soak-test units it doesn't require debuggers/pods and infrastructure to the same degree to monitor/log units.

On a good day it can bracket the offending instruction, and I don't even need specific source

https://github.com/cturvey/RandomNinjaChef/blob/main/KeilHardFault.c

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