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/