Hello!
I failed trying initialize input capture mode for a couple of days on this device. I am little frustrated at this moment.
I am not so new to freescale controllers, working on different HC08/ HCS08 and HCS12 types. I started two years ago from zero, never done coding before. But at this time I can say that these controllers are very "cool" and I like the work with them.
To my setup/problem:
I have a windsensor wich sending pulses to my QG8 Demoboard. The windsensor is driven by two fans wich I can control in speed. I have also a debouncing circuit between my sensor and the QG8. I want in the end configuration measuring the windspeed. Input capture seems to be the best solution for me. I also have to say, I never worked with the TPM Module before.
I have two variables
TPMCH0VAL_RISE: DS.B 2
TPMCH0VAL_FALL: DS.B 2
and reading/store the channel register by
ldhx TPMC0VH+TPMC0VL
sthx TPMCH0VAL_RISE
I can also do another way
mov TPMC0VH,TPMCH0VAL_RISE
mov TPMC0VL,TPMCH0VAL_RISE+1
Wich is the better way?
In Debug mode I can see that the variable TPMCH0VAL_RISE do not change when I let the fans blowing faster or slower. (This is my problem)
Here is my code:
In this code I trying to understand the basics of the input capture function. This means that this code is not the "last word". I only trying here to capture a rising edge and store it to my variable in the first step. If this works I will try to switch to falling edge cause I have to measure one period. One period consists falling and rising edge.
TPMCH0VAL_RISE: DS.B 2
TPMCH0VAL_FALL: DS.B 2
TPMCH0VAL: DS.B 2
;
; code section
;
ORG ROMStart
_Startup:
LDHX #RAMEnd+1 ;initialize the stack pointer
TXS
lda #%00000011 ;ResetPin enable
sta SOPT1
lda #%10010111 ;OSC Trimm ~8MHz
sta ICSTRM
mov #%11000111,ICSC1 ;int. Osc. on
mov #%00000000,ICSC2 ;ext. Osc. off
CLI ;enable interrupts
jsr init_timer ;initialize the timer
mainLoop:
BRA mainLoop
init_timer:
mov #%00000000,TPMMODH ;I am not sure what should stand here for input capture
mov #%00000001,TPMMODL ;But I know I should write a value in it for normal counter operation
mov #%01000100,TPMC0SC ;Timer 1 Channel 0,Input capture only, rising edges only
mov #%00001000,TPMSC ;Interrupt disabled, work as input capture, busclock = sourceclock, Divided by 1
rts
;**************************************************************
;* spurious - Spurious Interrupt Service Routine. *
;* (unwanted interrupt) *
;**************************************************************
spurious: ; placed here so that security value
NOP ; does not change all the time.
RTI
TPMOVF_ISR: ;I will never come here with this timersetup
sei
nop
cli
rti
TPMCH0_ISR: ;Start of Timer 1 Channel 0 ISR
RISING_EDGE:
;pshh ;save H:X
sei ;disable (whole) interrupts
ldhx TPMC0VH+TPMC0VL ;Load 16 Bit value to Index Register
sthx TPMCH0VAL_RISE ;save content to "my defined Ram variable"
lda TPMC0SC
bclr 7,TPMC0SC ;clear Channel 0 Flag
;mov #%01011000,TPM1C0SC ;setup Channel 0 for falling edge (i also should
;measure the other side of one period)
FALLING_EDGE:
;brclr 7,TPM1C0SC,FALLING_EDGE ;wait here for the falling edge
;ldhx TPM1C0VH+TPM1C0VL ;Load 16 Bit value to Index Register
;sthx TPM1CH0VAL_FALL ;save content to "my defined Ram variable"
;lda TPM1C0SC
;bclr 7,TPM1C0SC ;clear Channel 0 Flag
;mov #%00001000,TPM1SC ;Interrupts enabled, work as input capture,
;busclock = sourceclock, Divided by 1,
;this stand here cause I do only
;once a timer initialisation after reset and
;this should be enought
;pulh ;restore H:X
cli ;enable (whole) interrupts
rti ;End of interrupt
;**************************************************************
;* Interrupt Vectors *
;**************************************************************
ORG Vrti
DC.W spurious ; RTI
DC.W spurious ; RESERVED2
DC.W spurious ; RESERVED3
DC.W spurious ; ACMP
DC.W spurious ; ADC
DC.W spurious ; KEYBOARD
DC.W spurious ; IIC
DC.W spurious ; SCITX
DC.W spurious ; SCIRX
DC.W spurious ; SCIERR
DC.W spurious ; SPI
DC.W spurious ; MTIM
DC.W spurious ; RESERVED 13
DC.W spurious ; RESERVED 14
DC.W spurious ; RESERVED 15
DC.W spurious ; RESERVED 16
DC.W spurious ; TPMOVF
DC.W spurious ; TPMCH1
DC.W TPMCH0_ISR ; TPMCH0
DC.W spurious ; RESERVED
DC.W spurious ; LVD
DC.W spurious ; IRQ
DC.W spurious ; SWI
DC.W _Startup ; RESET
END
Can anyone tell me please am I on the right way?
Wich way is better to save the content of the Timerregister mov or ldhx?
How I can see "more" in Debug mode?
cause this?***When background mode is active, the timer counter and the coherency mechanism are frozen such that the
buffer latches remain in the state they were in when the background mode became active even if one or
both bytes of the counter are read while background mode is active.***
In the Datasheet stands:
When either byte of the 16-bit capture register is read, both bytes are latched into a buffer to support
coherent 16-bit accesses regardless of order.
WHere is this buffer?
Please give me somone some input wich I can capture!
Best regards
Ingo Kauf
已解决! 转到解答。
Hello Ingo,
In addition to the problem mentioned by Tony P, I see that you have a modulo setting of $0001. This would mean that the 16-bit counter would toggle between $0000 and $0001 values, not what you require. The modulo setting should be either zero (free running) or $FFFF to maximize the TPM overflow period. I suspect there may be some misunderstanding of the input capture process.
If the period you are trying to measure should exceed the TPM overflow period, you will also need to take into account the number of overflows that occurs, which is a much more complicated process. If you choose not to count the overflows, there will be a minimum wind speed that can be measured. In this case, you will still need to monitor the overflows so that the period reading may be rejected if two overflow events should occur without at least one intervening input capture event.
Another possibility for increasing the range of the period measurement, and maintain accuracy at higher speeds, would be to dynamically change the prescale setting to increase the overflow period for low wind speeds, and reduce the overflow period for higher speeds.
If the wind velocity sensor generates a number of pulses for each revolution of the anemometer, it should only be necessary to calculate the total period between pulses, say between the occurrence of each positive edge. It shouldn't be necessary to handle the timing of the opposite edge.
The way I would handle the period calculation would be to maintain RAM storage for the previous capture value TPREV, and the current period value PERIOD, and also the prescale value associated with the reading, if this is variable.
So within the TPM channel ISR,
; PERIOD = TPMC0V - TPREV 16-bit modulo calculation
lda TPMC0VL
tax
sub TPREV+1
sta PERIOD+1
lda TPMC0VH
psha
pulh
sbc TPREV
sta PERIOD
; Update TPREV ready for next event
sthx TPREV
The 16-bit PERIOD value will then need to be processed to calculate the wind speed, preferably using integer arithmetic, and presumably a wind speed display is then updated.
Regards,
Mac
Hello Mac, Hello tonyp!
Mac, you´re right. I am not (really) clear in the functions of the TPM module. I also never worked with the TPM module before. But I want to learn more about the functions of the TPM. For my basic understanding I wrote two programs. The first one starts the counter, counting up to a value and switches a LED on if the value is reached. The second uses the external clock source which comes from my anemometer, counting the pulses and after reaching the value in Modulo Register a LED starts to light.
Then I was trying to undestand the input capture function. The code in my first post, you can call it V 1.0, was my first experiment with the input capture function. After a my Post I ported the code to my MC9S08AW60 Demoboard cause there is one whole Port connected to a 8 Bit LED Band on PortF. So I can see more as on the QG8 Demoboard which have only two LED´s on it.
After reading the post from tonyp i modified the Timer ISR. I know that normally the H Register should be saved. But in this case i was not sure. It is a so small code only two interrupts and no hard 16 Bit instructions to Index Register. Now I am just reading the TPM1C0VL by lda and store it to my variable. In my MainLoop I load the variable and put it on PortF. I am able now to see what the timer do in input capture mode. The value in my variable change so fast and differs from my understanding. I thought that if the speed from my anemometer does not change, then the variable should be the same value since the last interrupt. That´s not the case! So I was trying to Stop and clear the timer in my ISR to get a new count. That´s also not working. I am talking about a ~8Mhz busclock and pulse about 20ms. I do not undestand why the value in my variable change so hard. It should be a linear value.
After this I modify the ISR to compare the TPM1CNTL and the TMP1C0VL Registers. These Registers have never the same value but I think there should be the same value in it. Confusing!
I have asked some questions about the input capture function which i am interrested in.
Could you please tell me:
In the Datasheet stands: When either byte of the 16-bit capture register is read, both bytes are latched into a buffer to supportcoherent 16-bit accesses regardless of order.
Where is this buffer? Do you have an address? $xxxx
How I can see "more" in Debug mode? cause this? ***When background mode is active, the timer counter and the coherency mechanism are frozen such that thebuffer latches remain in the state they were in when the background mode became active even if one orboth bytes of the counter are read while background mode is active.***(Is it general a problem to debug Interrupt routines?)
Wich way is better to save the content of the Timerregister mov or ldhx?(This is clear and allready explained by tonyp.)
Do you know a application note which handles the Timer?
Please correct me if i am wrong,
The counter starts counting up from zero in free running mode if all 16 Bit in the modulo register are set to zero.
In input capture mode, the counter is working continuously and writes the value of the current status in the channel value register immediately after an input capture event occurs.
Normally, measuring pulses (one pulse period) is done by adding the rising and the falling edge.
I really understand what you are telling me in your answer. Also the way you are going in your code. I think the most problem I have is handling and understanding the TPM Module. That can not work in a few days, that must have time. Three days for complete undestanding a HCS08 Timer is too short and without helpful experts like you and tonyp it´s allmost unpossible.
May if you are not so busy it would be nice to get an answer on my questions.
Thank you very much,
Best regards,
Ingo Kauf
Hello Ingo,
This document should help you. It is for the predecessor of the TPM, but it is essentially the same to use.
The coherency buffer is invisible to the user, it is at the same address.
The counter counts up from zero UNTIL it reaches the value in the modulo register, where it changes to zero.
Here is another document that may assist with your understanding of the TPM.
One obvious error is the use of TPMC0VH+TPMC0VL (addition of two consecutive addresses) as the target address for loading HX. You only need to supply the TPMC0VH (the address of the MSB of the 16-bit location) to the LDHX instruction. What you do ends up reading from a completely different memory address which is not related to the TPM. Anyway, having seen that, I didn't bother checking for any further mistakes. Correct this and let us know if you're still having trouble.
And you DO need the PSHH/PULH in the ISR but not the CLI before the RTI.