Wednesday, October 1, 2014

Embedded C Programming for ARM Cortex (Introduction)

If you are not familiar with embedded systems, when you look at a C code, you will notice some differences.

Before starting a programming tutorial i wanted to build a basic knowledge about embedded programming.


   
If you are designing windows applications in C, C++, C# ; data types are standard, your code can run on any machine running windows (if .net and other dependencies are supplied of course).

You don't have to know memory and peripheral addresses mostly. Bitwise operations are not common, you don't have to worry about cpu type, pin configuration, enabling clocks.

Probably you are not familiar with infinite while loop and RTOS (Real Time Operating System). Limited code and data memory restricts using big arrays.

Preprocessor directives and preprocessor macros are a little tricky usually. Portability is a big problem. If you write a program for STM32F1 even porting this program to STM32F4 can be pain in the ***.

1) Data Types

    Don't get surprized when you see uint8_t, uint16_t etc. All type definitions are in stdint.h header file. Some of the definitions are below :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    /* exact-width signed integer types */
typedef   signed          char int8_t;
typedef   signed short     int int16_t;
typedef   signed           int int32_t;
typedef   signed       __int64 int64_t;

    /* exact-width unsigned integer types */
typedef unsigned          char uint8_t;
typedef unsigned short     int uint16_t;
typedef unsigned           int uint32_t;
typedef unsigned       __int64 uint64_t

2) Preprocessor Directives and Macros

   Preprocessor directives and macros start with "#", sometimes you are going to encounter "\" character, it is used for line continuation. Some of the preprocessor directive keywords are :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#define
#if 
#else
#elif
#endif
#ifdef
#ifndef
#include
#line
#message
#pragma
#undef
#warning

Take a look at these ebook :
https://gcc.gnu.org/onlinedocs/gcc-4.0.4/cpp.pdf


3) Microcontroller Dependent Register Names

Even if you are goint to use higher level libraries, it would be handy to know basic register names. In some tutorials and examples register based operations are used, for example below code does not mean anything to you if you don't know the register names :

1
GPIOC->IDR & 0x0020


IDR is Input Data Register, this code reads Port C, Pin5. Below code is equivalent but easy to read.

1
GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)

4) Pin Configuration

Using GPIO pins is a little tricky for beginners at first. I am going to write a detailed gpio tutorial later but i want to make a brief explanation. Before using your MCU's gpio pins you have to make some effort, all pins are usually at floating input state initially.
  • Enable clock for related port. (Port A etc.)
  • Select related pins (Pin 0 etc.)
  • Select Mode (Input/Output/Alternate Function/Analog)
  • Select Speed (2-100Mhz)
  • Select Output Type (Push Pull/Open Drain)
  • Select Pull Property (Pull Up/Pull Down/No Pull)
Here is the code fragment of the algorithm above :


1
2
3
4
5
6
7
8
 GPIO_InitTypeDef GPIO_InitStruct;
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;   
 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;  
 GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;  
 GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
 GPIO_Init(GPIOC, &GPIO_InitStruct); 

Startup code is automatically generated by Keil and SystemInit function is called before main function. SystemInit function configures PLL parameters and sets the mcu at it's maximum frequency if possible.