AN1445
APPLICATION NOTE
USING THE ST7 SPI TO EMULATE A 16-BIT SLAVE
By Microcontroller Division Applications
INTRODUCTION
This application note describes how to emulate a 16-bit slave SPI using an ST7 microcontroller with an on-chip 8-bit SPI.
Figure 1. 16-bit SPI frame
bit 0 bit 1 bit 2 bit 3 bit 4 bit 5 bit 6 bit 7 bit 8 bit 9 bit 10 bit 11 bit 12 bit 13bit 14bit 15
1 PRINCIPLE
The ST7 SPI cell has a double buffer for receiving data using two 8-bit registers: a read register and a shift register (see Figure 2.). The application software accesses the read register to retrieve the received data. The 8-bit shift register is managed by hardware to receive the 8 bits of each byte. As each bit is received, it is shifted into the shift register. During byte reception, the read register is not changed. It contains the previously received byte which can still be read by software. At the end of byte reception, the 8-bit shift register is copied into the read register.
This double buffering makes it possible to receive 16-bit words. At the end of reception of the first byte, the shift register is copied into the read register, the SPIF flag is set and an interrupt can be generated. The next in-coming byte will be received in the shift register while the first byte is available in the read register. In order not to lose any bits, the software must be fast enough to read the first byte before the end of the reception of the second one.
Note: The SPISR (SPI Status Register) is also called SPICSR (SPI Control/Status Register) depending on which ST7 microcontroller device you use. In this application note, we’ll use the name SPISR for the status register.
AN1445/1101 |
1/7 |
USING THE ST7 SPI TO EMULATE A 16-BIT SLAVE
Figure 2. Data Register Block diagram
|
INTERNAL BUS |
|
|
DATA REGISTER |
|
|
READ REGISTER |
|
MOSI |
|
|
MISO |
8-BIT |
|
SHIFT REGISTER |
||
|
2 SOFTWARE
Figure 3. C code (COSMIC C Compiler) for the interrupt routine
@interrupt @nostack void SPI_Interrupt(void)
{
volatile TwoBytes twobytesDR;
if (ValBit(SPISR,SPIF)) // if a byte is received (SPIF=1) + first step to clear int flags
{
twobytesDR.b_form.low=SPIDR; //1st byte storage while(ValBit(SPISR,SPIF)); twobytesDR.b_form.high=SPIDR; //2nd byte storage
}
else // then MODF flag caused the interrupt -> add your own code here
{
SPICR=0xC4; // second step to clear MODF flag: write access to SPICR (init value)
}
}
2/7
USING THE ST7 SPI TO EMULATE A 16-BIT SLAVE
Figure 4. Disassembled interrupt routine code
_SPI_Interrupt:
btjf _SPISR,#7,L501 ld a,_SPIDR
ld _SPI_Interrupt$L-1,a
L311:
btjt _SPISR,#7,L311 ld a,_SPIDR
ld _SPI_Interrupt$L-2,a iret
L501:
ld a,#196 ld _SPICR,a iret
where:
typedef unsigned char u8; |
/* unsigned 8 bit type definition */ |
|
typedef signed char s8; |
/* signed 8 bit type definition */ |
|
typedef unsigned int u16; |
/ * unsigned 16 bit type definition */ |
|
typedef signed int s16; |
/* signed 16 bit type definition */ |
|
typedef unsigned long u32; |
/ * unsigned 32 bit type definition */ |
|
typedef signed long s32; |
/ * signed 32 bit type definition */ |
|
typedef union { |
/* unsigned 16 bit type for 8 & 16 */ |
|
u16 w_form; |
/* bit accesses: 16> var.w_form */ |
|
struct { |
/* 8> var.b_form.high/low |
*/ |
u8 high, low; |
|
|
} b_form; |
|
|
} TwoBytes; |
|
|
Note: On some devices, another flag called OVR (overrun) can also cause an SPI interrupt to occur. In this case, you will have to add some code to the interrupt routine to handle this.
3/7