In continuation of my previous post about setting up a counter via register access, I’m trying to setup Input Capture to measure a pulse’s period.
Previous Post: [url]https://www.ghielectronics.com/community/forum/topic?id=22822&page=2#msg212726[/url]
/*
I’ve tried to follow the reference guide’s example slightly modified for Channel 2 plus the GPIO alternate function setup for Timer 9 Input Channel 2. I seem to be getting Zero Values for both CCR1 and CCR2 which should show period and duty cycle. This is regardless of prescale value and frequency and duty cycle of the input PWM.
*/
So, I think I’ve got this working…but not as expected…but maybe I’ve misunderstood. Assuming the Timer Clock is at 168Mhz for the Cerb40II and the prescaler set in the code below, CCR1+CCR2 = Total Period. and CCR2/Total Period = Duty Cycle.
I though CCR1 was supposed to be the Period? Anyway, anyone else want to give this a try?
On another note, sometimes when I re-deploy CCR1 and CCR2 are zero and I need to unplug it, and redeploy to get it to work. Maybe a bug in the setup code?
Here’s my basic code:
public class STMInternalInputCapture
{
/* Example setup
This mode is a particular case of input capture mode. The procedure is the same except:
• Two ICx signals are mapped on the same TIx input.
• These 2 ICx signals are active on edges with opposite polarity.
• One of the two TIxFP signals is selected as trigger input and the slave mode controller
is configured in reset mode.
For example, you can measure the period (in TIMx_CCR1 register) and the duty cycle (in
TIMx_CCR2 register) of the PWM applied on TI1 using the following procedure (depending
on CK_INT frequency and prescaler value):
* 1. Select the active input for TIMx_CCR1: write the CC1S bits to ‘01' in the TIMx_CCMR1
register (TI1 selected).
* 2. Select the active polarity for TI1FP1 (used both for capture in TIMx_CCR1 and counter
clear): program the CC1P and CC1NP bits to ‘00' (active on rising edge).
* 3. Select the active input for TIMx_CCR2: write the CC2S bits to ‘10' in the TIMx_CCMR1
register (TI1 selected).
* 4. Select the active polarity for TI1FP2 (used for capture in TIMx_CCR2): program the
CC2P and CC2NP bits to ‘11' (active on falling edge).
* 5. Select the valid trigger input: write the TS bits to ‘101' in the TIMx_SMCR register
(TI1FP1 selected).
* 6. Configure the slave mode controller in reset mode: write the SMS bits to ‘100' in the
TIMx_SMCR register.
* 7. Enable the captures: write the CC1E and CC2E bits to ‘1' in the TIMx_CCER register.
*/
private Register TIMx_CCR1; //= new Register(); //+0x34 //this is the capture register1
private Register TIMx_CCR2;// = new Register(); //+0x38 //this is the capture register2
private Register TIMx_CNT; //register count
Register TIMx_EGR;
private const uint TIMx_BaseAddress = 0x40014000; //Timer 9 Base Address
private const uint TIMx_PSC_register = TIMx_BaseAddress + 0x28; //prescaler
private const uint GPIOA_BaseAddress = 0x40020000; //sect 8.4 -enable alternate function
private const uint GPIOA_AFRL_address = GPIOA_BaseAddress + 0x20; //enable the spcific alternate function for the specific pin
//register to turn timer on an off again
private const uint RCC_APB2ENR_register = 0x40023800 + 0x44;
private const uint TIMx_CCMR1_register = TIMx_BaseAddress + 0x18;
private const uint TIMx_CCER_register = TIMx_BaseAddress + 0x20;
private const uint TIMx_SMCR_register = TIMx_BaseAddress + 0x08;
private const uint TIMx_CR1_register = TIMx_BaseAddress + 0;
private const uint TIMx_CNT_register = TIMx_BaseAddress + 0x24; //the value of the counter
private const uint RCC_APB2RSTR_register = 0x40023800 + 0x24;
private const uint FCPU = 84 * 1000000; //the clocks are 84Mhz with 0 prescale
public STMInternalInputCapture()
{
init();
}
private void init()
{
TIMx_CCR1 = new Register(TIMx_BaseAddress+0x34); //+0x34 //this is the capture register1
TIMx_CCR2 = new Register(TIMx_BaseAddress + 0x38);
//Register RCC_APB2RSTR = new Register(RCC_APB2RSTR_register);
//RCC_APB2RSTR.SetBits(1 << 16);
//setup alternate function for the GPIO
Register GPIOA_MODER = new Register(GPIOA_BaseAddress);
GPIOA_MODER.SetBits(1 << 7 | 0 << 6);
Register GPIOA_AFRL = new Register(GPIOA_AFRL_address);//Alt Func register page 287 in Ref Manual & page 61 in Datasheet
GPIOA_AFRL.SetBits(0 << 15 | 0 << 14 | 1 << 13 | 1 << 12); //use AF3 "0011" TIM9_CH2
//this may be redundant
Register RCC_APB2ENR = new Register(RCC_APB2ENR_register);
RCC_APB2ENR.SetBits(1 << 16);
//setup prescaler
//The counter clock frequency CK_CNT is equal to fCK_PSC / (PSC[15:0] + 1).
Register TIMx_PSC = new Register(TIMx_PSC_register);
TIMx_PSC.Value = 0;
TIMx_PSC.Value = 419;
//step1
//capture/compare mode register 1
Register TIMx_CCMR1 = new Register(TIMx_CCMR1_register);//0x18 //TI2 CCS1 "10"
TIMx_CCMR1.ClearBits(1 << 1 | 1 << 0);
TIMx_CCMR1.SetBits(1 << 1);// | 0 << 0); //CH2 is input or CC1S
//step2
Register TIMx_CCER = new Register(TIMx_CCER_register); //0x20 ccenable register //step2
//TIMx_CCER.SetBits(0 << 3 | 0 << 1); //CC1p cc1np 00 //maybe clear bits to make sure?
TIMx_CCER.ClearBits(1 << 3 | 1 << 1); //00: noninverted/rising edge
//step3 don't need CCR2, but will setup anyway
TIMx_CCMR1.ClearBits(1 << 9 | 1 << 8);
TIMx_CCMR1.SetBits(1 << 8); //USE TI2
//step4 not needed, but will do anyway
TIMx_CCER.ClearBits(1 << 7 | 1 << 5);
TIMx_CCER.SetBits(1 << 7 | 1 << 5);//both edges?11
//step5 /6
Register TIMx_SMCR = new Register(TIMx_SMCR_register);
TIMx_SMCR.ClearBits(247); //11110111
//TS
TIMx_SMCR.SetBits(1 << 6 | 1 << 5 ); //SMS 110 TI2
//SMS
TIMx_SMCR.SetBits(1 << 2 );
TIMx_EGR = new Register(TIMx_BaseAddress + 0x14);
Register TIMx_DIER = new Register(TIMx_BaseAddress + 0x0C);
//Interrupt Fiddle
//TIMx_DIER.ClearBits(1 << 1);
//71 = 1000111
TIMx_DIER.ClearBits(71);
//TIMx_DIER.SetBits(1 << 6);
//TIMx_CCER.TIMx_DIER.SetBits(1 << 0 | 1 << 1 | 1 << 2);
TIMx_EGR.ClearBits(71);
/*
TIMx_EGR.SetBits(1 << 6);
TIMx_EGR.SetBits(1 << 1);
TIMx_EGR.SetBits(1 << 2);
TIMx_EGR.SetBits(1 << 0);
*/
//step 7
//enable the CC1E - Enable the counters!
TIMx_CCER.SetBits(1 << 0);
TIMx_CCER.SetBits(1 << 4);
TIMx_CNT = new Register(TIMx_CNT_register);
//ResetCounter();
}
public uint ReadCCR1()
{
return TIMx_CCR1.Value;
}
public uint ReadCCR2()
{
return TIMx_CCR2.Value;
}
public uint ReadTimerCount()
{
return TIMx_CNT.Value;
}
/// <summary>
/// Reset the TIMx_CNT register via the TIMx_EGR UG bit
/// </summary>
public void ResetCounter()
{
TIMx_EGR.SetBits(1 << 0);
}
}
public class Program
{
public static void Main()
{
STMInternalInputCapture sensor = new STMInternalInputCapture();
PWM pulses = new PWM(GHI.Pins.FEZCerb40II.PwmOutput.PA7, 15, .1, false);
pulses.Start();
while (true)
{
uint freqTime;
uint duty;
uint timer;
freqTime = sensor.ReadCCR1();
duty = sensor.ReadCCR2();
timer = sensor.ReadTimerCount();
Debug.Print("Ticks: " + freqTime.ToString());
Debug.Print("Duty Ticks: " + duty.ToString());
Thread.Sleep(1000);
}
}
}
}