cancel
Showing results for 
Search instead for 
Did you mean: 

Interconnect comparator to timer internally not working

Bence Péceli
Associate II

Hello,

I have a nucleof303k8 board on which I implemented a hysteresis current control.

This is done with the COMP2. I would like to know the average voltage which is connected to the inductive load in order to achieve the desired current.

My idea was to connect the comparator output to a timer input capture, which could then use dma to store the switching times, which are perfect to calculate this value.

However, I cannot get the comparator to trigger an input capture on the timer.

The comparator is switching correctly, and I can trigger the input capture with an input pin.

The init code of the comparator:

void MX_COMP2_Init(void)
{
  LL_COMP_InitTypeDef COMP_InitStruct = {0};
 
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
 
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
  /**COMP2 GPIO Configuration  
  PA7   ------> COMP2_INP
  PA12   ------> COMP2_OUT 
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  GPIO_InitStruct.Pin = LL_GPIO_PIN_12;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* COMP2 interrupt Init */
  NVIC_SetPriority(COMP2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(COMP2_IRQn);
 
  COMP_InitStruct.InputPlus = LL_COMP_INPUT_PLUS_IO1;
  COMP_InitStruct.InputMinus = LL_COMP_INPUT_MINUS_DAC1_CH2;
  COMP_InitStruct.OutputSelection = LL_COMP_OUTPUT_TIM3_IC1;
  COMP_InitStruct.OutputPolarity = LL_COMP_OUTPUTPOL_NONINVERTED;
  COMP_InitStruct.OutputBlankingSource = LL_COMP_BLANKINGSRC_NONE;
  LL_COMP_Init(COMP2, &COMP_InitStruct);
 
}

The init code of the timer:

void MX_TIM3_Init(void)
{
  LL_TIM_InitTypeDef TIM_InitStruct = {0};
 
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
 
  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);
  
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
  /**TIM3 GPIO Configuration  
  PA6   ------> TIM3_CH1 
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_2;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* TIM3 DMA Init */
  
  /* TIM3_CH1_TRIG Init */
  LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_6, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
 
  LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_6, LL_DMA_PRIORITY_LOW);
 
  LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_6, LL_DMA_MODE_CIRCULAR);
 
  LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_6, LL_DMA_PERIPH_NOINCREMENT);
 
  LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_6, LL_DMA_MEMORY_INCREMENT);
 
  LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_6, LL_DMA_PDATAALIGN_HALFWORD);
 
  LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_6, LL_DMA_MDATAALIGN_HALFWORD);
 
  /* TIM3 interrupt Init */
  NVIC_SetPriority(TIM3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(TIM3_IRQn);
 
  TIM_InitStruct.Prescaler = 0;
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
  TIM_InitStruct.Autoreload = 0xffff;
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
  LL_TIM_Init(TIM3, &TIM_InitStruct);
  LL_TIM_DisableARRPreload(TIM3);
  LL_TIM_SetClockSource(TIM3, LL_TIM_CLOCKSOURCE_INTERNAL);
  LL_TIM_SetTriggerOutput(TIM3, LL_TIM_TRGO_UPDATE);
  LL_TIM_DisableMasterSlaveMode(TIM3);
  LL_TIM_IC_SetActiveInput(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI);
  LL_TIM_IC_SetPrescaler(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1);
  LL_TIM_IC_SetFilter(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1);
  LL_TIM_IC_SetPolarity(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_BOTHEDGE);
 
}

And how I start the comparator and the timer:

  LL_COMP_Enable(COMP2); //reference is provided by dac
 
  TIM3->CCER &= ~TIM_CCER_CC1E;
  TIM3->CCMR1 &= ~TIM_CCMR1_CC1S_Msk;
  TIM3->CCMR1 = 01 << TIM_CCMR1_CC1S_Pos;
 
  //Enable Capture-compare on channel1
  TIM3->CCER |= TIM_CCER_CC1P_Msk | TIM_CCER_CC1NP_Msk; //both edges
  LL_TIM_EnableCounter(TIM3);
  LL_TIM_EnableIT_CC1(TIM3);
  TIM3->CCER |= TIM_CCER_CC1E;
  

With this setup, the comparator is working (output is visible on a led), the input capture can be triggered with a jumper, but the comparator cannot trigger an input capture.

Am I missing some additional register which needs to be set in order to enable the comparator input?

Thank you for the help!

1 ACCEPTED SOLUTION

Accepted Solutions

It works for me on a 'F303RB. I know it's a different chip, though.

(gdb) p /x *TIM3
$117 = {CR1 = 0x1, CR2 = 0x0, SMCR = 0x0, DIER = 0x0, SR = 0x1d, EGR = 0x0, CCMR1 = 0x1, CCMR2 = 0x0, CCER = 0xb,
  CNT = 0x4256, PSC = 0x0, ARR = 0xffff, RCR = 0x0, CCR1 = 0x0, CCR2 = 0x0, CCR3 = 0x0, CCR4 = 0x0, BDTR = 0x0,
  DCR = 0x0, DMAR = 0x1, OR = 0x0, CCMR3 = 0x0, CCR5 = 0x0, CCR6 = 0x0}
(gdb) p /x *COMP2
$119 = {CSR = 0x40002811}
(gdb) set GPIOA->ODR&=~(1<<7)
(gdb) p /x *COMP2
$120 = {CSR = 0x2811}
(gdb) p /x *TIM3
$121 = {CR1 = 0x1, CR2 = 0x0, SMCR = 0x0, DIER = 0x0, SR = 0x1f, EGR = 0x0, CCMR1 = 0x1, CCMR2 = 0x0, CCER = 0xb,
  CNT = 0x397c, PSC = 0x0, ARR = 0xffff, RCR = 0x0, CCR1 = 0xacc, CCR2 = 0x0, CCR3 = 0x0, CCR4 = 0x0, BDTR = 0x0,
  DCR = 0x0, DMAR = 0x1, OR = 0x0, CCMR3 = 0x0, CCR5 = 0x0, CCR6 = 0x0}
(gdb) set GPIOA->ODR|=(1<<7)
(gdb) p /x *TIM3
$122 = {CR1 = 0x1, CR2 = 0x0, SMCR = 0x0, DIER = 0x0, SR = 0x1f, EGR = 0x0, CCMR1 = 0x1, CCMR2 = 0x0, CCER = 0xb,
  CNT = 0x1a08, PSC = 0x0, ARR = 0xffff, RCR = 0x0, CCR1 = 0x325e, CCR2 = 0x0, CCR3 = 0x0, CCR4 = 0x0, BDTR = 0x0,
  DCR = 0x0, DMAR = 0x1, OR = 0x0, CCMR3 = 0x0, CCR5 = 0x0, CCR6 = 0x0}
(gdb)

JW

View solution in original post

8 REPLIES 8

Read out and check/post the COMP and TIM registers content.

JW

It works for me on a 'F303RB. I know it's a different chip, though.

(gdb) p /x *TIM3
$117 = {CR1 = 0x1, CR2 = 0x0, SMCR = 0x0, DIER = 0x0, SR = 0x1d, EGR = 0x0, CCMR1 = 0x1, CCMR2 = 0x0, CCER = 0xb,
  CNT = 0x4256, PSC = 0x0, ARR = 0xffff, RCR = 0x0, CCR1 = 0x0, CCR2 = 0x0, CCR3 = 0x0, CCR4 = 0x0, BDTR = 0x0,
  DCR = 0x0, DMAR = 0x1, OR = 0x0, CCMR3 = 0x0, CCR5 = 0x0, CCR6 = 0x0}
(gdb) p /x *COMP2
$119 = {CSR = 0x40002811}
(gdb) set GPIOA->ODR&=~(1<<7)
(gdb) p /x *COMP2
$120 = {CSR = 0x2811}
(gdb) p /x *TIM3
$121 = {CR1 = 0x1, CR2 = 0x0, SMCR = 0x0, DIER = 0x0, SR = 0x1f, EGR = 0x0, CCMR1 = 0x1, CCMR2 = 0x0, CCER = 0xb,
  CNT = 0x397c, PSC = 0x0, ARR = 0xffff, RCR = 0x0, CCR1 = 0xacc, CCR2 = 0x0, CCR3 = 0x0, CCR4 = 0x0, BDTR = 0x0,
  DCR = 0x0, DMAR = 0x1, OR = 0x0, CCMR3 = 0x0, CCR5 = 0x0, CCR6 = 0x0}
(gdb) set GPIOA->ODR|=(1<<7)
(gdb) p /x *TIM3
$122 = {CR1 = 0x1, CR2 = 0x0, SMCR = 0x0, DIER = 0x0, SR = 0x1f, EGR = 0x0, CCMR1 = 0x1, CCMR2 = 0x0, CCER = 0xb,
  CNT = 0x1a08, PSC = 0x0, ARR = 0xffff, RCR = 0x0, CCR1 = 0x325e, CCR2 = 0x0, CCR3 = 0x0, CCR4 = 0x0, BDTR = 0x0,
  DCR = 0x0, DMAR = 0x1, OR = 0x0, CCMR3 = 0x0, CCR5 = 0x0, CCR6 = 0x0}
(gdb)

JW

Thank you, ill check these against my settings.

Here are them for the time being.

(gdb) p *TIM3

$1 = {CR1 = 1, CR2 = 32, SMCR = 0, DIER = 2, SR = 29, EGR = 0, CCMR1 = 1,

 CCMR2 = 0, CCER = 11, CNT = 4331, PSC = 0, ARR = 65535, RCR = 0, CCR1 = 0,

 CCR2 = 0, CCR3 = 0, CCR4 = 0, BDTR = 0, DCR = 0, DMAR = 1, OR = 0,

 CCMR3 = 0, CCR5 = 0, CCR6 = 0}

(gdb) p /x (COMP_TypeDef) *COMP2

$6 = {CSR = 0x2c51}

Also in hex

(gdb) p/x *TIM3

$7 = {CR1 = 0x1, CR2 = 0x20, SMCR = 0x0, DIER = 0x2, SR = 0x1d, EGR = 0x0,

 CCMR1 = 0x1, CCMR2 = 0x0, CCER = 0xb, CNT = 0xf61f, PSC = 0x0,

 ARR = 0xffff, RCR = 0x0, CCR1 = 0x0, CCR2 = 0x0, CCR3 = 0x0, CCR4 = 0x0,

 BDTR = 0x0, DCR = 0x0, DMAR = 0x1, OR = 0x0, CCMR3 = 0x0, CCR5 = 0x0,

 CCR6 = 0x0}

Thank you very much for the help!

Comparing your register settings to mine made me realize the mistake!

The problem was that the LL library has a bug in this line:

#define LL_COMP_OUTPUT_TIM3_IC1_COMP2 (COMP_CSR_COMPxOUTSEL_3 | COMP_CSR_COMPxOUTSEL_1 | COMP_CSR_COMPxOUTSEL_0) /*!< COMP output connected to TIM3 input capture 1 (specific to COMP instance: COMP2) */

This sets the comparator output incorrectly!

Clearing the bit 0 of this section solved the problem and the input capture is generated correctly!

Thank you for the help again!

I find it a bit strange though that a bug like this is present in the officially released api for the microcontroller.

Gonna report now.

Thanks again!

Orulok hogy segithettem.

Coincidentally, I was due to do the same thing (although different COMP/TIM couple) today...

Btw., where do you switch on the clock? It was one of the the things that puzzled me https://community.st.com/s/question/0D50X0000C9doQzSQI/comp-and-opamp-clock-enable-missing-from-rcc-chapter-in-f3-rms

Take this as a lesson and a well deserved punishment for using unnecessary "libraries". Given how extensive task it is, they are inevitably buggy. The primary information source is always the RM/DS, and the mcu works according to the registers settings, ignoring any "library"... 🙂

Jan

@Amel NASRI​ ,

can this bug please be reported for fixing?

Thanks,

Jan

PS Please note that this again showcases the need for registrs' bitfields values to be properly and systematically defined in the CMSIS-mandated device header, of course properly reviewed. That, and not haphazardly defined constants in whatever "library" is currently en vogue...

Well you are right about the libraries being inevitably buggy, however they, together with CubeMX helps immensely when starting out.

There are so many things to learn, it is very useful to take some of that load off you at beginning.

They sometimes feel difficult to use though. When the RM explains something clearly and they introduce a layer of abstraction, that can be annoying.

I am not sure which clock you mean. Is it the peripheral clock? The clock configurations are set in CubeMX so I dont have that much insight about them, but are you 100% sure that they need a clock source?

After all these two are analogue and asynchronous circuits, they operate without any clock source. In general at least. It might be different when inside an MCU.

It's the digital interface to COMP and OPAMP, which needs the clock, i.e. the (here, sole) register. Without clock, you won't be able to write to it, and it would read always 0. Try it in debugger, just after reset.

As it's only a handful of registers for all the COMPs and OPAMPs, they are grouped with SYSCFG. So, look in your code, there must be somewhere a write of 1 into RCC_APB2ENR.SYSCFGEN.

JW