Skip to main content
Visitor II
November 25, 2023
Question

ADC input disturbed by PWM

  • November 25, 2023
  • 5 replies
  • 4027 views

I'm having an issue with my STM32F303RE. I'm using CubeMX to initialize ADC1_IN1 as single ended on PA0, and PWM generation on TIM2_CH1 on PA15. Unfortunately, PA0 will OUTPUT a voltage roughly proportional with the duty cycle of the PWM on PA15, i.e. setting the PWM (again, supposed to be on PA15) to 50% duty cycle results in about 1.5V on PA0. The PWM on PA15 is generated correctly. The PA0 voltage looks like a noisy but constant signal, it doesn't have the PWM signal "shape". PA0 is itself compatible with TIM2_CH1, so I guess something is bleeding over somewhere. Please help me fix this programmatically, I'm really not keen on redoing my circuit.

    This topic has been closed for replies.

    5 replies

    Super User
    November 25, 2023

    What is PA0 connected to externally? Note that results from floating ADC inputs are irrelevant.

    kristbloAuthor
    Visitor II
    November 26, 2023

    PA0 is connected to the current sense (IPROPI) pin of a DRV8251A motor driver, incidentally driven from the PWM of TIM2 on PA15 and PB3. The motor driver is supposed down if the current is too high, and I suspect that setting a voltage on the current sense pin is interpreted as just that.

     

    As far as I can see, though, the problem here is the bleeding of TIM2_CH1's PWM onto the wrong pin. The same setup (driver, ADC, PWM) works just fine for TIM15 (PA2, PA3) and ADC2 (PA4), and I'm observing the same failure mode on two identical PCB's -- so I don't think anything's fried.

     

    Thanks for replying so quickly btw. Left the office just after posting, but appreciate it.

    Super User
    November 27, 2023

    If channels were routed to the wrong pins, it would be a pretty major bug that would have turned up in the errata.

    Could be:

    • PA0 incorrectly configured (check GPIOA registers)
    • PA0 and PA15 shorted on the PWB (check continuity when board is unpowered)

    You have R_IPROPI on your board, right? Can't see it being due to a bad or malfunctioning DRV8251A in any way.

    kristbloAuthor
    Visitor II
    November 27, 2023

    I agree, that's kind of why I can't make sense of it. On a general note, where would I find such errata? I've been looking for a datasheet for the STM32F303 expecting to find a ~2000-page document with basically all I need to know about the mcu, but I can only seem to find application notes and such. I did find the HAL doc, though. I'm completely new to STM, and somewhat green on embedded programming as well.

     

     

    Which leads me to my followup: how can I check the register values? As I mentioned, the same setup works fine for a different combination of timer/adc/pins, so if anything it's CubeMX messing up the code generation (I'm using the makefile setting and programming in vscode fwiw). The init functions seem to be correct in that all the config information from the CubeMX GUI is carried over to the relevant init functions for ADC and PWM as far as I can see, but I haven't been able to go any deeper than that. Setting the ADC/PA0 pin to RESET_STATE in the GUI does remove the problem.

    I just realised that the F303 has DAC functionality. I'm not using it at all, but I suppose what I'm seeing can be said to be a noisy DAC output.

    My R_IPROPI is at about 500Ohms, and indeed, those drivers are pretty sturdy. I did suspect some sort of short in it. I didn't have time to unsolder it to remove it as an error source entirely, but the fact that the voltage is proportional to the PWM duty cycle and goes away when I set the pin to RESET_STATE pretty much confirms that the problem is somewhere on the STM.

    Super User
    November 27, 2023

    > On a general note, where would I find such errata? 

    Google "stm32f303 errata". I'm sure it's on the product page as well, but google is generally faster.

    https://www.st.com/resource/en/errata_sheet/es0204-stm32f303xbc-device-errata-stmicroelectronics.pdf

    > Setting the ADC/PA0 pin to RESET_STATE in the GUI does remove the problem.

    So probably it was misconfigured. Doesn't make a whole lot of sense to me why. PA0 is in input mode by default. Might want to dig into why that's happening. Step through and find out where the lower two bits in GPIOA_MODER get changed.

    When actively debugging, and paused, the "SFRs" window in CubeIDE will show the value of registers. Open it with Window -> Show View -> SFRs.

    Graduate II
    November 27, 2023

    ST puts the most important info usually into 2 documents:

    - datasheet: basic description only, but package and pins, including alternate function mapping

    - reference manual: detailed descriptions of all peripherals, down to registers and bits

    Here's what googling "STM32F303 datasheet" (or ref manual) got me:

    https://www.st.com/resource/en/datasheet/stm32f303cb.pdf

    https://www.st.com/resource/en/reference_manual/rm0316-stm32f303xbcde-stm32f303x68-stm32f328x8-stm32f358xc-stm32f398xe-advanced-armbased-mcus-stmicroelectronics.pdf

     

    kristbloAuthor
    Visitor II
    November 27, 2023

    Thanks! Reference manual was the magic phrase then, as my version of Google only gave me the basic stuff when I looked for data sheet.

     

    How about my other question about checking what the registers are actually initialized to/which pins are mapped to what functions? Does CubeMX put that in one of the plentiful .h-files it generates, or will I have to check each init function+call tree to see that each register is initiated correctly according to the ref manual?

    Super User
    November 27, 2023

    > what the registers are actually initialized to/which pins are mapped to what functions

    Read out and check/post GPIOA registers content.

    JW

    Super User
    November 27, 2023

    In the problematic state, read out and check/post GPIOA registers content.

    JW

    kristbloAuthor
    Visitor II
    November 27, 2023

    Thanks for your input, everyone! The code below shows the init function mapping the timers to their respective pins. They look correct to me, both for TIM2 and TIM15. I haven't been able to actually verify the memory contents as I'm using VSCode which isn't as capable as CubeIDE on that point apparently.

    @TDK, There is one point I'd like to emphasize, which after this (albeit incomplete) attempt at debugging has left me even more convinced that this should be in the errata: The signal I'm seeing on PA0 is NOT a PWM signal. It is a noisy, but steady state signal proportional to the PWM duty cycle. I'm feeding my STMF303RE 3.3V, so that means approximately 1.5V at 50% DT. Fwiw I'm running a PWM frequency of 25kHz. I'm also seeing it on both of my two STMs ordered at the same time, so maybe a batch error? PA0 is not supposed to be compatible with DAC, so at no valid config will there be a steady state voltage other than logic high/low on PA0, correct? Then there's the fact that the other driver on TIM15 and ADC2 are initialized similarly as TIM2 and ADC1, and that setup works fine -- again something which repeats for both of my STMs.

     

    The circuits for the two drivers are schematically identical, but the layouts are a little bit different for all four (2 driver layouts x 2 PCB designs) drivers. I beeped an unsoldered PCB of one of my two designs, and found no signs of shorts or other manufacturing defects.

    If the configurations available from the CubeMX GUI don't represent the actual full "configuration space" for the STM (i.e. it's actually possible to set PA0 as an analog output manually), then I guess that weakens my argument above, but I've all but convinced myself that this is a hardware error at this point.

    void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
    {
    
     GPIO_InitTypeDef GPIO_InitStruct = {0};
     if(timHandle->Instance==TIM2)
     {
     /* USER CODE BEGIN TIM2_MspPostInit 0 */
    
     /* USER CODE END TIM2_MspPostInit 0 */
     __HAL_RCC_GPIOA_CLK_ENABLE();
     __HAL_RCC_GPIOB_CLK_ENABLE();
     /**TIM2 GPIO Configuration
     PA15 ------> TIM2_CH1
     PB3 ------> TIM2_CH2
     */
     GPIO_InitStruct.Pin = GPIO_PIN_15;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
     GPIO_InitStruct.Pin = GPIO_PIN_3;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    
     /* USER CODE BEGIN TIM2_MspPostInit 1 */
    
     /* USER CODE END TIM2_MspPostInit 1 */
     }
     else if(timHandle->Instance==TIM15)
     {
     /* USER CODE BEGIN TIM15_MspPostInit 0 */
    
     /* USER CODE END TIM15_MspPostInit 0 */
    
     __HAL_RCC_GPIOA_CLK_ENABLE();
     /**TIM15 GPIO Configuration
     PA2 ------> TIM15_CH1
     PA3 ------> TIM15_CH2
     */
     GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     GPIO_InitStruct.Alternate = GPIO_AF9_TIM15;
     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
     /* USER CODE BEGIN TIM15_MspPostInit 1 */
    
     /* USER CODE END TIM15_MspPostInit 1 */
     }
    
    }

     

    Super User
    November 27, 2023

    > PA0 is not supposed to be compatible with DAC, so at no valid config will there be a steady state voltage other than logic high/low on PA0, correct?

    In output mode, or in input mode with a pullup or pulldown, yes. In floating input mode, or analog mode, it's going to have an undefined state and will be subject to interference. I think that's what is happening here.

    Doesn't really make sense why R_IPROPI isn't pulling it down though, or why configuring it to "reset state" changes things.