Selasa, 14 Desember 2010

Timer di STM32

Timer (TIM) di STM32 ternyata sangat kompleks, liat contoh2nya diperiperal driver ada banyak bangat. Untungnya ketemu tutorial timer di youtube walaupun dalam bahasa thailand tapi source codenya bisa dimengerti.

Untuk mendapatkan timer sebesar 1ms formulanya begini:

Time = SystemCoreClock \ ((TIM_Period+1) * (TIM_Prescaler+1))



1ms = 72MHz \ ((35999+1) * (1+1))

with prescaler 1 and TIM_CounterClock 24MHz:

1us = 24MHz \ ((23+1) * (0 + 1))

1ms = 24MHz \ ((23999+1) * (0+1))

with prescaler 999 and TIM_CounterClock 24KHz:
500ms = 24MHz \ ((1199+1) * (999+1))

1s = 24MHz \ ((23999+1) * (999+1))


or another formula is:

prescaler = (SystemCoreClock \ TIM_CounterClock) - 1;
prescaler = (24MHz \ 1MHz) - 1
prescaler = 23

1uS = 1MHz
1MHz = TIM_CounterClock \ (TIM_Period + 1)
1MHz = 1MHz \ (0 + 1)

with prescler 23 and TIM_CounterClock 1MHz:

to get 1us timer TIM_Period is 0

to get 1ms timer TIM_Period is 999


Note: cara lain untuk mendapatkan timer adalah menggunakan systick timer.

Source Code menggunakan STM32F100 Valueline discovery kit.
Hasil: Led hijau (PC9) akan toggle setiap 1s dan led biru (PC8) toggle setiap 500ms

main.c




/* Includes */
#include
#include "stm32f10x.h"


void setupHardware(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3, ENABLE);

/* GPIOC clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

/* Enable green led PC9 and blue led PC8 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOC, &GPIO_InitStructure);

/* Enable the TIM2 gloabal Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);
/* Enable the TIM3 gloabal Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);
}

void setupTimer()
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/*------------------------------------------
SystemCoreClock
Time = -----------------------------
(TIM_Period+1) * (TIM_Prescaler+1)


1ms = 72MHz \ ((35999+1) * (1+1))

with prescaler 1 and TIM_CounterClock 24MHz:

1us = 24MHz \ ((23+1) * (0 + 1))

1ms = 24MHz \ ((23999+1) * (0+1))

with prescaler 999 and TIM_CounterClock 24KHz:
500ms = 24MHz \ ((1199+1) * (999+1))

1s = 24MHz \ ((23999+1) * (999+1))


or another formula is:

prescaler = (SystemCoreClock \ TIM_CounterClock) - 1;
prescaler = (24MHz \ 1MHz) - 1
prescaler = 23

1uS = 1MHz
1MHz = TIM_CounterClock \ (TIM_Period + 1)
1MHz = 1MHz \ (0 + 1)

with prescler 23 and TIM_CounterClock 1MHz:

to get 1us timer TIM_Period is 0

to get 1ms timer TIM_Period is 999


------------------------------------------------*/
/* Enable Timer2 for every 1s
* This will blink green led*/

TIM_TimeBaseStructure.TIM_Period = 23999;
TIM_TimeBaseStructure.TIM_Prescaler = 999;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM2, & TIM_TimeBaseStructure);

/*Enable Auto reload */
TIM_ARRPreloadConfig(TIM2, ENABLE);

TIM_UpdateRequestConfig(TIM2, TIM_UpdateSource_Regular);

/* TIM IT Enable */
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

/* TIM2 Enable counter */
TIM_Cmd(TIM2, ENABLE);

/*Enable Timer 3 for every 500ms
* This will blink blue led */
TIM_TimeBaseStructure.TIM_Period = 11999;
TIM_TimeBaseInit(TIM3, & TIM_TimeBaseStructure);

/*Enable Auto reload */
TIM_ARRPreloadConfig(TIM3, ENABLE);

TIM_UpdateRequestConfig(TIM3, TIM_UpdateSource_Regular);

/* TIM IT Enable */
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

/* TIM3 Enable counter */
TIM_Cmd(TIM3, ENABLE);

}

/**
**===========================================================================
**
** Abstract: main program
**
**===========================================================================
*/
int main(void)
{
/* TODO - Add your application code here */
setupHardware();
setupTimer();
/* Infinite loop */
while (1)
{

}
}

#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) */

/* Infinite loop */
while (1)
{
}
}
#endif

/*
* Minimal __assert_func used by the assert() macro
* */
void __assert_func(const char *file, int line, const char *func, const char *failedexpr)
{
while(1)
{}
}

/*
* Minimal __assert() uses __assert__func()
* */
void __assert(const char *file, int line, const char *failedexpr)
{
__assert_func (file, line, NULL, failedexpr);
}



Jangan lupa tambah ini di file stm32f10x_it.c



void TIM2_IRQHandler(void)
{

if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
GPIO_WriteBit(GPIOC, GPIO_Pin_9, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_9)));
}
}

void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
GPIO_WriteBit(GPIOC, GPIO_Pin_8, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_8)));
}
}

8 komentar:

  1. Mas mau tanya, tutorial ini IDE nya pakai apa ya? Bisa jalan d coocox IDE gak?

    BalasHapus
  2. bisa saja, pakai command line gcc jg bisa. Banyak tutorialnya di google. Yang penting download peripheral driver dari stm32

    BalasHapus
    Balasan
    1. maaf izin tanya mas, cari di google nya diketik gimana? mohon bantuannya mas

      Hapus
  3. mau tanya gan,,saya bingung perhitungan di atas,,banyak banget ya n beda2 pula
    beda nya
    "1ms = 72MHz \ ((35999+1) * (1+1))" dg
    "1ms = 24MHz \ ((23999+1) * (0+1))" apa ya??
    trus juga pada
    " 1us = 24MHz \ ((23+1) * (0 + 1))" 23 itu apa ya??
    kok kalau 1ms pakai 23999??
    saya bingung,,maklum masih baru belajar ARM ne,,
    heheheee.....please help me

    BalasHapus
  4. 24Mhz itu kan 24000000 us, 1ms = 1000 us.
    24000000/1000 = 24000. Counter start dari 0 berarti upper bound 23999 (24000-1). Karena period kurang dari 65535 (max period di uc ini) tidak perlu prescaler. prescaler = 1. Yang diinput ke program, prescaler = (1-1) = 0.

    72000000/1000 = 72000
    Period tidak boleh lebih besar 65535. Jadi system clock harus dibagi dulu. Misal dibagi 2. 72000000/2 = 36000000
    36000000/1000 = 36000
    berarti period = 36000-1 dan prescaler (2-1). Terus jadi
    period = 35999 dan prescaler 1

    Mau pakai prescaler 72 bisa aja. 72000000/72 = 1000000
    1000000/1000 = 1000
    berarti period = 1000, tapi di set di program 1000-1 = 999. Set prescaler 72-1 = 71

    BalasHapus
  5. .wah ruwet sekali,,tp itu apa gak salah ya??
    24MHz itu kan 0,04167us ya??
    dan msh bingung ne gan,,
    "1ms = 24MHz \ ((23999+1) * (0+1))" 0 dr mna y gan??
    lalu periode tdk blh lbh dr 65535 dg 72000000/2 itu kn jg msh lbh besar 72000000/2,,ap prlu dibagi lg??

    jd gmn gan?? butuh pnerang ne???
    heheee.....
    sblm nya makasih y gan,,mulai paham se cm msh bnyakn bingung nya

    BalasHapus
  6. Sorry itu maksudnya 24Mhz = 1/24000000 s. 1s = 1000ms.



    Begini ada 2 block. block timer dan block source clock.

    Timer itu cuma counter, counting 0 sampai period (counting up), atau period sampai 0 (counting down).

    Maksimum number TIM_Period disini 65535 ini dah sesuai datasheet mereka. Untuk UC tipe lain mungkin beda nilai maks TIM_Period. Disclaimer: Saya dah ngk sentuh STM32 untuk waktu yg lama, mungkin nilai ini tidak akurat lagi.

    Misal target timer 12MHz dan system clock 24MHz.
    Cara pertama berikan block timer source clock 12 MHz.
    Untuk mendapatkan source clock 12Mhz ini masukan di TIM_Prescaler = 1 karena formatnya selalu divider - 1.

    Berarti source clock adalah 12MHz, nilai TIM_Period 0, outputnya timer 12MHz. Karena period 0 berarti

    Cara kedua set period = 2. jadi setiap 2 kali tick, output toggle. Karena tidak ada prescaler jadi source clock tetap 24MHz. Karena tiap 2 cycle output toggle high low, timer jadi punya frequensi 12MHz. Clock dibagi period itu lah frequensi timer.
    Format TIM_Period jadi period - 1. jadi ditulis TIM_Period = 1 bukan TIM_Period = 2;

    0 di pertanyaaan itu didapat dari prescaler yg dimau - 1.






    BalasHapus
  7. ok gan
    terimakasih banyak gan
    akhir nya sy sedikit paham,,sangat bermanfaat gan

    ayo gan di tunggu postingan selanjut nya,,
    ADC and DMA dunk........
    heheheee......

    BalasHapus