HCS08GB60 timer output compare interrupt

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

HCS08GB60 timer output compare interrupt

14,108 Views
agreer
Contributor I
Hello,
I have the HCS08GB60 demo board and am using the serial monitor functionality to program and debug my code via Codewarrior.
I have had several problems doing things that are relatively straightforward, at least they have been on the handful of other chips I've worked with.

First of all, I am unable to make the external oscillator work. Secondly, as I've recently learned, the RTI functionality does not work alongside the serial monitor.
As a result of not having RTI capability, I'm trying to setup a timer to generate a periodic interrupt as a pseudo-RTI.


Here is how I'm initializing the timer:
;;;;;;;;;;; INIT CODE
;; setup timer 1 module
; use system clock, prescale by 128
lda #(mCLKSB+mPS2+mPS1+mPS0)
sta TPM1SC

; setup timer 1 channel 1
; for output compare (used for periodic interrupt)
; output compare mode, software only, enable interrupt
lda #(mMS1A+mCH1IE)
sta TPM1C1SC

; reset the channel count value
; calculate the current counter value + delay value
; do: ix = ix + cnt (ix = RTIDelayH:RTIDelayL)
; current counter value ( cnt = TPM1CNTH:TPM1CNTL )
lda #RTIDelayL
add TPM1CNTL ; a = RTIDelayL + TPM1CNTL
tax ; x = a

lda #RTIDelayH
adc TPM1CNTH ; a = RTIDelayH + TPM1CNTH + c
psha
pulh ; h = a

; store ix in channel value reg (TPM1C1VH:TPM1C1VL)
sthx TPM1C1VH

; clear the channel flag
; read flag CH1F in TPM1C1SC
lda TPM1C1SC
; to clear flag, write zero to CH1F
bclr CH1F, TPM1C1SC
;;;;;;;;;;; END INIT CODE

Because of post size constraints, I will continue with the ISR code in my next post.
Labels (1)
0 Kudos
Reply
18 Replies

1,615 Views
RockyRoad
Contributor III

Agreer -

You said that you're using the serial monitor for debugging and it seems that you're not having any luck getting any interrupt service routines to run.

You said in one post that you were placing the timer interrupt at $FFF2. However, the serial monitor uses the hardware based vector relocation feature of the GB60. The vector relocation addresses are at $FBCC–$FBFD rather than from $FFCC–$FFFD. So the correct vector location for the timer interrupt would be $FBF2.

For a more complete discussion of this, you might check out AN2140 at: http://www.freescale.com/files/microcontrollers/doc/app_note/AN2140.pdf

0 Kudos
Reply

1,615 Views
agreer
Contributor I
Being a hardware redirection method, I don't need to change the ORG statement in my code. When my code is downloaded to the flash, it's automatically adjusted.

I did get the interrupt to work finally. I'm not sure what I did to make it work, everything in my code seems the same.

Thanks everyone for your help.
0 Kudos
Reply

1,615 Views
peg
Senior Contributor IV

Agreer,

I don't think you are understanding this fully.

I didn't before today as I have a USB Multilink. So today I slummed it with the serial monitor to understand how this works.

The hardware redirection simply means that when an interrupt occurs it goes looking for its vector in a new place (just below the protected block with the same negative offset as from FFFF. It doesn't somehow move the actual vector addresses down!

You can't write to the standard vector area anyway (its protected!)

So you can either put the vector yourself in the new place or, in Codewarrior turn on vector mirroring and it will do it for you magically.

But the important thing is that before you run, the interrupt routines' address must be in the new location, so if it doesn't work look in the memory window to see if its there (at FBF2 in this case).

 

BR

Peg

0 Kudos
Reply

1,615 Views
agreer
Contributor I
Actually, I understand exactly what is going on. As I said, in the process of writing the code to the flash, the vectors are moved to the proper place. It is perfectly ok for me to locate my reset vector at $FFFE in my source code.
Here is the explanation from the freescale document (AN2295D) describing the routines used by a PC program (Codewarrior in this case) used to write to the flash:

Interrupt Vector Table Relocation
After the ident information is read out of the MCU, the following operations within the image are carried out:
• The code is scanned to determine whether any interrupt vectors are present between the MCU interrupt vector table address and 0xFFFF (the last existing physical address of the M68HC(S)08 MCU).
• If interrupt vectors are present, relocation of these vectors is done as described in Interrupt Vector Table Relocation. Then, the original address spaces in the interrupt vector table are marked as unused (thus not being reprogrammed).


As you can see, the method determined by Freescale is to have the PC program move the vectors within the flash image before writing them to the chip. I understand that the vectors need to be located at the proper place on the hardware, but you misunderstand the method of putting the vectors there. By creating the "monitor" target in codewarrior, when the flash is programmed, the vectors located within that protected 1K of flash (containing the serial monitor code) are moved within the image before actually being programmed. I don't have to do anything special to accomplish this.

Yes, the vectors are actually moved down in the flash, not by the "vector redirection" itself, but by the program used to write to the flash.


thanks!

Message Edited by agreer on 02-15-200602:05 PM

0 Kudos
Reply

1,615 Views
ok2ucx
Contributor IV

Hi there,

interrupt vectors relocation (done by PC) works for AN2295 HC(S)08 Serial Bootloader, *not* for S08 Serial Monitor (desribed in AN2140). Please, do not mix these two.

AN2295 Bootloader has been started years ago and was made to program Flash over the serial line (no interrupt vectors mangling needed for the final code, etc.).

While Serial monitor was made for S08 only and to allow debugging over Serial line. AN2140 requires the vectors to be redirected (in the user code).

Regarding the code itself, I was able to replicate it here, the last version as it is worked OK assuming that counter variable was placed in Zero page. INC instruction does not work with extended addressing.

Although the code works with real hardware, I was not able to make it 'running' in the P&E simulator though.

Regards, Pavel Lajsner, Freescale Roznov

 

P.S. One little hint:

; clear the channel flag
lda TPM1C1SC ; read flag CH1F in TPM1C1SC
bclr CH1F, TPM1C1SC ; to clear flag, write zero to CH1F

maybe simplified to:

; clear the channel flag
bclr CH1F, TPM1C1SC ; to clear flag, write zero to CH1F

since BCLR/BSET instructions are read-modify-write thus read-before-clear condition is met using just BCLR. P.

Message Edited by ok2ucx on 02-17-200602:13 PM

0 Kudos
Reply

1,615 Views
agreer
Contributor I
Here is the code inside the timer ISR:
;;;;;;;;;;; TIMER1CH1 ISR
;;; handle the psuedo-RTI interrupt - generated by TPMCH1
RTI_Handler:
sei ; disable interrupts
pshh ; save h reg

; reset the channel count value
; calculate the current counter value + delay value
; do: ix = ix + cnt (ix = RTIDelayH:RTIDelayL)
; current counter value ( cnt = TPM1CNTH:TPM1CNTL )
lda #RTIDelayL
add TPM1CNTL ; a = RTIDelayL + TPM1CNTL
tax ; x = a

lda #RTIDelayH
adc TPM1CNTH ; a = RTIDelayH + TPM1CNTH + c
psha
pulh ; h = a

; store ix in channel value reg (TPM1C1VH:TPM1C1VL)
sthx TPM1C1VH

; clear the channel flag
; read flag CH1F in TPM1C1SC
lda TPM1C1SC
; to clear flag, write zero to CH1F
bclr CH1F, TPM1C1SC


;lda SRTISC
; clear RTI flag
;ora mRTIACK
;sta SRTISC

pulh ; restore h
cli ; enable interrupts
rti
0 Kudos
Reply

1,615 Views
agreer
Contributor I
I have not included the code which simply blinks an LED in the ISR. As far as I can tell, the ISR is never entered. I used a similar setup with output compare on channel 0 to implement a timed delay and it worked fine.
If anyone has some experience with this or with the demo board, please offer some advice or suggestions.
Your help is greatly appreciated!

Thanks!
0 Kudos
Reply

1,615 Views
rocco
Senior Contributor II


agreer wrote:
. . . As far as I can tell, the ISR is never entered. . .
Agreer:
I just noticed that you didn't post the lines that initialize the interrupt vector. Maybe the interrupt is in fact occurring, but not getting into your ISR because of a misdirected vector?

just a thought . . .
0 Kudos
Reply

1,615 Views
agreer
Contributor I
Hey Rocco,
here is how I setup the vector.

ORG $FFF2
DC.W RTI_Handler ; TPMCH1
0 Kudos
Reply

1,615 Views
agreer
Contributor I
I've incorporated your suggestions into my code and it still doesn't work. The interrupt service routine is never entered.
Here's what I've got:

RTI_init:
;; setup timer 1 module
mov #(mCLKSB+mPS2+mPS1+mPS0),TPM1SC
mov #(mMS1A+mCH1IE),TPM1C1SC
; reset the channel compare value
mov #RTIDelayL,TPM1C1VL
mov #RTIDelayH,TPM1C1VH
sthx TPM1CNTH ; write to counter to clear it
; clear the channel flag
lda TPM1C1SC ; read flag CH1F in TPM1C1SC
bclr CH1F, TPM1C1SC ; to clear flag, write zero to CH1F
rts
0 Kudos
Reply

1,615 Views
agreer
Contributor I
Here is the rest of my new code:

RTI_Handler:
; do something here...

; reset the channel compare value
; calculate the current compare value + delay value
lda #RTIDelayL
add TPM1C1VL ; a = RTIDelayL + TPM1C1VL
sta TPM1C1VL
lda #RTIDelayH
adc TPM1C1VH ; a = RTIDelayH + TPM1C1VH + c
sta TPM1C1VH

; clear the channel flag
lda TPM1C1SC ; read flag CH1F in TPM1C1SC
bclr CH1F, TPM1C1SC ; to clear flag, write zero to CH1F
rti
0 Kudos
Reply

1,615 Views
peg
Senior Contributor IV

Hi agreer,

Below is your last version of code that I have added to in order to get it to work
on an Axiom M68DEMO908GB60 board.

I had to add the following that you either didn't have or didn't tell us about.

(1) disable COP
(2) enable ints
(3) set CLKSA rather than CLKSB as I am running in SCM mode and XCLK is disabled in this mode
(4) a reset vector

So let us know what you were doing wrong

Peg

.NOLIST
#include "9S08GB60v1rdp.inc"
.LIST

 ORG RamStart
RTIDelayL equ 33
RTIDelayH equ 44
counter  rmb 1

 ORG RomStart

 lda #(mCOPT+mSTOPE+mBKGDPE)
 sta SOPT   ;disable COP (1)
 CLI    ;enable ints (2)
 mov #0,counter
 mov #%00001111,PTFD
 mov #%00001111,PTFDD
 jsr RTI_init
 bra *

RTI_init:
;; setup timer 1 module
 mov #(mCLKSA+mPS2+mPS1+mPS0),TPM1SC ;(3)
 mov #(mMS1A+mCH1IE),TPM1C1SC
; reset the channel compare value
 mov #RTIDelayL,TPM1C1VL
 mov #RTIDelayH,TPM1C1VH
 sthx TPM1CNTH ; write to counter to clear it
; clear the channel flag
 lda TPM1C1SC ; read flag CH1F in TPM1C1SC
 bclr CH1F,TPM1C1SC ; to clear flag, write zero to CH1F
 rts

RTI_Handler:
; do something here...
 inc counter
 lda counter
 coma
 sta PTFD
; reset the channel compare value
; calculate the current compare value + delay value
 lda #RTIDelayL
 add TPM1C1VL ; a = RTIDelayL + TPM1C1VL
 sta TPM1C1VL
 lda #RTIDelayH
 adc TPM1C1VH ; a = RTIDelayH + TPM1C1VH + c
 sta TPM1C1VH

; clear the channel flag
 lda TPM1C1SC ; read flag CH1F in TPM1C1SC
 bclr CH1F,TPM1C1SC ; to clear flag, write zero to CH1F
 rti

 ORG $FFF2
 DC.W RTI_Handler ; TPMCH1

 ORG $FFFE
 DC.W ROMStart ;(4)

0 Kudos
Reply

1,615 Views
agreer
Contributor I
Have you actually verified that this code works on your board? I can't get it to work in the simulator or on the board. The interrupt is never entered. My code was that same as yours except for I used CLKSB instead of CLKSA. I made that change in my code and it still won't work. I even created a whole new codewarrior project and put your code into it. That doesn't work either.
I've never had so much trouble configuring an interrupt. I miss my AVR chips, they always worked.

How did you configure your ICG regs?
0 Kudos
Reply

1,615 Views
peg
Senior Contributor IV

Hi agreer,

The code I posted is the *entire code*

just assemble it and download it.

I am looking at the flashing LED's as I write this.

I have not configured any ICG regs.

I am relying on power up defaults for everything you don't see explicitly set here.

I used PE assembler CASMHC08_Pro.

Codewarrior is probably _helping_ you by initialising stuff that you don't know about.

The code I have supplied is the absolute bare minimum required to get this done, you need everything that is there. It is intended to show you what you *have* to do not neccessarily what you should do.

If you don't touch any clock regs you will get Self Clocked Mode at untrimmed 4MHz. This will do for LED flashing. The XCLK signal is disabled in this mode and so you can't use it as a source for the timer.

 

Regards

Peg

0 Kudos
Reply

1,615 Views
rocco
Senior Contributor II
Agreer:
I cannot see anything obvious why your code would not work. It looks fine, but the way I do it is a little different, and maybe this will help.

During initialization, I would not add the delay value to the current timer value. I would avoid reading the timer anywhere I can be interrupted.

Instead:
Load the delay value directly into the timer value registers, and then reset the timer by writing to it. Do this for initialization only.

Then, in the interrupt service routine:
Add the delay value to the old value register contents, rather than the current counter. This does two things:
1) It avoids reading the timer which, because of its latches, always makes me nervous, and
2) It keeps your time more accurately, because it is not affected by interrupt latency. Each output compare is referenced to the prior output compare, rather than where the timer might have been during the ISR.

Again, I don't see how what you are doing would cause a problem, but I never do until after I have a problem fixed.

One other thing, you may want to remove the SEI and CLI instructions from the ISR. The cpu sets the interrupt flag automatically upon dispatching the interrupt, so the SEI instruction is basically a nop. But the CLI would cause a pending interrupt to be serviced before the RTI instruction could execute, stacking up multiple interrupts. The RTI instruction will clear the interrupt flag for you.

hope this helps . . .
0 Kudos
Reply

1,615 Views
agreer
Contributor I
Hi Rocco,
thanks for the insight. There is one subtle problem with what I was intending to do. I planned to continue using the output compare timed delay routine on channel zero. If I setup the timer reg value to be something other than $0000, then my delay routine won't calculate the proper value to stop delaying. I suppose I could solve that problem by using timer 1 channel 0 for the timed delay and timer 0 channel 0 for the isr generator. I'll give it a shot and post back on the results.
I have to say, I can't find anything fundamentally wrong with my code and it's maddening. The few things I've tried with this mcu aren't very difficult but they just don't seem to work. I'm not sure if the problem is with my code, the mcu, or the demo board and serial monitor interfering.

thanks again!
0 Kudos
Reply

1,616 Views
peg
Senior Contributor IV

Hi agreer,

I can see anything wrong either. (except for the int vector perhaps)

A few other pointers:

it looks like you may be using old 05 code (or you may be an old 05 coder)

you can replace:

 lda #(mCLKSB|mPS2|mPS1|mPS0)
 sta TPM1SC
with:
 mov #(mCLKSB|mPS2|mPS1|mPS0),TPM1SC

and:

 lda #RTIDelayL
 add TPM1CNTL ; a = RTIDelayL + TPM1CNTL
 tax ; x = a

 lda #RTIDelayH
 adc TPM1CNTH ; a = RTIDelayH + TPM1CNTH + c
 psha
 pulh ; h = a

 store ix in channel value reg (TPM1C1VH:TPM1C1VL)
 sthx TPM1C1VH

with


 lda #RTIDelayL
 add TPM1CNTL ; a = RTIDelayL + TPM1CNTL
 sta TPM1C1VL
 lda #RTIDelayH
 adc TPM1CNTH ; a = RTIDelayH + TPM1CNTH + c
 sta TPM1C1VH

the latches will handle the two 8 bit writes to the 16 bit register.

You should also change to adding to the previous compare like rocco suggested!

In the int handler you can do something similar and throw out the sei cli and the push/pull of h as you won't affect it.

All of the above won't make it work but it will look nicer doing nothing :smileyhappy:

Have you run your code in a simulator and set a breakpoint in the int handler???

BR

Peg

0 Kudos
Reply

1,616 Views
agreer
Contributor I
Hey peg,

You are right, I've neglected a few commands like 'mov'. I need to study the instruction set of this chip a little more. I've been back and forth with a few different chips lately and sometimes I get the details of each blurred with the others.
thanks!
0 Kudos
Reply