I'm wondering if anybody else has run into a problem with RTXTiny51 and the SiLabs processor. I'm using the C8052F62 processor, am using a LOT of the peripherals and have IO lines and interrupt routines all over the place. The SiLabs devices, having a lot of peripherals, have paged Special Function Registers, and - the crux of the difficulty - have a neat little stack mechanism for storing the current SFR page and automatically setting the proper one during an interrupt. The SRF page pointer is pushed onto a special hardware stack at an interrupt and popped again at the next RTI. RTXTiny not being optimized for the SI Labs processors and the SFRPAGE register, one has to set the SFRPAGE to page 0 before making any RTXTiny Call so that it will talk properly to the Timer 0. So far, so good. A tech note suggests setting the SFR page before any Timer 0 accesses in Conf_tny.A51, but there's a problem with that as discussed below. I've been chasing down another rather subtle problem and the fix has me stymied. The RTX51Tiny timer call is entered, obviously enough, with an interrupt by the Timer 0 overflow. If you look carefully at the code in Conf_Tny.A51 the return from the user code (the macro at the top into which one can stick your own stuff to be executed every clock tick) at the top of the file returns with an RETI; more stuff having to do with checking the status of suspended tasks is executed further down and then the routine returns to whence it came originally with a RET. This all means that if the timer interupt happens to occur just after you've set the SFR register to something other than 0, the SFR page is popped from the NEXTSFR register into the SFRPAGE register prematurely - at the return from the user code macro - and screws up the TR0 calls in the rest of the task-checking code. If you follow the tech-note suggestion and set the SFRPAGE to 0 at each Timer 0 function, then it won't be correct (again, if the interrupt happens after you've set the SFRPAGE but before you've actually used it) when the interrupt returns to the original code. The code is rather complex, there are interactions with the task management system, and swapping the RETI and RET commands around ends up with the program in an infinite loop the first time that you call an RTX51 wait() function. I need to investigate further, but seems like something causes the interrupt to talk to the wrong register page. Any assistance would be appreciated.
Paul, sorry for being so late on this issue. However, we would like to get a better understanding for the problem. Disabling Round-Robin scheduling and setting the SFRPAGE to 0 before calling an RTX51 Tiny function should do the job. When you are doing this, do you still encounter problems? Reinhard
Yes, if you diasable everythink you'll have no problem. Or try to move call to hw_timer(with its RETI) after the all timer 1 acces code(timer1 update code) in conf_tny file. I look only briefly in the conf_tny file but maybe helps. Roman
Actually, disabling everything _won't_ solve the problem. The problem is that the user HW_TIMER_CODE's RTI at the end of the Macro does not return to the user code but goes instead to Update 8051 Interrupt Timer code which returns to the user code with an RET. The RTI pops the SFRPAGE stack too soon, leaving it on the wrong page for the subsequent calls to Timer 0. Here is my code with patches: ... ; SFR Symbols PSW DATA 0D0H ACC DATA 0E0H B DATA 0F0H SP DATA 81H DPL DATA 82H DPH DATA 83H TCON DATA 88H TMOD DATA 89H TL0 DATA 8AH TL1 DATA 8BH TH0 DATA 8CH TH1 DATA 8DH IE DATA 0A8H SFRPAGE DATA 84H ;BLASE 8/1/05 CONFIG_PAGE EQU 0x0F ;BLASE 8/22/05 LEGACY_PAGE EQU 0x00 ;BLASE 8/22/05 TIMER01_PAGE EQU 0x00 ;BLASE 8/22/05 ; TCON TF1 BIT 8FH TR1 BIT 8EH TF0 BIT 8DH TR0 BIT 8CH IE1 BIT 8BH IT1 BIT 8AH IE0 BIT 89H IT0 BIT 88H ; IE EA BIT 0AFH ES BIT 0ACH ET1 BIT 0ABH EX1 BIT 0AAH ET0 BIT 0A9H EX0 BIT 0A8H ; Check Configuration Values NAME ?RTX51_TINY_KERNAL PUBLIC ?RTX_CURRENTTASK PUBLIC ?RTX_RAMTOP PUBLIC os_switch_task PUBLIC ?RTX?SET_ISR EXTRN NUMBER (?RTX_MAXTASKN) ; max Task Number ?RTX_RAMTOP EQU RAMTOP ?RTX_CLOCK EQU -INT_CLOCK ?RTX_REGISTERBANK EQU INT_REGBANK * 8 DSEG AT ?RTX_REGISTERBANK DS 2 ; temporary space ?RTX_SAVEACC: DS 1 saveacc EQU R2 ; for access in interrupt service routine ?RTX_SAVEPSW: DS 1 savepsw EQU R3 ; for access in interrupt service routine ?RTX_CURRENTTASK: DS 1 currenttask EQU R4 ; for access in interrupt service routine EXTRN DATA (RTX_SFRStorage) ;BLASE 8/22/05, for temporary storage of SFR IF (TIMESHARING <> 0) ?RTX_ROBINTIME: DS 1 robintime EQU R5 ; for access in interrupt service routine ENDIF IF (CODE_BANKING <> 0) EXTRN DATA (?B_CURRENTBANK) EXTRN CODE (?B_RESTORE_BANK) ENDIF ;------------------------------------------------ ; Table of Task Entry Pointers ;------------------------------------------------ PUBLIC ?RTX_TASKENTRY ?RTX?TASKENT?S SEGMENT CODE RSEG ?RTX?TASKENT?S ?RTX_TASKENTRY: DS 2 ;------------------------------------------------ ; Table of Stack Pointers for each task ;------------------------------------------------ PUBLIC ?RTX_TASKSP ?RTX?TASKSP?S SEGMENT IDATA RSEG ?RTX?TASKSP?S ?RTX_TASKSP: DS 1 ;------------------------------------------------ ; Table of Task Timer/State Pointers ;------------------------------------------------ PUBLIC ?RTX_TASKSTATUS ?RTX?TASKSTATE?S SEGMENT IDATA RSEG ?RTX?TASKSTATE?S ?RTX_TASKSTATUS: TimerVal: DS 1 ; Task Timer (Software Timer for each task) TaskState: DS 1 ; Task Status (state of each Task) ; Definitions for Bits in Task State ; TaskState.0 = Wait for Signal ; TaskState.1 = Wait for TimeOut ; TaskState.2 = Signal Flag ; TaskState.3 = TimeOut Flag ; TaskState.4 = Task Ready (Wait for Running) ; TaskState.5 = Task Active (enabled with os_create) ; TaskState.6 = Round Robin Time Out ; TaskState.7 = Run Flag ; byte mask definitions K_SIG EQU 1 K_TMO EQU 2 SIG_EVENT EQU 4 TMO_EVENT EQU 8 K_READY EQU 16 K_ACTIVE EQU 32 K_ROBIN EQU 64 K_IVL EQU 128 ; not a task state bit; only used in os_wait RDY_EVENT EQU 128 ; READY status flag K_RDY EQU 128 ; bit position definitions B_WAITSIG EQU 0 B_WAITTIM EQU 1 B_SIGNAL EQU 2 B_TIMEOUT EQU 3 B_READY EQU 4 B_ACTIVE EQU 5 B_ROBIN EQU 6 B_IVL EQU 7 ; not a task state bit; only used in os_wait B_RDY EQU 7 IF (TIMESHARING OR CPU_IDLE_CODE) ?RTX?BITS SEGMENT BIT RSEG ?RTX?BITS ENDIF IF (TIMESHARING) ?RTX_TS_DELAY: DBIT 1 ; Status bit set when task switch in progress ENDIF IF (CPU_IDLE_CODE) ?RTX_ISR_SIG: DBIT 1 ; Status bit set when interrupt or os_set_signal ENDIF CSEG AT 0BH JMP TIMERINT ?RTX?CODE SEGMENT CODE RSEG ?RTX?CODE USING 0 ; Registerbank 0 for following code IF (FREE_STACK <> 0) ?RTX_STACKERROR: STACK_ERROR ; User defined Stack Error Code ENDIF HW_TIMER: HW_TIMER_CODE TIMERINT: IF (LONG_USR_INTR) PUSH ACC MOV A,PSW ANL A,#018H XRL A,#?RTX_REGISTERBANK JNZ CONT_TIMINT ; avoid recursive timer interrupt POP ACC RETI ; Return from Recursive Timer Interrupt CONT_TIMINT: POP ACC ENDIF CALL HW_TIMER ; Enable Interrupts again. MOV ?RTX_SAVEPSW,PSW MOV PSW,#?RTX_REGISTERBANK MOV saveacc,ACC ; ACC required by some Cygnal devices ; Update 8051 Interrupt Timer MOV RTX_SFRStorage, SFRPAGE ;Blase 8/22/05 - store SFRPAGE from whatever was interrupted MOV SFRPAGE, #TIMER01_PAGE ;Blase 8/22/05 - Use TIMER01_PAGE CLR TR0 MOV A,TL0 ADD A,#LOW (?RTX_CLOCK + 7) MOV TL0,A MOV A,TH0 ADDC A,#HIGH (?RTX_CLOCK + 7) MOV TH0,A SETB TR0 MOV SFRPAGE, RTX_SFRStorage ;Blase 8/22/05 - put the current SFR page back
Move CALL HW_TIMER after last line you posted. Roman
We have another variant for this: http://www.keil.com/support/docs/3104.htm Reinhard
I didn't want to screw up the order of things, so I left the CALL HW_TIMER where it was.