Handling multiple input signals
Version #2 – co-operative scheduler
Version #3 – pre-emptive scheduler
Midterm question
Light sensor is in front of the door
+5V
Light signs on light sensor
If person blocking light – light
sensor output is low -- Active low
logic
Output of light sensor connected to
PF5
Program stops “immediately” when
owner pushes and releases a
button.
10k
resistor
PF6
Button connected to PF6 line
Show the count of the people on
the LCD using WriteLCD( int
count).
GROUND
GROUND
Design component
Key part of the design – Neither action must block the other action
Light sensor
If high – nobody has ever blocked the sensor, or somebody has blocked
the sensor at moved on
If low – somebody is still blocking the sensor
Must count “1 person enter or leave” as the signal goes from low to high
Button
If high – owner has not pressed the button or else has pressed the button
and released it.
If low – is pressing the button – people can still be entering and leaving
store.
Must stop the program as the signal goes from low to high
Approach #1 – Superloop approach
based on Lab. 1 ideas
While (loop is not stopped) {
Read GPIO Flags
4 possible things possible
At least 2 true at the same time
1.
2.
3.
4.
Light sensor PF 5 is high
Light sensor PF 5 is low
Button PF 6 is high
Button PF 6 is low
We want to take action – on the “edge of the signal”.
We don’t want to take action on the “level of the signal”
}
One solution for the code
int count = 0;
int stop = 0;
#define PF5Mask 0x20
int oldPF5state = 0;
int Midterm(void) {
InitAllInterFaces( );
oldPF5State = ReadGPIOASM( ) & PF5Mask ;
While (stop != 1) {
int newPF5State = ReadGPIOASM( ) & PF5Mask ;
If PF5 was high before and high now – do nothing
If PF5 was low before and low now – do nothing
If PF5 was high before and low now – do nothing
If PF5 was low before and high now – ACT
if ( (oldPF5State == 0) && (newPF5State == PF5Mask) ) count++;
WriteLCD(count);
oldPF5State = newPF5State
You write the other code for the button
}
return count;
}
Using Lab. 2 ideas
Co-operative Scheduler
TTCOS_Init_Scheduler( );
press buttons
// Assume Ticks occur every 1 ms – which is faster than people move or
TTCOS_Add_Task(InitInterfaces, 0, 0)
TTCOS_Add_Task(WriteToLCD, 50, 100); // Update LCD every 1/10 second – faster than the eye
// These tasks ONLY work if no task waits, and no task causes an interrupt
TTCOS_Add_Task(Count_People, 5, 10); // Worry about people moving
TTCOS_Add_Task(CheckButton, 6, 10);
// Worry about the button being pressed
TTCOS_Add_Task(Stop_System, 7, 10);
// Do we need to stop the system
TTCOS_Star_Scheduler( );
While (1) {
TTCOS_GoToSleep( );
TTCOS_DispatchTasks( );
}
Using Lab. 2 ideas
Co-operative Scheduler
int count_G = 0;
int stop_G = 0;
int oldState_G = 0;
void InitInterfaces(void) {
FINAL EXAM HINT
InitAllInterfaces( );
oldState_G = ReadGPIO( ) & PEOPLEMASK;
You write
}
the code for
void WriteToLCD(void) {
WriteLCD(count_G); 50, 100); }
CheckButton( )
void Count_People(void) {
and convert into
int newstate = ReadGPIO( ) & PEOPLEMASK;
assembly code
if ( (oldstate == 0) && (newState == PEOPLEMASK) ) count_G++;
oldState = newState;
}
void StopSystem(void) {
static systemStopped = 0;
if (systemStopped == 1) return;
if (stop_G == 1) {
TTCOS_Stop(WriteToLCD); TTCOS_Stop(CountPeople); TTCOS_Stop(CheckButton)
systemStopped = 1;
}
}
Using Lab. 2 ideas
Event Driven Using Interrupts
InitAllInterfaces( );
SetUpPFInterrupts( );
StartPFInterrupts( );
while (1) {
/* Wait for interrupts to occur in the background */
idle( );
-- Low power mode
}
void InitAllInterfaces(void) {
InitLEDs( );
InitLCDScreen( );
// Init GPIO using C/C++
*pFIO_DIR = 0; // Do properly with AND and OR
*pFIO_MASKA_D = 0; // All interrupts off – channel 1
*pFIO_MASKB_D = 0; // All Interrupts off – channel 2
*pFIO_POLAR = 0;
*pFIO_EDGE = 0;
// Will become very important
*pFIO_BOTH = 0;
// Will become important
*pFIO_INEN = 0x0600; need PF5 (0x20) and PF6 (0x40);
}
PF registers
Direction, Data, Polarity and Enable all the same from Lab. 1
Flag Mask registers – 14-11
Flag mask Interrupt data register – basically which
PF pins have been set to allow to cause interrupt
Flag mask Interrupt Set register – sets PF pin that is allowed to
cause an interrupt, without the need for a read – or mask – write
operation
Flag Mask Interrupt Clear register – which PF pin is no longer
allowed to cause an interrupt without the need for a read – and
mask – write operation
Flag interrupt Sensitivity register (FIO_EDGE) –
set for edge-sensitive
FIO_BOTH allows you to cause interrupts on “both” leading
and trailing edges of PF signals
7/31/2017
Thermal Arm Wrestling,
Copyright M. Smith, ECE, University of Calgary,
Canada
10 / 24 + extras
EX_INTERRUPT_HANDLER(PFInter)
All PF interrupts are multiplexed. That
means any interrupt on PF line gets to
same ISR
We get here if
PF5 line goes from low to high
PF6 line goes from low to high
How do we know which one interrupted
If PF5 interrupt then FIO_FLAG bit 5 is high
If PF6 interrupt then FIO_FLAG bit 6 is high
Interrupt routine looks like this
#define BIT5 0x20
#define BIT6 0x40
extern volatile int count;
extern volatile int stop;
EX_INTERRUPT_HANDLER(PFInterrupt) {
short int whichInterrupt = *pFIO_FLAG_D & (BIT6 | BIT5);
// Brackets around (BIT6 | BIT5); very important in Quiz 3
if ( (whichInterrupt & BIT5) == BIT5) { // Brackets important in Quiz 3
count++;
*pFIO_FLAG_D &= ~BIT5; // Clear interrupt bit
or
*pFIO_FLAG_C = BIT5;
// Clear interrupt bit
}
}
if ( (whichInterrupt & BIT6) == BIT6) { // Brackets important in Quiz 3
stop = 1;
*pFIO_FLAG_D &= ~BIT6; // Clear interrupt bit
or
*pFIO_FLAG_C = BIT6;
// Clear interrupt bit
}
// Can you translate this into assembly code for post-lab quiz 3
Getting interrupts to work
void SetUpInterrupts( ) {
//
SetUp_VectorTable( );
Lab. 3
//
SetUp_IMASK( );
Lab. 3
register_handler(ik_ivg12, PFInterrupt);
SetUp_SIC_MASK( );
SetUp_PFLinesForInterrupts( );
}
Lab. 3
Lab. 3
Getting interrupts to
work
void SetUpInterrupts( ) {
//
//
//
SetUp_VectorTable( );
Lab. 2
SetUp_IMASK( ); Lab. 2
register_handler(ik_ivg12, PFInterrupt);
SetUp_SIC_MASK( );
Lab. 2
*pSIC_IMASK = 0x00100000
// SetUp_PFLinesForInterrupts( );
*pFIO_FLAG_D = 0;
// In case interrupt waiting
*pFIO_MASKA_S = (BIT5 | BIT 6);
}
void StartInterrupts( ) {
*pFIO_FLAG_C = (BIT4 | BIT5); // Waiting
*pFIO_MASKA_D = (BIT4 | BIT5); Lab. 2
}
Other approaches
We could
Use PF Interrupt A
for PF5 line
and PF Interrupt B
for PF6 line
Writing 2 ISR’s
Example interrupt routine In
assembly code
Design the code
Start the special ISR instructions
Write “the subroutine” part of the ISR
Finish the special ISR instructions
Test the code
Optimize for FAST ISR
ISR routines are marked for efficiency
Design the code
Fix the easy bits
-- Unoptimized code okay at this point
Add in the code
HINT:
Easier to optimize
if use higher registers first
Optimize the code – save ONLY the
registers used
ENTER 10 cyles
205 1+
206 1+
207
6+
209
2+4
210
1+
211
1
2121
214
1
215
1?
216
2
217
2+4
218
1
224 5 jump
Missing ssync( )
236 RTI 10 cycles
© Copyright 2026 Paperzz