2017-07-24 7 views
1

Diese Frage hat ihren Ursprung in my other question. Ich habe mich entschieden, eine neue zu erstellen, weil es eine ganz besondere Sache ist, die ich nirgends finden konnte.Erstellen eines Impulses im niedrigen Zustand mit Output Compare, muss standardmäßig hoch sein. + Timer wird bei Bedarf nicht aktiviert.

In einem STM32F415 möchte ich den Output Compare eines Timers standardmäßig hoch und niedrig für die Anzahl der Taktzyklen, die ich ihm erzähle. Mein Ziel ist es, deaktivieren einen Timer mit einem anderen Timer. In der Reference Manual Seite 620 gibt es ein Beispiel für Verwenden eines Timers zum Aktivieren eines anderen Timers.

In meinem Fall möchte ich, dass TIM3 TIM2 und TIM4 steuert, um TIM5 zu steuern. TIM2 und TIM5 lösen DAC-Anfragen an die DMA aus, und sie funktionieren gut. Diese

ist, wie I initialisieren TIM3 (diese Funktion in Haupt vor der Endlosschleife genannt wird):

void TIM3_Config(void) 
{ 
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; 
TIM_OCInitTypeDef   TIM_OCInitBaseStructure; 

TIM_DeInit(TIM3); 

// TIM3 Periph clock enable 
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 

// Time base configuration 
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 
TIM_TimeBaseStructure.TIM_Period = 0x46;  //ARR = 70 (cycles low will be 0-63) 
TIM_TimeBaseStructure.TIM_Prescaler = 0; 
TIM_TimeBaseStructure.TIM_ClockDivision = 0; 
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 

// TIM3 Output Compare configuration 
TIM_OCStructInit(&TIM_OCInitBaseStructure); 
TIM_OCInitBaseStructure.TIM_OCMode=TIM_OCMode_Active; 
TIM_OCInitBaseStructure.TIM_Pulse=0x3C; //CCR 
TIM_OCInitBaseStructure.TIM_OutputState=TIM_OutputState_Enable; 
TIM_OC1Init(TIM3,&TIM_OCInitBaseStructure); 
TIM3->CCMR1 &= 0xFFF7;  // OC1PE: Output compare 1 preload disabled 
TIM3->CCMR1 &= 0xFFFC;  // CC1S[1:0]=00 CC1 channel is configured as output. 
TIM3->CR1 |= 0x8; 
TIM3->CR2 |= 0x40; 
TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_OC1Ref);  // MSM[2:0] = 100 OC1REF as TIM3 TRGO 

TIM_Cmd(TIM3, ENABLE); 
} 

Dann wird in den entsprechenden DMA-IRQ-Handler:

void DMA1_Stream6_IRQHandler(void)   /* DAC2 */ 
{ 

if (DMA_GetITStatus(DMA1_Stream6,DMA_IT_HTIF6) == SET) 
{ 
    DMA_ClearITPendingBit(DMA1_Stream6,DMA_IT_HTIF6); 

    TIM3->CNT = 0x0;  // Reset timer 
    TIM3->CR1 |= 0x1;  // Enable timer 
} 
/* Some code for the Transfer Complete case */ 
} 

In einer anderen Programmpunkt Ich ändere den CCR entsprechend der Anzahl der Zyklen, die der Slave-Timer (TIM2 oder TIM5) deaktiviert werden soll.

Mein Hauptproblem ist, dass es überhaupt nicht funktioniert, und während des Debugging habe ich festgestellt, dass TIM3 und TIM4 aktivieren Anweisungen nichts zu tun: das Freigabebit (CEN im TIMx CR1 Register) bleibt '0' anstatt auf '1' zu wechseln. Die TIM2- und TIM5-Initialisierung ist ziemlich gleich, ohne den Output Compare und mit der Gated Input-Konfiguration zu dem entsprechenden Timer TRGO, und sie können ohne Probleme aktiviert und deaktiviert werden.

Ich habe keine Bedingung oder Einschränkung gefunden, wie ich einen Timer aktivieren sollte, der mein Programm beeinflussen könnte, also bin ich ein bisschen damit verloren.

Jede Hilfe wäre willkommen, danke!

+0

TL; DR, aber: Verwenden Sie nicht diese Bloatware STlib/"HAL". Es macht Ihren Code nicht mehr portierbar, verlangsamt ihn aber durch unnötigen Overhead. – Olaf

Antwort

0

Wenn das OPM Bit gesetzt ist, wird das CEN Bit auf 0 zurückgesetzt, sobald der Zähler fertig ist, also funktioniert vielleicht alles richtig, aber Sie können es nicht sehen, weil es zu schnell geschieht. Setzen Sie einige Bits in den APB Freeze-Registern, DBGMCU->APB1_FZ in Ihrem Fall, wenn Sie die Timer mit einem Debugger untersuchen möchten. Oder verlangsamen Sie alles bis zum Crawlen, ich habe es mit Prescalern gemacht und den Kern auf der internen HSI-Uhr ohne PLL ausgeführt.

Nichtsdestotrotz kann ich der Meinung der Mehrheit hier nur zustimmen, dass die Verwendung von SPL oder HAL für Timer nur eine Verschwendung von verschiedenen Ressourcen (des Programmierers und des Controllers) ist. Das Arbeiten mit Registern erzeugt einen kürzeren, einfacheren Code und ist auch ziemlich portabel. Ich habe es tatsächlich auf einem STM32L1 getestet, aber ich bin mir ziemlich sicher, dass es auch auf einem F415 funktionieren würde.

#define PRESCALER 0xFFFFU 
#define TDELAY  8U 

void gatedtimer(void) { 
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN; 
    RCC->APB1RSTR = RCC_APB1RSTR_TIM2RST | RCC_APB1RSTR_TIM3RST; 
    RCC->APB1RSTR = 0; 

    TIM2->PSC = PRESCALER; // a BIG prescaler to slow things down to observable speed 
    TIM2->EGR = TIM_EGR_UG; // force prescaler update 
    TIM3->PSC = PRESCALER; // same prescaler to all timers 
    TIM3->EGR = TIM_EGR_UG; // force prescaler update 
    // of course you should omit the above in production code 

    TIM2->SMCR = (0b010U << TIM_SMCR_TS_Pos) // Trigger selection ITR2 = TIM3 
       | (0b101U << TIM_SMCR_SMS_Pos); // Gated Mode 
    TIM2->CR1 = TIM_CR1_CEN; // start the slave 

    TIM3->CR2 = (0b100U << TIM_CR2_MMS_Pos); // "100: Compare - OC1REF signal is used as trigger output (TRGO)" 
    TIM3->CCMR1 = (0b110U << TIM_CCMR1_OC1M_Pos); // "110: PWM mode 1 - In upcounting, channel 1 is active as long as TIMx_CNT < TIMx_CCR1 else inactive." 
    TIM3->CCR1 = TDELAY; // "some delay" is required for the timer hw to start a pulse 

    while(TIM2->CNT < 20U) 
     printf("TIM2->CNT=%lu TIM3->CNT=%lu\n", TIM2->CNT, TIM3->CNT); // slave runs normally 

    TIM3->ARR = TDELAY + 30; // set delay length 
    TIM3->CR1 = TIM_CR1_CEN | TIM_CR1_OPM; // start the master in one pulse mode 

    while(TIM3->CR1 & TIM_CR1_CEN) // CEN bit will be reset 
     printf("TIM2->CNT=%lu TIM3->CNT=%lu\n", TIM2->CNT, TIM3->CNT); // slave stops when master CNT reaches TDELAY 
    while(TIM2->CNT < 40) 
     printf("TIM2->CNT=%lu TIM3->CNT=%lu\n", TIM2->CNT, TIM3->CNT); // slave resumes counting 
} 
Verwandte Themen