This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

get your IAR assembler IRQ templates

IRQ's should be fast and quick as to not interfere with other IRQ's
Fine-tuned Asm code  will help to make them short and sweet.

And I never liked how C handles TAIV registers, a visual mess.
And I don't like to have a offset jump limit, so I use a branch look-up table instead of a jmp table.

        NAME   TA0_IRQ           ; module name
        #include "msp430.h"      ; #define controlled include file
        PUBLIC  TIMER0_CCR0      ; make the main label visible outside this module
        COMMON  INTVEC(1)
        ORG     TIMER0_A0_VECTOR
        DC16    TIMER0_CCR0		 ; set irq vector for ccr0
	    ORG     TIMER0_A1_VECTOR 
        DC16    TIMER0_A1		 ; set irq vector for all other
        RSEG    CODE			 ; place program in 'CODE' segment
TIMER0_A1						
	    mov.w	&TAIV, R4 		 ; R4 is never used by C, so make it the default IRQ scratch register	 
	    mov.w	T0_A1_T(R4), PC	 ; Branch lookup Table, this avoids the ±128 jmp limit
resrvd  reti
T0_A1_T DC16 resrvd, TIMER0_CCR1, TIMER0_CCR2, resrvd, resrvd, TIMER0_TA, resrvd, resrvd	


TIMER0_CCR0
	// CCR0 your code here 
	reti

TIMER0_CCR1
	// CCR1 your code here
	reti

TIMER0_CCR2
	// CCR2 your code here
	reti
	
TIMER0_TA
	// OverFlow your code here
	reti
	
	END

Mixing C and Assembler with the MSP430: SLAA140


I attached IRQ templates for PORT 1 & 2 and TA0 and TA1
IAR, Project> Add Files...
add: extern public_name (to the main/calling module)

IAR_IRQ_Templetes.zip

  • Tony Philipsson said:
    ; R4 is never used by C, so make it the default IRQ scratch register

    Never say never.

    True, R4 and R5 are usually not used by C. Thus they can be used by the assembler coded freely. In this case, they are global and persistent too.

    Tony Philipsson said:
    ; Branch lookup Table, this avoids the ±128 jmp limit

    On the other hand, if the ISRs are "fast and quick", they might fit within jmp range and jmp is faster than Branch lookup.

  • >if the ISRs are "fast and quick", they might fit within jmp range and jmp is faster than Branch lookup.

    But as you don't need to re-jump (two changes to PC) as that is happening when using a jump table.
    In the above TAIV example there is just a single branch, directly to intended target address.
    Getting 64K jump space and may not even loose 1 cycle (I updated cycle count)
    I had a IRQ routine that was "fast and quick" but as it had so many stages, though each stage is only ~6 instructions
    I still ran out of 128 (I think it's 512word) jump range.

    And if your ISR is a module (the table will have modules direct address), not worrying where in flash the compiler put it is nice.
    This is all leading up to my future F#/asm/Spin type msp430 programmer, were all these complexities will be hidden from user.

    Option1:
    add &TAIV, PC  ; 3 cycles (I think IAR is wrong as any changes to PC adds one cycle =4 cycles)
    jmp CCR1          ; 2 cycles

    Option2:
    mov &TAIV, R4 ; 3 cycles
    BR table(R4)       ; 3 cycles

  • Eedited!!

    Tony Philipsson said:
    Getting 64K jump space and loosing 1 cycle I think is worth it.

    Yes, I agree, and R4 is used as a temporary storage.

    Tony Philipsson said:
    I had a IRQ routine that was "fast and quick" but as it had so many stages, though each stage is only ~6 instructions
    I still ran out of 128 jump range.

    Whereas I had an IRQ that was best handled by a State Machine. Thus I would like to use R4 as the State of the State Machine.

    add &TAIV, PC
    BR R4

  • old_cow_yellow said:
    Never say never.

  • old_cow_yellow said:
    Never say never.

  • What is "Normal use" anyway?

    For quick IRQs, don't waste cycles by pushing/pulling registers to the stack.

    Dedicate 2 scratch registers for main and 2 for irq's.
    R4 and R5 looks like a good choice to be the default irq scratch.

    So I guess the correct settings would be Not used or regvar use.

    __no_init int  __regvar scratch1 @ __R4;

  • Tony Philipsson said:
    __no_init int  __regvar scratch1 @ __R4;

    I think that will work if you write both main and ISR in c. If you write main in c and ISR in assembly, then your ISR must push R4 before you use is as scratch, and pop R4 before your reti. Otherwise the scatch1 in main will be corrupted by your ISR.

    Select Not used will work better if you write main in c and ISR in assembly which needs a scratch register without push pop.

    I do not use c and do not know much about c. I use the assembler in IAR Kickstart because it is relatively stable, free, and have no size limit. I occasionally play with the size limited c complier just out of curiosity.

  • Yes, it's +-512 words. For the JMP instructions, the lower 10 bits are the offset in words.

    IIRC the compiler may use any available register for local variables or intermediate results. Sure, only the necessary number of registers is used (so they don't need to be saved and restored on function entry/exit), but AFAIK there is no register that is excluded from usage.
    On old MSPGCC, R4 was used as frame pointer, since during multiplications, the stack pointer changes (for storing SR), shifting the access to local variables on the stack. Sometimes, this use was optimized away if it turned out to be no required (directly using SP), but not always.

    In general, in ISRs no register may be clobbered. Which makes it difficult if one splits from the ISR entry to different code parts. If the entry code requires a register (and therefore has to save it on stack), all code parts it later jumps to need to restore it.
    So if data storage is required, use a memory location. Luckily, the MSP structure allows working with memory directly as if it were a large number of slow-access register (unlike other processors where you need to load data into a register first before you can modify it)

    Regarding the timing, yes, the add should be 4 cycles. Same for the BR. However, the option2 is then not only still slower by one cycle, it is also larger and requires a register, so R4 needs to be stored (another 2 bytes and cycles).
    Well, if you encounter a range problem with the first option (the linker will tell you) you can always add an additional jump or branch to the largest code part (so the others come closer). Remember, you can even put them before the ISR entry too :)

**Attention** This is a public forum