Hello- I am using the 56807 with the Motorola SDK. I am tryng to measure the pulse-width of a ~50Hz squarewave using the capture registers on two timers (one to save the rise time, one to save the fall time). The rise and fall interrupts fire correctly, but the values returned by the SDK function ioctl(...,QT_READ_CAPTURE_REG,...) are strange at best (the rise and fall times are usually separated by only 1 clock cycle, which is near impossible). I am connecting the signal generator to timer D0 and using that pin as input to both timers. Here is the code - thanks for any input. dave #include <stdio.h> #include "port.h" #include "arch.h" #include "io.h" #include "led.h" #include "qtimerdrv.h" #include "periph.h" #include "fcntl.h" #include "quadraturetimer.h" static void CallbackOnRisingEdge(qt_eCallbackType CallbackType, void* pParam); static void CallbackOnFallingEdge(qt_eCallbackType CallbackType, void* pParam); const qt_sState quadParam1 = { /* Mode = */ qtCount, /* InputSource = */ qtCounter0Input, /* InputPolarity = */ qtNormal, /* SecondaryInputSource = */ 0, /* CountFrequency = */ qtRepeatedly, /* CountLength = */ qtPastCompare, /* CountDirection = */ qtUp, /* OutputMode = */ qtToggleOnCompare, /* OutputPolarity = */ qtNormal, /* OutputDisabled = */ 0, /* Master = */ 0, /* OutputOnMaster = */ 0, /* CoChannelInitialize = */ 0, /* AssertWhenForced = */ 0, /* CaptureMode = */ qtRisingEdge, /* CompareValue1 = */ 0xFFFF, /* CompareValue2 = */ 0xFFFF, /* InitialLoadValue = */ 0x0000, /* CallbackOnCompare = */ { 0, 0 }, /* CallbackOnOverflow = */ { 0, 0 }, /* CallbackOnInputEdge = */ { CallbackOnRisingEdge, 0 } }; const qt_sState quadParam2 = { /* Mode = */ qtCount, /* InputSource = */ qtCounter0Input, /* InputPolarity = */ qtNormal, /* SecondaryInputSource = */ 0, /* CountFrequency = */ qtRepeatedly, /* CountLength = */ qtPastCompare, /* CountDirection = */ qtUp, /* OutputMode = */ qtToggleOnCompare, /* OutputPolarity = */ qtNormal, /* OutputDisabled = */ 0, /* Master = */ 0, /* OutputOnMaster = */ 0, /* CoChannelInitialize = */ 0, /* AssertWhenForced = */ 0, /* CaptureMode = */ qtFallingEdge, /* CompareValue1 = */ 0xFFFF, /* CompareValue2 = */ 0xFFFF, /* InitialLoadValue = */ 0x0000, /* CallbackOnCompare = */ { 0, 0 }, /* CallbackOnOverflow = */ { 0, 0 }, /* CallbackOnInputEdge = */ { CallbackOnFallingEdge, 0 } }; Word16 RiseTime=0, FallTime=0, PW=0; int PwUpdated =0, PrevPW=0;; UWord16 TimerD0; /* file handles */ UWord16 TimerD1; static int LedFD; /********************************************************************* ********/ main() { LedFD = open(BSP_DEVICE_NAME_LED_0, 0); ioctl(LedFD, LED_OFF, LED_GREEN); TimerD0 = open(BSP_DEVICE_NAME_QUAD_TIMER_D_0, 0, &quadParam1 ); TimerD1 = open(BSP_DEVICE_NAME_QUAD_TIMER_D_1, 0, &quadParam2 ); ioctl(TimerD0, QT_DISABLE, (void*)&quadParam1 ); ioctl(TimerD1, QT_DISABLE, (void*)&quadParam2 ); ioctl(TimerD0, QT_ENABLE_CAPTURE_REG, (void*)&quadParam1 ); ioctl(TimerD1, QT_ENABLE_CAPTURE_REG, (void*)&quadParam2 ); ioctl(TimerD0, QT_ENABLE, (void*)&quadParam1 ); ioctl(TimerD1, QT_ENABLE, (void*)&quadParam2 ); while(1) /* executive loop */ { if (PwUpdated) { PrevPW = PW; PwUpdated = 0; } } } /********************************************************************* ********/ void CallbackOnRisingEdge(qt_eCallbackType CallbackType, void* pParam) { ioctl(LedFD, LED_ON, LED_GREEN); ioctl(LedFD, LED_OFF, LED_RED); RiseTime = ioctl(TimerD0, QT_READ_CAPTURE_REG, (void*) &quadParam1 ); } void CallbackOnFallingEdge(qt_eCallbackType CallbackType, void* pParam) { ioctl(LedFD, LED_OFF, LED_GREEN); ioctl(LedFD, LED_ON, LED_RED); FallTime = ioctl(TimerD1, QT_READ_CAPTURE_REG, (void*) &quadParam2 ); PW = FallTime-RiseTime; PwUpdated = 1; } |
|
Measuring PW using Quad Timer Captures
Started by ●November 26, 2002
Reply by ●November 26, 20022002-11-26
Hey Dave,
I'm using the 56807 for pulse width measurement
as well but I use the gated clock mode instead. This mode proved to be a bit
more reliable than trying to capture the rise and fall times of a particular
signal. I can remember getting screwy number until I switched to the gated clock
mode. Remember that you have to consider the pulse width that you are measuring
is within the limits of your prescale value settings so that your counter
doesn't overflow before the end of your measurement. If it does then things
can get messy and you will probably end up sacrificing the resolution or
accuracy. The following code was a simple test program I wrote to simulate
the state of charge (SOC) output signal on an electric vehicle. The SOC signal
is not always active and when the vehicle reaches 100% then a DC signal is
present on the line. I have included a timeout timer so that it doesn't get
stuck if nothing fires off the interrupts. If it does happen to timeout, then it
will read the input source and take action accordingly.
here is the setup:
ThinkSOCTmrParm0 => fake signal
generator.
PeridTmrParm1
=> timeout timer
SocTmrParm0 =>
gated counter for measuring pulse width
things to note:
/* Mode =
*/
qtGatedCount, /* InputSource = */ qtPrescalerDiv128, // sets up the granularity of the measurement /* InputPolarity = */ qtInverted, // my signals are inverted coming in so you may need to change this /* SecondaryInputSource = */ qtCounter1Input, // you need to specify which pin you are reading Lastly, read the section 14.6.4 in the dsp5680x users manual if you
want to know how the gated count works.
Hope you find this helpful
Best Regards
Victor
Victor Miramontes
Principal Engineer
Advanced Mobility Systems, LLC
1960 Chicago Ave, Suite D-20
Riverside CA, 92507
tel. 909.276.9746
fax.909.276.9747
m...@admosys.com
m...@ieee.org
/* File:
main.c
Author:
Victor Miramontes. m...@ieee.org.
11-1-01
-modified soc function to use less timers and better resolution -also modified safeguard against timer locking up if SOC on thinks reaches 100 % and signal is always high. -fixed when no signal is present -clean up code 11-2-01 -make sure to check appconfig.h for Think SOC simulation -simulated Think SOC is output on TimerC0 I/O signal and read into TC1 I/O 11-2-01 Updated code to correctly use the DSP frequency
counter to measure the pulse
width of the SOC signal. IPBus clock rate is 36MHz thought the SDK claims it runs at 40MHz. The SOC signal from the Think is a PWM signal which is delivered at a frequency of 200Hz. The duty cycle indicates the SOC for the Think Scaling: 0 - 100 % Duty Cycle for 0 ~ 100 % State of Charge The signal is read from the % of positive portion of the signal 11-3-01 Tested code on protoboard */
#include
"arch.h"
#include "bsp.h" #include "port.h" #include "quadraturetimer.h" #include "led.h" UWord16 GetSOCstatus(void); static void ThinkSocInt(qt_eCallbackType
CallbackType, void* pParam);
static void SocTimerInt(qt_eCallbackType CallbackType, void* pParam); static void SocTmrFail(qt_eCallbackType CallbackType, void* pParam); const qt_sState ThinkSOCTmrParm0 = { // fake sigal generator output is
a 90% duty cycle 200Hz square wave.
/* Mode =
*/
qtCount,
/* InputSource = */ qtPrescalerDiv128, /* InputPolarity = */ qtNormal, /* SecondaryInputSource = */ 0, /* CountFrequency =
*/ qtRepeatedly,
/* CountLength = */ qtUntilCompare, /* CountDirection = */ qtUp, /* OutputMode =
*/
qtToggleUsingAlternateCompare,
/* OutputPolarity = */ qtNormal, // change to qtInverted for vehicle simulation /* OutputDisabled = */ false, /* Master =
*/
0,
/* OutputOnMaster = */ 0, /* CoChannelInitialize = */ 0, /* AssertWhenForced = */ 0, /* CaptureMode =
*/
qtDisabled,
/* CompareValue1 =
*/ 0x008d, //
200Hz 90% duty 0008d , 057e
/* CompareValue2 = */ 0x04f1, // 04F1 /* InitialLoadValue = */ 0x0000, /* CallbackOnCompare =
*/ { 0, 0 },
/* CallbackOnOverflow = */ { 0, 0 }, /* CallbackOnInputEdge = */ { 0, 0 } }; const qt_sState PeridTmrParm1 = { /* Mode =
*/
qtCount,
/* InputSource = */ qtPrescalerDiv128, /* InputPolarity = */ qtNormal, /* SecondaryInputSource = */ 0, /* CountFrequency =
*/ qtRepeatedly,
/* CountLength = */ qtUntilCompare, /* CountDirection = */ qtUp, /* OutputMode =
*/
qtAssertWhileActive,
/* OutputPolarity = */ qtNormal, /* OutputDisabled = */ true, /* Master =
*/
0,
/* OutputOnMaster = */ 0, /* CoChannelInitialize = */ 0, /* AssertWhenForced = */ 0, /* CaptureMode =
*/
qtDisabled,
/* CompareValue1 =
*/
0x20F5, // Check every 10 ms
/* CompareValue2 = */ 0x0000, /* InitialLoadValue = */ 0x0000, /* CallbackOnCompare =
*/ { SocTmrFail, 0},
/* CallbackOnOverflow = */ { 0, 0 }, /* CallbackOnInputEdge = */ { 0, 0 } }; const qt_sState SocTmrParm0 = { /* Mode =
*/
qtGatedCount,
/* InputSource = */ qtPrescalerDiv128, /* InputPolarity = */ qtInverted, /* SecondaryInputSource = */ qtCounter1Input, /* CountFrequency =
*/ qtRepeatedly,
/* CountLength = */ qtPastCompare, /* CountDirection = */ qtUp, /* OutputMode =
*/
qtAssertWhileActive,
/* OutputPolarity = */ qtNormal, /* OutputDisabled = */ true, /* Master =
*/
0,
/* OutputOnMaster = */ 0, /* CoChannelInitialize = */ 0, /* AssertWhenForced = */ 0, /* CaptureMode =
*/
qtFallingEdge,
/* CompareValue1 =
*/ 0x0000,
/* CompareValue2 = */ 0x0000, /* InitialLoadValue = */ 0x0000, /* CallbackOnCompare =
*/ { 0, 0 },
/* CallbackOnOverflow = */ { 0, 0 }, /* CallbackOnInputEdge = */ { SocTimerInt, 0 } }; int ThinkSocTmr,SOCFailTmr;
int SocTimer; /// these need to be moved out of the GetSocStatus function to work static UWord32 CapReg=0,CapReg1=0,Duty=0; static UWord16 SocCounter=0; static bool SocReady = false, SocFinished = false, SocFailse; // end UWord32 temp2; void main (void) { int LedFD; LedFD = open(BSP_DEVICE_NAME_LED_0,
0); // init LED's
ioctl(LedFD, LED_OFF, LED_GREEN); ThinkSocTmr =
open(BSP_DEVICE_NAME_QUAD_TIMER_C_0, 0, NULL); // Start think
SOC sig gen.
ioctl(ThinkSocTmr, QT_ENABLE, (void*)&ThinkSOCTmrParm0); while(1)
{ temp2 =GetSOCstatus(); while(1) { if(SocReady) ioctl(LedFD, LED_ON, LED_YELLOW); } } // end while loop } /// end main UWord16 GetSOCstatus(void) { UWord32 temp; SocTimer = open(BSP_DEVICE_NAME_QUAD_TIMER_C_1, 0, NULL); ioctl(SocTimer, QT_ENABLE, (void*)&SocTmrParm0); SOCFailTmr =
open(BSP_DEVICE_NAME_QUAD_TIMER_C_2, 0, NULL);
ioctl(SOCFailTmr, QT_ENABLE, (void*)&PeridTmrParm1); while(!SocFinished) { if(SocReady) { SocReady= false; SocFinished = true; if(!SocFail) { temp=(CapReg1*0x0064); Duty= (temp/0x057E); } else Duty = 0; } } ioctl(SOCFailTmr, QT_DISABLE, NULL); return Duty; } //static void ThinkSocInt(qt_eCallbackType CallbackType, void* pParam) //{ // ioctl(LedFD, LED_TOGGLE, LED_GREEN); //} void SocTmrFail(qt_eCallbackType CallbackType, void* pParam) { if ((periphMemRead(&ArchIO.TimerC.Channel1.StatusControlReg) & 0x0800)==0) { if((periphMemRead(&ArchIO.TimerC.Channel1.StatusControlReg) & 0x0100)) { SocReady= true; SocFailse; CapReg1=0x057E; }
else { SocReady= true; SocFail=true; ioctl(LedFD, LED_OFF, LED_GREEN); } } } void SocTimerInt(qt_eCallbackType CallbackType, void* pParam) { CapReg1Reg; CapReg = ioctl(SocTimer, QT_READ_CAPTURE_REG, NULL); ioctl(SocTimer, QT_ENABLE, (void*)&SocTmrParm0); if(++SocCounter%4==0) { ioctl(SocTimer, QT_DISABLE, NULL); SocReady = true; ioctl(LedFD, LED_ON, LED_RED); } }
|
Reply by ●November 27, 20022002-11-27
We have developed our own low-level drivers for frequency and/or period measurement, using any of the Quad Timers that have an I/O pin. Details on our low-level drivers are in 2 messages I posted to this group: - 10:09am, September 24, 2002: "RE: [motoroladsp] Doubt regarding context saving for SCI callback routine." - 6:43am, September 25, 2002: "RE: [motoroladsp] Timer Pins, more I/O" The first message describes the "Super Fast" interrupt for the Quad Timer frequency and/or period measurement, and the second message has a ZIP file that contains the complete source code for the interrupt and data processing functions, in the file "io_func.c". These functions are: static void init_frequency_inputs(void); static void read_frequency_inputs( void ); void process_frequency_inputs( void ); void Freq_Period_Input_ISR( WORD status, // Status read from the DSP Timer DSP_TIMER_T *p_dsp_timer, // Pointer to the DSP Timer DSPTMR_FP_DATA_T *p_dsp_fp_data // Pointer to the input data structure ); The attached file "anaiodef.h" contains the following typedef for the DSPTMR_FP_DATA_T structure: // Frequency/period input data structure (one for each input). typedef struct { SWORD ad_idx; // Index into the ANA_DATA array union { // Union for the raw data input LWORD fp_count; // The whole frequency/period count struct { // Structure for the parts of the count WORD fp_lsw; // Freq./Period least significant word WORD fp_msw; // Freq./Period most significant word } parts; } raw_data; LWORD fp_start_val; // Count at the start point LWORD fp_end_val; // Count at the end point SWORD fp_meas_type; // 0 == count pulses, else from period SWORD ignore_count; // Ignore next count when mode changed SWORD count_index; // Index into the count_data[] array WORD count_data[ FREQ_COUNTS_PER_SEC ]; SWORD raw_fp_meas_type; // 0 == count pulses, else from period LWORD raw_fp_data; // Raw frequency data (period or count) } DSPTMR_FP_DATA_T; This low-level driver software uses the Overflow Interrupt to extend the counter to 32 bits, by counting overflows in the "raw_data.parts.fp_msw" variable. The 32-bit value of the counter is read from the "raw_data.fp_count" variable. By reading from the Capture Register (CAP), we are able to read the number of IPBus clock cycles with zero error, please see Section 14.7.5 "Capture Register (CAP)" in the DSP56F80x User's Manual. Our software only captures one edge of the input signal, but you can put a different value in the Status and Control Register (SCR) Input Capture Mode value, please see Section 14.7.2.9 "Input Capture Mode (Capture Mode) - Bits 7-6" in the DSP56F80x User's Manual. The period of one cycle is the difference between the "end" and "start" values in the structure, for example: LWORD period_value; DSPTMR_FP_DATA_T *p_fp_data = &g_dsp_tmrb0_data; period_value = p_fp_data->fp_end_val - p_fp_data->fp_start_val; This is, of course, the count of Primary Count Source clock pulses (ie IP_Bus_Clock/1) in one complete cycle. This is converted to the frequency value in the function process_frequency_inputs(). You can use a similar calculation to convert the count to the true period value. We don't use the SDK low-level I/O drivers at all, so if you want to use the method shown above, you will have to figure out how to do it on your own. I hope this information is helpful to you. Regards, Art Johnson Senior Systems Analyst PMC Prime Mover Controls Inc. 3600 Gilmore Way Burnaby, B.C., Canada V5G 4R8 Phone: 604 433-4644 FAX: 604 433-5570 Email: http://www.pmc-controls.com -----Original Message----- From: dflieb20 [mailto:] Sent: Tuesday, November 26, 2002 12:53 PM To: Subject: [motoroladsp] Measuring PW using Quad Timer Captures Hello- I am using the 56807 with the Motorola SDK. I am tryng to measure the pulse-width of a ~50Hz squarewave using the capture registers on two timers (one to save the rise time, one to save the fall time). The rise and fall interrupts fire correctly, but the values returned by the SDK function ioctl(...,QT_READ_CAPTURE_REG,...) are strange at best (the rise and fall times are usually separated by only 1 clock cycle, which is near impossible). I am connecting the signal generator to timer D0 and using that pin as input to both timers. Here is the code - thanks for any input. dave #include <stdio.h> #include "port.h" #include "arch.h" #include "io.h" #include "led.h" #include "qtimerdrv.h" #include "periph.h" #include "fcntl.h" #include "quadraturetimer.h" static void CallbackOnRisingEdge(qt_eCallbackType CallbackType, void* pParam); static void CallbackOnFallingEdge(qt_eCallbackType CallbackType, void* pParam); const qt_sState quadParam1 = { /* Mode = */ qtCount, /* InputSource = */ qtCounter0Input, /* InputPolarity = */ qtNormal, /* SecondaryInputSource = */ 0, /* CountFrequency = */ qtRepeatedly, /* CountLength = */ qtPastCompare, /* CountDirection = */ qtUp, /* OutputMode = */ qtToggleOnCompare, /* OutputPolarity = */ qtNormal, /* OutputDisabled = */ 0, /* Master = */ 0, /* OutputOnMaster = */ 0, /* CoChannelInitialize = */ 0, /* AssertWhenForced = */ 0, /* CaptureMode = */ qtRisingEdge, /* CompareValue1 = */ 0xFFFF, /* CompareValue2 = */ 0xFFFF, /* InitialLoadValue = */ 0x0000, /* CallbackOnCompare = */ { 0, 0 }, /* CallbackOnOverflow = */ { 0, 0 }, /* CallbackOnInputEdge = */ { CallbackOnRisingEdge, 0 } }; const qt_sState quadParam2 = { /* Mode = */ qtCount, /* InputSource = */ qtCounter0Input, /* InputPolarity = */ qtNormal, /* SecondaryInputSource = */ 0, /* CountFrequency = */ qtRepeatedly, /* CountLength = */ qtPastCompare, /* CountDirection = */ qtUp, /* OutputMode = */ qtToggleOnCompare, /* OutputPolarity = */ qtNormal, /* OutputDisabled = */ 0, /* Master = */ 0, /* OutputOnMaster = */ 0, /* CoChannelInitialize = */ 0, /* AssertWhenForced = */ 0, /* CaptureMode = */ qtFallingEdge, /* CompareValue1 = */ 0xFFFF, /* CompareValue2 = */ 0xFFFF, /* InitialLoadValue = */ 0x0000, /* CallbackOnCompare = */ { 0, 0 }, /* CallbackOnOverflow = */ { 0, 0 }, /* CallbackOnInputEdge = */ { CallbackOnFallingEdge, 0 } }; Word16 RiseTime=0, FallTime=0, PW=0; int PwUpdated =0, PrevPW=0;; UWord16 TimerD0; /* file handles */ UWord16 TimerD1; static int LedFD; /********************************************************************* ********/ main() { LedFD = open(BSP_DEVICE_NAME_LED_0, 0); ioctl(LedFD, LED_OFF, LED_GREEN); TimerD0 = open(BSP_DEVICE_NAME_QUAD_TIMER_D_0, 0, &quadParam1 ); TimerD1 = open(BSP_DEVICE_NAME_QUAD_TIMER_D_1, 0, &quadParam2 ); ioctl(TimerD0, QT_DISABLE, (void*)&quadParam1 ); ioctl(TimerD1, QT_DISABLE, (void*)&quadParam2 ); ioctl(TimerD0, QT_ENABLE_CAPTURE_REG, (void*)&quadParam1 ); ioctl(TimerD1, QT_ENABLE_CAPTURE_REG, (void*)&quadParam2 ); ioctl(TimerD0, QT_ENABLE, (void*)&quadParam1 ); ioctl(TimerD1, QT_ENABLE, (void*)&quadParam2 ); while(1) /* executive loop */ { if (PwUpdated) { PrevPW = PW; PwUpdated = 0; } } } /********************************************************************* ********/ void CallbackOnRisingEdge(qt_eCallbackType CallbackType, void* pParam) { ioctl(LedFD, LED_ON, LED_GREEN); ioctl(LedFD, LED_OFF, LED_RED); RiseTime = ioctl(TimerD0, QT_READ_CAPTURE_REG, (void*) &quadParam1 ); } void CallbackOnFallingEdge(qt_eCallbackType CallbackType, void* pParam) { ioctl(LedFD, LED_OFF, LED_GREEN); ioctl(LedFD, LED_ON, LED_RED); FallTime = ioctl(TimerD1, QT_READ_CAPTURE_REG, (void*) &quadParam2 ); PW = FallTime-RiseTime; PwUpdated = 1; } _____________________________________ Note: If you do a simple "reply" with your email client, only the author of this message will receive your answer. You need to do a "reply all" if you want your answer to be distributed to the entire group. _____________________________________ About this discussion group: To Join: To Post: To Leave: Archives: http://www.yahoogroups.com/group/motoroladsp More Groups: http://www.dsprelated.com/groups.php3 ">http://docs.yahoo.com/info/terms/ | |||
|