Skip to main content
Visitor II
February 18, 2020
Solved

Interconnect comparator to timer internally not working

  • February 18, 2020
  • 5 replies
  • 2582 views

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!

    This topic has been closed for replies.
    Best answer by waclawek.jan

    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

    5 replies

    Super User
    February 18, 2020

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

    JW

    Super User
    February 18, 2020

    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

    Visitor II
    February 18, 2020

    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}

    Super User
    February 18, 2020

    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

    Visitor II
    February 18, 2020

    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.

    Super User
    February 18, 2020

    @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...

    Super User
    February 18, 2020

    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