AT89S52 Software Generated Interrupt

Discussion in 'Embedded Systems and Microcontrollers' started by Dseng, May 14, 2016.

  1. Dseng

    Thread Starter New Member

    Jan 13, 2016
    20
    2
    I am trying to generate an interrupt via software in an Atmel AT89S52. It's my understanding that I can set TCON.1 to generate a software interrupt but, for some reason, after I set it, it's not branching to the ISR. It works fine when I do a hardware interrupt. Here is some basic code I wrote to test it. Am I missing something?

    org 0
    SJMP RESET
    org 3
    LJMP ISERV

    RESET: MOV IE,#81H ;ENABLE INTERRUPT
    SETB TCON.1 ;GENERATE AN INTERRUPT

    HERE: SJMP HERE

    ISRV: MOV A,#0FFH ;IT NEVER GETS TO THIS POINT
     
  2. MrChips

    Moderator

    Oct 2, 2009
    12,453
    3,371
    Sorry, I could not find any software interrupt for the AT89S52.
    Presumably you are attempting to set the External Interrupt flag IE0 in TCON.
    That does not do it. The hardware has to set the flag.
     
  3. Dseng

    Thread Starter New Member

    Jan 13, 2016
    20
    2
    Last edited: May 16, 2016
  4. MrChips

    Moderator

    Oct 2, 2009
    12,453
    3,371
    Maybe it works on a 8051 but not on the AT89S52.
    Did you check to see if an external interrupt works?
     
  5. Dseng

    Thread Starter New Member

    Jan 13, 2016
    20
    2
    I am thinking that may be the case. The datasheet doesn't say squat about the TCON register. It's only mentioned once in the entire datasheet and that is to show it's location in memory.

    The hardware interrupt works like a charm.
     
  6. MrChips

    Moderator

    Oct 2, 2009
    12,453
    3,371
    Information on TCON can be found in the Atmel 8051 Microcontrollers Hardware Manual.

    I suppose you can generate an external interrupt by connecting an I/O pin to the external interrupt pin /INT0.

    Why do you want to generate a SWI?
     
  7. Papabravo

    Expert

    Feb 24, 2006
    10,180
    1,800
    The way I did it on multiple Atmel parts was by setting one of the 8-bit timers to expire after 1 tick of the clock. Setting the timer run bit is all you have to do to trigger an interrupt.
    Also I did not see in your code where you set the GLOBAL interrupt enable bit.

    EDIT: Sorry, the loading of IE with #81 sets the global enable.

    The TCON register is not where the external interrupt flags are located. Bits 0 and 1 of TCON only configure the behavior of the external interrupt to various conditions on the pin. In fact I don't think it is possible to set the external interrupt flag with an instruction. Since vectoring to the ISR also clears the external interrupt flag there is no need to do it in the firmware. Timer flags are a different story and that is why I used them for that purpose.
     
    Last edited: May 15, 2016
  8. Dseng

    Thread Starter New Member

    Jan 13, 2016
    20
    2
    I'm using the interrupt routine for power up/down. I want to generate a software interrupt to power down if it's been left on too long with no user activity.

    Writing 81H to the IE register should set the gate (IE.7) for all interrupts and enable INT.0 (IE.0). Writing this number makes the hardware interrupt work. Is there anotjer bit that should be set?

    After sleeping on it, I think I will have the interrupt routine call a power up or power down routine and have the timer call the power down routine. The one click timer also looks like a good idea.
     
    Last edited by a moderator: May 15, 2016
  9. Papabravo

    Expert

    Feb 24, 2006
    10,180
    1,800
    I looked at several Atmel datasheets and I could not find any evidence of a software accessible flag for either external interrupt 0 or external interrupt 1. I think this might be common to all 8051 derivatives.
     
  10. dannyf

    Well-Known Member

    Sep 13, 2015
    1,836
    367
    Your issue is likely somewhere else.

    The following code pieces for example flips an led within the timer0 isr:

    Code (Text):
    1.  
    2. ...
    3.  
    4. //tmr0 isr
    5. void _tmr0_isr(void) interrupt TF0_VECTOR {
    6.     //clear the flag                    //automatically done by hardware
    7.     IO_FLP(LED_PORT, LED);                //flip the led
    8.     //_tmr0_isr_ptr();                    //call the handler
    9. }
    10.  
    11. //other code pieces
    12. ...
    13. int main(void) {
    14.     //set up the mcu
    15.     ...
    16.     while (1) {
    17.         //IO_FLP(LED_PORT, LED);        //flip the led
    18.         delay(LED_DLY);
    19.         TF0 = 1;                        //trigger the isr
    20.     }
    21. }
    22.  
    23.  
     
  11. Dseng

    Thread Starter New Member

    Jan 13, 2016
    20
    2
    I solved this problem by setting a "NO_INTERRUPT" flag when the time out timer ran out and then called the ISR. Before exiting the ISR I popped the stack and pushed a 0000 onto it so the program would return to the beginning of the program. Then I checked the flag and if it is high then left the routine using a RET instruction otherwise I left using RETI. It seems to work.
     
  12. Papabravo

    Expert

    Feb 24, 2006
    10,180
    1,800
    BEWARE! The 8051 can have priority levels assigned to interrupts. When there is an interrupt, the status of the priority level is saved to allow nested interrupts. Vectoring to address 0 will not handle the priority flag correctly. The only thing that can fix this problem is a HARD RESET. If this problem bites you, it will be a stone bitch to figure out. You really should avoid "cute" solutions like this. If you want to run the risk, it's all on you. That's why you get paid big bucks to take the call at 3 AM.
     
  13. Dseng

    Thread Starter New Member

    Jan 13, 2016
    20
    2
    But I didn't enter the ISR through an interrupt. I simply called the routine when the timer ran out. There was no interrupt.
     
  14. Papabravo

    Expert

    Feb 24, 2006
    10,180
    1,800
    I have no idea what you think you are doing, and it sounds pretty off the wall. Maybe you could post you code so we can know what your actually doing.
     
  15. Dseng

    Thread Starter New Member

    Jan 13, 2016
    20
    2
    My previous post was a little confusing. When I say "timer" I don't mean an internal 8051 timer. I'm talking about three memory locations that count how long it has been since a button on the panel has been pressed. No interrupts are generated when these "timers" run out. My code is contained in the next post.
     
    Last edited: May 23, 2016
  16. Dseng

    Thread Starter New Member

    Jan 13, 2016
    20
    2
    Code (Text):
    1.  
    2. THRM:   ;REGULATE THE TEMPERATURE   CALLS HERE ONCE PER SECOND.
    3.             CLR     F1              ;RESET SECOND UP FLAG
    4.             CLR        TCI                ;DISABLE TIMER INTERRUPT
    5.             LCALL   THERMO         ;CHECK THE TEMPERATURE AND TURN THE HEATER ON OR OFF
    6.             CLR        PSW.3            ;SELECT RB0
    7.             DJNZ    SECCNT,THRM9    ;HAS IT BEEN 1 MINUTE SINCE A BUTTON HAS BEEN PRESSED?
    8.             DJNZ    MINCNT,CONTINUE ;IF YES THEN HAS IT BEEN 20 MINUTES SINCE A BUTTON HAS BEEN PRESSED?
    9.             CLR        TCI                ;IF YES THEN DISABLE TIMER INTERRUPT
    10.             ORL        P1,#0FH            ;TURN OFF ALL DIGITS
    11.             MOV        Y,#4            ;NUMBER OF TIMES TO BEEP
    12. BEEPAGN:    LCALL    BEEPT1            ;BEEP FOR 1 SECOND. THE BUZZER IS TOGGLED VIA T1.
    13.             CLR        PSW.3            ;SELECT RB0
    14.             MOV        R1,#250            ;WAIT 500 MSEC BETWEEN BEEPS
    15.             LCALL    MSEC
    16.             MOV        R1,#250
    17.             LCALL    MSEC
    18.             DJNZ    Y,BEEPAGN
    19.          
    20.             MOV        MINCNT,#TOM        ;RESET MINUTES FOR TIMEOUT COUNTER
    21.             DJNZ    TIMEOUT,CONTINUE;HAVE NO BUTTONS BEEN PRESSED FOR 2 HOURS?
    22.             SETB    SHDFLAG            ;IF YES THEN SET SHUT DOWN FLAG AND CALL INTERRUPT SERVICE ROUTINE
    23.             LCALL    ISERV            ;GO TO INTERRUPT SERVICE ROUTINE AND SHUT DOWN.
    24.  
    25. CONTINUE:    MOV     SECCNT,#TOS     ;OTHERWISE RESET FOR ANOTHER MINUTE
    26. THRM9:     SJMP    LOOP
    27. ;
    28. ;INTERRUPT SERVICE ROUTINE: POWER BUTTON.
    29.  
    30. ISERV:     CLR        TCI                    ;DISABLE TIMER
    31.             ANL        P3,#WHOFF            ;TURN OFF THE WATER AND HEATERS
    32.             ORL        P1,#1FH                ;TURN OFF ALL DISPLAYS
    33.          
    34.             CLR        PSW.3                ;SELECT RB0
    35.             MOV        R1,#30    ;<---was 250            ;WAIT 1 SEC
    36. release:    jnb        p3.2,release    ;wait for button release
    37.             JB        PONOFF,OFF            ;IF WE ARE OFF THEN WE WANT TO TURN BACK ON.
    38.             SETB    PONOFF                ;LET THE SYSTEM KNOW WE ARE TURNING ON THE POWER
    39.             SJMP    ON
    40. OFF:        CLR        PONOFF                ;LET THE SYSTEM KNOW WE ARE TURNING OFF.
    41.  
    42. ON:            POP        0E0H                ;CLEAR THE STACK - POP IT INTO THE ACCUMULATOR
    43.             POP        0E0H
    44.             MOV        A,#25H
    45.             PUSH    0E0H                ;SET THE STACK TO RETURN TO BEGINING
    46.             MOV        A,#00H
    47.             PUSH    0E0H
    48.          
    49.             JB        SHDFLAG,SDOWN        ;IF WE HAVE NOT TIMED OUT THEN THIS ROUTINE WAS CALLD BY AN INTERRUPT
    50.             RETI                        ;AND WE NEED THE RETI INSTRUCTION
    51.  
    52. SDOWN:        CLR        SHDFLAG                ;OTHERWISE, WE HAVE TIMED OUT AND NEED TO RESET THE TIME OUT SHUT DOWN FLAG
    53.             RET                            ;AND RETURN VIA A RET INSTRUCTION BECAUSE THIS ROUTINE WAS NOT CALLED BY AN INTERRUPT.
    54.  
    55. [code]
     
Loading...