Embedded System Lab Manual
Embedded System Lab Manual
To interface and program GPIO ports in C using STM32 (blinking led, push buttons).
Apparatus Required:
1. Start.
2. Enable Clock for the required GPIO ports (GPIOA for the button, GPIOC for the
LED).
3. Configure GPIO Pins:
a) Configure PA0 (button) as input.
b) Configure PC13 (LED) as output.
4. While (1) (Infinite loop):
1. Check Button State:
a) If PA0 is high (button pressed), turn on the LED.
b) If PA0 is low (button not pressed), turn off the LED.
2. Add a delay to debounce the button and give time for the LED to be visible.
5. End.
Theory:
➢ General Purpose Input/Output (GPIO) pins are one of the most commonly used
features of microcontrollers, including the STM32 series. These pins can be
configured as inputs or outputs and are controlled via registers that interface with the
hardware. STM32 microcontrollers offer a wide range of GPIO pins across different
ports, typically labelled as GPIOA, GPIOB, GPIOC, etc., each of which has a set of
pins that can be individually configured for various purposes.
CONFIGURING GPIO FOR BLINKING LEDS:
For blinking an LED, the GPIO pin connected to the LED must be configured
as an output. The general steps are:
1. Before using any GPIO port, the clock for that port must be enabled using the RCC
(Reset and Clock Control) registers.
2. Configure the pin as an output by setting the MODER register appropriately.
3. LEDs generally require push-pull output mode to allow driving the LED with a full
voltage swing.
4. Turn the LED on, set the output pin to high; to turn it off, set the output pin to low.
5. Create a visible blinking effect, introduce a delay after changing the pin state.
A push button needs to be configured as an input pin. The general steps are:
1. As with the LED, the clock must be enabled for the GPIO port.
2. Configure the pin as an input using the MODER register.
3. Often, a push button input requires an internal pull-up or pull-down resistor. This
ensures that the input pin is in a defined state when the button is not pressed (i.e.,
avoiding a floating pin).
• Use the PUPDR register to configure either a pull-up or pull-down resistor for
the pin.
4. The state of the button can be read by checking the IDR register.
Procedure:
a) LED Blinking:
b) Push button:
Start
Setup
No
Button
pressed?
Yes
Toggle
LED (ON)
No
Button
released?
Yes
Toggle LED
(OFF)
Program:
a) LED Blinking:
#include "stm32f4xx.h"
#define LED_PIN GPIO_PIN_13
#define GPIOC_CLK_EN (RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN)
int main(void)
{
GPIO_Init();
while (1)
{
GPIO_Write_LED(1);
delay(1000000);
GPIO_Write_LED(0);
delay(1000000);
return 0;
}
b) Push button:
#include "stm32f4xx.h"
#define BUTTON_PIN GPIO_PIN_0
#define LED_PIN GPIO_PIN_13
#define GPIOA_CLK_EN (RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN)
#define GPIOC_CLK_EN (RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN)
void GPIO_Init(void)
{
GPIOA_CLK_EN;
GPIOC_CLK_EN;
uint8_t GPIO_Read_Button(void)
{
return (GPIOA->IDR & BUTTON_PIN) ? 1 : 0;
}
delay(1000000);
}
return 0;
}
Result:
Thus, the interfacing and programming GPIO ports in C using STM32 (blinking led,
push buttons) was verified and executed successfully.
EXPERIMENT 2
Apparatus Required:
Theory:
• GPIO interrupts allow the MCU to respond to external events, like a button press,
without polling.
Start
Initialize system
clock and GPIO
Configure EXTI
(External
Interrupt) for PA0
Enable interrupt in
NVIC
Wait in infinite
loop
Button Press
Detected on PA0
Interrupt triggered
EXTI0_IRQHandler
runs
Toggle LED on
PA1
Return to main
loop (wait again)
Program:
#include "stm32f10x.h"
void GPIO_Config(void);
void EXTI0_IRQHandler(void);
int main(void) {
GPIO_Config();
while (1) {
void GPIO_Config(void) {
GPIOA->CRL |= GPIO_CRL_CNF0_1;
GPIOA->ODR |= GPIO_ODR_ODR0;
GPIOA->CRL |= GPIO_CRL_MODE1_1;
EXTI->IMR |= EXTI_IMR_MR0;
EXTI->FTSR |= EXTI_FTSR_TR0;
NVIC_EnableIRQ(EXTI0_IRQn);
}
void EXTI0_IRQHandler(void) {
GPIOA->ODR ^= GPIO_ODR_ODR1;
EXTI->PR |= EXTI_PR_PR0;
Result:
To configure the STM32 Timer module to generate periodic time delays using
register-level programming.
Apparatus Required:
Theory:
Procedure:
Start
Configure PA1 as
output pin
Loop: Check if
update flag (UIF)
is set
No
If yes?
Yes
Toggle LED
on PA1
Clear UIF
flag
Program:
#include "stm32f10x.h"
void delay_init(void);
void GPIO_Config(void);
int main(void) {
GPIO_Config();
delay_init();
while (1) {
GPIOA->ODR ^= GPIO_ODR_ODR1;
void GPIO_Config(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
GPIOA->CRL |= GPIO_CRL_MODE1_1;
void delay_init(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
TIM2->PSC = 7200 - 1;
TIM2->ARR = 10000 - 1;
}
Result:
Thus, the configuration of STM32 Timer module to generate periodic time delays
using register-level programming was successfully executed.
EXPERIMENT 4
To generate a Pulse Width Modulation (PWM) signal using Timer 3 (TIM3) on the
STM32F4 microcontroller and simulate it using Keil µVision.
Apparatus Required:
Theory:
Pulse Width Modulation (PWM) is a technique used for controlling the power
delivered to electronic devices such as motors, LEDs, and communication signals. In
STM32F4, timers are used to generate PWM signals. TIM3 is a general-purpose timer
with multiple channels, allowing flexible PWM configurations. In this experiment, PA6 is
configured as TIM3 Channel 1, generating a PWM signal with a 100 Hz frequency and a
50% duty cycle.
Procedure:
1. Open Keil µVision and create a new project for the STM32F4 microcontroller.
2. Add the STM32F4 Standard Peripheral Library to the project.
3. Write the C program to configure TIM3 for PWM generation on PA6.
4. Compile the code and load it into the Keil µVision simulator.
5. Run the simulation and use the virtual oscilloscope to observe the PWM waveform.
6. Verify that the PWM signal has a 100 Hz frequency with a 50% duty cycle.
Flowchart:
Program:
#include "stm32f4xx.h"
void PWM_Init(void)
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
TIM2->PSC = 1600 – 1;
TIM2->ARR = 1000 – 1;
TIM2->CCR1 = 500;
TIM2->CCMR1 |= TIM_CCMR1_OC1PE;
TIM2->CCER |= TIM_CCER_CC1E;
TIM2->CR1 |= TIM_CR1_CEN;
int main(void)
SystemInit();
PWM_Init();
while (1)
}
Result:
Thus, the PWM signal was successfully generated on PA6 using TIM3 with a
frequency of 100 Hz and a 50% duty cycle. The waveform was observed and verified using
Keil µVision's virtual oscilloscope.
EXPERIMENT 5
Apparatus Required:
Theory:
Procedure:
1. Open Keil µVision and create a new project for the STM32F4 microcontroller.
2. Add the STM32F4 Standard Peripheral Library to the project.
3. Write the C program to initialize SPI1 and send data to a display.
4. Compile the code and load it into the Keil µVision simulator.
5. Run the simulation and use the virtual logic analyser to observe SPI signals.
6. Verify that SPI data is transmitted correctly.
Flowchart:
Start
Configure PA5
(SCK), PA7
(MOSI) as
Alternate Function
(SPI1)
Configure PA4
(CS) as Output
Initialize SPI1 in
Master Mode
Send Initialization
Commands to
Display
Observe SPI
Communication in
Simulation
End
Program:
#include "stm32f4xx.h"
void SPI1_Init(void);
void GPIO_Init(void);
void Display_Reset(void);
void Display_Init(void);
int main(void) {
GPIO_Init();
SPI1_Init();
Display_Reset();
Display_Init();
while (1) {
Display_Command(0xA5);
Display_Data(0xFF);
}
void SPI1_Init(void) {
SPI1->CR1 = 0;
SPI1->DR = data;
void GPIO_Init(void) {
GPIOA->OSPEEDR |= (3U << 8) | (3U << 12) | (3U << 14); // High speed
GPIOA->PUPDR &= ~(3U << 8) | (3U << 12) | (3U << 14);
}
void Display_Reset(void) {
GPIOA->BSRR = RST_PIN;
SPI1_Transmit(cmd);
GPIOA->BSRR = CS_PIN;
GPIOA->BSRR = DC_PIN;
SPI1_Transmit(data);
GPIOA->BSRR = CS_PIN;
void Display_Init(void) {
Display_Command(0x01);
Display_Command(0x29);
Result:
ADC INTERFACING
Aim:
1. To interface an audio sensor using the 12-bit ADC module of the STM32F4
microcontroller.
2. To use Direct Memory Access (DMA) to read ADC data and transfer it to a local
variable for efficient processing.
Apparatus Required:
Theory:
Analog-to-Digital Converters (ADCs) are used to convert analog signals into digital
values for processing by a microcontroller. The STM32F4 series features a 12-bit ADC that
provides high-precision sampling, suitable for interfacing with analog sensors such as
microphones.
Direct Memory Access (DMA) is a feature that allows peripherals to transfer data
directly to memory without CPU intervention, reducing processing overhead and improving
real-time performance. By using DMA with ADC, we can continuously sample an audio
signal and store it in memory for further analysis.
Procedure:
Start
Configure ADC
for Single
Conversion Mode
Start ADC
Conversion
Convert to Voltage
Level
Display or Store
Data
Repeat Process
End
Program:
#include "stm32f4xx.h"
#define ADC_CHANNEL 0
void ADC_Init(void);
uint16_t Read_ADC(void);
void ADC_Init(void) {
ADC1->SQR3 = ADC_CHANNEL;
uint16_t Read_ADC(void) {
return ADC1->DR;
int main(void) {
uint16_t adcValue;
ADC_Init();
while (1) {
adcValue = Read_ADC();
}
2. ADC with DMA:
#include "stm32f4xx.h"
#define ADC_CHANNEL 0
uint16_t adcBuffer[10];
void ADC_DMA_Init(void);
void ADC_DMA_Init(void) {
ADC1->SQR3 = ADC_CHANNEL;
DMA2_Stream0->CR = 0;
DMA2_Stream0->PAR = (uint32_t)&ADC1->DR;
DMA2_Stream0->M0AR = (uint32_t)adcBuffer;
DMA2_Stream0->NDTR = 10;
int main(void) {
ADC_DMA_Init();
while (1) {
Result:
1. Successfully interfaced an audio sensor with the STM32F4 ADC and observed the
sampled values.
2. Successfully implemented DMA to transfer ADC data to a local variable, reducing
CPU overhead and improving real-time processing.
EXPERIMENT 7
To design and implement a PWM-based speed control system for a DC motor using a
potentiometer, interfaced with an STM32 microcontroller at the register level.
Apparatus Required:
Theory:
Pulse Width Modulation (PWM) is a technique where the duty cycle of a pulse signal
is varied to control the speed of a DC motor. The STM32 microcontroller generates PWM
signals using its Timer module.
1. The potentiometer (10KΩ) is used as an analog input to control the PWM duty cycle.
2. The ADC (Analog-to-Digital Converter) reads the voltage from the potentiometer.
3. The PWM signal is generated using Timer2 of STM32.
4. The duty cycle of the PWM is adjusted based on the ADC reading.
5. The L298N Motor Driver is used to drive the DC motor.
Procedure:
Start
Initialize GPIO,
ADC, Timer
Read Analog
Value from
Potentiometer
using ADC
Update Timer
PWM Duty Cycle
(TIM2->CCR2)
Apply PWM
Signal to Motor
Driver (L298N)
Motor Speed
Adjusts Based on
Potentiometer
Position
Repeat
Continuously
Program:
#include "stm32f10x.h"
void GPIO_Config(void);
void ADC_Config(void);
void TIM2_PWM_Config(void);
uint16_t Read_ADC(void);
int main(void) {
uint16_t adc_value;
uint16_t pwm_duty;
GPIO_Config();
ADC_Config();
TIM2_PWM_Config();
while (1) {
adc_value = Read_ADC();
TIM2->CCR2 = pwm_duty;
void GPIO_Config(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
void ADC_Config(void) {
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
ADC1->SMPR2 |= ADC_SMPR2_SMP0;
ADC1->SQR3 = 0;
ADC1->CR2 |= ADC_CR2_ADON;
uint16_t Read_ADC(void) {
ADC1->CR2 |= ADC_CR2_ADON;
return ADC1->DR;
void TIM2_PWM_Config(void) {
TIM2->PSC = 71;
TIM2->ARR = 1000;
TIM2->CCMR1 |= TIM_CCMR1_OC2PE;
TIM2->CCER |= TIM_CCER_CC2E;
TIM2->CR1 |= TIM_CR1_CEN;
}
Result:
Thus, the design and implementation of PWM-based speed control system for a DC
motor using a potentiometer, interfaced with an STM32 microcontroller at the register level
To implement multiple Free RTOS tasks with different priorities, demonstrate the use
of delay functions, and dynamically delete tasks on an STM32 microcontroller at the register
level.
Apparatus Required:
Theory:
Task Priorities:
Start
Initialize STM32
GPIO and Clock
Create Button
Task (Highest
Priority)
Start FreeRTOS
Scheduler
Button Task:
If button pressed
delete Task2
LED2 stops
toggling
Remaining tasks
continue based on
their
delays/priorities
Program:
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
void GPIO_Config(void);
int main(void) {
GPIO_Config();
vTaskStartScheduler();
while (1);
void GPIO_Config(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0);
GPIOA->CRL |= GPIO_CRL_CNF0_1;
GPIOA->ODR |= GPIO_ODR_ODR0;
GPIOA->CRL |= GPIO_CRL_MODE1_1;
GPIOA->CRL |= GPIO_CRL_MODE2_1;
GPIOA->CRL |= GPIO_CRL_MODE3_1;
while (1) {
GPIOA->ODR ^= GPIO_ODR_ODR1;
vTaskDelay(pdMS_TO_TICKS(1000));
while (1) {
GPIOA->ODR ^= GPIO_ODR_ODR2;
vTaskDelay(pdMS_TO_TICKS(500));
while (1) {
GPIOA->ODR ^= GPIO_ODR_ODR3;
vTaskDelay(pdMS_TO_TICKS(300));
while (1) {
vTaskDelete(Task2_Handle);
vTaskDelay(pdMS_TO_TICKS(100));
Result:
Thus, the implementation of multiple Free RTOS tasks with different priorities,
demonstrate the use of delay functions, and dynamically delete tasks on an STM32
microcontroller at the register level was successfully executed.