Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maybe add duty cycle measurement to the simpletools library #180

Open
AndyLindsay opened this issue Jan 3, 2019 · 1 comment
Open

Maybe add duty cycle measurement to the simpletools library #180

AndyLindsay opened this issue Jan 3, 2019 · 1 comment

Comments

@AndyLindsay
Copy link
Contributor

/*

  Example uses counter modules to measure a duty cycle on P3.
  For more info on counter modules, download the Propeller Manual from 

    https://www.parallax.com/downloads/propeller-manual

  ... and see pages 95 - 98

  Also,

    https://www.parallax.com/propeller/qna/Content/QnaTopics/QnaCounters.htm

    https://www.parallax.com/sites/default/files/downloads/AN001-P8X32ACounters-v2.0.pdf


  Use Run with Terminal to see this output

    duty cycle generated = 0
      duty cycle measured  = 0

      duty cycle generated = 100
      duty cycle measured  = 100

      duty cycle generated = 1
      duty cycle measured  = 1

      duty cycle generated = 25
      duty cycle measured  = 25

      duty cycle generated = 50
      duty cycle measured  = 50

      duty cycle generated = 75
      duty cycle measured  = 75

      duty cycle generated = 99
      duty cycle measured  = 99

*/  


#include "simpletools.h"


int dutyCycle(int pin, int timeout, int scale);


int dcTest;


int main()
{
  low(3);
  pause(85);
  dcTest = dutyCycle(3, 85, 100); 
  print("duty cycle generated = 0\r");
  print("duty cycle measured  = %d\r\r", dcTest);
  
  high(3);
  pause(85);
  dcTest = dutyCycle(3, 85, 100); 
  print("duty cycle generated = 100\r");
  print("duty cycle measured  = %d\r\r", dcTest);

  // Start pwm signal tcycle = 40 ms.
  pwm_start(40000); 

  pwm_set(3, 0, 400);
  pause(85);
  dcTest = dutyCycle(3, 85, 100); 
  print("duty cycle generated = 1\r");
  print("duty cycle measured  = %d\r\r", dcTest);

  pwm_set(3, 0, 10000);
  pause(85);
  dcTest = dutyCycle(3, 85, 100); 
  print("duty cycle generated = 25\r");
  print("duty cycle measured  = %d\r\r", dcTest);

  pwm_set(3, 0, 20000);
  pause(85);
  dcTest = dutyCycle(3, 85, 100); 
  print("duty cycle generated = 50\r");
  print("duty cycle measured  = %d\r\r", dcTest);

  pwm_set(3, 0, 30000);
  pause(85);
  dcTest = dutyCycle(3, 85, 100); 
  print("duty cycle generated = 75\r");
  print("duty cycle measured  = %d\r\r", dcTest);

  pwm_set(3, 0, 39600);
  pause(85);
  dcTest = dutyCycle(3, 85, 100); 
  print("duty cycle generated = 99\r");
  print("duty cycle measured  = %d\r\r", dcTest);

}


/**

  @brief measure ratio of tHigh / (tHigh + tLow) in terms of some integer scale value.  

  @param pin I/O pin measuring the signal.

  @param timeout ms to wait.  Use at least two full signal cycles, three to be safe.
  If the frequency varies, make sure to use enough ms for two cycles at the lowest 
  frequency.

  @param scale number to multiply by factional value duty cycle.  For percent duty
  cycle, use 100.  

  WARNING: This function starts to roll over when scale * phsa > 2^31.  Since phsa
  is in 12.5 ns units, an example to cause this would be if you choose a scale of 
  10,000 and allow your measurement's high time to exceed 2684 us.  
  Example: 2685 us * 80 ticks/us * 10,000 = 2,148,000,000 > 2,147,483,648

  @returns scale * tHigh / (tHigh + tLow) or -1 if timeout occurred mid-measurement.

*/  

int dutyCycle(int pin, int timeout, int scale)
{
  // Check state in case of timeout
  int state = input(pin);
  
  // Define timeout in terms of clock ticks
  int dt = timeout * (CLKFREQ/1000);

  // Mark free running clock counter time
  int t = CNT;
  
  // Assuming other functions in the application have been using counter modules, 
  // configure CTRA/B, FRQA/B, and PHSA/B.

  // Set up free running counter module A to masure high time clock ticks  
  CTRA = (1000 << 26) | pin;
  FRQA = 1;

  // Set up free running counter module B to masure low time clock ticks
  CTRB = (1100 << 26) | pin;
  FRQB = 1;
  
  // Set up pin mask
  int mask = 1 << pin;
  int phsa, phsb;

  // Wait for high to low transition 
  while(INA & mask) if(CNT - t > dt) break;

  // Start free-running high measurement while signal is low
  PHSA = 0;

  // Wait for low to high transition
  while(!(INA & mask)) if(CNT - t > dt) break;

  // Start free running low measurement while signal is high
  PHSB = 0;

  // Wait for high to low transition
  while(INA & mask) if(CNT - t > dt) break;

  // Complete high time measurement
  phsa = PHSA;

  // Wait for low to high transition
  while(!(INA & mask)) if(CNT - t > dt) break;

  // complete low time measurement
  phsb = PHSB;

  // print("phsa = %d, phsb = %d\r", phsa, phsb);

  // Turn off counter modules for other functions to use them.
  CTRA = 0;
  CTRB = 0;

  // If timeout, return 100, 0, or -1 for 
  if(CNT - t > dt)
  {
    // Signal was high the whole time
    if(state == 1 && phsb == 0) return scale; 

    //Signal was low the whole time
    else if(state == 0 && phsa == 0) return 0;

    // Timeout occurred mid-measurement.
    else return -1;
  }
  else
  {  
    // If no timeout, return the duty cycle measurement.  
    int dc = (phsa * scale) / (phsa + phsb);
    return dc;
  }    

}  
@AndyLindsay
Copy link
Contributor Author

Change the function name/arguments to int get_dutyCycle(int pin, int msTimeout, int scale);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant