Handling both RTCC and WKEN_B interrupts
I looked through the standard books, datasheets, whatever, and didn't find my answer.
If I enter an ISR through a WKEN_B interrupt, does this reset/clear the RTCC?· Meaning, if I have RTCC set to overflow at 2us, and I trigger as a result of edge detection, will the next overflow happen 2us later or some amount less than 2us(ie whatever was left on the clock)?· Do I have to manually reset RTCC if I want this functionality(if so, how to?)
I'm guessing the counter (re)starts when I *leave* the ISR as a result of the "RETURNINT" SX/B command or the reti, retiw (IIRC) instructions.· This is the functionality I need.
Thanks.
Keith
·
If I enter an ISR through a WKEN_B interrupt, does this reset/clear the RTCC?· Meaning, if I have RTCC set to overflow at 2us, and I trigger as a result of edge detection, will the next overflow happen 2us later or some amount less than 2us(ie whatever was left on the clock)?· Do I have to manually reset RTCC if I want this functionality(if so, how to?)
I'm guessing the counter (re)starts when I *leave* the ISR as a result of the "RETURNINT" SX/B command or the reti, retiw (IIRC) instructions.· This is the functionality I need.
Thanks.
Keith
·

Comments
The RTCC and RB edge detection are totally independent, although there is ony one interrupt vector, and that is at $000. When either RTCC overflows or an edge is detected, the processor switches to the interrupt routine at that $000 vector.
During an ISR entry due to an edge detect event, the RTCC keeps counting as per normal. Should the value of the RTCC counter have been such that a rollover occurs while it was already in the ISR, then that occurrence would go unnoticed by the interrupt routine and must make specific code to poll the value of the RTCC, and deal with the roll-over in your (ISR) software.
The RTCC is not cleared or adjusted by the processor when an edge detect interrupt occurs, and the next interrupt would occur at the normal next 2 uSec interval. Clearly you will have a conflict if the 2 uSec time roll-over occurs while you are already in an edge detect interrupt. Polling for this occurrence while in interrupt allows you to deal with that.
Cheers,
Peter (pjv)
The first solution may not work if the overflow occurs in those few cycles it takes to compare and decide.
In a nutshell the RTCC is not cleared, if this is the behavior you want, you'll have to clear it manually.
We want an interval of 100 cycles ( 50 Mhz / 500Khz ) or 2 microseconds / .02 microseconds.· The RTCC interrupt happens when the RTCC goes from 255 to 0, so it is counting up during your interrupt.·
Suppose your interrupt took 50 cycles, or half what we want as an interval.· When you do the RETIW with W holding -100, at the end just before the return, the RTCC gets loaded with 50 - 100 or -50 which means it will take it 50 cycles to hit again 0 and trip the interrupt.· Just what you want for regular periodic interrupts.
But that isn't quite what we want.
Remember, in the case of the MFM decoder, we want to use the RTCC as a one shot timer of sorts.·· And the interval you end up with isn't really too critical.· We want to sample a little bit longer than half a cell time, or 2 microseconds.· With no pre scaler on the RTCC we are looking at the 100 counts.
What you want to have happen is for a B pin interrupt to happen so you are in sync,· shift that 1 bit into your bit accumulator or MFM shift register, whatever you want to call it.· You then want to load the RTCC register with 255-100 or· 155 and do a normal RETI.· The additional time just moves us out a little so we don't get an RTCC interrupt before a possible B edge detect.· If you don't get a transition before the 2 microseconds plus a little, the RTCC interrupt happens, you check the B pin WKPND register, and if it isn't set, you clock a 0 into your MFM shift register.· Then reload the timer as before to wait for the next (approximately) half bit boundary.
To make it easier, you could always clear the RTCC at the start of an interrupt, no matter the cause.· At the end do the standard RETIW with the -100 value in W and the intervals will be close enough for jazz. The time should only be off by the difference in cycles from the start of the interrupt to the clear, which, should only be the interrupt latency of 3 cycles plus 1 if you always have the RTCC in register space and use CLR RTCC as the first instruction. If that is a problem, you can just off set the value of W before the RETIW.
Here is my cut at it, tested on SXsim, seems to work the way I intended it to.· Boy that formatted code window has issues with tabs.......
;============================================================================== ; ; Title: Amiga MFM grabber ; Version: 1.0.0-0 ; Desc: SX28-to act as simple phase lock loop to snag MFM data ; Author: Mike Chadwick ; Created: 03/13/2005 ; Modified: ; Released: ; ;============================================================================== ; Device Directives ;============================================================================== device SX28,oschs3,turbo,stackx,bor42,protect,watchdog Irc_cal IRC_SLOW freq 50_000_000 reset Main LIST Q=37 ;============================================================================== ; Program Revision Levels and ID ;============================================================================== VERSION_MAJOR equ $01 VERSION_MINOR equ $00 REVISION equ $00 PLATFORM equ $00 ID 'MFM1001' ;============================================================================== ; Revision History ;============================================================================== ; ; 1.0.0-0 Test Version, uses watchdog timer, enables brownout at 4.2V ;============================================================================== ; NOTES ;============================================================================== ; ; ;============================================================================== ; Global Includes ;============================================================================== error P1W 'Current Program Version:MFM ', VERSION_MAJOR, '.',VERSION_MINOR,'.',REVISION,'-',PLATFORM ; ;============================================================================== ; Defines to Activate Test Features ;============================================================================== ; ;============================================================================== ; CONSTANTS ;============================================================================== ; Mode settings for the various I/O registers TRIS equ $0F ; 1 pin tristated, 0 pin outputs PLP equ $0E ; 1 pull up disabled, 0 pull up enabled LVL equ $0D ; 1 input level TTL, 0 input level CMOS ST equ $0C ; 1 disable schmidt trigger input, 0 enable schmidt trigger input WKEN equ $0B ; 1 disable wake up on pin, 0 enable wake up on pin WKED equ $0A ; 1 select falling edge wake up, 0 select rising edge wake up WKPND equ $09 ; 1 edge detected since last clear, 0 no edge detected CMP equ $08 ; bit 7-Comparator enabled if 0 ; bit 6-Comparator output enabled if 0 ; bit 0 read comparator result ;============================================================================== ; Setup and enable RTCC interrupt, WREG register, RTCC/WDT prescaler ;============================================================================== ;?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!? ; Virtual Peripheral Guidelines Tip: ; ; The suggested default values for the option register are: ; - Bit 7 set to 0: location $01 addresses the W register (WREG ; - Bit 5 set to 0: RTCC increments on internal transitions ; - Bit 3 set to 1: Prescaler assigned to WatchDog Timer ; ; If a routine must change the value of the option register (for example, to ; access the RTCC register directly), then it should restore the default value ; for the option register before exiting. ; ;?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!? RTCC_ON = %10000000 ;Enables RTCC at address $01 (RTW hi) ;*WREG at address $01 (RTW lo) by default RTCC_ID = %01000000 ;Disables RTCC edge interrupt (RTE_IE hi) ;*RTCC edge interrupt (RTE_IE lo) ;enabled by default RTCC_INC_EXT = %00100000 ;Sets RTCC increment on RTCC pin transition (RTS hi) ;*RTCC increment on internal instruction (RTS lo) ;is default RTCC_FE = %00010000 ;Sets RTCC to increment on falling edge (RTE_ES hi) ;*RTCC to increment on rising edge (RTE_ES lo) is ;default RTCC_PS_ON = %00000000 ;Assigns prescaler to RTCC (PSA lo) RTCC_PS_OFF = %00001000 ;Assigns prescaler to WDT (PSA lo) ; prescaler Division Ratio ; 2 1 0 RTCC WDT WDT PS_000 = %00000000 ; 0 0 0 1:2 1:1 0.016 sec PS_001 = %00000001 ; 0 0 1 1:4 1:2 0.032 sec PS_010 = %00000010 ; 0 1 0 1:8 1:4 0.064 sec PS_011 = %00000011 ; 0 1 1 1:16 1:8 0.128 sec PS_100 = %00000100 ; 1 0 0 1:32 1:16 0.256 sec PS_101 = %00000101 ; 1 0 1 1:64 1:32 0.512 sec PS_110 = %00000110 ; 1 1 0 1:128 1:64 1.024 sec PS_111 = %00000111 ; 1 1 1 1:256 1:128 2.048 sec ; we are set to have RTCC at $01, increment on internal instructions, prescaler assigned to ; WDT and longest prescaler interval OPTIONSETUP equ RTCC_ON|RTCC_PS_OFF|PS_111 ; the default option setup for this program. RTW equ $80 ; 0 - register $01 is W, 1 - RTCC RTI equ $40 ; 0 - RTCC roll over interrupt enabled, 1 - disabled RTS equ $20 ; 0 - RTCC increments on internal instruction cycle, 1 - transition of RTCC pin RTE equ $10 ; 0 - RTCC incrments on low to high transition, 1 - high to low PSA equ $08 ; 0 - prescaler assigned to RTCC, 1 - prescaler assigned to Watch Dog Timer PS2 equ $04 ; prescaler Division Ratio PS1 equ $02 ; 2 1 0 RTCC WDT WDT PS0 equ $01 ; 0 0 0 1:2 1:1 0.016 sec ; 0 0 1 1:4 1:2 0.032 sec ; 0 1 0 1:8 1:4 0.064 sec ; 0 1 1 1:16 1:8 0.128 sec ; 1 0 0 1:32 1:16 0.256 sec ; 1 0 1 1:64 1:32 0.512 sec ; 1 1 0 1:128 1:64 1.024 sec ; 1 1 1 1:256 1:128 2.048 sec ;============================================================================== osc equ 50_000_000 ; assume 50 MHz oscillator ISR_freq equ 500_000 ; protocol related constants ; the initial times 10 and subsequent +5 s are to force rounding to take place at the proper ; points ; the final divide by 10 removes the initial factor of 10 ; proper ISR rate to produce accurate baud rates is 307200, or 614400. ; actual ISR rate with a 50 Mhz crystal is osc/ISR_count ; percent error is (ISR_real-ISR_freq)*100)/ISR_freq ISR_count equ ((osc*10/ISR_freq)+5)/10 ISR_real equ (osc/ISR_count) ; calculate the error to .1% resolution ; Real frequency is too high IF (ISR_real) > (ISR_freq) ISR_Error equ ((ISR_real-ISR_freq)*1000)/ISR_freq error P1W 'ISR Frequency is: ', ISR_real, ' Hz, high by',ISR_Error, ' %' ELSE ; Real frequency is too low ISR_Error equ ((ISR_freq-ISR_real)*1000)/ISR_freq error P1W 'ISR Frequency is: ', ISR_real, ' Hz, low by .',ISR_Error, ' %' ENDIF ; not used in this example Half_ms_count equ osc*5/ISR_count/10000 ; timer period in microseconds TIMER_INCREMENT equ (1_000_000*Half_ms_count/(ISR_real/10)+5)/10 error P1W 'Timer period: ',TIMER_INCREMENT,' microseconds.' ;=============================================================================== ; PIN ASSIGNMENTS ;=============================================================================== ; ; +------v------+ ; 1 --| Vss /MCLR |-- 28 ; 2 --| RTCC OSC1 |-- 27 ; 3 --| Vdd OSC2 |-- 26 ; 4 --| Vdd RC7 |-- 25 PD7 ; 5 --| N/C RC6 |-- 24 PD6 ; 6 --| RA0 RC5 |-- 23 PD5 ; 7 --| RA1 RC4 |-- 22 PD4 ; 8 --| RA2 RC3 |-- 21 PD3 ; 9 --| RB3 RC2 |-- 20 PD2 ;MFM_input_pin 10 --| RB0 RC1 |-- 19 PD1 ; 11 --| RB1 RC0 |-- 18 PD0 ; 12 --| RB2 RB7 |-- 17 PRNT_ATTN ; 13 --| RB3 RB6 |-- 16 PDBUS_OE ; 14 --| RB4 RB5 |-- 15 DEBUG_OP ; +-------------+ ; Ubicom SX28 ; DIP package ;============================================================================== ; I/O PORTS & RELATED CONSTANTS ;============================================================================== MFM_IN_PIN equ rb.0 ; Input from Disk Drive DEBUG_OP equ rb.5 ; output for timing debug PDBUS_OE equ rb.6 ; Printer data bus Output Enable PRNT_ATTN equ rb.7 ; Printer Attention line PDBUS equ rc A_TRIS equ %00000000 ; ra all pins output so no troubles A_INIT equ %00000000 ; init to 0 A_PLP equ %00000000 ; disable pullups a all pins are outputs A_LVL equ %00000000 ; CMOS input levels B_TRIS equ 1 << .PDBUS_OE + 1 << . MFM_IN_PIN ; set up the inputs B_INIT equ 1 << .PRNT_ATTN ; attention line initially high, all else low ; enable pullups on b inputs and data outputs B_PLP equ 1 << .PDBUS_OE + 1 << . MFM_IN_PIN B_WKED equ %11111111 ; all pins set to detect falling edges B_WKEN equ ~1 << .MFM_IN_PIN ; disable wake up on pin except MFM input B_SCHMIDT equ %00000000 ; all set to schmidt trigger B_LVL equ %00000000 ; CMOS input levels ; default port c to all output except the ; receive data input C_TRIS equ %11111111 ; all pins on bus input for now C_INIT equ %00000000 ; all outputs low to start C_PLP equ %00000000 ; enable pullups on all c pins C_SCHMIDT equ %00000000 ; all set to schmidt trigger C_LVL equ %00000000 ; CMOS input levels ;============================================================================== ; MEMORY BANKS ;============================================================================== GLOBAL_MEM equ $08 ; BANK_0 equ $10 ; BANK_1 equ $30 ; BANK_2 equ $50 ; BANK_3 equ $70 ; BANK_4 equ $90 ; BANK_5 equ $b0 ; BANK_6 equ $d0 ; BANK_7 equ $f0 ; ;============================================================================== ; BANKED MEMORY ;============================================================================== ISR_BANK equ BANK_0 ; used to hold whatever ;============================================================================== ; GLOBAL MEMORY ;============================================================================== org GLOBAL_MEM ; start of global register space GLOBAL_MEM_mode ds 1 ; temp to keep track of mode register in the ISR GLOBAL_MEM_shifter ds 1 ; stores incomming data from the Disk GLOBAL_MEM_bitcounter ds 1 ; bit counter for receiving bits GLOBAL_MEM_ISR_temp ds 1 ; temporary used by the ISR only ;============================================================================== ; BANKED MEMORY ;============================================================================== ; Interrupt Routine pointers and data ;------------------------------------------------------------------------------ org ISR_BANK ;------------------------------------------------------------------------------ ;============================================================================== ;------------------------------------------------------------------------------ ; CODE MEMORY ORGANIZATION ;------------------------------------------------------------------------------ ;============================================================================== PAGE_0 equ $000 PAGE_1 equ $200 PAGE_2 equ $400 PAGE_3 equ $600 ISR_PAGE equ PAGE_0 ; ISR and initialization MAIN_PAGE equ PAGE_1 ; State Machines NA1 equ PAGE_2 ; NA2 equ PAGE_3 ; ;============================================================================== ; WATCH EXPRESSIONS ;============================================================================== ;============================================================================== ; INTERRUPT SERVICE ROUTINE ;============================================================================== ;=============================================================================== org ISR_PAGE ;=============================================================================== ISR setb DEBUG_OP ; set a bit to scope so we can see what happens clr RTCC ; reset the RTCC in case it was a pin interrupt mov GLOBAL_MEM_mode,m ; save the mode mov m,#WKPND ; set to test our bit mov !RB,#0x00 ; get the wake pending bit, into w not w ; invert the bit so we match the original circuit mov GLOBAL_MEM_ISR_temp,w ; use a global for tmp so no bank junk rr GLOBAL_MEM_ISR_temp ; rr to get our transition bit into the carry rr GLOBAL_MEM_shifter ; from the schematic, the data comes in MSbit first djnz GLOBAL_MEM_bitcounter,:exit_isr mov GLOBAL_MEM_bitcounter,#8 ; reset bit counter mov PDBUS,GLOBAL_MEM_shifter ; output new data to the data bus :exit_isr mov m,GLOBAL_MEM_mode ; restore the mode mov w,#-ISR_count CLRB DEBUG_OP ; clear the bit so we see how long the ISR takes retiw ; return from interrupt and adjust the rtcc ;============================================================================== ; set up port direction and data registers, initialize the I/O init_io mov m,#WKED ; b edged detection mov rb, #B_WKED ; mov m, #WKPND ; clear any wakeup pending bits clr w ; so we don't fire the interrupt immediately mov !rb,w ; clear any wake up pending bits mov m, #WKEN ; wakup on b transition mov !rb, #B_WKEN mov m, #PLP ; Set the pullup values mov !ra, #A_PLP mov !rb, #B_PLP mov !rc, #C_PLP mov m, #LVL ; set the input levels TTL or CMOS mov !ra, #A_LVL mov !rb, #B_LVL mov !rc, #C_LVL mov m, #ST ; set schmidt trigger inputs mov !rb, #B_SCHMIDT mov !rc, #C_SCHMIDT mov ra, #A_INIT mov rb, #B_INIT mov rc, #C_INIT mov m, #TRIS ; Force mode to TRIS mov !ra, #A_TRIS mov !rb, #B_TRIS mov !rc, #C_TRIS ret ;------------------------------------------------------------------------------ ;============================================================================== ; initialize any variables used by the virtual peripherals ; i.e. the registers used to receive and transmit Serial data init_vp ; clear all general memory and global registers clr fsr ; only clear the registers once setb fsr.3 ; forces skipping the i/o registers :gloop clr ind ; clear reg indexed by fsr inc fsr sb fsr.4 jmp :gloop ; loop until fsr becomes $10 :bloop setb fsr.4 clr ind ; clear reg indexed by fsr ijnz fsr, :bloop ; loop until fsr becomes zero mov GLOBAL_MEM_bitcounter, #8 mov ! option,#OPTIONSETUP ; start the ball rolling ret ;============================================================================== ; Reset Location must be in Page 0 ;============================================================================== Main call init_io ; initialize the IO bits and state call init_vp ; initialize the RAM for all the VPs :forever clr !WDT ; whack the watchdog timer mov m,#TRIS ; set to control the output port to the printer ; we don't really need to do this in the loop ; because the ISR saves and restores it mov w,#C_TRIS ; assume we want to tristate the output port sb PDBUS_OE ; if they pull it low, enable the PDBUS outout clr w ; enable the outputs mov !PDBUS,w ; movb PRNT_ATTN, GLOBAL_MEM_bitcounter.3 ; copy 3rd bit of counter ; to the attention pin ; will be high when we start ; go low while shifting ; and high again ; for at least 2 microseconds ; after we load data jmp :forever ;----------------------------------------------------------------- END ;-----------------------------------------------------------------Post Edited (Michael Chadwick) : 3/14/2005 8:12:10 PM GMT
I've made several attempts in SX/B writing the code with a couple different approaches.· None of them have panned out.· I'm sure I'm dealing with sync problems at this point --- I have to play with this stuff more before it starts to get intuitive...· I guarantee my problem is I'm not handling the RTCC correctly.
I'll take a good look at your code.
Thanks to everyone who replied.
Keith
·
Here is a debugging trick you might already be using. Set an output bit at the start of the ISR and clear it at the end. Assuming your scope has dual trace, you can look at when the ISR happens in relation to the incomming data, and see how long the ISR takes by the length of the pulse.
I've edited the code I posted to show that.
If you have more than 2 channels, or if your scope has an external trigger, you could sync on the attention line to the PC and see where the end of the byte is and when the PC is supposed to be transfering it. That would sync you to the start of the next byte, so you could see what should be coming into the shifter, as well as if the attention line is getting set every 8 bits.
Another variation would be to copy the state of the WKPND bit to the output bit, so you can see whether the ISR is interrpreting the data as a 0 or a 1.
With a scope and an output bit, you can get some good visibility into what your code is doing relative to the data.
Mike
<vent> You know, I've been programming(on the side, not for a living) half-seriously for probably about 15 years. Nothing irks me more than to have something very very simple NOT work. It's not the COMPLICATED things I get mad about not working -- I expect to have problems and to spend lots of troubleshooting time on HARD problems. But the easy stuff, that's just supposed to work on its face, that's what I get mad about not working </vent>
I don't particularly like my current routines anyways. I'm going to shift more of the programming out of the ISR and more into the main --- which I guess is a good design goal. Keep the ISR as short as possible.
Keith
My most memorable bug was in my Z80 assembler days, working on the program for a piece of test equipment, a scanning optical densitometer. Used to measure color test targets on printing.
I had coded some new scan routines to do automatic color bar recognition, that seemed to be working pretty well. Finished them up on a Monday. The gizmo was going to be shipped on Tuesday, so it all looked good. Everything tested out OK.
On Tuesday morning the head of the service department, who was going to do the installation, ran through a test of the unit's function, part of which was to test the scanning on the customer's color bar. Didn't work. Bombed most convincingly.
What the *&#%? "It worked fine yesterday!"
I scratched my head a bit thinking about the problem and a light bulb went off. The scanner had a real time clock that displayed the date and time on a CRT as part of the instrument's display. I reset the date to Monday.
It worked just fine. Oooops.
In my scanning code, I had re-used the memory locations used by the clock output. Perfectly legal, and sometimes a must to re-use temp ram like that, which was always in short supply. (1984 ish, ram wasn't cheap.)
But I had forgotten to *clear* it first. Or at least a particular byte that I used to hold flags indicating the state of the scan.
So the program would work fine, except on Tuesdays and Thursdays. Fortunately I found it pretty quickly, and the service guy was able to load the unit into the company van and deliver it on time.
But I won't forget that one.
As you hunt your bugs, keep in mind that the processor (usually) is doing *exactly* what you told it to do.
Mike
This is entirely OT BUT Pantone has this really cute handheld spectro-colorimeter.· Under $250 too!
http://www.pantone.com/products/products.asp?idSubArea=0&idArea=2&showNav=94&idProduct=373
I've contemplating buying one but the reports on it aren't very favorable --- at least not in the serious context....
Keith
Post Edited (Keith M) : 3/17/2005 4:15:39 PM GMT