Thông báo

Collapse
No announcement yet.

Lỗi PWM của STM32F103xx

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • Lỗi PWM của STM32F103xx

    Chào các Bác. Em đang làm pwm cho con STM32 thì gặp lỗi như sau:
    - Em cần băm một chùm xung và sau đó lại nghỉ, tần số PWM là 20KHz. Chu kỳ cứ lặp lại liên tục. giá trị PWM được lấy từ môt mảng cố định. Các giá trị trong mảng là khác nhau và cố định. Em dùng AVR và PIC thì khi băm PWM và nhìn trên oscillocope thì thấy giữa các chùm xung là đều nhau và giống nhau, không bị co giãn, thấy nó theo đúng quy luật của mảng. Khi dùng STM32 thì nó bị co giãn và PWM không ổn định, có lúc nó còn mất một hai xung pwm. Các bác xem video này sẽ thấy rõ: Dạng xung co giãn - YouTube
    - Em có gửi kèm theo code, các bác xem giúp em xem lỗi ở chỗ nào. Em đã dùng nhiều mạch để test thử nhưng xung ra đều giống nhau. Loay hoay 3 tuần rồi mà chưa tìm được nguyên nhân. Cũng nhờ các cao thủ rồi mà chưa được. Mong các bác giúp em với.
    Cảm ơn các bác nhiều.



    Code:
    #include "stm32f10x.h"
    void RCC_Configuration(void);
    void GPIO_Configuration(void);
    void delay_init(void);
    void Delay(__IO uint32_t nTime);
    void TimingDelay_Decrement(void);
    void pwm_init(void);
    int main(void);
    static __IO uint32_t TimingDelay;
    const uint16_t volt_tb[64] = {  28,  28,  57,  57,  85,  85, 112, 112, 139, 139, 164, 164, 187, 187, 209, 209, 229, 229, 247, 247, 263, 263, 276, 276, 287, 287, 295, 295, 300, 300, 303, 303, 303, 303, 300, 300, 295, 295, 287, 287, 276, 276, 263, 263, 247, 247, 229, 229, 209, 209, 187, 187, 164, 164, 139, 139, 112,  112,  85,  85,  57,  43,  28,  14};
    void RCC_Configuration(void)
    {
      
        /* PCLK1 = HCLK/4 */
      RCC_PCLK1Config(RCC_HCLK_Div1); //clock cho PCLK = 36MHz
        
        /* TIM4 clock enable */
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
      
      /* GPIOA and GPIOB clock enable */
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
                             RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
        
    }
    
    
    void GPIO_Configuration(void)
    {
      GPIO_InitTypeDef GPIO_InitStructure;
      
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable | GPIO_Remap_TIM4, ENABLE);    
      
        /*GPIOB Out put PWM */
        /* TIM4: CH1,CH2,CH3 PWM */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);
    }
    
    
    /* 
         *    Setup SysTick Timer for 1 msec interrupts  
         *      SystemCoreClock is defined in system_stm32f10x.c
         - thoi gian "delay_"(Hz) duoc tinh = SystemCoreClock/delay_;
         vi du: delay_ = 1ms = 1000Hz => SystemCoreClock/1000;
         */
    void delay_init(void)
    {
        if (SysTick_Config(SystemCoreClock / 20000)) //delay 50us
        {         
            /* Capture error */ 
            while (1)
            {            
            }
        }
    }    
    
    
    
    
    /**
      * @brief  This function handles SysTick Handler.
      * @param  None
      * @retval None
      */
    void SysTick_Handler(void)
    {
        TimingDelay_Decrement();
    }
    /**
      * @brief  Inserts a delay time.
      * @param  nTime: specifies the delay time length, in milliseconds.
      * @retval None
      */
    void Delay(__IO uint32_t nTime)
    { 
        TimingDelay = nTime;
    
    
        while(TimingDelay != 0);
    }
    
    
    /**
      * @brief  Decrements the TimingDelay variable.
      * @param  None
      * @retval None
      */
    void TimingDelay_Decrement(void)
    {    
        if (TimingDelay != 0x00)
        { 
            TimingDelay--;
        }
    }
    
    
    void pwm_init(void)
    {
        uint16_t PrescalerValue = 0; //phep chia he so timer
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;    
    
    
      /* Compute the prescaler value */
      
        PrescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;  //tan so timer TIM4 clock = 24MHz
      
        //PrescalerValue = 0;
        /* Time base configuration */
      
        TIM_TimeBaseStructure.TIM_Period = 600;//600;//600; 20KHz
      TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;  //chia tan so cho timer
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM_CounterMode_CenterAligned1;//TIM_CounterMode_Up;    
    
    
      TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
    
    
      /* PWM1 Mode configuration: Channel1 */
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = 0;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//TIM_OCPolarity_High;  //tin hieu PWM nguoc
      TIM_OC1Init(TIM4, &TIM_OCInitStructure);
      TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);
    
    
      /* PWM2 Mode configuration: Channel2 */
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = 0;
        //TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;     
      TIM_OC2Init(TIM4, &TIM_OCInitStructure);
      TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);
    
    
      /* PWM3 Mode configuration: Channel3 */
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = 0;
      //TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//TIM_OCPolarity_High;
      TIM_OC3Init(TIM4, &TIM_OCInitStructure);
      TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);
    
    
      TIM_ARRPreloadConfig(TIM4, ENABLE);
    
    
      /* TIM3 enable counter */
      TIM_Cmd(TIM4, ENABLE);
        
    }
    
    
    
    
    
    
    int main(void)
    {
        uint32_t _index=0;
        uint8_t blink=0;
        RCC_Configuration();
        GPIO_Configuration();
      pwm_init();
      delay_init();
        while(1)
        {
            _index++;
            if(_index==64)//chum xung co 64 gia tri trong mang volt_tb[]
            {
                _index = 0;
                blink=~blink;
            }
            if(blink) //nua ban ky dau co chum xung
            {
                TIM4->CCR1= volt_tb[_index];
            }
            else  //nua ban ky tiep theo khong co xung
            {
                TIM4->CCR1=0;
            }
            Delay(2);        
        }
    
    
        
    }
    
    
    #ifdef  USE_FULL_ASSERT
    
    
    /**
      * @brief  Reports the name of the source file and the source line number
      *         where the assert_param error has occurred.
      * @param  file: pointer to the source file name
      * @param  line: assert_param error line source number
      * @retval None
      */
    void assert_failed(uint8_t* file, uint32_t line)
    {
      /* User can add his own implementation to report the file name and line number,
         ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    
    
      while (1)
      {}
    }
    
    
    #endif
    
    
    /**
      * @}
      */ 
    
    
    /**
      * @}
      */
    n
    ĐT: 0986 492 489

    Tham khảo:

  • #2
    Em làm trên con F4 cũng bị lỗi này. Đo bằng bộ phân tích logic thì khi zoom lớn lên thì ko thấy gì bất thường, nhưng để nhỏ lại cũng ko đều. Đo bằng osilo cũng bị giống bác.

    Giải pháp điện tử của bạn

    Comment


    • #3
      Bác cũng bị như vậy và bác xử lý bằng cách nào thế ạ?
      n
      ĐT: 0986 492 489

      Tham khảo:

      Comment


      • #4
        Lỗi Pwm với con nầy ấy hả các bác @@. Chết em roài, đang tính làm bộ đk với con này


        Add: 97 Quán Nam - Lê Chân - Hải Phòng.
        Tel: 031 518648 Phone: 0904 283 505

        Comment


        • #5
          PWM nếu mình cho một giá trị cố định ví dụ gán bằng 50 thì nó ra chuẩn nhưng cứ thay đổi giá trị như việc phát một chùm xung có độ rộng không giống nhau là có lỗi. Mình chưa hiểu nổi nữa. Các cao nhân nào gặp lỗi này rồi xin chỉ giúp. Cảm ơn
          n
          ĐT: 0986 492 489

          Tham khảo:

          Comment


          • #6
            Mình không dùng STM32 nên không comment kỹ cho bạn được, nhưng mình thấy một số vấn đề như sau:
            - Giả sử bạn config đúng Systick timer xảy ra interrupt mỗi 1mS => Khi bạn gọi Delay(2), chương trình của bạn thực tế chỉ có thể delay trong khoảng từ 1mS đến 2mS (phụ thuộc vào giá trị của systick timer tại thời điểm bạn gọi (Systick timer lúc mới vừa qua 0 hay gần tràn)). Nó chỉ "khá chuẩn" khi bạn gọi delay một giá trị lớn (50? 100?) thôi. Với vấn đề này, khoảng cách giữa các lần update của bạn có thể bị biến đổi.
            - Nhìn comment của bạn ở trong hàm delay_init(void) thì hình như bạn config timer này có period = 20uS chứ không phải là 1mS
            - Cái clip của bạn mình xem không được rõ lắm. Nhưng có vẻ là M=5mS và tần số lấy mẫu của oscilloscope là 100kS/s. Mỗi burst 64 lần update hết khoảng 6-7mS (hơn 1 ô trên màn hình oscilloscope), nên khoảng cách giữa các lần update chỉ khoảng 100uS. Trong khi đó, khoảng cách giữa các sample của oscilloscope chỉ có 10uS => Dạng sóng bạn nhìn thấy có vẻ giống như mất 1-2 xung là có thể hiểu xảy ra.
            - Để phân tích chính xác các tín hiệu nhanh và trong một thời gian dài như thế này thì dùng oscilloscope không thể chính xác được mà phải dùng logic analyzer. Phía trên có bạn bảo dùng logic analyzer để đo thì không thấy vấn đề => Chắc là không có vấn đề thật.

            STM32 nó ra được mấy năm rồi nên khả năng hardware có lỗi ngớ ngẩn thế này gần như không thể có được đâu. Các scenario thế này được thằng IP designer test trên simulation, thằng SoC validation test tiếp, xong thằng làm cái lib nó lại test 1 lần nữa. Các thằng khác nhau test bằng các kiểu khác nhau
            nên khả năng lọt lỗi kiểu basic là rất thấp.

            Comment


            • #7
              Cảm ơn bác Elenor đã dành thời gian trả lời.
              Em cũng đã thử nhiều cách để xác minh. Cả dùng ngắt timer để độ chính xác cao. Mỗi khi lật em cho thêm một chân ra để kiểm tra độ chính xác thời gian nhưng kết quả xem vẫn tương tự. Nó vẫn bị co giãn bác ạ. Em dùng con AVR thì nó cho xung ra xem bằng oscillo rất chuẩn. Tần số pwm giống nhau. Dạng chùm xung rất đẹp và giống nhau, không bị mất xung. Em cho qua một bộ kích bằng mostfet và lọc đầu ra để kiểm tra thì thấy đúng là chùm xung pwm không chuẩn lắm. Tín hiệu sau khi lọc bị méo mà không theo quy luật. Bài toán này em làm với con AVR thì đã thành công. Loay hoay mãi mà chưa được. Bác xem em còn lỗi chỗ nào không? Cảm ơn các bác đã nhiệt tình comment.
              n
              ĐT: 0986 492 489

              Tham khảo:

              Comment


              • #8
                Như trên mình cũng đã nói, nếu chỉ nhìn vào dạng sóng bạn gửi thì không thể biết được là nó đang chạy giống như bạn mong đợi hay không Mình cũng không chắc là việc viết hàm delay như trên có gây ra vấn đề hay không. Do vậy, bạn có thể dùng những cách sau để tìm ra chỗ lỗi:
                - Sau lệnh blink=~blink, bạn hãy toggle 1 chân nào đó (gọi là chân A) và dùng oscilloscope để đo tín hiệu giữa các xung ở chân này. Nếu nó đều nhau thì có lẽ là nó đang hoạt động đúng ý bạn. Nếu nó không thì bạn disable cái timer xuất PWM xem. Nếu sau khi disable nó vẫn sai thì có nghĩa là liên quan đến cái delay thật, còn nếu khi disable PWM nó trở thành đúng thì sẽ là lỗi liên quan đến PWM. Trong trường hợp này bạn có thể sang debug bước tiếp theo. Nhưng trước đó thì check xem co enable interrupt của cái timer để xuất PWM không, priority của timer này so với systick là như thế nào, nếu cái timer này có priority cao hơn systick thì có thể ảnh hưởng đến cái delay.
                - Bạn hãy toggle 1 chân nào đó khác (gọi là chân B) lúc update duty của PWM. Đặt trigger của oscilloscope theo sườn lên hoặc xuống của tín hiệu ở bước bên trên (chân A), zoom oscilloscope ra để xem có thật sự là khoảng cách giữa các lần update này không đúng với mong muốn của bạn hay không.

                Thực sự là với cái dạng sóng như hiện tại mà bạn gửi thỉ không thể biết được vấn đề cụ thể là gì, và đó có thực sự là vấn đề hay không.

                Comment


                • #9
                  Cảm ơn bác đã cố vấn.
                  Em test thử nếu cho một chân đảo mỗi khi phát xung thì độ rộng là chuẩn và em khẳng định là chỗ pwm có vấn đề bất thường bác ạ. Em cũng làm với các chíp khác nên em thấy chưa ổn ở chíp này nhưng không biết là do phần cứng hay phần mềm để điều chỉnh. Lượng người có kinh nghiệm trong STM32 thì ít comment nên càng khó khăn cho người mới tiếp cận. Rất mong được các bác giúp đỡ.
                  n
                  ĐT: 0986 492 489

                  Tham khảo:

                  Comment


                  • #10
                    Mọi người có thể sẽ support bạn được nhiều hơn nếu bạn vẽ (hoặc chụp lại) dạng sóng sai (theo sugestion thứ 2 phía trên của mình) và vẽ ra dạng sóng kỳ vọng của bạn

                    Thêm 1 lưu ý là không phải với mọi con chip khi bạn update duty thì duty mới sẽ out ngay, mà đôi khi phải đến chu kỳ sau duty mới mới được áp dụng

                    Comment

                    Về tác giả

                    Collapse

                    minhhieu 4 vợ + 10 con + 5 bồ bịch Tìm hiểu thêm về minhhieu

                    Bài viết mới nhất

                    Collapse

                    Đang tải...
                    X