0% found this document useful (0 votes)
1 views

Embedded System Lab Manual

The document outlines a series of experiments focused on interfacing and programming GPIO ports using STM32 microcontrollers, including blinking LEDs and handling push buttons. It details the necessary apparatus, algorithms, theory, procedures, flowcharts, and example code for each experiment, demonstrating concepts like interrupt programming, timer configuration for delays, and PWM signal generation. Each experiment concludes with a confirmation of successful execution of the tasks described.

Uploaded by

mmmsmaheshwaran
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1 views

Embedded System Lab Manual

The document outlines a series of experiments focused on interfacing and programming GPIO ports using STM32 microcontrollers, including blinking LEDs and handling push buttons. It details the necessary apparatus, algorithms, theory, procedures, flowcharts, and example code for each experiment, demonstrating concepts like interrupt programming, timer configuration for delays, and PWM signal generation. Each experiment concludes with a confirmation of successful execution of the tasks described.

Uploaded by

mmmsmaheshwaran
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 44

EXPERIMENT 1

INTERFACING AND PROGRAMMING GPIO PORTS IN C USING


STM32 (BLINKING LED, PUSH BUTTONS)
Aim:

To interface and program GPIO ports in C using STM32 (blinking led, push buttons).

Apparatus Required:

1. Personal Computer (PC).


2. STM32CubeIDE.
3. Keil µVision.
4. Proteus.
Algorithm:

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:

INTRODUCTION TO GPIO IN STM32:

➢ 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.

CONFIGURING GPIO FOR PUSH BUTTONS (INPUT):

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:

1. Open the software and create new project.


2. Select the STM32 Microcontroller.
3. Enable GPIO output mode of LED.
4. Generate the project in Keil µVision simulation software for the program.
5. Compiling and flashing the code.
6. Open the proteus and create a new schematic.
7. Run the simulation and observe the LED response.
Flowchart:

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)

void delay(volatile uint32_t count)


{
while(count--);
}
void GPIO_Init(void)
{
GPIOC_CLK_EN;
GPIOC->MODER &= ~GPIO_MODER_MODE13;
GPIOC->MODER |= GPIO_MODER_MODE13_0;
}
void GPIO_Write_LED(uint8_t state)
{
if (state)
{
GPIOC->ODR |= LED_PIN;
}
else
{
GPIOC->ODR &= ~LED_PIN;
}
}

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 delay(volatile uint32_t count)


{
while(count--);
}

void GPIO_Init(void)
{
GPIOA_CLK_EN;
GPIOC_CLK_EN;

GPIOA->MODER &= ~GPIO_MODER_MODE0;


GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR0;

GPIOC->MODER &= ~GPIO_MODER_MODE13;


GPIOC->MODER |= GPIO_MODER_MODE13_0;
}

uint8_t GPIO_Read_Button(void)
{
return (GPIOA->IDR & BUTTON_PIN) ? 1 : 0;
}

void GPIO_Write_LED(uint8_t state)


{
if (state)
{
GPIOC->ODR |= LED_PIN;
}
else
{
GPIOC->ODR &= ~LED_PIN;
}
}
int main(void)
{
GPIO_Init();
while (1)
{
if (GPIO_Read_Button())
{
GPIO_Write_LED(1);
}
else
{
GPIO_Write_LED(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

INTERRUPT PROGRAMMING EXAMPLES THROUGH GPIOS


Aim:

To demonstrate interrupt-based programming through GPIOs on an STM32


microcontroller using external interrupt lines (EXTI) and handle them at the register level.

Apparatus Required:

1. Personal Computer (PC).


2. STM32CubeIDE.
3. Keil µVision.
4. Proteus.
Algorithm:

1. Initialize system clocks and GPIO ports.


2. Configure GPIO pin as input (button) and output (LED).
3. Configure EXTI to generate an interrupt on a button press.
4. Enable corresponding NVIC interrupt.
5. In the ISR (Interrupt Service Routine), toggle the LED.
6. Debounce if required.

Theory:

GPIO Interrupts Overview

• GPIO interrupts allow the MCU to respond to external events, like a button press,
without polling.

• EXTI (External Interrupt/Event Controller) in STM32 handles GPIO interrupt


requests.

NVIC – Nested Vectored Interrupt Controller

• NVIC handles interrupt prioritization and dispatching.

• Specific interrupt lines are mapped to NVIC vectors.

Interrupt Trigger Types

• Rising edge, falling edge, or both edges.

• Configured via EXTI_FTSR (Falling Trigger Selection Register) and EXTI_RTSR


(Rising Trigger Selection Register).
Procedure:

1. Configure PA0 as input for the button (with pull-up).


2. Configure PA1 as output for the LED.
3. Enable clock for AFIO (Alternate Function IO) and EXTI line.
4. Configure EXTI0 to detect falling edge on PA0.
5. Enable EXTI0 interrupt in NVIC.
6. Write an interrupt handler to toggle PA1.
7. Press the button to generate an interrupt and observe the LED toggling.
Flowchart:

Start

Initialize system
clock and GPIO

Set PA0 as input


(button)

Set PA1 as output


(LED)

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

Clear interrupt flag

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) {

// Main loop does nothing. LED controlled by interrupt.

void GPIO_Config(void) {

RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN;

GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0);

GPIOA->CRL |= GPIO_CRL_CNF0_1;

GPIOA->ODR |= GPIO_ODR_ODR0;

GPIOA->CRL &= ~(GPIO_CRL_MODE1 | GPIO_CRL_CNF1);

GPIOA->CRL |= GPIO_CRL_MODE1_1;

AFIO->EXTICR[0] &= ~AFIO_EXTICR1_EXTI0;

EXTI->IMR |= EXTI_IMR_MR0;

EXTI->FTSR |= EXTI_FTSR_TR0;

NVIC_EnableIRQ(EXTI0_IRQn);

}
void EXTI0_IRQHandler(void) {

if (EXTI->PR & EXTI_PR_PR0) {

GPIOA->ODR ^= GPIO_ODR_ODR1;

EXTI->PR |= EXTI_PR_PR0;

Result:

Thus, the demonstration of interrupt-based programming through GPIOs on an


STM32 microcontroller using external interrupt lines (EXTI) and handle them at the register
level was successfully executed.
EXPERIMENT 3

CONFIGURATION OF STM32 TIMER MODULE TO GENERATE


PERIODIC DELAYS
Aim:

To configure the STM32 Timer module to generate periodic time delays using
register-level programming.

Apparatus Required:

1. Personal Computer (PC).


2. STM32CubeIDE.
3. Keil µVision.
4. Proteus.
Algorithm:

1. Configure GPIO pin as output (e.g., PA1 for LED).


2. Enable clock for TIM2.
3. Set Prescaler (PSC) and Auto-reload (ARR) for desired delay.
4. Enable the timer.
5. Toggle the LED inside a loop or interrupt based on timer flag.

Theory:

• STM32 timers are hardware peripherals used for time-based operations.


• You can configure them to generate interrupts or perform actions at specific
intervals.
• Timer registers like PSC (Prescaler) and ARR (Auto-reload Register) help divide
the system clock and set the delay period.
• TIMx->CNT is the counter register that increments with each timer tick.

Procedure:

1. Initialize system clock.


2. Configure PA1 as output.
3. Enable TIM2 and set its PSC and ARR.
4. Start the timer.
5. Poll the UIF (Update Interrupt Flag) or use interrupt.
6. Toggle LED when the flag is set.
7. Clear the flag manually (if polling).
Flowchart:

Start

Enable GPIOA and


TIM2 clocks

Configure PA1 as
output pin

Set TIM2 PSC and


ARR for 1s delay

Start TIM2 counter

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) {

if (TIM2->SR & TIM_SR_UIF) {

TIM2->SR &= ~TIM_SR_UIF;

GPIOA->ODR ^= GPIO_ODR_ODR1;

void GPIO_Config(void) {

RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

GPIOA->CRL &= ~(GPIO_CRL_MODE1 | GPIO_CRL_CNF1);

GPIOA->CRL |= GPIO_CRL_MODE1_1;

void delay_init(void) {

RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;

TIM2->PSC = 7200 - 1;

TIM2->ARR = 10000 - 1;

TIM2->CR1 |= TIM_CR1_CEN; // Enable counter

}
Result:

Thus, the configuration of STM32 Timer module to generate periodic time delays
using register-level programming was successfully executed.
EXPERIMENT 4

PWM GENERATION USING PWM MODULE ON STM32


Aim:

To generate a Pulse Width Modulation (PWM) signal using Timer 3 (TIM3) on the
STM32F4 microcontroller and simulate it using Keil µVision.

Apparatus Required:

1. Personal Computer (PC).


2. STM32CubeIDE.
3. Keil µVision.
4. Proteus.
Algorithm:

1. Enable clocks for GPIOA and TIM3.


2. Configure PA6 as an alternate function (TIM3_CH1).
3. Set up TIM3 with a prescaler to achieve a 100 Hz PWM frequency.
4. Configure TIM3 in PWM mode 1.
5. Set the compare register (CCR1) for a 50% duty cycle.
6. Enable TIM3 to start generating the PWM signal.
7. Simulate and verify the waveform using Keil µVision.

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;

GPIOA->MODER &= ~(3U << (0 * 2));

GPIOA->MODER |= (2U << (0 * 2));

GPIOA->AFR[0] |= (1U << (0 * 4));

TIM2->PSC = 1600 – 1;

TIM2->ARR = 1000 – 1;

TIM2->CCR1 = 500;

TIM2->CCMR1 |= (6U << TIM_CCMR1_OC1M_Pos);

TIM2->CCMR1 |= TIM_CCMR1_OC1PE;

TIM2->CCER |= TIM_CCER_CC1E;

TIM2->CR1 |= TIM_CR1_CEN;

int main(void)

SystemInit();

PWM_Init();

while (1)

// Main loop - PWM is running

}
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

INTERFACING AN SPI BASED DISPLAY MODULE


Aim:

To implement Serial Peripheral Interface (SPI) communication using SPI1 on


STM32F4 and simulate data transmission using Keil µVision.

Apparatus Required:

1. Personal Computer (PC).


2. STM32CubeIDE.
3. Keil µVision.
4. Proteus.
Algorithm:

1. Enable clocks for GPIOA and SPI1.


2. Configure PA5 (SCK) and PA7 (MOSI) as alternate function SPI1.
3. Configure PA4 (CS) as an output and set it high (inactive).
4. Initialize SPI1 in master mode with a baud rate of fPCLK/16.
5. Enable SPI1.
6. Implement a function to send data via SPI1.
7. Initialize the display by sending necessary commands.
8. Transmit data in a loop while maintaining the CS signal.
9. Simulate and verify data transmission using Keil µVision.

Theory:

Serial Peripheral Interface (SPI) is a synchronous serial communication protocol used


for data exchange between microcontrollers and peripherals such as sensors, displays, and
memory devices. SPI operates in a master-slave configuration, using MOSI (Master Out
Slave In), MISO (Master In Slave Out), SCK (Serial Clock), and CS (Chip Select) signals.

In this experiment, SPI1 is configured in master mode to communicate with a display.


The SPI clock is set to fPCLK/16, and full-duplex mode is enabled. Data is transmitted over
MOSI, while CS is manually controlled to select the display.

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

Enable Clock for


GPIOA and SPI1

Configure PA5
(SCK), PA7
(MOSI) as
Alternate Function
(SPI1)

Configure PA4
(CS) as Output

Initialize SPI1 in
Master Mode

Set Baud Rate and


Enable SPI1

Send Initialization
Commands to
Display

Enter Loop: Send


Data via SPI1

Observe SPI
Communication in
Simulation

End
Program:

#include "stm32f4xx.h"

#define CS_PIN (1U << 4)

#define DC_PIN (1U << 6)

#define RST_PIN (1U << 7)

void SPI1_Init(void);

void SPI1_Transmit(uint8_t data);

void GPIO_Init(void);

void Display_Reset(void);

void Display_Command(uint8_t cmd);

void Display_Data(uint8_t data);

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) {

RCC->APB2ENR |= (1U << 12);

RCC->AHB1ENR |= (1U << 0);

GPIOA->MODER |= (2U << 10) | (2U << 14);

GPIOA->AFR[0] |= (5U << 20) | (5U << 28);

SPI1->CR1 = 0;

SPI1->CR1 |= (1U << 2);

SPI1->CR1 |= (3U << 3);

SPI1->CR1 |= (1U << 9);

SPI1->CR1 |= (1U << 8);

SPI1->CR1 |= (1U << 1);

SPI1->CR1 |= (1U << 0);

SPI1->CR1 |= (1U << 6);

void SPI1_Transmit(uint8_t data) {

while (!(SPI1->SR & (1U << 1)));

SPI1->DR = data;

while (SPI1->SR & (1U << 7));

void GPIO_Init(void) {

RCC->AHB1ENR |= (1U << 0);

GPIOA->MODER |= (1U << 8) | (1U << 12) | (1U << 14);

GPIOA->OTYPER &= ~(CS_PIN | DC_PIN | RST_PIN);

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

for (volatile int i = 0; i < 100000; i++);

GPIOA->BSRR = RST_PIN;

for (volatile int i = 0; i < 100000; i++);

void Display_Command(uint8_t cmd) {

GPIOA->BSRR = (DC_PIN << 16);

GPIOA->BSRR = (CS_PIN << 16);

SPI1_Transmit(cmd);

GPIOA->BSRR = CS_PIN;

void Display_Data(uint8_t data) {

GPIOA->BSRR = DC_PIN;

GPIOA->BSRR = (CS_PIN << 16);

SPI1_Transmit(data);

GPIOA->BSRR = CS_PIN;

void Display_Init(void) {

Display_Command(0x01);

for (volatile int i = 0; i < 100000; i++);


Display_Command(0x11);

for (volatile int i = 0; i < 100000; i++);

Display_Command(0x29);

Result:

Thus, the SPI communication was successfully implemented using SPI1 on


STM32F4. The data transmission was verified in Keil µVision using the virtual logic
analyser, confirming correct SPI signal generation and display initialization.
EXPERIMENT 6

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:

1. Personal Computer (PC).


2. STM32CubeIDE.
3. Keil µVision.
4. Proteus.
Algorithm:

1. ADC Interfacing with Audio Sensor:


1. Initialize the ADC peripheral.
2. Configure the ADC input pin as an analog input.
3. Start ADC conversion.
4. Read the ADC result register.
5. Convert the digital value to voltage and display it.
6. Repeat the process continuously.

2. ADC with DMA:


1. Enable the ADC and DMA clock.
2. Configure the ADC in continuous mode.
3. Configure DMA to transfer ADC values to a memory buffer.
4. Start ADC conversion.
5. Allow DMA to automatically transfer data.
6. Process the received data in the main loop.

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:

1. Interfacing an Audio Sensor with ADC:


1. Configure the ADC peripheral in single conversion mode for a 12-bit
resolution.
2. Connect the analog output of the audio sensor to the ADC input pin (e.g.,
PA0).
3. Configure the sampling time and enable continuous conversion mode.
4. Read ADC values and convert them to a voltage level.
5. Display the sampled values on a virtual oscilloscope in Keil µVision.

2. Using DMA to Read ADC Data:


1. Enable the ADC and DMA clock in the microcontroller.
2. Configure the ADC in continuous mode with DMA enabled.
3. Configure the DMA controller to transfer ADC data to a memory buffer.
4. Start ADC conversion and let DMA handle the data transfer automatically.
5. Monitor the transferred data in a watch window in Keil µVision.
Flowchart:

Start

Enable ADC and


GPIO Clocks

Configure ADC
for Single
Conversion Mode

Start ADC
Conversion

Read Digital Value


from ADC Register

Convert to Voltage
Level

Display or Store
Data

Repeat Process

End
Program:

1. ADC Interfacing with Audio Sensor:

#include "stm32f4xx.h"

#define ADC_CHANNEL 0

void ADC_Init(void);

uint16_t Read_ADC(void);

void ADC_Init(void) {

RCC->APB2ENR |= (1 << 8);

RCC->AHB1ENR |= (1 << 0);

GPIOA->MODER |= (3 << (ADC_CHANNEL * 2));

ADC1->CR2 |= (1 << 0);

ADC1->SQR3 = ADC_CHANNEL;

ADC1->CR2 |= (1 << 30);

uint16_t Read_ADC(void) {

while (!(ADC1->SR & (1 << 1)));

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) {

RCC->APB2ENR |= (1 << 8);

RCC->AHB1ENR |= (1 << 0);

RCC->AHB1ENR |= (1 << 22);

GPIOA->MODER |= (3 << (ADC_CHANNEL * 2));

ADC1->CR2 |= (1 << 1);

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;

DMA2_Stream0->CR |= (1 << 10) | (1 << 8) | (1 << 6);

DMA2_Stream0->CR |= (1 << 0);

ADC1->CR2 |= (1 << 8);

ADC1->CR2 |= (1 << 0);

ADC1->CR2 |= (1 << 30);

int main(void) {

ADC_DMA_Init();
while (1) {

// Data is automatically transferred to adcBuffer[]

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

CREATE A PROJECT TO DEVELOP PWM BASED SPEED CONTROL


OF DC MOTOR USING POTENTIOMETER CONNECTED TO STM32
GPIO
Aim:

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:

1. Personal Computer (PC).


2. STM32CubeIDE.
3. Keil µVision.
4. Proteus.
Algorithm:

1. Initialize GPIO, ADC, and Timer* in STM32.


2. Read the analog value* from the potentiometer using *ADC*.
3. Map the ADC value* (0-4095) to *PWM duty cycle* (0-100%).
4. Set the PWM duty cycle* based on the ADC value.
5. Update PWM continuously* to control motor speed.

Theory:

PWM (Pulse Width Modulation):

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.

STM32 PWM Working:

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:

1. Connect the Potentiometer:


i. One terminal to 3.3V.
ii. Second terminal to GND.
iii. Wiper (middle pin) to PA0 (ADC1_IN0).
2. Connect the Motor Driver (L298N) to STM32:
i. PWM output (PA1 - TIM2_CH2) to IN1 of L298N.
ii. Enable Pin of L298N to 5V.
iii. Motor connected to OUT1 and OUT2 of L298N.
iv. 12V power to the L298N.
3. Initialize STM32 registers for ADC and PWM.
4. Read ADC values continuously and adjust the PWM duty cycle accordingly.
5. Observe motor speed changes based on potentiometer adjustments.
Flowchart:

Start

Initialize GPIO,
ADC, Timer

Read Analog
Value from
Potentiometer
using ADC

Map ADC Value to


PWM Duty Cycle

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

pwm_duty = (adc_value * 1000) / 4095;

TIM2->CCR2 = pwm_duty;

void GPIO_Config(void) {

RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;

GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0);

GPIOA->CRL &= ~(GPIO_CRL_MODE1 | GPIO_CRL_CNF1);

GPIOA->CRL |= (GPIO_CRL_MODE1_1 | GPIO_CRL_MODE1_0);


GPIOA->CRL |= GPIO_CRL_CNF1_1;

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;

while (!(ADC1->SR & ADC_SR_EOC));

return ADC1->DR;

void TIM2_PWM_Config(void) {

TIM2->PSC = 71;

TIM2->ARR = 1000;

TIM2->CCMR1 |= TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2;

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

was successfully executed.


EXPERIMENT 8

PROJECT TO CREATE MULTIPLE FREE RTOS TASKS WITH

DIFFERENT PRIORITIES, IMPLEMENTATION OF DELAY

FUNCTIONS AND DELETE TASKS DYNAMICALLY


Aim:

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:

1. Personal Computer (PC).


2. STM32CubeIDE.
3. Keil µVision.
4. Proteus.
Algorithm:

1. Initialize STM32 hardware and FreeRTOS kernel.


2. Create multiple tasks with different priorities.
3. Implement delay functions inside tasks.
4. Use a button to trigger task deletion dynamically.
5. Observe task execution sequence.

Theory:

FreeRTOS is a real-time operating system (RTOS) that provides multitasking by


allowing multiple tasks to run concurrently based on their priority.

Task Priorities:

1. Each task is assigned a priority level.


2. Higher priority tasks pre-empt lower priority ones.

Task Delay Functions:

1. vTaskDelay() suspends a task for a specified time.


2. vTaskDelete() dynamically removes a task.

Dynamic Task Deletion:

1. Tasks can be deleted at runtime using vTaskDelete().


2.
Procedure:

1. Initialize the STM32 system clock and GPIO.


2. Enable FreeRTOS kernel and create tasks.
3. Assign different priorities to tasks.
4. Introduce delays using vTaskDelay().
5. Use vTaskDelete() to remove a task dynamically.
6. Observe LED toggling sequences (indicating task execution).
Flowchart:

Start

Initialize STM32
GPIO and Clock

Create Task1 Create Task2 Create Task3


(Low Priority - (Medium Priority - (High Priority -
LED1) LED2) LED3)

Create Button
Task (Highest
Priority)

Start FreeRTOS
Scheduler

Task1: Toggle Task2: Toggle Task3: Toggle


LED1 every 1 sec LED2 every 500ms LED3 every
300ms

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 Task1(void *pvParameters);

void Task2(void *pvParameters);

void Task3(void *pvParameters);

void Button_Task(void *pvParameters);

TaskHandle_t Task2_Handle = NULL;

TaskHandle_t Task3_Handle = NULL;

void GPIO_Config(void);

int main(void) {

GPIO_Config();

xTaskCreate(Task1, "Task 1", 128, NULL, 1, NULL);

xTaskCreate(Task2, "Task 2", 128, NULL, 2, &Task2_Handle);

xTaskCreate(Task3, "Task 3", 128, NULL, 3, &Task3_Handle);

xTaskCreate(Button_Task, "Button Task", 128, NULL, 4, NULL);

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

GPIOA->CRL |= GPIO_CRL_MODE1_1;

GPIOA->CRL &= ~(GPIO_CRL_MODE2 | GPIO_CRL_CNF2);

GPIOA->CRL |= GPIO_CRL_MODE2_1;

GPIOA->CRL &= ~(GPIO_CRL_MODE3 | GPIO_CRL_CNF3);

GPIOA->CRL |= GPIO_CRL_MODE3_1;

void Task1(void *pvParameters) {

while (1) {

GPIOA->ODR ^= GPIO_ODR_ODR1;

vTaskDelay(pdMS_TO_TICKS(1000));

void Task2(void *pvParameters) {

while (1) {

GPIOA->ODR ^= GPIO_ODR_ODR2;

vTaskDelay(pdMS_TO_TICKS(500));

void Task3(void *pvParameters) {

while (1) {
GPIOA->ODR ^= GPIO_ODR_ODR3;

vTaskDelay(pdMS_TO_TICKS(300));

void Button_Task(void *pvParameters) {

while (1) {

if (!(GPIOA->IDR & GPIO_IDR_IDR0)) {

vTaskDelete(Task2_Handle);

GPIOA->ODR &= ~GPIO_ODR_ODR2;

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.

You might also like