Skip to main content
Explorer II
December 28, 2023
Solved

I2C action from timer callback

  • December 28, 2023
  • 7 replies
  • 3316 views

Hi,
I am working with STM32G4 and I have problem reading/writing the I2C data with in the  timer callback.
I have Timer1 calling my interrupt callback every 50 microseconds which is working well.
I have I2C read/write functions which are working well.I2C is not Interrupt based.
The problem occur while reading/writing the I2C data within the timer callback
I am unable to read/write  the I2C data in the timer interrupt callback
Below is the timer callback

 

 

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
 if (htim == &htim1)
 {
	 if(dcheck.flagon_2sec1){
	 dcount.s_2_sec1++;
		if(dcount.s_2_sec1==40000){
			delay.flag_2sec1 = 1;
		 expander_read(&hmcp,REGISTER_INPUT,data);
			dcount.s_2_sec1=0;
			dcheck.flagon_2sec1=0;
		}
	 }
 
 }
 }

 

 

Normal I2C read/write working but with in the timer callback its not working.
Can anyone suggest.
Thanks

 

    This topic has been closed for replies.
    Best answer by AScha.3

    When only using 50us timer, i would make a simple counter in the INT and set a global (volatile) variable, to start the i2c command.

    volatile int aa, start_i2c = 0 ;
    
    in INT:
    aa++;
    if (aa>2000) {aa=0; start_i2c = 1; }
    
    
    in main loop then:
    ...
    if(start_i2c==1)
    {
    start_i2c=0;
    ... >> do i2c things...
    }
    ...

    7 replies

    Super User
    December 28, 2023

    "not working" is a very vague description, be more precise what happens.

    Same with expander_read which probably nobody except you has ever heard of.

    Note that the callbacks run in handler mode, which may prevert other interrupts from running depending on priority... settings. Such as another timer that may not tick while in the callback.

    hth

    KnarfB

     

     

    Explorer II
    December 28, 2023

    Hi @KnarfB,

    1.I am interfacing IO expander with STM32G4


    Same with expander_read which probably nobody except you has ever heard of.


     

    expander_read(&hmcp,REGISTER_INPUT,data);

     

    This will read the input register of expander and data present in the input register will be saved to data variable.

    2.

    "not working" is a very vague description, be more precise what happens.


    While debugging I found that its entering into the timer callback 2sec delay check but its not reading the io expander input register. I changed the read operation with io expander output register write .I can't able to read/write in the timer callback.
    If I do the same operation other than timer callback its working.

    3.For I2C I am not using interrupt to give the priority.
    4.IO expander driver reference .I took this as reference for my IO expander driver development. Its working well other than timer callback

    Please suggest.
    Thanks

    Super User
    December 28, 2023

    Hi,

    50us - really ??  In this time you can send on standard I2C about 5 bit , on hi-speed I2C (400kHz) two bytes ...

    No useful setting, simply said. 

    First calculate, how many byte you want to transfer on I2C , at 100 or 400kHz, then add some "free" time for the cpu (to do anything else than I2C), so you get the useful/possible timer setting.

    Explorer II
    December 28, 2023

    Hi @AScha.3 ,

    I thought of using same timer callback for all delay requirements.
    In my application 50us delay required for high priority operation that's why I took 50 usec delay.
    I checked for 50us ,800 usec delays in other functions(related to PWM/ADC ) they are working fine.
    But for I2C communication(read/write) not working with in the timer callback.
    I need to do i2c read& write  after 2sec and 100 msec delays. Its not working.
    1.Can I take other timer interrupt with less time?
    2.For read I need to read 8 bit register and for write I need to write 8 bits data.
    Please suggest
    Thanks

    Super User
    December 28, 2023

    1: If your i2c tx/rx needs not to be "sync" to the 50us timer (anyway almost impossible) use other timer with making 100ms delay or whatever, or set it with trigger from your 50us timer, counting 2000 triggers -> 100ms (almost sync to the 50us event )

    2: ok . At 100ms or 2s interval i see no problem with using the i2c .

    Explorer II
    December 28, 2023

    @AScha.3,

    I will try the first suggestion and also 
    If I want to use the  50us timer any suggestions.

    Thanks

    AScha.3Answer
    Super User
    December 28, 2023

    When only using 50us timer, i would make a simple counter in the INT and set a global (volatile) variable, to start the i2c command.

    volatile int aa, start_i2c = 0 ;
    
    in INT:
    aa++;
    if (aa>2000) {aa=0; start_i2c = 1; }
    
    
    in main loop then:
    ...
    if(start_i2c==1)
    {
    start_i2c=0;
    ... >> do i2c things...
    }
    ...
    Explorer II
    December 28, 2023

    Hi @AScha.3 ,
    I tried above way but after expander_write execution not going inside if loop. 

    aa++;

     

    if (aa > 40000) {

    aa = 0;

    start_i2c = 1;

    }
    previously same logic I checked inside HAL_TIM_PeriodElapsedCallback()
    that time execution not going inside the if loop.

     

    volatile int aa, start_i2c = 0 ;
    
    function_on(){
    expander_write_GPIO(&hmcp ,HIGH);
    if(start_i2c){
     start_i2c=0;
     tca9537_write_gpio(&hmcp ,TCA9537_OUTPUT_IO12_HIGH);
     }
    }
    void TIM1_IRQHandler(void) {
     aa++;
    
     if (aa > 40000) {
     aa = 0;
     start_i2c = 1;
     }
     
    }

     

     

    Super User
    December 28, 2023

    Check and clear the flag that is triggering the TIM1 handler, otherwise it will continuously trigger. Look at how HAL_TIM_IRQHandler does it.

     

    Explorer II
    December 29, 2023

    Hi @TDK ,
    I tried below way to clear the triggering flag of timer but I am facing same problem execution not going inside the
    if(delay.flag_2sec1 == 1) loop.

     

     void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
    	if (htim == &htim1)//50 usec timer interrupt
    	 {
     if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET) {
     // Clear the update interrupt flag for TIM1
     __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE);
    	 if(dcheck.flagon_2sec1){
    	 dcount.s_2_sec1++;
    		 if(dcount.s_2_sec1==40000){
    			 delay.flag_2sec1 = 1;
    			 dcount.s_2_sec1=0;
    			 dcheck.flagon_2sec1=0;
    		 }
    	 }
     }
    }
    //function using 2sec delay
    void on(){
     expander_write(&hmcp,IO1_HIGH);
     dcheck.flagon_2sec1=1;
     if(delay.flag_2sec1 == 1){
     delay.flag_2sec1 = 0;
     expander_read(&hmcp,REGISTER_INPUT,data);
     }
     if(data==0x80){
     expander_write(&hmcp,IO2_HIGH);
     }
    }
    
    
    //main.c
    HAL_TIM_Base_Start_IT(&htim1);

     

     Is this what were you suggesting or something else? Please suggest.
    In other functions I used 50 us and 800 us delay from same timer callback its working fine. So,I think timer is clearing before adding clear the flag logic.
    I am facing this issue with I2C read/write only with timer interrupt.
    Thanks




    Explorer II
    December 29, 2023

    Hi @TDK , @AScha.3,
    below is my delay application and usage.

     

    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
    	if (htim == &htim1)//50 usec timer interrupt
    	 {
    	 if(dcheck.flagon_100msec){
    	 	dcount.m_100_sec++;
    			if(dcount.m_100_sec==2000){
    			 delay.flag_100msec = 1;
    			 dcount.m_100_sec=0;
    			 dcheck.flagon_100msec=0;
    			}
    	 }
    	 if(dcheck.flagon_2sec1){
    	 dcount.s_2_sec1++;
    		 if(dcount.s_2_sec1==40000){
    			 delay.flag_2sec1 = 1;
    			 dcount.s_2_sec1=0;
    			 dcheck.flagon_2sec1=0;
    		 }
    	 }
     }
    }
    //function using 2sec and 100 ms delay
    void on(){
     (io expander-inpur register read)
     make I01 HIgh
     //need 2sec delay here
     dcheck.flagon_2sec1=1;
     if(delay.flag_2sec1==1){
     (io expander-inpur register read)
     delay.flag_2sec1==0
     }
     check IO0 value
     //need delay 2sec delay here 
     dcheck.flagon_2sec1=1
     if(delay.flag_2sec1==1){
     IO2 HIGH
     delay.flag_2sec1==0
     }
     //need delay 100 msec here
     dcheck.flagon_100msec=1
     if(delay.flag_100msec ==1){
     IO1 Low
     delay.flag_100msec ==0
     } 
     }
    
    }
    
    
    //main.c
    HAL_TIM_Base_Start_IT(&htim1);
    on();

     

    Now what I observed is I2C read/write is working with above logic
    but in on() function first checking 2 sec delay since 2sec by not completed by timer  its going to next statement same with next 2 sec delay and then for 100 msec delay when its reached by timer its going inside and performing the logic inside 100ms flag and for one 2sec delay its performing the 100 msec delay logic 20 times.
    This is I observed.
    But what I need is 
    after making IO1 HIgh I need 2sec (non blocking) delay then read expander then 2sec delay(non blocking) and make IO2 HIGH and 100 ms delay (non blocking) make IO1 Low.

    Please suggest.
    Thanks



    Thanks

    Super User
    December 29, 2023

    In your last post you were writing TIM1_IRQHandler yourself, now you're using HAL. Either is fine, but let's stick to one so we can make progress.

    If using HAL and HAL_TIM_PeriodElapsedCallback is called, the flag has already been cleared in HAL_TIM_IRQHandler.

    Explorer II
    January 2, 2024

    Hi @TDK,
    I am using HAL library only. Sorry for the confusion caused.
    My application: after making IO1 High I need 2sec (non blocking) delay then read expander then 2sec delay(non blocking) and make IO2 HIGH and 100ms delay (non blocking) make IO1 Low.
    In below logic while checking 2sec flag if it not high its going to next logic performing those instruction execution.
    But my issue is I need 2sec delay(make I01 High) and 100ms delay.
    dcheck.flagon_2sec1=1,where should I make this flag high?
    I will call on() function in my logic only one time so when it enters inside logic it should perform the all the operation inside the on() function.
    Please suggest.

     

    void on(){
     (io expander-inpur register read)
     make I01 HIgh
     //need 2sec delay here
     dcheck.flagon_2sec1=1;
     while(delay.flag_2sec1==1){
     (io expander-inpur register read)
     delay.flag_2sec1==0
     dcheck.flagon_2sec2=1
     }
     check IO0 value
     //need delay 2sec delay here 
     dcheck.flagon_2sec2=1
     while(delay.flag_2sec2==1){
     IO2 HIGH
     delay.flag_2sec2==0
     dcheck.flagon_100msec=1
     }
     //need delay 100 msec here
     while(delay.flag_100msec ==1){
     IO1 Low
     delay.flag_100msec ==0
     } 
     }

     


     

    Super User
    January 2, 2024

    You can't have a non-blocking 2 second delay in the middle of code unless you're using an OS such as FreeRTOS.

    Consider instead having a timer callback trigger every 100 ms and advance a state machine to perform the required logic. First time it's called will be t=0, 20th time will be at t=2s, etc...

    Explorer II
    January 5, 2024
    When only using 50us timer, i would make a simple counter in the INT and set a global (volatile) variable, to start the i2c command.
    
    volatile int aa, start_i2c = 0 ;
    
    in INT:
    aa++;
    if (aa>2000) {aa=0; start_i2c = 1; }
    
    
    in main loop then:
    ...
    if(start_i2c==1)
    {
    start_i2c=0;
    ... >> do i2c things...
    }
    ...

    Thanks @TDK @AScha.3 for the support. Above suggestion worked for me. Below suggestion will do the work.



    You can't have a non-blocking 2 second delay in the middle of code unless you're using an OS such as FreeRTOS.

    Consider instead having a timer callback trigger every 100 ms and advance a state machine to perform the required logic. First time it's called will be t=0, 20th time will be at t=2s, etc...

     

     


    Apart from timer related doubts my I2C didn't worked before when I tried the accepted solution I figured out that before  I called I2C handler in main() function it made it local and in other files I can't able to read and write the io expander i2c and now  I mentioned handler before main() function as global and nowI can able to read/write. That's mistake from my side.

    Thanks