Hola,
It appears that you require to read a sequence of 8 pulse periods, and on completion to display all 8 values to the SCI. Your code will not achieve this, primarily because 'flag' is set, within the ISR, after each period. So afer the first period is obtained, you attempt to display all of the periods - random data will be displayed for most.
One solution is to store each pulse period within the ISR code, and set 'flag' only after all the 8 pulses are completed. To achieve this, the period data should be stored within a single, global array variable, rather than eight separate variables.
I have not seen your initialisation code for the ICS module. You have stated that you have a bus frequency of 4 MHz, but this will not be accurately achieved unless the internal reference within the ICS is trimmed with an appropriate value. Otherwise the bus frequency error can be very large. The non-volatile (NV) trim value needs to be determined and programmed during the programming process for the MCU. Your code then requires to read this value, and transfer to the ICS trim register.
My suspicion that this may not have been done was alerted by your baud register setting for the SCI module. In all probability, you would require 9600 bits per second, but your current baud register setting would be erroneous if the bus frequency were actually 4.00 MHz. The bus frequency error would also give period measurement errors.
Your present code is very difficult to understand, and will be very inefficient, such as the following instances -
.
- The use of the global variable 't9' within the send_char() funcion, in lieu of using a function parameter. I cannot see any reason for this.
. - Your reluctance to make use of ASCII character constants. The use of '0' is more meaningful than either 48 or 0x30.
. - Your reluctance to make use of "backslash character constants" to represent ASCII control characters. '\r' is more meaningful than 13 or 0x0D.
. - The use of multiple variables, rather than a single array variable, for the various period data.
. - The "inlining" of your display code (within main() function) requires a large amount of code and is very repetitive. This should be handled as separate functions. One function would display a single result. Another function could then call this function, to consecutively display all eight results from within a 'for' loop.
. - I notice that you have modified the send_char() function so that a wait for the completion of the current character transmission occurs before the function exits. Previously, there was a wait until the previous character was completed, prior to sending the current character. The second method is more efficient, as other operations outside of the function may occur during the character transmission period, thus reducing the wait period.
. - Your additional read of TPM1CH0SC register, prior to TPM1CH0SC_CH0F = 0; is unnecessary. This is because the latter is actually a "read-modify-write" process.
Here is a code example that takes into account my various comments -
#define MAXDATA 8// Global variables:volatile byte flag;volatile word timedat[MAXDATA];// Function prototypes:void disp_data( void);void send_period( word n);void send_char( byte val);void MCU_init( void);/*************************************************?********************/void main(void){ MCU_init(); // Initialise MCU registers EnableInterrupts; for ( ; ; ) { // Main loop __asm wait; __RESET_WATCHDOG(); if (flag) { // Test for period data complete disp_data(); // Display period data to SCI flag = 0; TPM1C0SC_CH0F = 0; // Clear TPM channel flag TPM1C0SC = 0x48; // Next capture on falling \_ edge } }}/*********************************************************************/// Display period data to SCIvoid disp_data( void){ byte i; for (i = 0; i < MAXDATA; i++) { send_char( 'T'); send_char( i + '0'); send_char( '='); send_period( timedat[i]); }}/*********************************************************************/// Send period result to SCIvoid send_period( word n){ send_char( n / 10000 + '0'); n %= 10000; send_char( n / 1000 + '0'); n %= 1000; send_char( n / 100 + '0'); n %= 100; send_char( n / 10 + '0'); send_char( n % 10 + '0'); send_char( '\r'); send_char( '\n');}/*********************************************************************/// Send character to SCIvoid send_char( char val){ while (!(SCIS1 & 0x80)); // Wait until ready to send SCID = val;}
// ISR functions:// TPM1 module, channel 0:__interrupt VectorNumber_Vtpm1ch0 void ISR_TPM1CH0( void){ static byte count = 0; static word t; TPM1C0SC_CH0F = 0; // Clear flag if (TPM1C0SC_ELS0A) { // This interrupt for rising _/ edge timedat[count++] = TPM1C0V - t; // Pulse period if (count < MAXDATA) { // Data table is not full TPM1C0SC = 0x48; // Capture on next falling \_ edge } else { // Data table is full count = 0; // Ready for next set of data flag = 1; // Flag data complete TPM1C0SC = 0x00; // Disable further interrupts } } else { // This interrupt for falling \_ edge t = TPM1C0V; // Start of pulse TPM1C0SC = 0x44; // Capture on next rising _/ edge }}
I also used a separate function for the MCU initialisation. This is more complete than the previous code, and is more extensively documented. It contains the initialisation for the ICS module. Initialisation to this extent, or more, is probably necessary for most projects.
// Initialise MCU registersvoid MCU_init( void){ // Initialise GPIO: PTAPE = 0xFF; // Enable pullups PTADD = 0x00; // All pins are inputs PTBPE = 0xFF; // Enable pullups PTBDD = 0x00; // All pins are inputs PTCPE = 0xFF; // Enable pullups PTCDD = 0x00; // All pins are inputs //--------------------------------------------------- // Write-once registers: SOPT1 = 0b10100110; /* ||| ||+-- RSPTE No reset pin ||| |+--- BKGDPE BGGD/MS pin enabled ||| +---- TPM1PS TPM1 -> PTA6,PTA7 ||+------- STOPE STOP instr. enabled ++-------- COPT COP period ~256 ms */ SOPT2 = 0b00000000; /* |+-------- COPW Normal COP operation +--------- COPCLKS 1kHz clock source */ SPMSC1 = 0b00011100; /* |||||| +-- BGBE Band gap disabled |||||+---- LVDE LVD enabled ||||+----- LVDSE LVD enabled in STOP |||+------ LVDRE LVD reset ||+------- LVWIE No LVW interrupt |+-------- LVWAK Acknowledge LVW flag (W) +--------- LVWF LVW flag (R) */ SPMSC2 = 0b00100000; /* |||| +-- PPDC No partial power-down |||+---- PPDACK Acknowledge PPD flag (W) ||+----- PPDF PPD flag (R) |+------ LVWV LVW trip level 4.3V +------- LVDV LVD trip level 4.0V */ //--------------------------------------------------- // ICS module: // FEI mode - bus frequency 4-5 MHz, depending on trim // Internal reference trimmed to 31.25kHz for 4 MHz bus ICSC1 = 0b00000110; /* |||||||+-- IREFSTEN ||||||+--- IRCLKEN Clock O/P for RTC module |||||+---- IREFS Internal reference ||+++----- RDIV No ext. reference ++-------- CLKS FLL output */ ICSC2 = 0b01000000; /* |||||||+-- EREFSTEN ||||||+--- ERCLKEN |||||+---- EREFS Not external reference ||||+----- LP |||+------ HGO ||+------- RANGE ++-------- BDIV FLL O/P divide by 2 */ ICSSC = 0b00000000; /* |||||||+-- FTRIM Fine trim bit ||||||+--- OSCINIT (R) ||||++---- CLKST (R) |||+------ IREFST (R) ||+------- DMX32 ++-------- DRST (R) ++-------- DRS Low range (W) */ // Test whether NV trim value has been programmed if (NVICSTRM == 0xFF) { // Action here for unprogrammed NV trim value, e.g. flash LED for ( ; ; ); // Wait for watchdog timeout reset } // Trim reference oscillator - NV values for 31.25kHz ICSTRM = NVICSTRM; ICSSC_FTRIM = NVFTRIM_FTRIM; //--------------------------------------------------- // SCI module: SCIBD = 26; // Baud rate 9600bit/s with 4 MHz bus SCIC1 = 0x00; SCIC2 = 0x0C; // No interrupts //--------------------------------------------------- // TPM1 module: TPM1MOD = 0x00; // Ensure free-running mode TPM1C0SC = 0x48; // Next capture interrupt on falling \_ edge TPM1C0SC_CH0F = 0; // Ensure flag is clear TPM1SC = 0x0A; // Enable TPM - bus clock source, prescale 4 flag = 0; // Global variable}
I have also attached the full CW project (V6.3) for the above code, to see if you have any compiler problems.
Regards,
Mac