Sabtu, 03 September 2011

Tutorial 3 - Led Blink Dan Button

Kita akan mengedit main.c dari tutorial 2. Function yang ditambahkan adalah DelayMs, function ini akan membuat microcontroller menunggu selama x milisecond. Ada modifikasi jg di file stm32f10x_it.c di function Systick_Handler.
Perhatikan pada function DelayMs, saya menggunakan down counter dimana nilai uDelayTimerCounter ditest apakah tidak bernilai 0. Mentest suatu variable dengan bilangan 0 lebih effisien daripada mentest variable <= X.

Tidak Efisien:


if(uDelayTimerCounter >= milis)
uDelayTimerCounter++;



Code diatas tidak effisien karena processor akan mentest overflow dari data type variable tsb.

Untuk membuat USER button berfungsi, clock pada APB2 GPIO A perlu dienable. USER button dalam discovery board dihubungkan pada port PA0.
Perhatikan pada main loop, kita mengambil nila dari USER button 2 kali dengan delay sebesar X ms. Ini dimaksudkan untuk memastikan apakah button masih ditekan.

file main.c



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

volatile uint32_t uDelayTimerCounter;

void initBoard()
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Aktifkan clock untuk portC. Lihat Discovery Board manual page 8 atau STM32F100RBT6B block diagram */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

/* Enable GPIO Port A */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

/* Konfigurasi led hijau di pin PC9*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

/* Gunakan mode PushPull, led akan nyala bila diberi tegangan (aktif high) */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

/* default speed 50Mhz, pin akan didrive sangat cepat */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

/* Inisialisasi PORT C */
GPIO_Init(GPIOC, &GPIO_InitStructure);


/* Konfigurasi USER button di GPIO PA0*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

/* Gunakan mode Input floating */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

/* default speed 50Mhz, pin akan didrive cepat */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

/* Inisialisasi PORT C */
GPIO_Init(GPIOA, &GPIO_InitStructure);


/* Konfigurasi systick timer setiap 1ms. Systick interrupt akan aktif setiap 1ms.
* Systick interrupt akan di handle oleh function Systick_Handler di file stm32f10x_it.c
* Note: Microcontroller pada board ini mempunyai clock max 24Mhz, dalam 1 detik clock ticknya 24.000.000
* berarti dalam 1/2 detik, clock tick 24Mhz/2 = 12Mhz
* Dalam 1ms clock tick adalah 24.0000
* Systick_Config akan error bila diberi nilai 24.000.000
*/
if (SysTick_Config(SystemCoreClock / 1000))
{
/* Capture error */
while (1);
}

}

void ledOn()
{
/* Set bit 1 to PC9 */
GPIO_SetBits(GPIOC, GPIO_Pin_9);
}

void ledOff()
{
/* Reset bit PC9*/
GPIO_ResetBits(GPIOC, GPIO_Pin_9);
}

void DelayMs(uint32_t milis)
{
uDelayTimerCounter = milis;

/* Loop sampai uDelayTimerCounter = 0
* Nilai uDelayTimerCounter akan berkurang tiap 1ms (lihat functino Systick_Handler)
* */
while(uDelayTimerCounter!=0);

}

int main(void)
{
int buttonState = 0; /* By default button is no pressed */
int ledStatus = 0;

initBoard();
ledOff();

/* Main loop. Never exit from this main loop */
while(1){
if(ledStatus == 0){
ledOn();
DelayMs(500);
ledOff();
DelayMs(100);
}

/* Nilai buttonState akan 1 apabila button dalam keadaan idle
* buttonState akan 0 apabila button ditekan
*/
buttonState = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);
if(buttonState == 1){
/* Tunggu sebentar, check lagi apakah button masih ditekan */
DelayMs(50);
buttonState = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);
if(buttonState == 1){
ledStatus = !ledStatus;
/* Tambah delay untuk nunggu button debounce */
DelayMs(500);
}
}
}
return 0;
}




file stm32f10x_it.c




/* Gunakan keyword extern apabila variable atau function
* dideclare di file lain
*/
extern void ledOn(void);
extern void ledOff(void);
extern uint32_t uDelayTimerCounter;

/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
void SysTick_Handler(void)
{
if(uDelayTimerCounter!=0)
--uDelayTimerCounter;
}





Next PwM di STM32

Jumat, 02 September 2011

Tutorial 2 - Led blink

Lanjutan dari tutorial 1.

1. Buka file src/main.c, hapus semua baris di main.c kita akan menulis code dari scratch supaya lebih ringkas dan mudah dimengerti. Code tinggal di copy paste aja, keterangannya ada di source code.

file main.c



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



void initBoard()
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Aktifkan clock untuk portC. Lihat Discovery Board manual page 8 atau STM32F100RBT6B block diagram */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

/* Konfigurasi led hijau di pin PC9*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

/* Gunakan mode PushPull, led akan nyala bila diberi tegangan (aktif high) */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

/* default speed 50Mhz, pin akan didrive sangat cepat */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

/* Inisialisasi PORT C */
GPIO_Init(GPIOC, &GPIO_InitStructure);

/* Konfigurasi systick timer setiap 500ms. Systick interrupt akan aktif setiap 500ms.
* Systick interrupt akan di handle oleh function Systick_Handler di file stm32f10x_it.c
* Note: Microcontroller pada board ini mempunyai clock max 24Mhz, dalam 1 detik clock ticknya 24.000.000
* berarti dalam 1/2 detik. clock tick 24Mhz/2 = 12Mhz
* Systick_Config akan error bila diberi nilai 24.000.000
*/
if (SysTick_Config(SystemCoreClock / 2))
{
/* Capture error */
while (1);
}

}

void ledOn()
{
/* Set bit 1 to PC9 */
GPIO_SetBits(GPIOC, GPIO_Pin_9);
}

void ledOff()
{
/* Reset bit PC9*/
GPIO_ResetBits(GPIOC, GPIO_Pin_9);
}


int main(void)
{
initBoard();

/* Main loop. Never exit from this main loop */
while(1){


}
return 0;
}




modifikasi functino Systick_Handler difile stm32f10x_it.c



extern void ledOn(void);
extern void ledOff(void);
static volatile int ledStatus = 0;
/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
void SysTick_Handler(void)
{
if(ledStatus){
ledOff();
}else{
ledOn();
}
ledStatus = !ledStatus;
}



Systick timer adalah system timer yang sengaja dibuat untuk memudahkan porting antar OS.
Perhatikan keyword volatile pada baris static volatile int ledStatus = 0. Volatile menginstruksikan compile untuk tidak mengoptimisasi variable ledStatus. Karena variable ledStatus dipanggil dari interrupt, dan bisa dipanggil kapan saja.
Sebagai catatan, setiap variable yg dipangil dari interrupt harus diberikan keyword volatile.



Selanjutnya Bikin delay dan tambah input button..


Tugas:
1. Setiap 500ms blinkledHijau(PC9) dan ledBiru (PC8).
2. Ganti waktu timer jadi 200ms.
3. Gunakan led external dan hubungkan dengan pin PA2, buat blink setiap 500ms.

Kamis, 01 September 2011

Tutorial 1 - Create Project With Atollic IDE

Tutorial STM32 Discovery board menggunakan compiler Atollic.

1. Buka aplikasi atollic untuk STM32. Jika belum diinstall bisa didownload free (limited edition) dari website Atollic http://www.atollic.com. Pada saat installasi, installation key akan dibuat dan anda harus registrasi dengan mengisikan nama, email, alamat, etc.

2. Klik menu File->New->C Project. Dialog new project akan muncul. Ketik nama project tut1-ledblink. Project type STM32 C Project, dialog baru akan muncul.
Di bagian target pilih:
- evaluation board: STM32_Discovery
- Floating point: Software (default)
- Code location: Flash (default)
Instruction set thumb2
Endianess little endian
Optimization biarkan default

Klik next. Pilih debug probe ST-LINK.
Klik Next. Pilih configurations Debug dan Release
Klik Finish.

3. Atollic akan membuat project dengan template default, yaitu LED PC8 (led biru) dan PC9 (led hijau) akan toggle apabila button USER di teken.
Klik project->Build All (Ctrl+B). Klik Run->Debug (F11). Pertama kali mungkin akan ditanya konfigurasi debug, pilih saja nilai defaultnya lalu klik finish.


Setiap mulai debugging, program akan berhenti di awal funtiono main. Klik resume (f8) untuk melanjutkan debugging.

Pastikan led hijau pada board menyala, dan apabila button user (button biru) ditekan led biru akan nyala dan led hijau akan mati.

Selanjutnya tutorial 2 akan membuat led blink setiap 500ms.

Kamis, 30 Desember 2010

STM32 blink led using assembly

Semingguan coba belajar bahasa assembly buat ARM (thumb2), ternyata emang sangat susah.
Mayan dikit2 dah ngerti kalau buat debug yg codenya keluar assembler doang.
Program berikut cuma blink led setiap 500ms. Beberapa address masih di hard code (bad programming).




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

/* define compiler specific symbols */
#if defined ( __CC_ARM )
#define __ASM __asm /*!< asm keyword for ARM Compiler */
#define __INLINE __inline /*!< inline keyword for ARM Compiler */

#elif defined ( __ICCARM__ )
#define __ASM __asm /*!< asm keyword for IAR Compiler */
#define __INLINE inline /*!< inline keyword for IAR Compiler. Only avaiable in High optimization mode! */

#elif defined ( __GNUC__ )
#define __ASM __asm /*!< asm keyword for GNU Compiler */
#define __INLINE inline /*!< inline keyword for GNU Compiler */

#elif defined ( __TASKING__ )
#define __ASM __asm /*!< asm keyword for TASKING Compiler */
#define __INLINE inline /*!< inline keyword for TASKING Compiler */

#endif

__IO uint32_t TimingDelay;
void Delay(__IO u32 time)
{
TimingDelay = time;
while(TimingDelay!=0);
}

void TimingDelay_Decrement(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}


inline void ledLoop(void)
{
__ASM volatile("ldr r1,=0x40011000\n\t" //load GPIOC address
"ldr r2,=0x100\n\t" //load Pin_8
"ledloop:"

"str r2,[r1,#0x10]\n\t" //set GPIOC->BSRR = Pin_8

"ldr r0,=500\n\t" //set Delay argument, time = 500ms
"bl Delay\n\t" //call function Delay

"ldr r2,=0x100\n\t" //load Pin_8
"str r2,[r1,#0x14]\n\t" //set GPIOC->BRR = Pin_8

"ldr r0,=500\n\t" //set Delay argument, time = 500ms
"bl Delay\n\t" //call function Delay

"bl ledloop\n\t" //goto to label ledloop and never return
:::"r0", "r1","r2", "cc", "memory");

}
inline int addition(int val1, int val2)
{
int temp;
__ASM volatile(
"add %[result],%[val1],%[val2]\n\t" //result = val1+val3
"mov r2,#100\n\t" //set loop count = 100
"loopi1:\n\t"
"add %[result],%[result],#1\n\t" //result = result+1
"subs r2,r2,#1\n\t" //decrement loopcoount
"bne loopi1\n\t" //if not zero then keep looping


:[result]"=r" (temp)
:[val1]"r" (val1), [val2]"r" (val2)
: "r2", "cc"
);
return temp;
}
/**
**===========================================================================
**
** Abstract: main program
**
**===========================================================================
*/
int main(void)
{

int newval=0;
/* GPIOC clock enable */
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

newval = addition(1,5);

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

if (SysTick_Config(SystemCoreClock / 1000))
{
/* Capture error */
while (1);
}

ledLoop();
/* 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);
}

Sabtu, 18 Desember 2010

RTOS CooCox di STM32F100 Discovery Kit

Punya dua buku tentang RTOS MicroC/III dapat gratis dari Micrium, setelah baca-baca setengah dan mau download RTOS MicroC/III ternyata harus register dengan email yang non gratisan (gmail atau yahoo). Setelah baca-baca license MicroC/III kok kayaknya untuk evaluationnya tidak gratis kecuali untuk academy, maksudnya ada upfront payment untuk bisa coba RTOS ini. Akhirnya buku tersebut saat ini jadi pajangan aja.

Sempet coba FreeRTOS yang licensenya GPL3-Modified, tetapi mengalami kegagalan. FreeRTOS dapat di compile dengan Atollic TrueStudio (free version), tapi crash saat menjalankannya.

Hari ini coba CooCox CoOS (http://www.coocox.org) Free dengan BSD License. Setelah ganti config sedikit dan hapus interrupt handler di file stm32f10x_it.c karena sudah di handle oleh CoOs, compile sukses dan jalan tanpa crash. Walaupun baru coba dua task untuk led blinking.

Mantap, sekarang dah bisa multitasking. Project file akan di upload nanti.

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)));
}
}

Rabu, 24 November 2010

Welcome STM32 MCU


Asyik, dapat STM32 microcontroller eval board gratis dari ARM Tech Con senilai $11.85 (Mouser.com). Namanya STM32 Value Line Discovery Kit. Board ini merupakan evaluation board dengan Microcontroller STM32F100RBT6B dengan :

128KB Flash
8Kb RAM
24 Mhz clock
12 bit ADC 16 channel
7 x 16 bit Timer/PWM
2xSPI
2xI2C
CEC
3xUSART
51 GPIO

STM32F100 adalah MCU low cost dari series STM32 dengan core ARM - Cortex M3. Kelas diatas series ini adalah STM32F107 dengan I2S, USB, CAN, SDIO, Ethernet, clock sampai 72Mhz.
ST menyediakan SDK & source code untuk MCU ini (peripheral firmware library), programmer tidak perlu memprogram dengan register secara langsung.

Software:
Keil
Atollic (Free Version)
STM32 GCC (Free)

Saya Menggunakan Atollic free version, cukup mudah tapi banyak popup message.

http://www.mouser.com/stm32discovery/