Library to Capture the +ve and -ve Pulsewidth of a signal

Dependents:   PulseWidthCapture_Program

PulseWidthCapture.cpp

Committer:
Ellor1
Date:
2014-12-11
Revision:
2:857c3c8e7a2f
Parent:
1:6bb38ae2e503

File content as of revision 2:857c3c8e7a2f:

 /* mbed Library - PulseWidthCapture
 * Copyright (c) 2014
 * released under MIT license http://mbed.org/licence/mit
 */
/***********************************************************************//**
 * @file        PulseWidthCapture.cpp
 * @brief       cpp file for the PulseWidthCapture library. 
 * @version     0.0
 * @date        03 Dec 2014
 * @author      Callum Ellor
 **************************************************************************/
/***************************************************************************
 * Revision     Date        Comments
 *----------    --------    -----------------------------------------------
 *
 *  0.0         03/12/14    Initial creation
 ***************************************************************************/

#include "mbed.h"
#include "TextLCD_16x4.h"
#include "USBSerial.h"
#include "PulseWidthCapture.h"

//USBSerial serial;
TextLCD lcd(P0_21, P0_20, P1_15, P0_19, P0_5, P0_4, TextLCD::LCD16x4); // rs, e, d4, d5, d6, d7

/*Status Led's to check that program is entering ISR's   */

DigitalOut led(P0_9);
DigitalOut led2(P0_8);
//DigitalOut led3(P0_7);
DigitalOut led4(P0_17);

AnalogIn Ain(P0_11);

Capture *Capture::instance;

/*********************************************************************//**
 * @brief       Create a Capture object and configure it. 
 * @param       None   Uses P1_29 as the Capture input (Pin 7)
  * @param      None   Uses P0_12 as the Capture input (Pin 16)
 * @return      None
 **********************************************************************/
Capture::Capture(void)          //Capture Constructor
{       

    /* Configure registers */

    /* Set up clock and power, using default peripheral system clock divider */  // See page 30 of the 11U24 User Guide 
    
    LPC_SYSCON->SYSAHBCLKCTRL |=   CT32B0_CLK_ENABLE; // setup 32 bit Timer 0 Clock
        
    LPC_SYSCON->SYSAHBCLKCTRL |=   CT32B1_CLK_ENABLE; // setup 32 bit Timer 1 Clock
    
    LPC_SYSCON->SYSAHBCLKCTRL |=   CT16B0_CLK_ENABLE; // setup 16 bit Timer 0 Clock
    
    LPC_CT32B0->PR  =  0;                           // set Prescale to 0 to use 48MHz Clock
    LPC_CT32B1->PR  =  0;                           // set Prescale to 0 to use 48MHz Clock
    LPC_CT16B0->PR  =  1000;                        // set Prescale to 1000 to use 48KHz Clock
       
    /* Configure IOCON for the proper function of the capture pin. Setup PIO1_29 for Capture */
    LPC_IOCON->PIO1_29 = (CT32B0_CAP1); // See page 125 of the 11U24 User Guide   
      
    /* Configure IOCON. Setup TMS_PIO0_12 for Capture mode, also set up for Digital Function mode */     
    LPC_IOCON->TMS_PIO0_12 = CT32B1_CAP0 | ADMODE; // See page 94 of the 11U24 User Guide
                     
    // Select the capture edge and interrupt mode
    /* will start capturing on the rising edge of CT32B0_CAP1 (P1_29) will also generate an interrupt */
    LPC_CT32B0->CCR =   CCR_CAP1RE  | CCR_CAP1I;    // See page 357 of the 11U24 User Guide 
    
    /* will start capturing on the falling edge of CT32B1_CAP0 (TMS_P0_12) will also generate an interrupt */
    LPC_CT32B1->CCR =   CCR_CAP0FE  | CCR_CAP0I;    // See page 356 of the 11U24 User Guide 

    /* Setup match register for 16 bit timer. will interrupt when value in MR0 matches the value in the Timer Counter TC
    will also reset the timer TC when the value in MR0 is matched*/
  
    LPC_CT16B0->MCR =   CT16B0_MR0I | CT16B0_MR0R;  // See page 337 of the 11U24 User Guide 
  
    // Set up the Count Control Register for Timer mode, and to clear the timer on a falling edge
    LPC_CT32B0->CTCR = CT32B0_CTCR_CTM_TIMER | CT32B0_CTCR_ENCC | CT32B0_CTCR_SEICC_CAP1FE; // See page 361 of the 11U24 User Guide 
    
   // Set up the Count Control Register for Timer mode, and to clear the timer on a rising edge
    LPC_CT32B1->CTCR = CT32B1_CTCR_CTM_TIMER | CT32B1_CTCR_ENCC | CT32B1_CTCR_SEICC_CAP0RE;// See page 362 of the 11U24 User Guide 
               
   // Clear interrupt flags
    LPC_CT32B0->IR = CT32B0_IR_CR1INT;      // See page 353 of the 11U24 User Guide            
    
    LPC_CT32B1->IR = CT32B1_IR_CR0INT;      // See page 353 of the 11U24 User Guide 
    
    LPC_CT16B0->IR = CT16B0_IR_MR0INT;      // See page 335 of the 11U24 User Guide 
    

    //* Attach IRQ
    instance = this; 
    NVIC_SetVector(TIMER_32_0_IRQn, (uint32_t)&_Fall_ISR);    //setuip ISR's
    NVIC_SetVector(TIMER_32_1_IRQn, (uint32_t)&_Rise_ISR); 
    NVIC_SetVector(TIMER_16_0_IRQn, (uint32_t)&_Wait_ISR);

}

/*********************************************************************//**
 * @brief        Start capturing data. Enable 32 Bit Timer 0 & Timer 1 for interrupt an start the timer
 **********************************************************************/
void Capture::Start_1(void) {
                            
    /* Enable interrupt for CAPTURE  */
    NVIC_EnableIRQ(TIMER_32_0_IRQn); 
    
    // Start the timer
    LPC_CT32B0->TCR =  CT32B0_TCR_CEN; // enable. See page 354 of the 11U24 User Guide 
    
}

void Capture::Start_2(void) {
                    
    /* Enable interrupt for CAPTURE  */
    NVIC_EnableIRQ(TIMER_32_1_IRQn); 
    
    // Start the timer
    LPC_CT32B1->TCR =  CT32B1_TCR_CEN; // enable
     
}

/*********************************************************************//**
Debug code to test what values are in certain registers when writing the program
 **********************************************************************/
 
 unsigned int Capture::Debug(void) {
 
 debug = LPC_IOCON->TMS_PIO0_12 ;  // to check the values in registers (This example checks whats in register the IOCON register for TMS_PIO0_12
 
 return debug;
 
}
 
/*********************************************************************//**
Wait function that interrupts the program once the value in the match register matches whats in the TC register. This then jumps to the 
Wait_ISR routine which displays the data to the screen or LCD
 **********************************************************************/
 
 
void Capture::Wait(void) {
    
    //led3 = !led3;
    
     //Enable interrupt 
    NVIC_EnableIRQ(TIMER_16_0_IRQn);        //Enable 16 bit timer 0 for interrupt
    
    // Start the timer
    LPC_CT16B0->TCR =  CT16B0_TCR_CEN; // enable

    LPC_CT16B0->MR0 = 1000000000;
     
}

/* Capture Fall_ISR instantiator */   
void Capture::_Fall_ISR(void)
{
    instance->Fall_ISR();
}
 
/* Capture Rise_ISR instantiator */    
void Capture::_Rise_ISR(void)
{
    instance->Rise_ISR();
}

/* Capture Wait_ISR  instantiator */    

void Capture::_Wait_ISR(void)
{
    instance->Wait_ISR();
}


/*********************************************************************//**
 * @brief        Capture interrupt service routine for falling edge. 
 **********************************************************************/
void Capture::Fall_ISR(void) {

    static int capturesum = 0;                           // set variable capturesum to 0
    
    led = !led;                                          // status led to check that program has entered ISR
    capturesum = LPC_CT32B0->CR2;                        // read the value in LPC_CT32B0->CR2 and store in variable 'capturesum'
                                                         // It is necessary to use "CR2" in order to get the proper
                                                         // offset from the base address (an issue with CMSIS)
    fall = (((float)capturesum/48003280)*1000000);       // Convert the value in the capture register into a value in us. the internal clock 
                                                         // was measured at 48003280 so this has been used for the calculations.
                                                         // It is neccessary to assign the 'float' data type to 'capturesum' at this point 
                                                         // otherwise the variable fall which has been set to float will return a value of 0.
                    
    LPC_CT32B0->IR |= CT32B0_IR_CR1INT;                  // Clear the interrupt
             
    return;

}

/*********************************************************************//**
 * @brief        Capture interrupt service routine for rising edge. 
 **********************************************************************/
void Capture::Rise_ISR(void) {

    static int capturesum_2 = 0;    // Accumulates the readings
  
    led2 = !led2;
    capturesum_2 = LPC_CT32B1->CR0;
    rise = (((float)capturesum_2/48003280)*1000000);
    LPC_CT32B1->IR |= CT32B1_IR_CR0INT; 
      
    return;
}

/*********************************************************************//**
 * @brief        Wait interrupt service routine to display the results to a screen/lcd at set intervals 
 **********************************************************************/

void Capture::Wait_ISR(void) {
    
    NVIC_DisableIRQ(TIMER_32_0_IRQn);                   //disable 32 bit timer 0 interrupt so that the Wait_ISR can continue uninterrupted
    NVIC_DisableIRQ(TIMER_32_1_IRQn);                   //disable 32 bit timer 1 interrupt so that the Wait_ISR can continue uninterrupted
    
    led4 = !led4;                                       // status led to test that Wait_ISR is being entered
   
    period = rise + fall;                               // calculation for period
   // freq = (1/(float)period)*1000000;                   // calculation for frequency (not required)                                
    ADCdata = Ain * 10;                                 // calculation to convert ADC value to 10V
    
  /*  if (freq < 1000) {                                // unit conversion for frequency
      freq_unit = "Hz";
      freq1 = freq;
      }
      else if (freq > 1000) {
      freq1 = freq/1000;
      freq_unit = "KHz";
    }
*/

    if (period < 1000) {                                // unit conversion for period
        per_sec_unit = "us";
        period1 = period;
        }
     else if (period > 1000) {
         period1 = period/1000;
         per_sec_unit = "ms";
         }   
         
    if (rise < 1000) {                                  //unit conversion for +ve Pulsewidth
        rise_sec_unit = "us";
        rise1 = rise;
        
        }
     else if (rise > 1000) {
         rise1 = rise/1000;
         rise_sec_unit = "ms";
         }   
         
    if (fall < 1000) {                                  //unit conversion for -ve Pulsewidth
        fall_sec_unit = "us";
        fall1 = fall;
        }
     else if (fall > 1000) {
         fall1 = fall/1000;
         fall_sec_unit = "ms";
         }   
          
/* Display Rise, Fall, Period and Voltage to LCD screen */

    lcd.locate(0,0);    
    lcd.printf("Rise:");
    lcd.locate(0,1);
    lcd.printf("Fall:");
    lcd.locate(0,2);
    lcd.printf("Per:");
    lcd.locate(0,3);
    lcd.printf("Voltage:");
   // lcd.printf("Freq:");
    
    
    
/* These values are the ones that change over the course of the program so they have been put seprately to the values above
   Because individual lines on the LCD can't be cleared due to limitaions of the hardware to clear an individual line write blanks to the display
   for eg. lcd.printf("           ");
 */
 
 
    lcd.locate(5,0);
    lcd.printf("%.2f", rise1);
    lcd.locate(14,0);
    lcd.printf("%s", rise_sec_unit);        
    lcd.locate(5,1);
    lcd.printf("%.2f", fall1);
    lcd.locate(14,1);
    lcd.printf("%s", fall_sec_unit);
    lcd.locate(4,2);
    lcd.printf("%.2f", period1);
    lcd.locate(14,2);
    lcd.printf("%s", per_sec_unit);
    lcd.locate(8,3);
    lcd.printf("%.2f", ADCdata);
    lcd.locate(15,3);
    lcd.printf("V");
    //lcd.printf("%.2f %s", freq1, freq_unit);
    
    

    //if (serial.writeable())                                       // write values to serial (some issues seen with serial where the serial port hangs causing
                                                                    // the program not to work. Sometimes works and sometimes it doesn't
    //{
     
    //serial.printf("rise:%f \n\r", rise);
   // serial.printf("fall:%f \n\r", fall);
   // serial.printf("period:%f \n\r", period);
    //serial.printf("freq:%f \n\r", freq);
    //serial.printf("ADC:%f \n\r", ADCdata);
    //serial.printf("hello");
     // } 

    NVIC_EnableIRQ(TIMER_32_0_IRQn);                        //re-enable 32 bit timer 0 for interrupts
    NVIC_EnableIRQ(TIMER_32_1_IRQn);                        //re-enable 32 bit timer 1 for interrupts
    
    LPC_CT16B0->IR |= CT16B0_IR_MR0INT;                     // Clear the interrupt
    
    return;
    
    }