Picproje Elektronik Sitesi

MİKRODENETLEYİCİLER => ARM => Konuyu başlatan: SB7 - 20 Mayıs 2023, 18:45:12

Başlık: Timer ARR Değeri Güncelleme Problemi
Gönderen: SB7 - 20 Mayıs 2023, 18:45:12
Selamlar,

STM32f103 blue pill ile belirli frekanslarda PWM üretmeye çalışıyorum.Bir dizi içindeki sayılar, ilgili Timer ARR  registerine yazılıyor. Yazdığım kod 2 cycle da bir doğru çalışıyor ve program her başa dönünce 65ms bir ölü zaman oluşuyor.

Amacım bu şekilde olan;
uint32_t period[5] = {5000,1000,2000,8000,4000};period değerlerini ARR registerine yüklemek.

Sonsuz döngüde yapılan işlem;
while (1)
{   
for (i=0;i<5;i++){
GPIOC->ODR ^= GPIO_Pin_13;
TIM2->ARR = period[i];
DelayMs(100);
}
}
(C13 pininin toggle edilmesi debug için)


Timer ayarlarım bu şekilde;

void PWM_Init()
{
//TIMER AYARLARI

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
GPIO_InitTypeDef GPIO_InitStruct;


RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseInitStruct.TIM_Prescaler = 71;
TIM_TimeBaseInitStruct.TIM_Period = 25000;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);

TIM_Cmd(TIM2, ENABLE);

// PWM AYARLARI

TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;

TIM_OCInitStruct.TIM_Pulse = 0;
TIM_OC1Init(TIM2, &TIM_OCInitStruct);
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);

// PA0 PWM CIKIS PINI OLARAK AYARLANDI

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}


 Lojik analizör çıktısı da bu şekilde;


(https://i.ibb.co/W69wc8C/L-A.png) (https://ibb.co/W69wc8C)

Bir taşma olabilir düşüncesiyle Timer CCR registerine en küçük ARR değerinin yarısını yüklüyorum ancak program başa dönünce tekrar ölü zamanlar gerçekleşiyor. Sebebi nedir sizce?
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: Z80 - 20 Mayıs 2023, 23:03:33
void TIMER2_AYAR()
{

    RCC->APB1ENR |=  RCC_APB1ENR_TIM2EN;    // TIMER2 clock aç      
    TIM2->PSC     =  0;             // 72 MHz
    TIM2->ARR     =  1024-1;                // 72MHz/1024=70KHz(1024 resolution)               
    TIM2->CCMR1  |=  TIM_CCMR1_OC1M_1;            // PWM mode 1
    TIM2->CCMR1  |=  TIM_CCMR1_OC1M_2;
    TIM2->CCMR1  |=  TIM_CCMR1_OC1PE;            // Preload register TIMx_CCR1 aç
    TIM2->CCER   |=  TIM_CCER_CC1E;             // OC1 PWM çikisi aç
    TIM2->CR1    &= ~TIM_CR1_CMS;        // PWM kenar mode
    TIM2->CCR1    =  PWM_DEGERI;        // PWM degeri yükle       
    TIM2->CR1    |=  TIM_CR1_CEN;        // Timer2 aç
   
}   

Bu TIMER2 PWM ayar koduyla olması gerekir. 
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: SB7 - 20 Mayıs 2023, 23:46:37
@Z80 hocam cevabınız için teşekkür ederim, mesajınızı görünce hemen hızlıca denedim. Aynı sorun devam ediyor. 65ms ölü zamanlar yine oluşuyor.

İlk peryot sorunsuz istediğim frekanslar üretiliyor sonrasında da bu şekilde;

(https://i.ibb.co/YbcZfJj/2.png) (https://ibb.co/YbcZfJj)

Normalde C13 toggle olduğu süre boyunca aynı frekansta sinyal üretmesi gerekiyor ama burda sağında ve solunda 65ms beklemeler oluyor.

(https://i.ibb.co/vmKGb3L/1.png) (https://ibb.co/vmKGb3L)
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: SB7 - 21 Mayıs 2023, 00:00:11
uint32_t period[7] = {25000,25000,10000,[b]1000[/b],10000,25000,25000};
Bu şekilde denedim ortada 1.000 değerinde sadece sorun oluyor bu haliyle, 1.000 değerini 7.000 ve üzeri yapınca sorun olmuyor. Sanırım ani yüksek değer değişimlerinde saçmalıyor MCU.

Bu iş için bir işlem kısıtı mı var? Bilginiz var mı?
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: Z80 - 21 Mayıs 2023, 00:14:33
TIM2->CR1    &= ~TIM_CR1_CEN;        // Timer2 kapat
TIM2->ARR     =  period[i];                         
TIM2->CR1    |=  TIM_CR1_CEN;        // Timer2 aç

1. Şunu bir dene. Timer2 kapat, ARR yükle, tekrar aç.
2. TIM2->ARR     =  period; bunu peşpeşe iki sefer yap.
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: SB7 - 21 Mayıs 2023, 00:32:44
Hocam ikisini de denedim sonuç aynı, yakın değerlerde düzgün ama ani düşük değer gidince 65ms beklemeler oluyor.

Kodların tamamı;
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_tim.h"
#include "delay.h"

// FONKSIYON TANIMLAMALARI

void PWM_Init(void);
void GPIO_Configuration(void);


uint8_t i = 0;
uint32_t period[7] = {25000,25000,10000,1000,10000,25000,25000};
int main(void)
{
    DelayInit();
    PWM_Init();
  GPIO_Configuration();
    TIM2->CCR1 = 200;
    while (1)
    { 
        for (i=0;i<7;i++){
        GPIOC->ODR ^= GPIO_Pin_13;   
            TIM2->CR1    &= ~TIM_CR1_CEN;        // Timer2 kapat
            TIM2->ARR    =  period[i];
            TIM2->ARR    =  period[i];
            TIM2->CR1    |=  TIM_CR1_CEN;        // Timer2 aç
           
        DelayMs(100);
        }
       
}
}

void PWM_Init()
{
    //TIMER AYARLARI
   
    GPIO_InitTypeDef GPIO_InitStruct;

TIM2->PSC = 71;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // TIMER2 clock aç     
TIM2->PSC = 71;// 72 MHz
TIM2->ARR =1024-1;// 72MHz/1024=70KHz(1024 resolution)                 
TIM2->CCMR1 |= TIM_CCMR1_OC1M_1; // PWM mode 1
TIM2->CCMR1 |= TIM_CCMR1_OC1M_2;
TIM2->CCMR1 |= TIM_CCMR1_OC1PE; // Preload register TIMx_CCR1 aç
TIM2->CCER |= TIM_CCER_CC1E; // OC1 PWM çikisi aç
TIM2->CR1 &= ~TIM_CR1_CMS; // PWM kenar mode
TIM2->CCR1 = 500;
TIM2->CR1 |= TIM_CR1_CEN; // Timer2 aç
   
    // PA0 PWM CIKIS PINI OLARAK AYARLANDI
   
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
   
   
}


//GPIO AYARLARI
void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

  //C13 CIKIS
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStruct);
}



Sonuç bu;

(https://i.ibb.co/R2kBRGT/3.png) (https://ibb.co/R2kBRGT)
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: Z80 - 21 Mayıs 2023, 00:55:29
Yarın bir deneyeyim bakalım nolacak.
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: ahmet2015 - 21 Mayıs 2023, 08:13:30
İşlemci frekans ayarını 72mhz olarak ayarla düzelir.

while döngüsünde bu yeterli

      for (i=0;i<7;i++){
      GPIOC->ODR ^= GPIO_Pin_13;
      TIM2->ARR    =  period[i];
      DelayMs(100);
      }
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: ahmet2015 - 21 Mayıs 2023, 09:06:29
Bu değerlere göre osilaskop çıktısı aşağıda.

(https://i.ibb.co/txq61TH/RIGOL003.png) (https://ibb.co/txq61TH)
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: ahmet2015 - 21 Mayıs 2023, 09:22:15
Buda stm32cubeide proje dosyası çalışmak isteyenler için.

https://disk.yandex.com.tr/d/m1b_2-6qiGvPuQ (https://disk.yandex.com.tr/d/m1b_2-6qiGvPuQ)
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: Tagli - 21 Mayıs 2023, 09:59:19
Yazılanlara alıcı gözüyle bakmadım ama ilk aklıma gelen şey ARR'nin yanlış zamanda güncellenmesi oldu. Örnek vereyim: ARR 1000 olsun, ve belli bir anda CNT 750 olsun mesela. Tam bu anda, ARR'yi 500 yaptığını düşün. Bu burumda CNT'nin mevcut değeri ARR'den büyük kaldığı için, update event oluşana kadar CNT önce bir 65535'e kadar gidecek, sonra sıfırlanacak ve ancak tekrar 500 olunca update event üretilecek.

Buna çare olarak, ARR sadece bir update event olduğunda, yani timer sıfırlandığında güncellenmeli. Bu işlemi kolaylaştırmak için CR1'in ARPE bitini 1 yapabilirsin. Bu durumda ARR'ye yazdığın değer, yazdığın anda değil, timer taşmasından (update event) sonra geçerli olur ancak. Gerekmesi durumda update event'i EGR'nin UG bitini 1 yaparak da tetikleyebilirsin. Genelde ilk ayarlar yapıldıktan sonra ARR ve PSC'nin güncellenmesi için kullanıyorum bunu.
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: SB7 - 21 Mayıs 2023, 11:25:23
@ahmet2015 hocam uğraşıp osiloskop görüntüsüne kadar atmışsınız teşekkür ederim. Sorun çalışıp çalışmaması değil, arada düzgün çalışması. Ben de skobu küçük bir alanda tutsam doğru çalıştığı anlar oluyor, her 2-3 peryotta 1 kez yanlış çalışması problem.

@Tagli hocam nokta atışı oldu, ARPE bitini 1 yaptığım anda düzeldi. Üstelik CCR ARR den büyük olsa bile çalışıyor, önceden korkarak değer gönderiyordum çok teşekkür ederim hocam çok makbule geçti.

@Z80 hocam siz de çok uğraştınız tekrar teşekkür ederim size de.
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: Tagli - 21 Mayıs 2023, 12:26:05
Bu preload özelliği ARR ve CCRn register'ları için opsiyonel olarak etkinleştirilebiliyor. Varsayılan olarak kapalı. PSC için ise hep etkin, kapatmak mümkün değil.
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: SB7 - 02 Haziran 2023, 14:38:23
Chat GPT ye de sordum, cevap inanılmaz : )

STM32F103 gibi bazı mikrodenetleyicilerde, sürekli olarak otomatik yeniden yükleme kaydına (ARR) değer yüklemeniz durumunda bir ölü zaman oluşabilir. Bu durum, bir güncelleme olayının meydana gelmesini beklemek zorunda olmanızdan kaynaklanır.

TIMx_CR1 kaydındaki ARPE (Otomatik Yeniden Yükleme Ön Yükleme Etkinleştirme) bitinin ayarlı olması durumunda, otomatik yeniden yükleme kaydına yapılan her yazma işlemi, güncelleme olayı gerçekleştiğinde veya gölge kayıtların güncellenmesini sağlamak için yapılan diğer bir işlem sırasında aktarılır. Bu durumda, otomatik yeniden yükleme kaydına sürekli olarak yeni değerler yüklemeniz, bir güncelleme olayının tamamlanmasını beklemeniz gerektiği anlamına gelir. Bu bekleme süresi, ölü zamanların oluşmasına neden olabilir.

Ölü zamanı azaltmak veya ortadan kaldırmak için aşağıdaki yöntemleri düşünebilirsiniz:

1.TIMx_CR1 kaydındaki ARPE bitini sıfıra ayarlayarak otomatik yeniden yükleme ön yükleme işlemini devre dışı bırakın. Bu durumda, otomatik yeniden yükleme kaydına her değer yükleme işlemi, hemen etkili olur.

2.Ölü zamanları minimize etmek için DMA (Direct Memory Access) kullanmayı düşünebilirsiniz. DMA, yazılımın müdahalesi olmadan bellekten periferiklere veya periferiklerden belleğe veri transferi yapabilen bir mekanizmadır. Bu şekilde, otomatik yeniden yükleme kaydına yapılan yazma işlemleri DMA aracılığıyla gerçekleştirilebilir ve işlemci ölü zamanlarını en aza indirebilir.

3.Ölü zamanları en aza indirmek için kesme tabanlı bir yöntem kullanabilirsiniz. TIMx_SR kaydındaki UIF (Update Interrupt Flag) bayrağını izleyerek güncelleme olayını tespit edebilir ve bu bayrak ayarlandığında uygun işlemleri gerçekleştirebilirsiniz. Bu sayede, otomatik yeniden yükleme kaydına yeni değerler yükledikten sonra beklemek zorunda kalmadan devam edebilirsiniz.

Bu yöntemler, ölü zamanları azaltmaya yardımcı olabilir. Hangi yöntemi tercih edeceğiniz, uygulamanızın gereksinimlerine ve kullanım senaryonuza bağlı olarak değişebilir.
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: Tagli - 02 Haziran 2023, 21:27:50
Alıntı yapılan: SB7 - 02 Haziran 2023, 14:38:23Chat GPT ye de sordum, cevap inanılmaz : )
Gömülü sistemler üzerine bu kadar bilgi sahibi olabileceğini ummamıştım açıkçası  :o
Acaba verileri nereden topluyor? Reference manual'leri de tarıyor olabilir mi?
Başlık: Ynt: Timer ARR Değeri Güncelleme Problemi
Gönderen: SB7 - 02 Haziran 2023, 21:43:27
Sorunuzu ilettim hocam cevap bu şekilde;
Alıntı YapOpenAI tarafından sağlanan genel bir veritabanı kullanıyorum ve bu veritabanı, geniş bir yelpazede kaynakları içermektedir. Bunlar arasında üreticilerin resmi belgelendirme dokümanları da bulunmaktadır. Ancak, kesin bir kaynaktan veri topladığımı veya belirli bir referans kılavuzunu taradığımı doğrulayamam çünkü ben bir yapay zeka dil modeliyim ve doğrudan erişimim veya hatırlama yeteneğim yok. Bu nedenle, verilerim OpenAI tarafından sağlanan eğitim veri setine dayanır ve genel bilgilendirme amacıyla sağlanır.