cancel
Showing results for 
Search instead for 
Did you mean: 

Interrupts with STM8S003F3P6 and TIM2

David Instone
Associate II
Posted on June 17, 2017 at 12:50

STVD 4.3.10

Cosmic V4.3.7

eBay el cheapo STM8S003F3P6 (The blue one with the LED on B5)

Hello all. I am having a bit of a problem with I suspect basic interrupt coding. I have the LED blinking at a variable rate with a variable delay so all the port setups are OK but when I try to use TIMs with an interrupt it appears that I cannot change the Update Interrupt flag. In the debugger the interrupt service routine is entered, I can single step through it and toggle the LED but as soon as it is finished it goes straight back to the start of the Int routine. In the watch window the UIF flag does not get changed no matter what code I use but I can change it manually. In which case the program just seems to hang at the end of the interrupt routine. Here is the code

#define TIM2_CR1_ARPE    ((uint8_t)0x80) /*!< Auto-Reload Preload Enable mask. */

#define TIM2_CR1_OPM     ((uint8_t)0x08) /*!< One Pulse Mode mask. */

#define TIM2_CR1_URS     ((uint8_t)0x04) /*!< Update Request Source mask. */

#define TIM2_CR1_UDIS    ((uint8_t)0x02) /*!< Update DIsable mask. */

#define TIM2_CR1_CEN     ((uint8_t)0x01) /*!< Counter Enable mask. */

#define TIM2_IER_UIE     ((uint8_t)0x01) /*!< Update Interrupt Enable mask. */

#define TIM2_SR1_UIF     ((uint8_t)0x01) /*!< Update Interrupt Flag mask. */

/*SR2*/

void main( void )

{

    disable_interrupts();

    SetupOutputPortB();

    InitialiseTimer2();

    SetupTimer2();

    //enable_interrupts();

    main_loop();

  return;

}

void main_loop(void)

{

  while(1)

  {                     

    // Our LED is on Port B5

    //Turn on and off the output and then delay

            delay(40000);

            GPIOB->ODR ^= BIT5; //1<<5;// PB.5 XOR PIN5 Toggle

// Delay blink works fine

  }

}

void InitialiseTimer2()

{

TIM2->CR1 = 0;               // Turn everything TIM2 related off.

TIM2->IER = 0;

TIM2->SR1 = 0;

TIM2->SR2 = 0;

TIM2->CCER1 = 0;

TIM2->CCER2 = 0;

TIM2->CCER1 = 0;

TIM2->CCER2 = 0;

TIM2->CCMR1 = 0;

TIM2->CCMR2 = 0;

TIM2->CCMR3 = 0;

TIM2->CNTRH = 0;

TIM2->CNTRL = 0;

TIM2->PSCR = 0;

TIM2->ARRH  = 0;

TIM2->ARRL  = 0;

TIM2->CCR1H = 0;

TIM2->CCR1L = 0;

TIM2->CCR2H = 0;

TIM2->CCR2L = 0;

TIM2->CCR3H = 0;

TIM2->CCR3L = 0;

}

void SetupTimer2()

{

TIM2_PSCR = 0x000f;      // 2^PSC[3:0] Prescaler.

TIM2->ARRH = 0xef;      // c3 195 High byte of 50,000.

TIM2->ARRL = 0xfe;         // 55 85 Low byte of 50,000.

TIM2->CR1 |= TIM2_CR1_ARPE;   //0x80;     Auto reload preload enabled

TIM2->IER |= TIM2_IER_UIE;      //0x01;    TIM2 Update Interrupt enabled

TIM2->CR1 |= STM8_TIMx_CR1_CEN;   //0x01;    Turn ON timer

}

@far @interrupt void TIM2_UPD_OVF_IRQHandler(void);

//#define IRQ13 TIM2_UPD_OVF_IRQHandler

@interrupt void TIM2_UPD_OVF_IRQHandler(void){

// Interrupt routine is called no problem.

GPIOB->ODR ^= BIT5;             // PB.5 XOR PIN5

/* Even TIM2_SR1 = 0; Does not work  */

TIM2_SR1 ^= TIM2_SR1_UIF; //; 0x01

/*Reset the interrupt otherwise it will fire again straight away.

  Which it does anyway */

// disable_interrupts();

}

So can anybody figure out what I am missing here?

6 REPLIES 6
David Instone
Associate II
Posted on June 17, 2017 at 15:23

Here is the first offender

TIM2_SR1 ^= TIM2_SR1_UIF; //; 0x01

Which should be

TIM2->SR1 &= 0xfe; or

TIM2->SR1 &= !TIM2_SR1_UIF;

I also found

TIM2_PSCR = 0x000f;      // 2^PSC[3:0] Prescaler.

That should be

TIM2->PSCR = 0x000f;      // 2^PSC[3:0] Prescaler.

Like I changed all the others to. Bit of a problem when cutting and pasting from examples for all different compilers. Makes for a good bug hunt though

Posted on June 17, 2017 at 15:31

Are you sure the RMW form is correct, doesn't it just use a Write-Zero model?

TIM2->SR1 = !TIM2_SR1_UIF;

The &= form has a side-effect of clearing interrupts that occur between the Read and Write phases.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on June 18, 2017 at 07:53

Thanks Clive. Looking at this in the debugger,

temp = !TIM2_SR1_UIF;

TIM2->SR1 = temp;

!0x01 becomes 0x00. Therefore

TIM2->SR1 = !TIM2_SR1_UIF;

Not only resets the UIF but clobbers all the other bits in SR1. I would prefer to change only the bit I am after for portability and code safety reasons. That leads me to this to fix the &= phase delay problem as well

_asm('BRES TIM2_SR1, BIT0');

Which of course does not work in the compiler. 'symbol not defined' and the Cosmic manual so far says close enough to 'it cannot be done'.

'

Note that there is no direct connection possible with existing C objects.

'

So it is not good for portability or readability but I am left with this for the moment.

_asm('BRES 0x5304, ♯ 0'); // Clear TIM2 UIF

Not perfect but it is flashing the LED.

Posted on June 18, 2017 at 15:14

Sorry, tilde operation is likely the one we want, shouldn't have cut-n-pasted

TIM2->SR1 = ~TIM2_SR1_UIF;

Where ~0x01 is 0xFE

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on June 19, 2017 at 16:37

 ,

 ,

Of course the tilde. Why didn't I think of that. However it still does an arbitrary change to all the other bits as well so not ideal. So looking at this.

_asm('BRES 0x3c55, ♯ 0'),

 ,

 , ,  ,scratch[0] ^= 0x01,

 ,

 , ,  ,scratch[1] = ~scratch[2],

Leading the compiler to generate this

 ,53 , , , , , , , , , , , , , , , , , , , , , 12  , ,  ,_asm('BRES 0x3c55, ♯ 0'),

 ,

 , 56 , 0000 72113c55 , , , , , BRES 0x3c55, ♯ 0

 ,

 , 58 , , , , , , , , , , , , , , , , , , , , , 13  , ,  ,scratch[0] ^= 0x01,

 ,

 , 60 , 0004 b601 , , , , , , , ,  , , ,  ,ld , ,  ,a,_scratch+1

 ,

 , 61 , 0006 a801 , , , , , , , ,  , , ,  ,xor , ,  ,a, ♯ 1

 ,

 , 62 , 0008 b701 , , , , , , , ,  , , ,  ,ld , ,  ,_scratch+1,a , 63 , , , , , , , , , , , , , , , , , , , , , 14  , ,  ,scratch[1] = ~scratch[2],

 ,

 , 65 , 000a be04 , , , , , , , ,  , , , ldw , ,  ,x,_scratch+4

 ,

 , 66 , 000c 53 , , , , , , , , , ,  , , ,  , cplw , ,  ,x

 ,

 , 67 , 000d bf02 , , , , , , , ,  , , ,  ,ldw , ,  ,_scratch+2,x

The manual describes the BRES instruction as a Read,Modify,Write operation anyway so all three are much the same in that regard. The only real difference is the extra program space required and in the instruction length and therefore the clock cycles required. I have not found any documentation on the instruction set that gives that sort of detail though. BRES is shorter and only one instruction and I did try to write a sub to create the text string from but there appears to be no sprintf in Cosmic and then I tried this

char command[64] = 'BRES 0x3c55, ♯ 0',

 ,

 ,

 , ,  ,_asm(command),

But it gives me

♯ error cpstm8 main.c:16(0) bad _asm() argument type

Even with all &,,[],[0] ... variants I could think of

At this stage I think the slightly less aesthetic _asm('BRES 0x3c55, ♯ 0'), hardcoding is the winner.

Posted on June 19, 2017 at 16:54

 ,

 ,

Pah! Why do I always think of these things after I posted? How about.

♯ define TIM2_UIF_RESET 'BRES 0x3c55, ♯ 0'

 ,

 ,

 , ,  ,_asm(TIM2_UIF_RESET),

Which compiles to

 , 53 , , , , , , , , , , , , , , , , , , , , , 12  , ,  , _asm(TIM2_UIF_RESET),

 ,

 , 56 , 0000 72113c55 , , , , , BRES 0x3c55, ♯ 0

I dont think I have broken any code beautification rules there have I? It is certainly the most efficient method in code size and execution speed and does not clobber any other bits. It specifically alters only the one required. Portability is still an issue but it could go in the headers along with all the other device specific defines so that is solved too.