Jump to content
43oh

Probably dumb question regarding timers


Recommended Posts

yes

 

How precise do you want the rate and what characteristic do you want for the adjustment? Linear with resistance? More precision at one end or the other? How much resolution?

 

 

Without the answers to these questions, I'll give a basic summary of one way to approach it.

 

Connect the pot between Vcc and Gnd, and the wiper to a ADC input. This gives 1024 steps for freq selection. For (fairly) precise timing, you will need a crystal, but the standard clock system is pretty good, and will give greater resolution. At 5.5Hz, the higher speed osc will be 176Hz. At the low end, you are looking at 32Hz. Consider only the higher frequency, and every 32 transitions of that (every 16 full cycles) toggle the lower frequency output. For a symmetric square wave, your maximum basic timing is 362Hz.

 

If you aren't concerned about exact frequency, or having perfectly uniform steps, it is easier. Assuming a main clock of 1MHz (the lowest G-series clock from DCO that is factory calibrated), you can built a table of 1024 divider values for the timerA, with the highest freq value being 2762 and the lowest being 31250, to get double your higher freq. Write an interrupt handler that toggles your high freq output on each interrupt and your low freq output every 32nd interrupt (using an counter in the interrupt handler to keep track). Periodically read the ADC for pot position, and use this to set your timerA period.

 

There are a lot of way to do these things, so I am not being really specific. You could just scale the ADC value by 28 and add 2760 to it for your period, if less linear behaviour is ok. A table will allow you to get very close to linear. The timer can be set up several ways. One easy way to handle it is let it free run, for a period of about 1/160th of a second. Each interrupt, add the count increment to the trigger value for the interrupt, Then have it interrupt on each period and use that to trigger the ADC read for pot position.

Link to post
Share on other sites

Outputting frequencies on a pin can be done by the timer modules without needing to use interrupts & manually toggling pin outputs. The MSP430G2553 for example has 2 timers so can produce 2 different frequencies.

 

The following code is based on the MSP430G2553 and will produce 1 frequency on P1.1, and 1/32 of that frequency on P2.0.  As you will note, there are no interrupts, and no code is used to toggle pin outputs - they are purely conrolled by the timer.  In fact, the CPU isn't doing anything in this example - in my loop I put it into Low-Power-Mode 3, to show that the timer is doing all the work.  The code is designed to run at a slow speed so the effect can be observed on the Launchpad's LED's.  Note that the standard launchpad has the LEDs connected to P1.0 & P1.6. But you can remove the jumpers and use a F-F cable to connect P1.1 & P2.0 to the LED-side of the pins where the jumper attaches.

 

I know this example isn't exactly what you were asking, but you should find it fairly trivial to make the necessary changes.

 

All you need to do to change the frequencies at run-time is alter the TA0CCR0 and TA1CCR0 registers. 

void setup()
{
  //This is designed to run on the MSP430G2553 which has 2 Timer A modules.
  //The output of TimerA0 Capture/Compare Register 0 is attached to P1.1
  //The output of TimerA1 Capture/Compare Register 0 is attached to P2.0
  //This will output a square wave on P1.1 & a square wave of 1/32 the 
  //frequency on P2.0
  //P1.1 & P2.2 can be jumpered to the Launchpad's LEDs for a visual 
  //indication of the operation.
  
  P1DIR |= BIT1; //P1.1 set to output
  P1SEL |= BIT1; //P1.1 set to SEL = select timer output
  P1SEL2 &= ~BIT1;  //P1.1 clear SEL2 = select timer output
  
  P2DIR |= BIT0;  //P2.0 set to output
  P2SEL |= BIT0;
  P2SEL2 &= ~BIT0;

//The desired frequency of the fast clock in Hz
#define FREQUENCY 2

//The value that we count up to. Shown like this to show how it is derived:
//clock frequency (nominally 12khz) divided by the amount we divide the timer
//by with our TAxCTL command, divided by the desired output frequency, divided by 2.
#define COUNT (12000 / 8 / FREQUENCY / 2 )

//note the exact frequency depends on the accuracy of the VLO clock, which is not very
//accurate. For more precise timing we could use the crystal as the timebase, or 
//the system clock.  Note that the maximum the timer can count to is 65536, so if 
//using the 16MHz system clock, speeds low enough to observe will be impossible to achieve.

   TA1CCR0 = 32 * (TA0CCR0 = COUNT); //set TimerA0 to our count, and TimerA1 to count*32. 
                                     //this will make TimerA1 run 32 times slower than TimerA0
   TA1CCTL0 = TA0CCTL0 = OUTMOD_4;   //Set to toggle the output every time the count hits CCR0.
   
   TA1CTL = TA0CTL =  TASSEL_1 // Source timer's clock from ACLK
                      | ID_3   // Divide by 8
                      | MC_1;   // Count up to TA0CCR0 mode
             
}

void loop()
{
  LPM3;  //stop in LPM3 mode. 
}
Link to post
Share on other sites

@@chicken, @@enl, @@grahamf72,

Thanks for the feedback.

 

I was a bit vague so here's another go at explaining it:

I'll begin with the typo. I put 5.5Hz, but meant 5.5KHz. It appears the TwoMSTimer library may not work.

 

I want to simulate the trigger signals generated by the crankshaft and camshaft sensors on my motorcycle, from 200 to 11000 RPM. The crankshaft has 32 teeth; the camshaft has 1. The camshaft rotates and 1/2 crankshaft speed. The crankshaft signals at 200 RPM will be 107 crank triggers per second (200 * 32 / 60) and at 11000 RPM there will be 5867 (11000 * 32 / 60). The camshaft signal at 200 RPM will be approximately 2 per second- (200 / 2 / 60) and at 11000 RPM will be 92 (11000 / 2 / 60). All results are rounded up to the nearest whole. It may be worth noting that the camshaft tooth is approximately 1mm thick so it's pulse is short making the two-timers idea not quite work as needed.

 

A potentiometer may not be necessary: I might do something with a terminal window where the user can input the RPM and the unit speeds or slows as necessary, approximately simulating normal engine speed changes. So if the user inputs 1500 and the unit is at 800 it'll increase RPM's in steps with each crank tooth event until it's at the target, maybe in steps of 5 RPM with every 2 crank signals or something like that.

 

Or maybe, have it start at 200 until the first 'cam' signal is generated then step up to 1000, which is the idle speed of my bike. Then pushing the user button accelerates and releasing it decelerates.

Link to post
Share on other sites

Still quite doable. Probably want linear response on a pot, So I would go with a table for the divisors. Either of the above methods will work, but to match the pulse width for the short pulse will be easier with the interrupts. As the cam turns at half crank, if it has one tooth for the sensor, that is divisor of 64, not 32. does it have 2 teeth?

 

This range is great enough that I would handle the low rate pulse with an interrupt, even if the high rate is handled with hardware. Interrupt each rising edge of high speed, and keep a counter in the ISR. At 0x1f in the low bits (easy test with AND), output  high, otherwise output low.

 

Your base freq at 11000RPM with 32 teeth on crank is 5867HZ, for a divisor at 1MHz of 85 if using up/down counting. Low end of 200RPM is 106.7HZ, for a divisor of 4716 at 1MHz. Using a clock  of 4MHz for the timer quadruples these divisor values and gives higher resolution for smoother transition.  16MHz clock with clock divisor of 2 gives best precision at 8 times these divisors.

 

Given the new info, and @@grahamf72 pointing out the easier way, I would likely go hardware for high rate with interrupt and counter for low. Update count limit each time the low rate is output is set low by reading ADC input, triggering next ADC cycle, and storing the new limit value in the CCR. The ADC reads are one cycle behind the response. Still better than the response of any throttle.

Link to post
Share on other sites

Apparently need a timer for USB, and this affects that. :(

 

Well, using @grahamf76 code, I can get up to around 750Hz for timer TA1, or rather count to 24000...?

 

 

I feel rather embarrassed since 25 years ago I could peek and poke an Apple and make sounds and graphics and now I'm like LPLDPDLDFPDFDLPEY.

Link to post
Share on other sites

Well, using @grahamf76 code, I can get up to around 750Hz for timer TA1, or rather count to 24000...?

 

As is, the code there will only go to 750Hz, but if you change the line where it says ID_3 (divide by 8) to ID_0 (divide by 1), you can get up to half the VLO clock speed, which will be approx 6kHz. If you use the 32768hz crystal you can get up to 16384kHz.

 

By changing the TASSEL_1 line to TASSEL_2, it will use the system clock (you will also have to change the LPM3 to LPM0 so the clock stays running) which Energia sets to 16MHz. With careful use of the count figure and divide ratio you can get anything from 15Hz to 8MHz.  A slight tweak to Energia so that you can use the 1MHz clock with the 2553, and you can go from just under 1Hz to 500kHz.  By using the Capture/Compare registers and their associated pins, you can also vary the duty cycle so that you can have a short pulse instead of a 50/50 square wave.  

 

The timers on the MSP430 are very powerful - I don't claim to be an expert on them though, I know enough to do the basics, but there is still a lot I haven't quite got a good handle on.

Link to post
Share on other sites

@@grahamf72, expert or not, you've given good suggestions.

6KHz is just above what I see being necessary, as evident by the calculations posted above. But I do want stability and accuracy so will probably use the crystal.

Looks like the time has finally, absolutely presented itself where I need an oscilloscope. I've been asked about this and how to do a missing tooth. :ohmy:

My situation doesn't need it, but others do. They use the missing tooth to establish some known crankshaft position in absence of the camshaft signal.

 

I wonder if it would be 'better' to run a timer to count the period between teeth and use a tooth count for the rest of that, and toggle a pin for the cam signal based on tooth count.

Basically at X RPM, the interval between teeth is Y timer duration, and after Y expires increase the tooth count meanwhile on the 64th tooth toggle the cam signal.

Kind of sounds like some sort of function generator would be better suited?

Link to post
Share on other sites

Decided to give @@chicken recommendation a look-see. The TwoMsTimer only goes down to 1ms so it would max out just above 1500 RPM (1ms = 1000Hz; 1000/32[teeth]*60[seconds]).

 

Since I eventually want this to be variable, it seems like the one way would be to set a timer running in continuous mode then interrupt on some count, varying the count to control the speed. Also, this could be useful for interpolating positions between teeth to trigger other events, which I want to accomplish eventually- reading ADC and maybe flipping some GPIO on cue. So 16MHz is probably where I'll end up at as long as the timer doesn't overflow at the slower speeds.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...