2016年10月17日 星期一

作業系統之前的程式 for stm32f4discovery (15) - 打造 1ms timer 使用 timer3

學者貴于行之,而不貴于知之。

弄懂了 stm32f407 clock tree 之後, 就可以精準的設定 timer, 上一篇是 systick 這次的是 timer3。

一樣得知道 timer3 接在哪個 bus 上, 參閱 fig 1, 在 APB1 上。

fig 1

也和上一篇一樣, 再呼叫 timer3.c L674 SystemInit() 之後:
sysclk (cpu 時脈): 168 MHz
AHB: 168 MHz
APB1: 42MHz
APB2: 84MHz
main PLL: 168 MHz

不一樣的是:

APB1 的除頻係數是 4, 所以 apb1 是 168/4=42, 然後到了 timer3 時, 會 X2, 所以 timer3 餵進來的時脈是 42*2=84 Mhz, 參考 ref 2 圈圈 8 的那個地方, 如果 APB1 的除頻係數是 1, timer3 的時脈就不會乘以 2, 也就是餵進來的時脈是 42 Mhz。

餵進來的時脈是 84Mhz, 也就是說 1/84000000 會計數一次, 數到 84000 之後就代表了 1 ms。觀念和 systick 一樣, 但是細節不一樣。

fig 2

要設定的相關暫存器:
  • CR1
  • PSC
  • ARR
  • DIER
  • SR
CR1:CKD 設定為 00 的話, 表示 CK_INT 進來的頻率是多少就是多少, CK_INT 就是上文提到的 84 Mhz。

CR1:DIR uncounter, downcounter 的設定, 往上遞增計數或往下遞減計數。

ARR: 假如設定 100, 就是在一個 clock 往上數到 100 或是從 100 往下數到 0。

PSC: 假如設定 84, 表示 84/84000000 會把 ARR 往上或是往下數一次。

DIER:UIE 1: update interrupt enabled, 計數的時間到了, 將中斷 bit on 起來。
SR:UIF 1: update interrupt pending, 中斷 bit on 起來, 用來檢查時間是不是到了。

PSC: 8400
ARR: 10

就是 8400/84000000 把 ARR 往上或是往下數一次, 以往上來舉例, 數到 10 就把中斷 bit on 起來, 剛好是 1ms。

PSC: 0
ARR: 84000

這組設定也是同樣效果, 騙你的, 雖然看起來也是 1/84000000 數 84000 次, 但是 ARR 是 16 bit, 無法接受 84000 這麼大的值, 16 bit 最大值是 65536。

timer3 還有很多暫存器可以設定, 相當複雜。

程式一樣很簡單, 算到 1ms 亮燈, 在 1ms 後, 暗燈, 一樣不使用 isr, 而是檢查 SR:UIF, 不使用 isr 是為了讓程式簡單一點, 文章雖然很短, 但把這些搞懂著實花了我不少時間, 希望有興趣的開發人員可以因為我的文章而減少學習時間, 把時間花在要完成的項目。

fig3 是 1ms 的 LA 波形圖, fig4 是 2ms LA 波形圖。

這個實驗是從《精通STM32F4(库函数版)》修改而來。

fig 3 1ms timer3

fig 4 2ms timer3

timer3.c
  1 #include "stm32.h"
  2 #include "stm32f4xx_usart.h"
  3 #include "stm32f4xx_rcc.h"
  4 #include "stm32f4xx_gpio.h"
  5 
  6 #include "stm32f4xx_tim.h"
  7 
 97 
 98 void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState)
 99 { 
100   /* Check the parameters */
101   assert_param(IS_RCC_APB1_PERIPH(RCC_APB1Periph));
102   assert_param(IS_FUNCTIONAL_STATE(NewState));
103 
104   if (NewState != DISABLE)
105   {
106     RCC->APB1ENR |= RCC_APB1Periph;
107   }
108   else
109   {
110     RCC->APB1ENR &= ~RCC_APB1Periph;
111   }
112 }
113 
139 void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState)
140 {
141   /* Check the parameters */
142   assert_param(IS_RCC_AHB1_CLOCK_PERIPH(RCC_AHB1Periph));
143 
144   assert_param(IS_FUNCTIONAL_STATE(NewState));
145   if (NewState != DISABLE)
146   {
147     RCC->AHB1ENR |= RCC_AHB1Periph;
148   }
149   else
150   {
151     RCC->AHB1ENR &= ~RCC_AHB1Periph;
152   }
153 }
495 
496 static void SetSysClock(void)
497 {
498 /******************************************************************************/
499 /*            PLL (clocked by HSE) used as System clock source                */
500 /******************************************************************************/
501   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
502   
503   /* Enable HSE */
504   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
505  
506   /* Wait till HSE is ready and if Time out is reached exit */
507   do
508   {
509     HSEStatus = RCC->CR & RCC_CR_HSERDY;
510     StartUpCounter++;
511   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
512 
513   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
514   {
515     HSEStatus = (uint32_t)0x01;
516   }
517   else
518   {
519     HSEStatus = (uint32_t)0x00;
520   }
521 
522   if (HSEStatus == (uint32_t)0x01)
523   {
524     /* Enable high performance mode, System frequency up to 168 MHz */
525     RCC->APB1ENR |= RCC_APB1ENR_PWREN;
526     PWR->CR |= PWR_CR_PMODE;  
527 
528     /* HCLK = SYSCLK / 1*/
529     RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
530       
531     /* PCLK2 = HCLK / 2*/
532     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
533     
534     /* PCLK1 = HCLK / 4*/
535     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
536 
537     /* Configure the main PLL */
538     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
539                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
540 
541     /* Enable the main PLL */
542     RCC->CR |= RCC_CR_PLLON;
543 
544     /* Wait till the main PLL is ready */
545     while((RCC->CR & RCC_CR_PLLRDY) == 0)
546     {
547     }
548    
549     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
550     FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
551 
552     /* Select the main PLL as system clock source */
553     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
554     RCC->CFGR |= RCC_CFGR_SW_PLL;
555 
556     /* Wait till the main PLL is used as system clock source */
557     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
558     {
559     }
560   }
561   else
562   { /* If HSE fails to start-up, the application will have wrong clock
563          configuration. User can add here some code to deal with this error */
564   }
565 
566 /******************************************************************************/
567 /*                        I2S clock configuration                             */
568 /******************************************************************************/
569   /* PLLI2S clock used as I2S clock source */
570   RCC->CFGR &= ~RCC_CFGR_I2SSRC;
571 
572   /* Configure PLLI2S */
573   RCC->PLLI2SCFGR = (PLLI2S_N << 6) | (PLLI2S_R << 28);
574 
575   /* Enable PLLI2S */
576   RCC->CR |= ((uint32_t)RCC_CR_PLLI2SON);
577 
578   /* Wait till PLLI2S is ready */
579   while((RCC->CR & RCC_CR_PLLI2SRDY) == 0)
580   {
581   }
582 }
583 
584 
585 void SystemInit(void)
586 {
587   /* FPU settings ------------------------------------------------------------*/
588   #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
589     SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
590   #endif
591 
592   /* Reset the RCC clock configuration to the default reset state ------------*/
593   /* Set HSION bit */
594   RCC->CR |= (uint32_t)0x00000001;
595 
596   /* Reset CFGR register */
597   RCC->CFGR = 0x00000000;
598 
599   /* Reset HSEON, CSSON and PLLON bits */
600   RCC->CR &= (uint32_t)0xFEF6FFFF;
601 
602   /* Reset PLLCFGR register */
603   RCC->PLLCFGR = 0x24003010;
604 
605   /* Reset HSEBYP bit */
606   RCC->CR &= (uint32_t)0xFFFBFFFF;
607 
608   /* Disable all interrupts */
609   RCC->CIR = 0x00000000;
610 
611 #ifdef DATA_IN_ExtSRAM
612   SystemInit_ExtMemCtl(); 
613 #endif /* DATA_IN_ExtSRAM */
614          
615   /* Configure the System clock source, PLL Multiplier and Divider factors, 
616      AHB/APBx prescalers and Flash settings ----------------------------------*/
617   SetSysClock();
618 
619   /* Configure the Vector Table location add offset address ------------------*/
620 #ifdef VECT_TAB_SRAM
621   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
622 #else
623   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
624 #endif
625 }
626 
665 
666 /**
667  * @brief  Main program.
668  * @param  None
669  * @retval None
670  */
671 int main(void)
672 {
673   // set to 168M
674   SystemInit();
675 
676   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
677   TIM_TimeBaseInitTypeDef time_init_struct;
678 
679   time_init_struct.TIM_Period = 10-1; // 16 uint size
680   time_init_struct.TIM_Prescaler = 8400-1;
681 
682   time_init_struct.TIM_CounterMode = TIM_CounterMode_Up;
683   time_init_struct.TIM_ClockDivision = TIM_CKD_DIV1; // TIM_CKD_DIV1: 0x0
684 
685   TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
686 
687   TIM_TimeBaseInit(TIM3, &time_init_struct);
688   TIM_Cmd(TIM3, ENABLE);
720 
721   GPIO_InitTypeDef GPIO_InitStructure;
722   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
723 
724   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
725   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
726   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
727   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
728   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
729   GPIO_Init(GPIOD, &GPIO_InitStructure);
730 
731 
732   while(1)
733   {
734 
735     GPIO_SetBits(GPIOD, GPIO_Pin_13); // orange led
736 
737     //Delay(0x3FFFFF);
738 
739 
740 #if 1
741     while(1)
742     {
743       if (TIM3->SR & 1)
744       {
745         TIM3->SR &= (~1);
746         break;
747       }
748     }
749 #endif
750     GPIO_ResetBits(GPIOD, GPIO_Pin_11 | GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
751     //Delay(0x3FFFFF);
752 
753 #if 1
754     while(1)
755     {
756       if (TIM3->SR & 1)
757       {
758         TIM3->SR &= (~1);
759         break;
760       }
761     }
762 #endif
763 
772   }
773 }

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。