Advanced Microcontroller Laboratory External Questions
Assembly Programs (Part A)
1. Write an assembly program to copy 10 of 32 bit data from source to
destination.
(Data: 0x12345678, 0x23456781, 0x34567821, 0x45678123, 0x56781234,
0x67812345, 0x78123456, 0x81234567, 0x92345678, 0xA2345678)
.syntax unified
.thumb
.thumb_func
.global main
main:
LDR R0, =source
LDR R1, =destination
MOV R2, #10
loop1:
LDR R3, [R0]
STR R3, [R1]
ADD R0, R0, #4
ADD R1, R1, #4
SUB R2, R2, #1
CMP R2, #0
BNE loop1
stop:
B stop
source:
.word 0x12345678, 0x23456781, 0x34567821, 0x45678123, 0x56781234
.word 0x67812345, 0x78123456, 0x81234567, 0x92345678, 0xA2345678
destination:
.data 40
2. Write an assembly program to copy a string from source to destination in
byte-byte sequence. (String: Exchange data)
.syntax unified
.thumb
.thumb_func
.global main
main:
LDR R1, =srcstr // Load source address into R1
LDR R0, =dststr // Load destination address into R0
BL strcpy // Call subroutine
stop:
B stop // Infinite loop
strcpy:
LDRB R2, [R1], #1 // Load byte from source and increment
STRB R2, [R0], #1 // Store byte to destination and increment
CMP R2, #0 // Check for null terminator
BNE strcpy // Loop until end of string
BX LR // Return from subroutine
// Define null-terminated source string
srcstr:
.string "Exchange data"
// Reserve destination space
dststr:
.space 30
3. Write an Assembly program to check whether the string stored at location
“string” is a palindrome or not. (Example String: MADAM)
.syntax unified
.thumb
.thumb_func
.global main
main:
LDR R0, =string // R0 = start of string
MOV R1, R0 // R1 = pointer to end search
find_end:
LDRB R2, [R1], #1 // Move R1 to null terminator
CMP R2, #0
BNE find_end
SUB R1, R1, #2 // Go back to last character (before null)
B Pal
stop:
B stop
Pal:
MOV R7, #0x0E // Default: not palindrome
again:
CMP R0, R1 // Check if pointers crossed or met
BHS yespal
LDRB R3, [R0], #1 // Load from front
LDRB R4, [R1], #-1 // Load from end
CMP R3, R4 // Compare both
BNE notpal
B again // Continue if equal
yespal:
MOV R7, #0x01 // Set palindrome flag
B done
notpal:
B done
done:
MOV PC, LR // Return
string:
.string "MADAM"
4. Implement subroutine nesting using stack
.syntax unified
.thumb
.thumb_func
.global main
.text
main:
MOV R0, #0x75 // Initialize R0
MOV R3, #5
PUSH {R0, R3} // Push R0 and R3 onto the stack
MOV R0, #6
MOV R3, #7
POP {R0, R3} // Restore values back to R0 and R3
Loop:
ADD R0, R0, #1
CMP R0, #0x80
BNE Loop // Loop until R0 == 0x80
MOV R1, #9
BL subroutine // Call the subroutine
MOV R3, #12 // Final value in R3
B. // Infinite loop (hold)
// Subroutine that introduces delay
subroutine:
PUSH {R1, LR}
MOV R1, #8
delay:
SUBS R1, R1, #1
BNE delay
POP {R1, PC}
5. Write an assembly program to compute the given Boolean expression and
store the result. (Boolean Expression: AB|~CB|ABC)
.syntax unified
.thumb
.thumb_func
.global main
.text
main:
// Load A, B, C values from memory
LDR R0, =A
LDR R3, [R0] // R3 = A
LDR R0, =B
LDR R4, [R0] // R4 = B
LDR R0, =C
LDR R5, [R0] // R5 = C
// ----- Compute intermediate terms -----
AND R6, R3, R4 // R6 = A & B (AB)
AND R7, R4, R5 // R7 = B & C (CB)
MVN R8, R7 // R8 = ~(B & C) (~CB)
AND R9, R5, R6 // R9 = C & (A & B) (ABC)
// ----- Combine: (AB | ~CB)
ORR R10, R6, R8 // R10 = AB | ~CB
ORR R10, R10, R9 // R10 = AB | ~CB | ABC (same as AB|~CB)
// Store result to memory for inspection
LDR R0, =RESULT
STR R10, [R0]
stop:
B stop // Halt here for debugger
// ---------------- Data Section ----------------
.data
.align 4
// >>> EDIT these 3 test values if you like <<<
// I’ve given distinct patterns so you can “see” the bitwise effects in debugger.
A: .word 0x0F0F0F0F
B: .word 0x33333333
C: .word 0xAAAAAAAA
RESULT: .word 0 // Output written here
.end
6. Convert word of little endian format to big endian format.
(Input: 0x12345678)
.syntax unified
.thumb
.thumb_func
.global main
.text
main:
// Load a 32-bit word in little endian format (for testing)
LDR R0, =0x12345678 // Input: 0x12345678
// Extract and shift each byte to its new position
// Byte 0 -> Byte 3
AND R1, R0, #0x000000FF // Extract byte 0
LSL R1, R1, #24 // Move to byte 3 (MSB)
// Byte 1 -> Byte 2
AND R2, R0, #0x0000FF00
LSL R2, R2, #8
// Byte 2 -> Byte 1
AND R3, R0, #0x00FF0000
LSR R3, R3, #8
// Byte 3 -> Byte 0
AND R4, R0, #0xFF000000
LSR R4, R4, #24
// Combine all
ORR R0, R1, R2
ORR R0, R0, R3
ORR R0, R0, R4
B . // Hold for inspection
Interfacing Programs (Part B)
1. Keypad Program
To design and implement a keypad interface program on the ARM
Cortex-M4 microcontroller that performs row-column scanning to detect
key presses from a 4x8 matrix keypad, identifies the specific key based
on its position, and prints the exact corresponding value to the serial
console. The program includes Detection of numeric keys (00 to
09),Special characters like ., +, -, x, /, %, Function keys like AC, CE, CHK,
=,Memory keys: MC, MR, M-, and M+.
Debounce delay is added to ensure accurate key detection. The program
uses a switch-case structure to print the key values in a user-readable
format upon each valid key press.
#include <MK66F18.h>
#include <stdio.h>
#include <stdlib.h>
#include"MK66_I2C_Functions.h"
int getkey(void);
int main()
{
I2C_init();
while(1)
getkey(); /* Call Getkey method */
}
int getkey(void)
{
unsigned char i,j,k,indx,t;
indx = 0x00; /* Index for storing the first value of */
for(i=0x00E;i>=0x00B;i<<=1) /* for 4 scanlines */
{
portC_write(i,0xFF); /* write data to scanline */
Read_portAB();
t = IF_PortA_Read_Value; /* Read readlines connected to P0*/
t = ~t;
if(t>0) /* If key press is true */
{
delay(6000); /* Delay for bouncing */
for(j=0;j<=7;j++) /* Check for 8 lines */
{
t >>=1;
if(t==0) /* if get pressed key*/
{
k = indx+j; /* Display that by converting to Ascii */
switch(k)
{
case 0x00: printf("\rkey Pressed = 00 ");
break;
case 0x01: printf("\rkey Pressed = 01 ");
break;
case 0x02: printf("\rkey Pressed = 02 ");
break;
case 0x03: printf("\rkey Pressed = 03 ");
break;
case 0x04: printf("\rkey Pressed = 04 ");
break;
case 0x05: printf("\rkey Pressed = 05 ");
break;
case 0x06: printf("\rkey Pressed = 06 ");
break;
case 0x07: printf("\rkey Pressed = 07 ");
break;
case 0x08: printf("\rkey Pressed = 08 ");
break;
case 0x09: printf("\rkey Pressed = 09 ");
break;
case 0x0A: printf("\rkey Pressed = . ");
break;
case 0x0B: printf("\rkey Pressed = + ");
break;
case 0x0C: printf("\rkey Pressed = - ");
break;
case 0x0D: printf("\rkey Pressed = x ");
break;
case 0x0E: printf("\rkey Pressed = / ");
break;
case 0x0F: printf("\rkey Pressed = %% ");
break;
case 0x10: printf("\rkey Pressed = AC ");
break;
case 0x11: printf("\rkey Pressed = CE");
break;
case 0x12: printf("\rkey Pressed = CHK");
break;
case 0x13: printf("\rkey Pressed = = ");
break;
case 0x14: printf("\rkey Pressed = MC");
break;
case 0x15: printf("\rkey Pressed = MR ");
break;
case 0x16: printf("\rkey Pressed = M- ");
break;
case 0x17: printf("\rkey Pressed = M+ ");
break;
}
return k;
}
}
}
indx += 8; /* If no key pressed increment index */
}
return 0;
}
2. Stepper Motor Program
To implement a program on the ARM Cortex-M4 microcontroller that
controls a stepper motor's rotation in both clockwise and anticlockwise
directions, using an interrupt-driven mechanism. The program features:
Initialization of PORTC pin 19 as an external interrupt input, which on
trigger toggles the motor's direction.
Clockwise rotation: Executed by sequentially energizing coils with the
pattern 0x88 → 0x44 → 0x22 → 0x11.
Anticlockwise rotation: Achieved by reversing the sequence: 0x11 →
0x22 → 0x44 → 0x88.
Rotation direction is printed on the terminal as "Clockwise" or
"AntiClockwise" each time the direction is toggled.
This setup allows dynamic direction control based on external input
(e.g., button press), showcasing the use of interrupts for motion control.
#include <stdio.H>
#include <MK66F18.h>
#include <stdio.h>
#include <stdlib.h>
#include"MK66_I2C_Functions.h"
void PORTC_IRQHandler(void);
void Direction(void);
void PORTC_IRQHandler(void)
{
PORTC_PCR19 |=(1<<24);
Direction();
}
static unsigned char Dir=0x00;
void Direction(void)
{
Dir = ~Dir; /* Reverse the Direction */
if(Dir)
printf(" Clockwise\n");
else
printf(" AntiClockwise\n "); /* Display "Anti Clockwise" on LCD */
}
int main()
{
SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;
PORTC_PCR19 = PORT_PCR_MUX(0x1); // GPIO is alt1 function for this pin
PORTC_PCR19 |= PORT_PCR_IRQC(0x9);
NVIC_EnableIRQ(PORTC_IRQn);
I2C_init();
printf(" Stepper Motor\n");
printf(" AntiClockwise\n");
while(1)
{
if(Dir) /* Clockwise Direction */
{ /* Write data for clock wise direction*/
portAB_write(0x88,0x00);
delay(60000);
portAB_write(0x44,0x00);
delay(60000);
portAB_write(0x22,0x00);
delay(60000);
portAB_write(0x11,0x00);
delay(60000);
}
else /* AntiClockwise Direction */
{ /* Write data for anti-clock wise direction*/
portAB_write(0x11,0x11);
delay(60000);
portAB_write(0x22,0x22);
delay(60000);
portAB_write(0x44,0x44);
delay(60000);
portAB_write(0x88,0x88);
delay(60000);
}
}
3. Seven Segment Display Program
To implement a program on the ARM Cortex-M4 microcontroller that
interfaces with a seven-segment display and continuously cycles through
values stored in a 2x4 character display array, displaying each character
using bitwise segment control. Features include:
Use of a 2D array display[2][4] containing 7-segment codes.
Array = { {0xc1,0xc6,0xc7,0xff}, {0xc1,0xc6,0xc7,0xff}};
Sequential display of 8 values (4 per row) by scanning through rows and
columns.
Bit-by-bit serial output to the display using GPIO pins and shift
operations.
Adequate delay is inserted to ensure visibility of each character.
This program verifies segment control logic, timing synchronization, and
character visualization on a seven-segment display.
#include <MK66F18.h>
#include <stdio.h>
#include <stdlib.h>
#include"MK66_I2C_Functions.h"
unsigned char display[2][4] = { {0xc1,0xc6,0xc7,0xff},
{0xc1,0xc6,0xc7,0xff}};
int main()
{
unsigned int i,j,k,s,m,a;
I2C_init();
delay(600);
delay(600);
portC_write(0x01,0x00);
portC_write(0x00,0x00);
while(1)
{
for(i=0;i<2;i++)
{
for(j=0;j<4;j++)
{
s = display[i][j];
for(k=0;k<8;k++)
{
m = s;
m = m & 0x80;
if(m == 0)
portAB_write(0x00,0x00);
else
portAB_write(0x00,0x01);
portC_write(0x01,0x00);
portC_write(0x00,0x00);
s <<= 1;
}
for(a=0; a<51; a++)
delay(900000);
}
}
}
return 0;
}
4. Dual DAC Program
To implement a waveform generation system using the Dual DAC
interface on the ARM Cortex-M4, capable of producing three distinct
analog waveforms based on user selection from the terminal input. The
program supports: 1) Square Wave: Generated by toggling the DAC
output between 0x00 (low) and 0xFF (high) continuously.
2) Triangular Wave: Formed by linearly increasing from 0x00 to 0xFF and
then decreasing back to 0x00.
3) Ramp (Sawtooth) Wave: Produced by continuously increasing output
from 0x00 to 0xFF and resetting.
The user is prompted via the serial console to enter 1, 2, 3, to select the
waveform. The program loops the chosen waveform indefinitely until
reset. Input validation is included to ensure only valid waveform options
are processed.
#include <MK66F18.h>
#include <stdio.h>
#include <stdlib.h>
#include"MK66_I2C_Functions.h"
int main()
{
unsigned int i=0;
I2C_init();
while(1)
{
printf("\nSelect number for desired Waveform\n\t 1- Square\n\t 2- Triangular \n\t 3-
Ramp/Sawtooth \n\t 4- Sine\n");
switch(getchar())
{
case '1' :
printf("\nPressed 1: Square Wave is Selected\n");
while(1) //square wave
{
portAB_write(0xFF,0xFF); //positive cycle
portAB_write(0x00,0x00); //negative cycle
}
case '2' :
printf("\nPressed 2: Triangular Wave is Selected\n");
while(1) // triangular wave
{
for(i=0;i<0xFF;i++) //rising slope
portAB_write(i,i);
for(i=0xFF;i>0;i--) //falling slope
portAB_write(i,i);
}
case '3' :
printf("\nPressed 3: Ramp/Sawtooth Wave is Selected\n");
while(1) //ramp or sawtooth wave
{
for(i=0;i<0xFF;i++) //rising slope
portAB_write(i,i);
}
case '4' :
printf("\nPressed 4: Sine Wave is Selected\n");
while(1) //sine wave
{
for(i=0;i<0xFF;i++)
portAB_write(a[i],a[i]);
}
default :
printf("\n Oops invalid Character\n ");
}
}
}