Skip to main content
David Instone
Associate II
June 17, 2017
Question

Interrupts with STM8S003F3P6 and TIM2

  • June 17, 2017
  • 6 replies
  • 2819 views
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?

    This topic has been closed for replies.

    6 replies

    David Instone
    Associate II
    June 17, 2017
    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

    Tesla DeLorean
    Guru
    June 17, 2017
    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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
    David Instone
    Associate II
    June 18, 2017
    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.

    Tesla DeLorean
    Guru
    June 18, 2017
    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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
    David Instone
    Associate II
    June 19, 2017
    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.