SPI hardware details -

advertisement
If we can just send
1 signal correctly
over the MOSI line!!!
Design and implementation
details on the way to a valid
SPI-LCD interface driver
To be tackled today








Review -- What is SPI?
Review -- What is the SPI “master slave” relationship?
How do we configure the SPI interface inside the Blackfin?
How do we activate the chip-select line – PF5?
Does activating the PF5 line as SPI output control mean we have to change
all the SetupPF8to11ASM( ) and other routines?
When do we activate the chip-select line, and how long for?
What happens when there is not a new value in the SPI transmit buffer – what
does the SPI interface do – it can’t do nothing – does it start transmitting zeros
(which would turn out all the LEDs we just turned on
One function left to be developed
•
•
•
InitHardware_SPI( ), NO_DELAY, RUN_ONCE)
perhaps contains InitializeSPI (unsigned short int SPI_baudrate);
and void StartSPI_ASM(void);
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
2 / 29
Lab 4 looks look – three new
tasks










InitScheduler( )
AddTask(InitHardware, NO_DELAY, RUN_ONCE)
AddTask(Init_SPIandLCD, NO_DELAY, RUN_ONCE)
AddTask(MeasureTemperatureTiming, NO_DELAY, 1);
AddTask(CalculateTemperature, QUARTER_SECOND, QUARTER_SECOND)
AddTask(DisplayTempertureLED, 3/8 seconds, QUARTER_SECOND)
AddTask(SPI_Message_HappyXmasLCD, 4.5_SECOND, TWO_SECOND);
AddTask(SPI_Message_TemperatureLCD, 5.5_SECOND, TWO_SECOND);
StartScheduler( )
Loop
•
•
GotoSleepTillInterrupt
Dispatch Tasks
•
-- DO CODE REVIEW
Init LCD Screen ( ) – This is
essentially “send a special message”
bool SPI_In_USE;
// ‘SEMAPHORE’ (lock)
short int sendMyMessage;
// ‘MESSAGE’ (simple)
char SPImessage[80];
// ‘MESSAGE’ body
char LCDcommandString[ ] = {0x30, 0x30, 0x22, 0x00 /* end of string character */};
// LOOK AT LAB. 4 PRELAB REFERENCE SHEET
#include <stdio.h>
void InitLCDSreen (void) {
if (SPI_In_Use == true) return; // Must wait till SPI interface is not in use by another task
// SPI_In_Use is false
// We want to use the SPI interface – block other tasks from using it
SPI_In_Use = true;
strcpy(SPImessage, LCDcommandString );
sendMyMessage = INSTRUCTION;
// DEFINE INSTRUCTION AS 2 SOMEWHERE
}
-- DO CODE REVIEW
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
4 / 26
SendMessageSPI_LCD( )
{
static int whichState = switch8HIGH;
static int messageElement = 0;
// Kill this task if all the elements in the message have been sent
if (numberCharactersToSend == 0) {
DeleteTask(sendMessageTaskNumber);
SPIinUse = false;
return;
}
-- DO CODE REVIEW
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
5 / 26
State 1 – send character + SW8
high + SW10 high IF data
#define SW8_high 0x100
-- DO CODE REVIEW
#define SW8_low 0x000
-- DO CODE REVIEW
#define SW10_High 0x800
-- DO CODE REVIEW
#define SW10_Low 0x000
-- DO CODE REVIEW
switch (whichState) {
case STATE1:
-- DO CODE REVIEW
// get the character to send and convert to short int value (SPI using 16-bit values)
unsigned short int SPIvalue = SPImessage(messageElement); // Next char to send
// set switch 8 high
SPIvalue = SPIvalue | SW8_high; -- DO CODE REVIEW
// Do we set switch 10 high
if (sendMyMessage == IS_INSTRUCTION) -- DO CODE REVIEW
SPIvalue = SPIvalue | SW10_high; -- DO CODE REVIEW
if (!SPIReady( ) ) return;
// The SPI device might not be ready if Blackfin too fast
WriteSPI(SPIvalue);
nextState = STATE2
break;
3/23/2016
6 / 26
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
Things we are missing
All relate to SPI HARDWARE




bool SPI_Ready(void)
void WriteSPI(unsigned short SPIvalue);
void InitSPI(void);
We are going to have to read the
reference sheet
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
7 / 26
Review -- Master / Slave concept
Slave Select (Chip Select)
We put a value into the Blackfin
SPI_TDBR register –
hardware does the rest




Blackfin sends out active low
chip select signal PF5
Blackfin sends out the “valuebits” on the MOSI signal.
Slave accepts signal as SS1
is connected to PF5
Then PF5 goes high – no
more information for SLAVE
If we get the first step correct –
then everything else should
happen automatically –
provided we have set up the
SPI interface correctly
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
8 / 29
Review -- – Using an SPI interface to
logic lab LED
SPI_TDBR
Blackfin Processor
SLAVE SELECT
PF5 used (PF0 to PF7)
MOSI
SPI_RXBR
SPI
CLOCK
MISO
SLAVE OUTPUT INTERFACE
SLAVE INPUT INTERFACE
LOAD
Slave to
LCD
CONTROL
DATA
CJ7 / CJ8 output to LED
3/23/2016
SWITCHES (LOGIC LAB)
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
9 / 29
Blackfin transmits 16 bits with
THIS format over the MOSI line
DB7, DB6, ………DB1, DB0
E – Enable / Strobe
RS
1  0 – When this line goes from high to the
low, then the command is send to (latched
into) LCD
We don’t care at the moment
0 – LCD instruction
THIS ISTo NEW
STUFF
make LCD respond to command 0x4F0
Blackfin must transmit
R/W
We justThen
want
“something”
0x5F0 ( E High )
1 – Read from LCD
0x4F0 ( E low )
valid
on
MOSI
line
0x5F0
(
E
high
)
0 – Write to LCD
1 – LCD data
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
10 / 29
Start with something we know
how to do – PF5 as Output signal


Need to set PF5 as output to make SPI work
But if we change Initialize_ProgrammableFlagsASM(); from Lab. 1
too much else MIGHT need changing
TEST(GPIO_Setup_TEST) {
CHANGING InitializePFIO would mean we would have to change all Tests
from Lab. 1
CHANGES NEEDED FOR LAB. 10 (FAR FUTURE)
BUT NOT NOW -- CAN WE DO SOMETHING ELSE?
}
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
11 / 29
void ChangePFtoOutputASM(int which_pins )
Make sure nothing else changes in
FIO_DIR – so read, then OR, then write
ONE SOLUTION -- Review for Quiz 3 and Final exam
PF5 GPIO changed to Output
without changing other things
#include <blackfin.h>
P1.L = lo (FIO_DIR);
P1.H = hi (FIO_DIR);
old_value_R1 = W[P1] (Z);
// Get old value -- unsigned
new_value_R2 = old_value_R1 | which_pins_R0 // INPAR1 in R0
W[P1] = new_value_R2;
ssync;
// Force Blackfin to do the write (store) NOW not later
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
12 / 29
Blackfin interface details
More slave side
Blackfin side
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
13 / 29
Concept



We write 16-bits (0xFF0A) into SPI_TDBR
Hardware transfers this to SHIFT register
•
•
Hardware sends out 1 bit from shift register over MOSI line to SLAVE each
clock tick – speeds up to 25 MHz per bit (way faster than LEDs flashing
speed)
Hardware receives 1 bit over MISO line from the SLAVE and puts into shift
register each clock tick – speeds up to 25 MHz per bit
Hardware transfers shift register value (from slave) into
SPI_RDBR (receive DBR)
•

0x F F 0 A
For next 16 ticks of SPI clock
•

SPI_TDBR now empty
SPI_RDBR is now FULL
This transmission over a serial line (16-bits 1 at a time) is much
slower than other internal Blackfin operation
•
Must be careful not to overwrite last transmission with new transmission by
“trying to hard” – writing values too quickly
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
14 / 29
TRY about 0x8000
to start with
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
15 / 29
SPI_registers -- Hardware Chap. 10
WHAT TO WORRY ABOUT
WHAT TO IGNORE


SPI_BAUD – We want to be able to change this – slow it down to ???
•
•
Maximum serial clock rate is ¼ of the system clock rate
SCK freq = Peripheral clock frequency / 2 * SPI_BAUD -- Many Mbits
SPI_FLG (Not SPI_FLAG) – do we need ChangePFtoOutputASM
•
•
FLS5 bit – activates PF5 as slave select line
FLG5 bit – could be used by us to control value of PF5 line (Slave select)
•
•
when FLG5 bit is low, PF5 output is low,
when FLG5 bit is high, PF5 output is high,
However we would rather have the SPI hardware change PF5 output line at the
correct time for us.
Page 10-12 of the manual says “if CPHA = 0, the SPI hardware sets the
output value (PF5) and the FLG5 bit (that developer sets) is ignored”
MEANS WE WOULD NOT NEED TO CHANGE InitGPIOFlagsASM( )
SOUNDS GOOD TO ME – JUST “SET PLS5 TO 1” AND THE PROCESSOR
DOES THE WORK -- except how do you make CPHA = 0?
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
16 / 29
SPI-registers -- more
SPI_STAT – SPI Status register


Has some read only bits
•
RO bits are changed by processor hardware – not us
Has some “write 1 to clear” sticky bits which are set when error condition occurs
•
Remember to to write 1 to clear these bits during SPI Setup
SPI_TDBR – transmit data buffer register


Value written to this register is transmitted over SPI interface
Writing to this register clears the SPI transmit interrupt signal
• One of the questions about writing the SPI_ISR function is
answered by this information 
• When we write to the SPI_TDBR register, the interrupt signal is
cleared automatically. We don’t have to clear a bit as we would do
with the core timer and general purpose timer register interrupts
• However we not writing an SPI_ISR – what a shame – all that
information going to waste
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
17 / 29
Status register information
RO and W1C bits -- SPI_Ready( );
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
18 / 29
Chapter 10 in reference manual
and reference sheet
SPI_Ready( ) code
We don’t have a “ready
to start ” bit – we
have a “have
finished” bit instead
NOTE RO not R0
(Read only)
SYSTEM CHANGED
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
19 / 29
All set in InitSPI( )
Set this
bit after
others set
Separate
line
of code
????
????
DON’T
SENT
ZERO

LCD
“STROBE”
IS 1 -> 0
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
20 / 29
SPI_CTL register
InitSPI( )
Values needed during setup









TIMOD – transfer initiation mode
•
•
01 – Start transfer with write to SPI_TDBR. Interrupt when SPI_TDBR is empty.
Timing issues possible here – get an interrupt after SPI_TDBR is empty the first time
PSSE – Slave Select Enable
•
0 – Disable – setting this as 1 makes this Blackfin a slave device. There might be circumstances
where you want one Blackfin as master, and another as a slave – but this is not one of them.
SIZE = 1 (16 bits)
LSBF – Last significant bit first
•
0 as we want MSBF first as that is the way the LCD interface has been designed
MSTR – master
•
1 as we want Blackfin to be master, not slave
SPE – SPI Enable
•
1 – but we might not want to do this during set-up, configure SPI up – then enable SPI as last step
WOM – Write open drain master
•
0 – Normal – because this was the way the interface was designed
EMISO – Enable MISO to allow slave to talk to master
•
0 – Not in this part of the lab
GM – Get more data
•
0 – when SPI_RDBR (receive buffer) is full – discard new incoming data – don’t really care at the
moment
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
21 / 29
SPI_CTL register
Things we still don’t understand

SZ – send zeros (or last word again)
when SPI_TDBR is empty
•
•


causes what to happen?
Sending zeros sounds bad as that
means the LCD will think we are
sending it commands
CPOL – clock polarity
•
Means what – and do we care?
CPHA – Clock Phase
•
•
When CPHA = 1, slave select controlled
by user software
When CPHA = 0, slave select controlled
by SPI hardware
MURPHY’S RULE – any bit whose function
is not obvious will be the key of whether
you get the interface to work or not

3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
22 / 29
VALID slave load on signal transition
VALID DATA STORED
Figure 10-11
SLAVE DATA IS LOADED
ON L-to-H CLOCK TRANSITION
Different than
Slave is SELECTED when PF5 = 0
INVALID slave load on signal transition
INVALID DATA STORED
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
23 / 29
We are now at the stage where we
can do some experimenting with the
hardware
We know that the following pins are “key” to the
operation of the SPI interface.
 MOSI – this will show the data being transmitted
from the SPI interface
 PF5 – chip select line
•
•

When this is pulled low, then the slave will accept any data
being transmitted, otherwise data is ignored
When this goes – low to high – then the serial data
transmitted to the slave is “latched” (converted into a
parallel signal that is then sent to LCD as a data or a
command request.
Place scope probes on these lines
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
24 / 29
Lab 4 quick test











InitScheduler( )
AddTask(InitHardware, NO_DELAY, RUN_ONCE)
AddTask(Init_SPIandLCD, NO_DELAY, RUN_ONCE)
AddTask(AnythingOnMOSILine, 4.5_SECOND, TWO_SECOND);
AddTask(MeasureTemperatureTiming, NO_DELAY, 1);
AddTask(CalculateTemperature, QUARTER_SECOND, QUARTER_SECOND)
AddTask(DisplayTempertureLED, 3/8 seconds, QUARTER_SECOND)
AddTask(SPI_Message_HappyXmasLCD, 4.5_SECOND, TWO_SECOND);
AddTask(SPI_Message_TemperatureLCD, 5.5_SECOND, TWO_SECOND);
StartScheduler( )
Loop
•
•
GotoSleepTillInterrupt
Dispatch Tasks
AnythingOnMOSILine( ) – This is
essentially “send a special message”
bool SPI_In_USE;
// ‘SEMAPHORE’ (lock)
short int sendMyMessage;
// ‘MESSAGE’ (simple)
char SPImessage[80];
// ‘MESSAGE’ body
char SimpleTest[ ] = {0xFF, 0xAA, 0x23, 0x67, EOS /* end of string character */};
#include <stdio.h>
void AnythingOnMOSILine (void) {
if (SPI_In_Use == true) return; // Must wait till SPI interface is not in use by another task
// SPI_In_Use is false
// We want to use the SPI interface – block other tasks from using it
SPI_In_Use = true;
strcpy(SPImessage, SimpleTest);
sendMyMessage = DATA;
// DEFINE INSTRUCTION AS 2 SOMEWHERE
}
-- DO CODE REVIEW
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
26 / 26
Concept




We write 16-bits (0xFF0A) into SPI_TDBR
Hardware transfers this to SHIFT register
•
0x F F 0 A
For next 16 ticks of SPI clock
•
•
Hardware sends out 1 bit from shift register over MOSI line to SLAVE each
clock tick – speeds up to 25 MHz per bit
Hardware receives 1 bit over MISO line from the SLAVE and puts into shift
register each clock tick – speeds up to 25 MHz per bit
Hardware transfers shift register value (from slave) into
SPI_RDBR (receive DBR)
•

SPI_TDBR now empty
SPI_RDBR is now FULL
This transmission over a serial line (16-bits 1 at a time) is much
slower than other internal Blackfin operation
•
Must be handled via interrupt control
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
27 / 29
Lab. 4 interface
SPI from Blackfin master
(MOSI, MISO, CLK, PF5
SPI to interface (slave)
(MOSI, MISO, CLK, slave
select )
LINES TO LOGIC LAB LED
LOOK HERE FOR
EXPECTED SIGNALS
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
28 / 26
What we should see on scope
Sending 0xFF, 0xAA, 0x23, 0x67, EOS
Make SPI_BAUD very large (very slow)
Connect Lab. 4 interface to logic lab lights (top)
See 0x05FF, 0x04FF, 0x05FF
Then 0x05AA, 0x04AA, 0x05AA
Then 0x0523, 0x0423, 0x0523
Then 0x0567, 0x0467, 0x0567
3/23/2016
IN ACTUAL LAB
YOU’LL GET A TEST
PROGRAM -RACING LIGHTS
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
29 / 29
Things we are missing
All relate to SPI HARDWARE



bool SPI_Ready(void) {
Check SPI Finished bit in SPI status register
}
void WriteSPI(unsigned short SPIvalue) {
Write the value to SPI transmit buffer register
}
void InitSPI(void) {
Set slave select in SPI flag register
Set Baud rate
Set all necessary bits in SPI Control register
Enable SPI interface
} 3/23/2016
30 / 26
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
Final Lab. 3 and Lab. 4








InitScheduler( ) -- Lab 3 looks something like this
AddTask(InitHardware, NO_DELAY, RUN_ONCE)
AddTask(MeasureTemperatureTiming, NO_DELAY, 1);
AddTask(CalculateTemperature, QUARTER_SECOND,
QUARTER_SECOND)
AddTask(DisplayTempertureLED, 3/8 seconds,
QUARTER_SECOND)
AddTask(FlashLED6, NO_DELAY, EIGHTH_SECOND
StartScheduler( )
Loop
•
•
GotoSleepTillInterrupt
Dispatch Tasks
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
31 / 29
Lab 4 looks look – three new
tasks










InitScheduler( )
AddTask(InitHardware, NO_DELAY, RUN_ONCE)
AddTask(Init_SPIandLCD, NO_DELAY, RUN_ONCE)
AddTask(MeasureTemperatureTiming, NO_DELAY, 1);
AddTask(CalculateTemperature, QUARTER_SECOND, QUARTER_SECOND)
AddTask(DisplayTempertureLED, 3/8 seconds, QUARTER_SECOND)
AddTask(SPI_Message_HappyXmasLCD, 4.5_SECOND, TWO_SECOND);
AddTask(SPI_Message_TemperatureLCD, 5.5_SECOND, TWO_SECOND);
StartScheduler( )
Loop
•
•
GotoSleepTillInterrupt
Dispatch Tasks
•
-- DO CODE REVIEW
Code reminder – using sprintf( )
Xmas message and temperature

I want to put the temperature (as a number) into a string that
gets transmitted over SPI – how would I do that using “C”?
volatile bool SPI_In_USE;
// ‘SEMAPHORE’ (lock)
volatile short int sendMyMessage;
// ‘MESSAGE’ (simple)
volatile char SPImessage[80];
// ‘MESSAGE’ body
volatile float temperature; // Calculated as a Lab. 3 Task // Know terms in red for final
#include <stdio.h>
-- DO CODE REVIEW
void SPI_Message_TemperatureLCD(void) {
if (SPI_In_Use == true) return; // Must wait till SPI interface is not in use by another task
// SPI_In_Use must be false – therefore we can change it and use SPI
// We want to use the SPI interface – block other tasks from using it
SPI_In_Use = true;
sprintf(SPImessage, “Temperature %f4.2 C”, temperature);
sendMyMessage = DATA;
// DEFINE DATA AS 1 SOMEWHERE
}
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
33 / 26
Init LCD Screen ( ) – This is
essentially “send a special message”
bool SPI_In_USE;
// ‘SEMAPHORE’ (lock)
short int sendMyMessage;
// ‘MESSAGE’ (simple)
char SPImessage[80];
// ‘MESSAGE’ body
char LCDcommandString[ ] = {0x30, 0x30, 0x22, 0x00 /* end of string character */};
// LOOK AT LAB. 4 PRELAB REFERENCE SHEET
#include <stdio.h>
void InitLCDSreen (void) {
if (SPI_In_Use == true) return; // Must wait till SPI interface is not in use by another task
// SPI_In_Use is false
// We want to use the SPI interface – block other tasks from using it
SPI_In_Use = true;
strcpy(SPImessage, LCDcommandString );
sendMyMessage = INSTRUCTION;
// DEFINE INSTRUCTION AS 2 SOMEWHERE
}
-- DO CODE REVIEW
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
34 / 26
We now need to do the message
handler task -- DO CODE REVIEW
enum {NO_MESSAGE, DATA, INSTRUCTION};
// Be able to explain “enum” for final
void SPI_MessageHandler(void) {
if ( sendMyMessage == NO_MESSAGE) return;
// Message to send – start up the sending task
numberCharactersToSend = strlen(SPIMessage);
sendMessageTaskNumber =
AddTask(SendMessageSPI_LCD, NO_DELAY,
AS_FAST_AS_POSSIBLE);
// Start with as FAST_AS_POSSIBLE with a slow value -- second / 20;
}
-- DO CODE REVIEW
3/23/2016
SPI and LCD
,
Copyright M. Smith, ECE, University of Calgary, Canada
35 / 26
Download