Input Laboratory: GPIO Pin control needed to have the Blackfin

advertisement
Input Laboratory:
GPIO Pin control needed to have the
Blackfin accept your commands
Re-uses information from ENEL353 and ENCM369
courses and text books combined with Blackfin DATA
manual to activate the Blackfin input device
(PF – programmable flags)
Reminder: How does a switch work?
The following – DOES NOT WORK
PRESS DOWN TO CLOSE
SPRING
TO CAUSE
SWITCH TO
OPEN AFTER
PUSH TO CLOSE
SWITCH OUTPUT
SWITCH INPUT
2 /25
One side of the switch must be pulled
“softly” to 3 V / 5V (pull up resistor).
Softly – Too much current -- device burn out / battery dead
3v
10k “PULL-UP”
resistor
I = V / R = ?? mA?
INPUT IS 3V
WHEN SWITCH
OPEN
PF8,
PF9, BLACKFIN
PF10 GPIO
LINES
PF11
INPUT IS 0V
WHEN SWITCH
CLOSED
GROUND (0V)
INPUT IS ???
WHEN SWITCH OPEN
3 /25
Blackfin has a GPIO data register
General purpose input/output
 16 GPIO lines come into the register
 Registers are based on flip-flops to store
(clocked)whether the input is 3V (high) or zero (low)
 16 flip flops put together make the FIO_FLAG_D
register
 The GPIO data register is memory mapped so no
special instructions needed, you “treat it (program it)
as if it was the same as any other memory locate”
 When you “read” from the GPIO register, you cause
a “load” of the input values into the flip-flop and out
onto the microcontroller’s data bus
4 /25
More details at
Registers used to control PF pins
www.electronics-tutorials.ws/logic/logic_9.html
This FIO_FLAG_D
HAS
PF 8, 9, 10, 11
DIRECTION IN
IN_ENABLE ON
PF 1, 5, 6, 7
DIRECTION OUT
NEED TO
CONFIGURE
DIRECTION
AND INPUT ENABLE
CONTROLREGISTERS
 Flag Data register (FIO_FLAG_D) -- READABLE
 Used to read the PF bits as an input -- (1 or 0)
AFTER DIRECTION / ENABLE CONTROL REGISTERS SET
 Need to read pins PF11 to PF8 ONLY, ignore all other pins values
 IGNORE MEANS -- Read 16-bit value, AND off unwanted bits, then use just bits 8 to 11
PF8
(PF1)
PF9
PF5
(PF6)
PF10
PF 7
PF11
5 /25
What we know about the way “front
panel” switches connected to BF533
SW1 is connected to PF8 input ofGPIO
SW2 is connected to PF9 input ofGPIO
SW3 is connected to PF10 input ofGPIO
SW4 is connected to PF11 input ofGPIO
The other pins in the GPIO interface are
used for “other” purposes on the Blackfin
board and MUST not have their values
changed e.g. Video device input port
6 /25
What we want to do?
Same as last Friday
LED code (and Lab. 0 code and Ass. 1 code)
using AND / OR MASKS but different application
Read the GPIO data register
Return (to programmer) ONLY the values in
pins 8 to 11. This means removing (masking
out) the other values (PF0 to PF7, PF12 to
PF15) which might have 1’s or 0’s in them
Value read from GPIO data register = 0x4723
 We only want to get the bits 0x0700 (SW1, SW2, SW3 pressed)
Value read from GPIO data register = 0x4023
 We only want to get the bits 0x0000 (no switches pressed)
Value read from GPIO data register = 0x4823
7 /25
 We only want to get the bits 0x0800 (SW4 pressed)
8 /25
What we have to code
using AND instructions with MASKs
MASK bit set to 1 for bits we keep, 0 for bits removed
#include <blackfin.h>
 IN_MASKALL = 0x0F00 (Bits 8, 9, 10, 11 are 1, other bits are
zero)
Value read from data register = 0x4623 (want PF8, 9, 10)
 IN_MASK89A set to 0x0700 -- Result = value & IN_MASK89A
 bit value result 0x0600 (SW2, SW3 on, SW1 off)
Value read from data register = 0x4123 (Want -- PF9 )
 IN_MASK9 set to 0x0200 -- Result = value & IN_MASK9
 Bit value results 0x0000 -- (SW2 (PF9) off)
.section program;
.global _ReadGPIOFlagsASM;
_ReadGPIOFlagsASM:
P0.L = lo(FIO_FLAG_D); P0.H = ……
R0 = W[P0] (Z); // Convert 16 bits to 32 bits
// via zero extension
// These are “bit settings” not a number
#define AND_MASK_ALLSW 0x0F00;
R1 = AND_MASK_ALLSW ; // Keep only bits 8, 9, 10, 11
// (connected to switches)
R0 = R0 & R1;
_ReadGPIOFlagsASM.END: RTS;
Value read from data register = 0x4923 (Want -- PF11)
 IN_MASK11 set to 0x0800 -- Result = value & IN_MASK11
 Bit value result 0x0800 – (SW4 (PF11) on)
9 /25
CODE DEFECT – Do review – syntax error (Where?)
FIRMWARE DESIGN DEFECT (Logical error) -- We
have not “initialized” the GPIO device interface (
“Initialize device” means “prepare the
device to make work”, in this case I / O
Always initialize device registers (part of
‘driver’ code) – Init_SwitchesASM( )
#include <blackfin.h>
.section program;
.global _ReadGPIOFlagsASM;
_ReadGPIOFlagsASM:
P0.L = lo(FIO_FLAG_D); P0.H = ……
………;
R0 = R0 & R1;
_ReadGPIOFlagsASM.END: RTS;
So the assembly code should look
something like this
11 /25
10 /25
Initialize the GPIO interface requires
change to many GPIO control registers
Turn the interrupts OFF for PF8 to PF11.
Do this WITHOUT changing the interrupt
behaviour for the other pins 0 to 7 and 12
to 15 (GPIO (hardware) MASK register)
Set the POLARITY register so that a 1
coming into pins PF8 to PF11 is read as a
HIGH (1). Do this without changing the
POLARITY behaviour of the other GPIO
pins 0 to 7 and 12 to 15 (GPIO POLAR )
Etc. etc.
12 /25
Assignment 1 – Software Coffeepot display control
Assignment 2 – Same Coffeepot Code
BUT display driven by PF interrupts
 If leave interrupts on, then a stray signal at the
GPIO input will cause the processor to “stop”
(crash) unless interrupts handled properly
 The GPIO POLAR register plays a big part of
how the processor reads values
Get the POLAR settings wrong causes very strange
behaviour where your code thinks things are working
when they are not, and thinks things are not working
when they are
Problems with Real-time operating system lab.
13 /25
So the GPIO_ INIT assembly code
looks something like this.
PPPP activated -- Lab 1 requirement
#include <blackfin.h>
.section program;
.global _InitGPIOFlagsASM; “LOOKS LIKE THIS” MEANS
_InitGPIOFlagsASM:
Pseudo code – concept okay, code perhaps not
CALL TurnInterruptsOff_PF8to11; // WHAT IS A CALL?
CALL SetPolarity_PF8to11;
CALL OtherStuff_PF8to11;
CALL SetDirection_PF8to1_CPP; // This code written in “C”
RTS;
// WHAT IS A RTS?
Lab. 1 – expectation
Demonstrate ability to Call C++ routines / functions from ASM
Call ASM routines / functions from ASM
 Set the DIRECTION register so that PF8 to
PF11 pins can be used as INPUT pinswithout
changing the behaviour of the other GPIO pins.
IF DONE INCORRECTLY CAN BURN OUT THE
CHIP. You don’t want a device sending a 1 to the
GPIO interface, while the interface is trying to output a
0. – Human microprocessor demo 
 AFTER all other initialization steps are complete
Set the ENABLE register so that pins PF8 to PF11
work without changing the behaviour of the other
GPIO pins. Power saving feature by turning off
unneeded input pins
14 /25
CALL and RTS instructions
Equivalents found on all processors
CALL -- Issued by “CALLEE” function to
cause “planned” entry to “CALLED” function
MUST include a “PLAN” to return to the “CALLEE”
function to execute the instructions after the CALL
instruction
RTS -- Issued by the “CALLED” function to
cause a “planned” re-entry to “CALLEE”
CALL Enable__PF8to11;
_InitGPIOFlagsASM.END:
Lab. 1 -- Initialize the GPIO interface
15 /25
MUST use the return “PLAN” set up by “CALLEE”
function to execute the instructions after the CALL
instruction (Otherwise processor hangs or
“Peter Pans” (Pans as a verb – Never-Never-Land)
16 /25
369 Review – How does the processor
handle instructions KNOW FOR QUIZZES
369 REVIEW : What if instruction is a
JUMP instruction?
Under control of BF533 program counter register (PC)
Repeat for ever
 Repeat for ever {
{
 Fetch an instruction (pointed to by PC)
 Increment the PC to point to ‘the next instruction
 Decode the instruction (work out what to do)
 Execute the instruction
 Write the instruction results back to registers or
Fetch an instruction (pointed to
by PC – at address N)
Increment the PC to point to
‘the next instruction’ (N + 1)
Decode the fetched instruction
(work out what to do)
Execute the fetched instruction
 Write the instruction results
back to registers or memory as
needed
memory as needed
If the instruction is a jump, then part of
the instruction is a label (address)
which must be put into PC so we
don’t fetch the NEXT instruction but
one further away in the code
17 /25
}
What if instruction is CALL? (often called
a JUMP TO SUBROUTINE instruction – JSR)
 Repeat for ever




 Write the instruction results back to registers or memory as needed
Fetch an instruction (pointed to by PC)
Increment the PC to point to ‘the next instruction
Decode the instruction (work out what to do)
Execute the instruction
Write the instruction results back to registers or memory as needed
If the instruction is a CALL (jump to function), then part of the
instruction is A PLAN to store a return address which must be put
into PC (during the “Called” RTS) so we can execute code in the
“CALLED” routines (MIPS link register – Blackfin RETS register)
}
If the instruction is a CALL (jump to
function), then part of the instruction is
A PLAN to store a return address
which must be put into PC (during the
“Called” RTS) so we can execute code
in the “CALLED” routines
(Firmware plan uses MIPS link
register – Blackfin RETS register)
18 /25
What if executing a RTS instruction?





Fetch an instruction (pointed to by PC)
Increment the PC to point to ‘the next instruction
Decode the instruction (work out what to do)
Execute the instruction
}
19 /25
If the instruction is return from subroutine
instruction (RTS) used by “CALLED” then we must
get back to “CALLEE” code. Put the stored value in
RETS register back into PC, which causes a jump
back to the ‘next instruction’ which we were going
to do before the software CALL happened
20 /25
Incorrect code – Arrows point to a hidden code
defect which stops the proper program operation
Correct code; LINK and UNLINK
should be a part of ALL subroutines
#include <blackfin.h>
.section program;
.global _InitGPIOFlagsASM;
_InitGPIOFlagsASM:
CALL TurnInterruptsOff_PF8to11;
// CALL means set Blackfin RETS register -- link register on MIPS
//
to point to instruction after CALL
//
RETS register = address of instruction labelled “next:”
next:
CALL SetPolarity_PF8to11; // These labels are “in our mind’s eye’
next2: CALL OtherStuff_PF8to11; // There for discussion purposes
Next3: CALL SetDirection_PF8to11_CPP; // Okay to add them for real
Next4:
CALL Enable__PF8to11; // Set RETS register to _InitGPIOFlagsASM.END
_InitGPIOFlagsASM.END: RTS; // RTS means JUMP RETS
// or “Change the PC to the value stored in RETS register
// What line of code will be executed when the RTS instruction finishes?
// meaning “where does the code jump to -- ANSWER PC
=_InitGPIOFlagsASM.END: -- Code is now in a for-ever nowhere loop ?
21 /25
#include <blackfin.h>
.section program;
.global _InitGPIOFlagsASM;
_InitGPIOFlagsASM:
LINK 16
// Save (write) first “CALLEE” RETS to the memory stack
CALL TurnInterruptsOff_PF8to11;
// InitGPIOFlagsASM now becomes “CALLEE”
// CALL means set RETS register
//
to point to instruction after CALL
//
RETS = next: in this case
next:
CALL SetPolarity_PF8to11;
next2: CALL OtherStuff_PF8to11; // IN LAB 1 – Some of these calls are to C++
Next3: CALL SetDirection_PF8to1; //
so that you can learn the technique
Next4: CALL Enable__PF8to11;
UNLINK; // Recover (get back) ORIGINAL CALLEE RETS from the
stack
22 /25
_InitGPIOFlagsASM.END: RTS; // This means JUMP RETS
// PC set to “saved” RETS so code “returns” to the function that called it
CALL TurnInterruptsOff_PF8to11ASM;
BAD CODING PRACTICE FOR LAB. 1
(Assignment
1, Lab. 0 etc)
#include <blackfin.h>
Lab 1: Other GPIO register flip flops
FIO_MASKA_D and FIO_MASKB_D
Stop this from happening unintentionally
 If bit X = 1, tell processor to cause an interrupt (change
program operation) when FIO_FLAG_D bit X is active
(changes to a 1 value)
.section program;
.global _TurnInterruptsOff_PF8to11ASM;
_ TurnInterruptsOff_PF8to11ASM:
P0.L = lo(FIO_MASK_A); P0.H = ……
R1 = 0;
W[P0] = R0;
ssync;
// Tell processor to do the write operation NOW
// REMEMBER – This processor does not
//
treat WRITEs as high priority
//
UNLESS 2 writes are waiting to happen
//
and a 3rd write is requested!!!!!
// DO same thing for FIO_MASK_B
23 /25
24 /25
TurnInterruptsOff_PF8to11ASM.END:
RTS
CALL TurnInterruptsOff_PF8to11;
GOOD CODING USING BITWISE &
INSTRUCTION TO CLEAR BITS TO ZERO
Lets call a “C++” function instead of
writing the code in assembly code
#include <blackfin.h>
#include <blackfin.h>
.section program;
.global _TurnInterruptsOff_PF8to11;
_ TurnInterruptsOff_PF8to11:
.section program;
.global _InitGPIOFlagsASM;
_InitGPIOFlagsASM:
LINK 16;
P0.L = lo(FIO_MASK_A); P0.H = ……
R0 = W[P0] (Z);
// Read all the bits
#define MASK_NOCHANGE_OTHERBITS 0xF0FF
R1 = MASK_NOCHANGE_OTHERBITS
R0 = R1 & R1;
// Bits 8 to 11 zero
W[P0] = R0;
// But other bits still the same
next:
next2:
Next3:
// DO same thing for FIO_MASK_B
CALL TurnInterruptsOff_PF8to11CPP__Fv;
// We must use “name mangling” to call C++ code
// Each compiler uses different “mane mangling” approach
// Solve as discussed in earlier lecture
CALL SetPolarity_PF8to11;
CALL OtherStuff_PF8to11;
CALL SetDirection_PF8to1;
Next4:
TurnInterruptsOff_PF8to11:
RTS
25 /25
Lets write this code in C instead
26 /25
Name mangling in CCES
TurnInterruptsOff_PF8to11CPP__Fv;
VDSP compiler name mangling
Place code in “InitGPIO.cpp
#include <blackfin.h>
void TurnInterruptsOff_PF8to11CPP(void) {
*pFIO_MASK_A = 0; // WRONG – need to use AND operation
ssync( );
// *pFIO_MASK_A = *pFIO_MASK_A & ~0x0F00
// What does the ~ (twiddle) operation perform?
// DO same thing for FIO_MASK_B
}
In assembly code the C++ function TurnInterruptsOff_PF8to11CPP( ) becomes
named
_TurnInterruptsOff_PF8to11CPP__Fv (name mangled)
In assembly code the C function TurnInterruptsOff_PF8to11C ( ) becomes
named _TurnInterruptsOff_PF8to11C
This convention allows the overloading of C++ functions (but not C)
CALL Enable__PF8to11;
UNLINK;
_InitGPIOFlagsASM.END: RTS;
27 /25
 In assembly code the C++ function TurnInterruptsOff_PF8to11CPP( ) becomes
named
_TurnInterruptsOff_PF8to11CPP__Fv (name mangled)
 In assembly code the C function TurnInterruptsOff_PF8to11C ( ) becomes named
_TurnInterruptsOff_PF8to11C
 This convention allows the overloading of C++ functions (but not C)
CCES compiler name mangling
 Not yet sure how is works – names start with _Z???? And end with ?? JITK
-- Since we don’t need (in this laboratory) to call overloaded C++ functions
from assembly code, then apply WAI_AT (slightly different than WAI-L)
 WIDFI
-- Lets call a C++ function that behaves like a C function and let
the COMPILER worry about NAME mangling (Delegate responsibility)
This is made to happen if we write the C++ code using this syntax
extern “C” void TurnInterruptsOff_PF8to11CPP(void) {
………. C++ code inside .cpp file
28 /25
}
Another GPIO register we need to set
correctly
29 /25
CALL EnablePins_PF8to11;
30 /25
GPIO pins can’t wander aimlessly
through life – they need direction 
#include <blackfin.h>
.section program;
.global _EnablePins_PF8to11;
_ EnablePins_PF8to11:
A key issue with GPIO is whether a pin is to
act as an input device (bringing things in
from the outside world into the Blackfin) or
as an output device (sending things from
the Blackfin to the outside world)
P0.L = lo(FIO_INEN); P0.H = ……
#define MASK_CHANGE_VALUES 0x0F00;
R1 = MASK_CHANGE_VALUES
W[P0] = R1;
EnablePins_PF8to11.END:
Another flip-flop (control register) group
controls whether the flip-flop outputs follow
the flip-flop inputs or are “high impedance” –
off – power saving but no useful value
RTS
WRONG LAB 1 CODING APPROACH: True this
enables bits 8 to 11, but it also DISABLES all the other
bits which might be used by other evaluation board
threads.
Need to use “OR” instruction after reading the enable
(control) register
31 /25
32 /25
Making sure that the FIO_DIR is correct
for LAB. 1 – NOTE FIO-DIR register may
need to change for later laboratories
Why do you need to know how to do
read (load) and write (store) on internal registers?
Flag Direction register (FIO_DIR)
 Used to determine from requirements if the PF bit is to be used for
input or output
 Need to set pins PF11 to PF8 for input, leave all other pins
unchanged -- WARNING CHIP DAMAGE (SMOKED) POSSIBLE
ISSUE
Write the Blackfin assembly language instruction(s) to load the
address of the internal programmable flag FIO_DIR register into
pointer register P1 – then SET the Blackfin PF lines to act as inputs
#include <blackfin.h>
P1.L = lo (FIO_DIR); P1.H = ….
AVOID Design Error
of “Changes all pins
// Check the requirements – need to have all input
// Manual says “setting a line for input means setting bit values to 0”
R0 = 0;
W[P1] = R0;
ssync;
// This changes “All pins”
// Force Blackfin to do the write (store) NOW not later
33 /25
Notice that previous slide WARNS
you about a design error in the code
We can’t do things this way as it changes
all the bits in the 16 flip-flops and we only
want to change 4 values in the flip-flops
WARNING -- The same design error is
introduced into Lab. 1 Task 3
However, the same design error is found
during the TDD tests – provided you look at
34 /25
Custom E-UNIT firmware tests can find
the design error
(This one fails -- does not check “possible non-use of AND / OR operations)
WatchDataClass( ); WATCH_MEMORY_RANGE( );
watchedmemory.getFinalValue( )
the test code to see whether what was being
tested was what needed to be tested
35 /25
36 /25
These tests DO find the design error
and in fact explain to you why it is likely that
your tests have failed.
But you have to read the message about the
Set pFIO_POLAR
Test failing and NOT ignore it
to a known
non-zero state
after saving old
pFIO_POLAR state
As in Lab. 0 Tests
Extra ideas you can use
Use switches to control RC car
Echoing Values from the switches to the
LED
Can be used to copy the switch presses to
the LED. If the LED outputs are connected
to the radio controlled car inputs, then we
can drive the car using the switches
(Last part of Lab. 1)
37 /25
Echoing the switches to the LED
Code in main( ) – written in C++
38 /25
Building a radio controlled car
4 Threads at least
int main( ) {
InitializeGPIOInterface( ); // Check Lab. 1 for “exact name needed”
InitializeFlashLEDInterface( ); // Check Lab. 1 for “exact name needed”
#define SWITCHBITS 0x0F00
// Look in MIPs notes about
//
using a mask and the
//
AND bit-wise operation
//
to select “desired bits”
SWITCHES ON FRONT PANEL
“INPUT COMMANDS:
LED LIGHTS ON FRONT PANEL
“CONTROLSIGNALS TO RF TRANS:
PROGRAMMABLE FLAGS
LED-CONTROLREGISTER
FIO_FLAG_D Register
EBIU INTERFACE
int ReadSwitches( )
while (1) {
// Forever loop
int GPIO_value = ReadBlackfinGPIOFlagsASM ( );
int desired_bits = GPIO_value & SWITCHBITS;
int LED_light_values = desired_bits >> 8;
uTTCOS_WriteLED(LED_light_values);
}
}
void WriteLED(int )
YOUR PROGRAM RUNNING ON THE BLACKFIN
ProcessDataASM( ) subroutine
// Bits in wrong position
VOICE
// to display on LEDS
39 /25
A/D
A/D D/A Interrupt routine
D/A
EAR
PHONES
40 /25
LEDs connected to FLASH port
BACK
FORWARD
RIGHT
LEFT
???
CONTROL ON
Might be
connected to
other things
DON’T
CHANGE
BEHAVIOUR
Blackfin BF533 I/O
41
Download