Lesson 3: Part 1: Interrupt - On-Board Input

Now we are able to read input status from the input pin. In the previous lesson, we have to keep reading the input pin to detect for button press. In a DVD player example, it is very unlikely user will be pressing the button(e.g. play button). But in order to cater for this user interaction, system have to keep reading the input, which is quite inefficient.

The better method would be configure the MCU in such that any input pin change, notify to the program via interrupt. The function that will be called when interrupt occur is called Interrupt Service Routine(ISR).

The following settings will be require to get this function to work:
  1. Configure input (as shown in previous lesson here)
  2. Configure MCU such that the input state change, it will trigger an interrupt
  3. Select rising/falling interrupt
  4. Enable interrupt
  5. Created ISR source code
The above should serve a guidelines as different interrupt architecture would require different configurations.

For input interrupt, 2 configuration is possible, namely: falling interrupt or rising interrupt. This essentially represent the signal state changes. Taking button as example, idle button state will have voltage high, when user press the button, voltage will change from high to low - falling interrupt. Similarly, rising interrupt occur when user release the pressed button.

Configure MCU For Input Interrupt

We need to figure out the SFR that enable interrupt to be generated, when our input change. 
SYSCFG_EXTICR1:EXTI0 = 0000
Notifying MCU Tie PA0 To Interrupt Line 0
EXTI_IMR:MR0 = 1
Enable Line 0 Interrupt

Select Falling/Rising Interrupt

EXTI_FTSR:TR1
Falling Trigger Enable For Button Press
EXTI_RTSR: TR1
Rising Trigger Enable For Button Release

Enable Interrupt

This is the best part of writing this lesson. I do not found any description on the technical document.  Thus I have no choice but skip this section while writing the source code, and the result: things does not work.

Scanning the document up and down doesn't have much, expect I spot a section on NVIC (Nested Vector Interrupted Controller), but no SFR at end of section. And later on I discovered this in debugging session:
NVIC Discovery in Debugger Mode
With this, I believe a section of the NVIC description has left out in technical document. Further digging into Keil header file leads me to below:

/** \brief  Structure type to access the Nested Vectored Interrupt Controller (NVIC).
 */
typedef struct
{
  __IO uint32_t ISER[1];                 /*!< Offset: 0x000 (R/W)  Interrupt Set Enable Register           */
       uint32_t RESERVED0[31];
  __IO uint32_t ICER[1];                 /*!< Offset: 0x080 (R/W)  Interrupt Clear Enable Register          */
       uint32_t RSERVED1[31];
  __IO uint32_t ISPR[1];                 /*!< Offset: 0x100 (R/W)  Interrupt Set Pending Register           */
       uint32_t RESERVED2[31];
  __IO uint32_t ICPR[1];                 /*!< Offset: 0x180 (R/W)  Interrupt Clear Pending Register         */
       uint32_t RESERVED3[31];
       uint32_t RESERVED4[64];
  __IO uint32_t IP[8];                   /*!< Offset: 0x300 (R/W)  Interrupt Priority Register              */
}  NVIC_Type;

Above looks promising with SFR 'ISER', which finally lead to below line to enable interrupt line 0:

NVIC->ISER[0] |= (0x01<<EXTI0_1_IRQn);

And it works! The bad thing, I spend about an hour just because of the missing specification.

**After contacted with ST FAE, they have point me to the document that have description on above SFR register. I do not understand why it is in separate document, my guess is they use the same document for all M0 core, which may include other STM series.

Writing ISR

Writing ISR is a bit tedious as you have to know how to 'tell' your compiler this is an ISR. Thus it generally varies from one compiler to the other one. In our case here, the vector is define in startup file as below:
ISR in startup_stm32f030.s
What we need to do is just declare a function with same name to 'connect' into it.

Lastly, in our ISR we may need to include a checking to ensure the interrupt source is indeed from button, and not from others by checking SFR below:
EXTI_PR:PR0
Reading Interrupt Source, and clearing it
Each time ISR is being called, we also need to clear the bit so that next interrupt could happen.

The Source Code

The complete source code has been push into git.

Lesson 2: Part 2: Controlling GPIO - On-Board Input - Input Reading

 Recite from Part 1, 3 configurations is require as below:

  1. Enable GPIO section for respective pin
    • SFR: RCC_AHBENR , bit: IOPAEN, value: 1
  2. Configure pin to input function
    • SFR: GPIOA_MODER, bit: MODER0, value: 00
  3. Reading input status
    • SFR: GPIOA_IDR, bit: IDR0
The corresponding C code for 3 cases above are:
  1. Enable GPIO section for respective pin
    • RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
  2. Configure pin to input function
    • GPIOA->MODER &= ~GPIO_MODER_MODER0;  //mask the bit to 00
    • GPIOA->MODER |= MODE_INPUT;         //set the bit
  3. Reading pin status into a variable
    • InputState = GPIOA->IDR & GPIO_IDR_0;
The main.c source code is shown as below, or retrieve from git:
#include "stm32f0xx.h"

void MCUInit(void)
{
    /* Input config */
    //Enable GPIO_A block
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
    //Configure PA0 as Input
    GPIOA->MODER &= ~GPIO_MODER_MODER0;//mask the bit to 00
}

int main(void)
{
    unsigned char InputState;
   
    MCUInit();
   
    while(1)
    {
        //read input state
        InputState = GPIOA->IDR & GPIO_IDR_0;
    }
}

Real Life Application

  1. Pressing play button in DVD to start video playback process.
  2. Pressing the power button at hand phone to lit up screen for phone unlock process

Exercise

  1. Since reset setting on GPIOA->MODER is already as input, try remove the configurations and see if input detection still works.
  2. Base on USER button state, change the LD3 LED state, for example:
    • when USER button press, turn on LD3 LED
    • when USER button release, turn off LD3 LED

Lesson 2: Part 1: Controlling GPIO - On-Board Input - SFR Study

Introduction

Push button provide a method for human to give input to the system. It can be requesting a system to start a process, or requesting a system to provide system state and etc. For example, pressing a button in remote control to perform volume up action, pressing start button in washing machine to initiate wash status.

In this lesson, we are be using out board button as system input.

Working Principles

When MCU pin is configure as input pin, the pin state (High or Low) can be read from software by accessing SFR. Below schematic is the circuit design for USER button in STM32F030 Discovery board.
USER Button (B1) <-> PA0
Refer to above circuit, PA0 is the input pin to MCU. When USER button is not press, PA0 signal will be 0V (read by software as Low state). When USER button is press, VDD will be supply at point 3,4, thus enabling PA0 to have VDD voltage, which is 3.3V(read by software as High state)

We need the following configuration to enable an input pin
  1. Enable GPIO section for respective pin
  2. Enable pin to be input function
  3. Read the current input state

Step 1: Enable PA0 GPIO Function

  1. Similar to lesson 1 part 1, we use the same SFR(RCC_AHBENR) to enable GPIO function, but PA0 require us to enable bit (IOPAEN)
Enable Bit IOPAEN In Register RCC_AHBENR

Step 2: Configure Pin To Be Input Pin

  1. Similar to lesson 1 part 1, we use the same SFR(GPIOx_MODER). Since we are looking at Port A, the right register is GPIOA_MODER
  2. PA0 refer to bit 0, thus we should be configure MODER0 to '00'
  3. If we refer to below, the reset state of the pin is 00, that means after power up the pin has been configure to input state. Thus, we can actually skip this setting in our coding.
Set MODER0 To '00' In Register GPIOA_MODER

Step 3: Reading Input State

  1. By reading register GPIOA_IDR,  bit IDR0, we will know the current state of the pin.
Reading IDR0 In Register GPIOA_IDR

Lesson 1: Part 4: Controlling GPIO - External Output - LED Control

To control external LED, the circuit would be as below:
PC9 With External LED


PC9 -> Orange Wire -> 30 Ohm Resistor* -> LED -> Black Wire -> GND
*Note: Use 30 Ohm resistor, image shown is NOT 30 Ohm resistor
*The resistor is use to limit the current, thus it is OK to put put before or after the LED.


As the voltage line at PC9 is only 3.3V, the LED may not achieve maximum brightness. But this example is good enough to demonstrate how we can connect to external device(LED).

A transistor(2N3904) can be use in order to increase control voltage to 5V.






Lesson 1: Part 3: Controlling GPIO - On-Board Output - LED Control

In this section we will be using what we learn from Part 1 and write some C code. Recite from Part 1, 3 configurations is require as below:
  1. Enable GPIO section for respective pin
    • SFR: RCC_AHBENR , bit: IOPCEN, value: 1
  2. Pin to be output function
    • SFR: GPIOC_MODER, bit: MODER9, value: 01
  3. Control the pin to be high state or low state
    • High state: SFR: GPIOC_ODR, bit: ODR 9, value: 1
    • Low state:  SFR: GPIOC_ODR, bit: ODR 9, value: 0
In order to access SFR in C language, we need to include a header files :
  •  #include stm32f0xx.h
 Open content of stm32f0xx.h by right click on source code file name, select 'Open document' as shown below:
Open SFR Define File
Inside the SFR files define all the SFR that we use in source code below.

Then the corresponding C code for 3 cases above are:
  1. Enable GPIO section for respective pin
    • RCC->AHBENR |= RCC_AHBENR_GPIOCEN;
  2.  Pin to be output function
    • GPIOC->MODER &= ~GPIO_MODER_MODER9;  //mask the bit to 00
    • GPIOC->MODER |= MODE_OUTPUT;         //set the bit
  3.  Control the pin to be high state or low state
    • High state:
      • GPIOC->ODR |= GPIO_ODR_9;
    • Low state:
      • GPIOC->ODR &= ~GPIO_ODR_9;
Below is the image for whole source code. You can either type out or just use Git link here.

Full Source Code To Control LD3

Real life applications:

  1. With proper hardware circuit, instead of turn on/off LED, we can turn on/off fan, light.
  2. Replacing the LED with IR transmittor, and with correct timing on turning on/off, we can use it as remote control, to control electrical appliances: TV, DVD.

Exercise

  1. In the source code we have turn on LED and turn off LED, why the LED is constantly turn on when program is running?
  2. Repeating Part 1 to 3 process, this time try controlling LD4 LED






Lesson 1: Part 2: Controlling GPIO - On-Board Output - Create New Project

This section will be demonstrating step to create new project.

 











Project -> New uVision Project


Select Device
Select Project Folder, Add Project Name
Select Startup -> Resolve -> OK
Right Click 'Source Group 1' -> Select 'Add New Item...'
C File -> main.c -> Add

Edit main.c -> Click Build Button -> 0 Error, 0 Warning
Project build successful when message shown : 0 Error(s), 0 Warning(s)


















Lesson 1: Part 1: Controlling GPIO - On-board Output - SFR Study

Introduction

As shown in the last video in 'Building First Example', there is 2 on-board LED, namely LD3 and LD4. In this lesson, we will be learning on controlling these LED.

LED typcial serve as system indicator to the user. It can be use to represent the current status of the process, current state of the system. For example, red LED in TV means the TV is in system standby. Or a light up LED in washing machine means that washing machine is power up.

Working Principles

Typical MCU will generally have pin that can be configure to input or output base on the software configuration. This is generally known as GPIO - General Purpose Input Output. When a pin is configure as output pin, software can control this pin to act as high state(making the pin to be 3.3V) or low state(pin to be 0V Ground). By changing the pin voltage between 3.3V, we are essentially turning on the LED and by 0V, turning off LED. There is more options we can control on GPIO, which is ignored to ease the explanation, you and refer to reference manual for detail description at GPIO sections.

In addition, MCU GPIO section can be enable/disable by software. This feature enable Engineer to disable unused section in order to reduce power consumption.

As summary, in order to control LED we need to configure:
  1. Enable GPIO section for respective pin
  2. Pin to be Output function
  3. Control the pin to be high state or low state
Lets take LD3 as an example.

Step 1: Finding Which MCU Pin Is Actually Controlling LD3

  1. To do this, we need the discovery board schematic, download from here, look for 'schematic pack'.
  2. From schematic PDF file, we can know LD3 is control by PC9, which is connected to MCU PC9 pin(refer to image below). PC9 is the keyword we need to use when programming this pin. 
  3. PC9 let us know it is at Port C, pin 9. These information is critical in deciding which SFR to use, which will demonstrate below.
LD3 -> PC9 -> Port-C, Pin9

Step 2: Enable PC9 GPIO Function

  1.  We need another document that would tell us how to enable GPIO function. This document is like that handbook of MCU which explains:
    • The system design of the MCU
    • The configurations and features for MCU peripheral
    • Some documents may provides example
  2. This handbook is the main reference while programming MCU. For this example, download it from here, refer to 'Reference Manual' section.
  3.  From the reference manual, refer to register name RCC_AHBENR.
    • SFR name: RCC_AHBENR, this will be the name we will be using in programming later on
    • Bit 19:  IOPCEN (We need to enable this bit to enable GPIO Port C9 functionality. In fact, once enable this block, all pin in PC0-PC15 will be enable)

Enable Bit IOPCEN In Register RCC_AHBENR

Step 3: Configure Pin To Be Output Pin

  1. Using the reference manual as in Step 2 above, this control is under SFR name is GPIOx_MODER
    • As shown in description, we need a value of '01' to configure pin as general purpose output mode.
    • Since out pin is PC9, so we should refer to MODER9, which is at bit 18 and 19. Thus we should be setting bit 18 to value 1, bit 19 to value 0.
Set MODER9 To '01' In Register GPIOC_MODER

 Step 4: Controlling Output Pin High(On LED) and Low (Off LED)


Setting bit ODR 9 '1' Or '0' In Register GPIOC_ODR

With these information in place, we can proceed creating empty project and start writing code, which will be explain in next section.

Pre-Lesson1: Part 6: Building First Example

First download example software(STSW-STM32140) from ST website here, as shown below.

Download Example Code - STSW-STM32140
 
 After unzip the file, browse to location as shown below and open uVisioni 5 project name STM32F0308-Discovery_Demo. We will be using this to ensure setup is working fine.

Since the project file is created for uVision4, there will be a pop up message asking to 'Migrate to Device Pack' or 'Install Legacy Support', just select 'Migrate to Device Pack'.
Launch Example Project File

Next click on 'Project' menu bar and select 'Build target'. Compilation will start with pop up of 'Build Output' window pane. At end of compilation you should see '0 Erros(s), 0 Warning (s)', which signify build successful.

Build Successful!

Before starting debugging session, ensure the correct debugger is being select.
  1. Go to menu bar 'Project' -> 'Options for target STM32F0308_Discovery' -> 'Debug' -> 'Use' -> 'ST-Link Debugger'. (Shown in below image)
  2. Click 'Settings' beside 'ST-Link Debugger' -> 'Flash Download' -> 'Add' -> 'STM32F0xx 64kB Flash'
  3. If you skip above steps, error message "Cannot Load Flash Device Description!" will pop up when you starting debugging process.
  4.  In dialog box 'Option for Target STM32F0308 Discovery', click on 'Utility' tab, under 'Use Target Driver For Flash Programming', select 'ST-Link Debugger'
Configure Debugger: ST-Link Debugger

Configure Debugger: ST-Link Debugger

Error Message When Not 'Configure Debugger: ST-Link Debugger'

Now we can start the debugging session, click on menu bar 'Debug' -> 'Start/Stop Debug Session'. Refer to below image, highlighted in black color box is tool bar button that is related to debugging process. For time being, just go to menu bar 'Debug' -> 'Run'.
Debugging Session Ready! Play time.
Now you should see one of the LED(label as LD3) is blinking. Pressing the USER button(label as USER) will:
  1. Light up another LED (LD4)
  2. change the blinking speed of the LED (LD3)
 This is the video showing the board behavior.
This conclude this session and ensure all the hardware, IDE, software tools is working fine. Then we can look into embedded system programming in no time.

Pre-Lesson 1: Part 5: IDE Setup : MDK-ARM

To install Keil MDK-ARM,  go to this link and follow the instruction. The good news is currently Keil is given free version for device STM32F030. 

 After MDK-ARM IDE is installed, additional packages need to be installed. Follow the instruction as shown below:





 

Pre-Lesson1: Part 4: Evaluation Kit Selection


Evaluation Kit Selection

To start with this course, I need to select a development board. And my selection is base on the following criteria:

1. ARM development board
2. Affordable
3. The microcontroller provide all the fundamentals peripheral (e.g i2c, UART, SPI bus)
4. Good development software(IDE) suitable for beginner
5. Preferably with on-board input (e.g button) and output (LED)
6. The microcontroller that is good enough to be use for DIY project, so anyone using it as learning also can turn it into something useful.

Base on above, I shortlisted these 2 boards: ST -STM32F0308Discovery and Freescale Kinetis FRDM -KL05Z. Refer below are the specifications of these 2 boards.



Base on criteria above, ST board is better especially with on-board input/output and with more peripheral. And I have selected STM32F0308. You can get the board from element14 at RM41.10. I strongly recommended you get a unit of this before proceed next.


More information about this kit: http://www.st.com/web/catalog/tools/PF259100

IDE Selection

In order to development software for STM32F030, we will need a software  IDE. There are many options available on market such as IAR, Keil MDK-ARM, Attolic, Coocox, Eclipse with plugin.

To avoid any hassle in IDE setup and ease of use, MDK-ARM is chosen. 

Pre-Lesson1: Part 3: Short Form & Annotation

This post listed all the short form name or annotation as reference:

DMA     : Direct Memory Access
IDE     : Integrated Development Environment
ISR     : Interrupt Service Routine
MCU     : Microcontroller
SFR     : Special Function Register
USART   : Universal Synchronous Asynchronous Receiver Transmitter

Pre-Lesson1: Part 2: About This Course

I will be teaching microcontroller programming in this section to anyone interested to pick up embedded system development. I will cover all the typical peripheral of microcontroller and how we can control each of the peripheral.

While I wish to covered everything from A to Z, this is simply impossible as I need to stay focus embedded system teaching. Thus, below are things I will (will not) cover.

Areas I will cover:
1. Learning how embedded system programming is done professionally
2. Some basic electronics circuit (enough to demonstrate embedded system programming)
3. Datasheet on microcontroller
4. Debugging

Areas I will NOT cover:
1. Arduino related
2. C language

Pre-Lesson1: Part 1: Introduction to Embedded System

Embedded system consists of hardware and software design in order to perform a specific function. For example, a radio, aeroplane navigation system or even an missile.

The diagram below shown and LCD Monitor, which consists of:
 - input for various video source (Digital Input - HDMI/DVI, analog RGB, or Video).
- Scaling Engine to resize the video source to fit into the panel size
- SDRAM for video buffering or application buffering
- LVDS Tx : digital signal that contain video signal to be display on LCD panel





In current embedded system design, it is commonly to have microcontroller or microprocessor. The microcontroller can be seen as a center processing engine that control the system operation. And the control is base on a dedicated firmware that loaded into the microcontroller. This firmware allow a flexible design in embedded system whereby a same microcontroller is allow to perform different task. A same microcontroller can be use in a burglar system as well as water heater system.