Asignment-4 CME 331 Total marks: 20 Submission Date: 14th November 2020
1. [3+3 Marks] Compare the following terms/units given in the left column and complete the table.
Items/units to compare Item-1 Item-2
Data memory vs. Holds the variables and results Holds the program's instruction and
Program memory temporarily and maybe overwritten while constant values to be executed and cannot
(type and purpose) running a program. be changed during execution.
External vs. Internal Asynchronous to the CPU is used to Generated by internal functional blocks or
interrupt respond to the external events any software specific exceptions. It is used
(operation and synchronously. Comes through hardware to keep internal I/O-CPU synchronization
application point of pins of the MCU. and to control software execution flow.
view)
Interrupt vector vs. Are fixed program memory address for Registers holding program memory
stack pointers specific interrupt sources, used to call ISR addresses (which may not be fixed), used
(functional and to return to the main program after the
application point of end of a subroutine / ISR.
view)
Interrupt vs. polling Advantage: Proper utilization of the CPU Advantage: Simple programming logic.
(using software loop) resources, and parallel processing. Disadvantage: CPU resources may be
based I/O reading Disadvantage: Programming complexity blocked.
(advantage may arise to prioritize while using
/disadvantage) multiple interrupts. May cause call back
/locking between ISRs.
2. [4 Marks] Write the sequential steps (or draw a flow diagram) that should be followed/ performed while using
an external interrupt in your program. [Hints: enabling the specific interrupt and their registers, I/O pin mode
changes, clearing the flags, writing an ISR, etc.]
1.) Define Registers for GPIO and NVIC registers
2.) Initialization:
a. GPIO Direction mostly as input
b. Enable GPIO pull-ups if needed
c. Enable clock gating for needed port
d. Disable all interrupt before configuration
e. Initialize /configure correct NVIC bits
f. Set interrupt signal type (edge /level / both)
g. Set priority of the interrupts
h. Enable interrupt (s)
3.) Write the interrupt handler
a. Set required SW flag (if needed)
b. Following steps can be done in ISR also-
i. Disable other interrupt (s) if required
ii. Execute the ISR functions (or Call the ISR)
iii. Clear interrupt flag
iv. Enable all interrupt (s)as needed or disabled at the beginning of this handler
4.) Write an ISR
a. If not done in step 3(b), can also be done here.
i. Disable other interrupt (s) if required
ii. Execute the ISR functions (or Call the ISR)
iii. Clear interrupt flag
iv. Enable all interrupt (s)as needed or disabled at the beginning of this handler
3. Design a stop-watch using the SysTick timer of Cortex-M4, according to the schematic shown in figure-1 (a).
The sample output is shown in figure 1 (b).
(a) (b)
Figure 1. (a) Schematic for the ST7735-LCD and switch(s) connection with the Launchpad. (b) Sample display on
the LCD.
Hints: PortF interrupt must be used to sense the switch press. SysTick interrupt should also be used to generate
a periodic interrupt after every one sec
a) [3 Marks] Write an algorithm using a flow diagram for the total system highlighting the following three
operations along with the main function, initialization, and proper implementation of the interrupts.
i. Switch press sensing
ii. One second signal using the SysTick
iii. Display-update function.
Main Loop (with display update) SysTick Handler PortF handler (Switch sensing)
b) [5 Marks] Write the program (c code) for the above (a) algorithm.
#include "ST7735.h"
#include "Systick.h"
//****************************DEFINITIONS****************************
//Port F
#define GPIO_PORTF_DATA (*((volatile unsigned long *)0x400253FC)) // p.615, data port, bit masking, p.608
#define GPIO_PORTF_DIR (*((volatile unsigned long *)0x40025400)) // p.616, set data flow direction
#define GPIO_PORTF_AFSEL (*((volatile unsigned long *)0x40025420)) // p.625, enable alternate functions
#define GPIO_PORTF_DEN (*((volatile unsigned long *)0x4002551C)) // p.636, make port digital
#define GPIO_PORTF_PUR (*((volatile unsigned long *)0x40025510)) // p.631, enable weak-pull-up, needed for SW1 and SW2
// register declaration: special code to activate SW2 (PF0)
#define GPIO_PORTF_LOCK (*((volatile unsigned long *)0x40025520)) // p.637, enable write access to GPIO_PORTF_CR
#define GPIO_PORTF_CR (*((volatile unsigned long *)0x40025524)) // p.638, commit reg, lock-unlocks AFSEL, PUR, PDR, DEN
// Nested Vectored Interrupt Controller (NVIC)
// SysTick info p.118
#define NVIC_ST_CTRL (*((volatile unsigned long *)0xE000E010)) // p.133, SysTick control and status
#define NVIC_ST_RELOAD (*((volatile unsigned long *)0xE000E014)) // p.135, 24-bit start value of SysTick
#define NVIC_ST_CURRENT (*((volatile unsigned long *)0xE000E018)) // p.136, 24-bit current value of SysTick
#define NVIC_SYS_PRI3 (*((volatile unsigned long *)0xE000ED20)) // p.167, System Handler Priority 3
// To use Port F interrupt
#define NVIC_EN0 (*((volatile unsigned long *)0xE000E100)) // p.137, IRQ 0 to 31 Set Enable Register
#define NVIC_PRI7 (*((volatile unsigned long *)0xE000E41C)) // p.147, IRQ 28 to 31 Priority
#define GPIO_PORTF_IS (*((volatile unsigned long *)0x40025404)) // p.617, int sense, 0 = edge, 1 = level
#define GPIO_PORTF_IBE (*((volatile unsigned long *)0x40025408)) // p.618, both edges
#define GPIO_PORTF_IEV (*((volatile unsigned long *)0x4002540C)) // p.619, int event, 0 = falling, 1 = rising
#define GPIO_PORTF_IM (*((volatile unsigned long *)0x40025410)) // p.620, int mask
#define GPIO_PORTF_MIS (*((volatile unsigned long *)0x40025418)) // p.622, masked int status, used here
#define GPIO_PORTF_ICR (*((volatile unsigned long *)0x4002541C)) // p.623, int flag clear, **must acknowledge**
// PLL registers
#define SYSCTL_RIS (*((volatile unsigned long *)0x400FE050)) // p.235
#define SYSCTL_RCC (*((volatile unsigned long *)0x400FE060)) // p.243
#define SYSCTL_RCGC2 (*((volatile unsigned long *)0x400FE108)) // p.249
//************Global Variables *************
unsigned int sw1_flag; // 1 = stop, 0 = run
unsigned int sec;
unsigned int min;
unsigned int bounce = 0;
unsigned int num_press;
//****************************INITIALIZATIONS****************************
void init_gpio (void) {
volatile unsigned long delay_clk; // delay for clock, must have 3 sys clock delay, p.424
SYSCTL_RCGC2 |= 0x00000020; // clock enable for port F, p.424
delay_clk = SYSCTL_RCGC2; // must delay for the clock to settle, no-operation
// Initial Port F
GPIO_PORTF_LOCK = 0x4C4F434B; //used to enable SW2
GPIO_PORTF_CR |= 0x1; //Allow access for control register
GPIO_PORTF_DIR &= ~0x11; //set PF4 (SW1) as input (value 0) (Switch 1)
GPIO_PORTF_AFSEL &= ~0x11; //disable alternate functions PF4 (page 672) (0 disabled; 1 enabled)
GPIO_PORTF_DEN |= 0x11; //enable digital functionality on PF1 - PF4 (page 683) (0 disabled; 1 enabled)
GPIO_PORTF_PUR |= 0x11; //enable pull-up resistor on PF4 (page 678) (0 diabled; 1 enabled)
}
// Initialization of PortF Interrupt, use 0x10 for SW1 (PF4) only, 0x01 for SW2 (PF0) only, and 0x11 for both
void init_portf_int (void)
{
GPIO_PORTF_IM &= ~0x11 ; // clear, disable (mask) int when config, p.609
GPIO_PORTF_IS &= ~0x11; // level sense for PF4 & PF0
GPIO_PORTF_IBE &= ~0x11; // not both edges for PF4 & PF0
GPIO_PORTF_IEV &= ~0x11; // falling edge event for PF4 & PF0
GPIO_PORTF_ICR = 0x11; // clear int flag
GPIO_PORTF_IM |= 0x11; // arm interrupt on PF4 & PF0 after configured
// we want INT30, i.e., 4n+2, 4*7+2, bits 23:21, we set priority level to say '5' ==> 101 => 1010 = A
NVIC_PRI7 = (NVIC_PRI7 & 0xFF0FFFFF)|0x00A00000; // priority 5, lower means higher priority
NVIC_EN0 = 0x40000000; // finally enable Interrupt # 30 (i.e., IRQ30 ==> bit 30 of NVIC_EN0), GPIO PortF
}
void init_SysTick (void)
{
NVIC_ST_CTRL = 0; // p.133, turn off SysTick during init
NVIC_ST_RELOAD = 16000000 - 1; // p.135, clock is 16MHz
NVIC_ST_CURRENT = 0; // any write to it clears it
NVIC_SYS_PRI3 = (NVIC_SYS_PRI3 & 0x00FFFFFF) | 0x40000000; // p.167, set priority 2 (bits 31:29)
NVIC_ST_CTRL = 0x07; // CLK_SRC = 1, INTEN = 1, ENABLE = 1
}
unsigned char hex2char(unsigned int hex)
{
if(hex <=0x09)
{
return (hex+0x30);
}
else if ( hex >=0x0A && hex <=0x0F)
{
return (hex+0x37);
}
else
{
return 0xFF;
}
}
void display_run (void){
ST7735_DrawChar(10, 10, 'R', ST7735_GREEN, 0, 2);
ST7735_DrawChar(25, 10, 'U', ST7735_GREEN, 0, 2);
ST7735_DrawChar(40, 10, 'N', ST7735_GREEN, 0, 2);
ST7735_DrawChar(55, 10, ' ', ST7735_GREEN, 0, 2);
}
void display_stop (void){
ST7735_DrawChar(10, 10, 'S', ST7735_RED, 0, 2);
ST7735_DrawChar(25, 10, 'T', ST7735_RED, 0, 2);
ST7735_DrawChar(40, 10, 'O', ST7735_RED, 0, 2);
ST7735_DrawChar(55, 10, 'P', ST7735_RED, 0, 2);
}
void display_count (void)
{
ST7735_DrawChar(10, 30, hex2char(min/10), ST7735_YELLOW, 0, 2); // Display 10's digit of count
ST7735_DrawChar(25, 30, hex2char(min%10), ST7735_YELLOW, 0, 2); // Display 1's digit of count
ST7735_DrawChar(40, 30, ':', ST7735_YELLOW, 0, 2); // Display 10's digit of count
ST7735_DrawChar(55, 30, hex2char(sec/10), ST7735_YELLOW, 0, 2); // Display 10's digit of count
ST7735_DrawChar(70, 30, hex2char(sec%10), ST7735_YELLOW, 0, 2); // Display 1's digit of count
}
int main(void) {
// Initialize ports
init_gpio();
init_portf_int ();
init_SysTick ();
// Initialize LCD display
ST7735_InitR(INITR_BLACKTAB); // Our display is actually BLACK TYPE of CHIP.
ST7735_FillScreen(ST7735_BLACK); // set screen to black
ST7735_SetRotation(3);
while(1)
{
if (sw1_flag)
{
display_run();
}
else
{
display_stop();
}
display_count();
}
}
void SysTick_Handler(void)
{
if (sw1_flag)
{
if (sec == 60)
{
if (min == 60)
{
min = 0;
}
else
{
min++;
}
}
else
{
sec++;
}
}
}
void GPIOPortF_Handler (void)
{
if (GPIO_PORTF_MIS &= 0x10) //0001 0000
{
sw1_flag = ~sw1_flag; // Flag to indicate SW1 has been pressed
}
if (GPIO_PORTF_MIS &= 0x01)
{
sec = 0;
min = 0;
}
GPIO_PORTF_ICR = 0x11;
}
c) [2 Marks] Write an algorithm using pseudocode for the same solution without using any interrupt.
1. Define all the registers
2. Configure & initialize the GPIO, other registers, and the LCD
3. Start a SW counter (CNT) for second counting on the scale of 10 mS.
4. Check the switches at every 100mS (using CNT)
5. Wait for a while to confirm switch press, if switch press detected.
6. Increase the second and/or minute values as required based on the CNT value
7. Update display at 1 S interval.
8. Initialize CNT to 0
9. Go to step 3