📄 spi_ee_int1.c
字号:
//-----------------------------------------------------------------------------
// EE_Read
//-----------------------------------------------------------------------------
//
// This routine reads and returns a single EEPROM byte whose address is
// given in <Addr>.
//
unsigned char EE_Read (unsigned Addr)
{
while (EE_Ready == FALSE); // wait for EEPROM available
EE_Ready = FALSE; // claim EEPROM
EE_Addr = Addr; // initialize EEPROM address
EE_WR = FALSE; // set up for READ operation
SPIF = 1; // initiate EEPROM operation
while (EE_Ready == FALSE); // wait for operation complete
return EE_Data; // return data
}
//-----------------------------------------------------------------------------
// EE_Write
//-----------------------------------------------------------------------------
//
// This routine writes a single EEPROM byte <value> to address <Addr>. Here
// we implement pre-write polling.
//
void EE_Write (unsigned Addr, unsigned char value)
{
while (EE_Ready == FALSE); // wait for EEPROM available
EE_Ready = FALSE; // claim EEPROM
EE_Addr = Addr; // initialize EEPROM address
EE_Data = value; // initialize EEPROM data
EE_WR = TRUE; // set up for WRITE operation
SPIF = 1; // initiate EEPROM operation
}
//-----------------------------------------------------------------------------
// Timer0_ISR
//-----------------------------------------------------------------------------
//
// Timer0 implements a delay which is used by the SPI0_ISR to manage setup
// and hold requirements on the EE_CS line. This ISR initiates a SPI0
// interrupt when called, and stops Timer0.
//
void Timer0_ISR (void) interrupt 1 using 3
{
TR0 = 0; // STOP Timer0
SPIF = 1; // initiate SPI0 interrupt
}
//-----------------------------------------------------------------------------
// SPI0_ISR
//-----------------------------------------------------------------------------
//
// This ISR implements a state machine which handles byte-level read and
// write operations to an attached EEPROM.
//
void SPI0_ISR (void) interrupt 6 using 3
{
enum SPI0_state { RESET, RD_S0, RD_S1, RD_S2, RD_S3, RD_S4, RD_S5, RD_S6,
RD_S7, WR_S0, WR_S1, WR_S2, WR_S3, WR_S4, WR_S5, WR_S6,
WR_S7, WR_S8, WR_S9, WR_S10, WR_S11, WR_S12, WR_S13,
WR_S14, WR_S15};
static enum SPI0_state state = RESET;
SPIF = 0; // clear SPI interrupt flag
switch (state) {
case RESET: // assert EE_CS; set Timer0 to cause SPI0 interrupt in
// 250ns (CS setup time); decode EE_WR to determine
// whether next state is RD_S0 (read) or WR_S0 (write).
EE_CS = 0; // assert CS signal on EEPROM
// set Timer0 to interrupt 250ns from now
ET0 = 0; // disable Timer0 interrupts
TCON &= ~0x30; // STOP Timer0 and clear overflow flag
TH0 = (-SYSCLK/4000000) >> 8; // set Timer0 to overflow in 250ns
TL0 = -SYSCLK/4000000;
ET0 = 1; // enable Timer0 interrupts
TR0 = 1; // START Timer0
// decode EE_Write flag to determine whether operation is a read
// or a write
if (EE_WR == TRUE) {
state = WR_S0; // set up for a write
} else {
state = RD_S0; // set up for a read
}
break;
case RD_S0: // transmit READ op-code
SPI0DAT = EE_READ; // transmit READ opcode
state = RD_S1; // advance to next state
break;
case RD_S1: // transmit MSB of Address
SPI0DAT = EE_Addr >> 8; // transmit MSB of Address
state = RD_S2; // advance to next state
break;
case RD_S2: // transmit LSB of Address
SPI0DAT = EE_Addr; // transmit LSB of Address
state = RD_S3; // advance to next state
break;
case RD_S3: // transmit dummy read to get data from EEPROM
SPI0DAT = 0; // transmit dummy read
state = RD_S4; // advance to next state
break;
case RD_S4: // wait 250ns (EEPROM CS hold time)
// set Timer0 to interrupt 250ns from now
ET0 = 0; // disable Timer0 interrupts
TCON &= ~0x30; // STOP Timer0 and clear overflow flag
TH0 = (-SYSCLK/4000000) >> 8; // set Timer0 to overflow in 250ns
TL0 = -SYSCLK/4000000;
ET0 = 1; // enable Timer0 interrupts
TR0 = 1; // START Timer0
state = RD_S5; // advance to next state
break;
case RD_S5: // raise CS and wait 500ns (EEPROM CS disable time)
EE_CS = 1; // de-assert EEPROM CS
// set Timer0 to interrupt 500ns from now
ET0 = 0; // disable Timer0 interrupts
TCON &= ~0x30; // STOP Timer0 and clear overflow flag
TH0 = (-SYSCLK/2000000) >> 8; // set Timer0 to overflow in 500ns
TL0 = -SYSCLK/2000000;
ET0 = 1; // enable Timer0 interrupts
TR0 = 1; // START Timer0
state = RD_S6; // advance to next state
break;
case RD_S6: // read data from SPI0 and post EEPROM ready
EE_Data = SPI0DAT; // read EEPROM data from SPI0
EE_Ready = TRUE; // indicate EEPROM ready for
// next operation
state = RESET; // reset state variable
break;
case WR_S0: // transmit WRITE ENABLE opcode
SPI0DAT = EE_WREN; // transmit WREN opcode
state = WR_S1; // advance to next state
break;
case WR_S1: // wait at least 250ns (CS hold time)
// set Timer0 to interrupt 250ns from now
ET0 = 0; // disable Timer0 interrupts
TCON &= ~0x30; // STOP Timer0 and clear overflow flag
TH0 = (-SYSCLK/4000000) >> 8; // set Timer0 to overflow in 250ns
TL0 = -SYSCLK/4000000;
ET0 = 1; // enable Timer0 interrupts
TR0 = 1; // START Timer0
state = WR_S2; // advance to next state
break;
case WR_S2: // raise CS and wait 500ns (CS disable time)
EE_CS = 1; // deassert CS
// set Timer0 to interrupt 500ns from now
ET0 = 0; // disable Timer0 interrupts
TCON &= ~0x30; // STOP Timer0 and clear overflow flag
TH0 = (-SYSCLK/2000000) >> 8; // set Timer0 to overflow in 500ns
TL0 = -SYSCLK/2000000;
ET0 = 1; // enable Timer0 interrupts
TR0 = 1; // START Timer0
state = WR_S3; // advance to next state
break;
case WR_S3: // assert CS and wait 250ns (CS setup time)
EE_CS = 0; // assert CS
// set Timer0 to interrupt 250ns from now
ET0 = 0; // disable Timer0 interrupts
TCON &= ~0x30; // STOP Timer0 and clear overflow flag
TH0 = (-SYSCLK/4000000) >> 8; // set Timer0 to overflow in 250ns
TL0 = -SYSCLK/4000000;
ET0 = 1; // enable Timer0 interrupts
TR0 = 1; // START Timer0
state = WR_S4; // advance to next state
break;
case WR_S4: // transmit WRITE opcode
SPI0DAT = EE_WRITE; // transmit WRITE opcode
state = WR_S5; // advance to next state
break;
case WR_S5: // transmit MSB of Address
SPI0DAT = EE_Addr >> 8; // transmit MSB of Address
state = WR_S6; // advance to next state
break;
case WR_S6: // transmit LSB of Address
SPI0DAT = EE_Addr; // transmit LSB of Address
state = WR_S7; // advance to next state
break;
case WR_S7: // transmit DATA
SPI0DAT = EE_Data; // transmit DATA
state = WR_S8; // advance to next state
break;
case WR_S8: // wait 250ns (CS hold time)
// set Timer0 to interrupt 250ns from now
ET0 = 0; // disable Timer0 interrupts
TCON &= ~0x30; // STOP Timer0 and clear overflow flag
TH0 = (-SYSCLK/4000000) >> 8; // set Timer0 to overflow in 250ns
TL0 = -SYSCLK/4000000;
ET0 = 1; // enable Timer0 interrupts
TR0 = 1; // START Timer0
state = WR_S9; // advance to next state
break;
case WR_S9: // deassert CS and wait 500ns (CS disable time)
EE_CS = 1; // deassert CS
// set Timer0 to interrupt 500ns from now
ET0 = 0; // disable Timer0 interrupts
TCON &= ~0x30; // STOP Timer0 and clear overflow flag
TH0 = (-SYSCLK/2000000) >> 8; // set Timer0 to overflow in 500ns
TL0 = -SYSCLK/2000000;
ET0 = 1; // enable Timer0 interrupts
TR0 = 1; // START Timer0
state = WR_S10; // advance to next state
break;
case WR_S10: // assert CS and wait 250ns (begin polling RDSR)
EE_CS = 0; // assert CS
// set Timer0 to interrupt 250ns from now
ET0 = 0; // disable Timer0 interrupts
TCON &= ~0x30; // STOP Timer0 and clear overflow flag
TH0 = (-SYSCLK/4000000) >> 8; // set Timer0 to overflow in 250ns
TL0 = -SYSCLK/4000000;
ET0 = 1; // enable Timer0 interrupts
TR0 = 1; // START Timer0
state = WR_S11; // advance to next state
break;
case WR_S11: // transmit Read Status Register opcode
SPI0DAT = EE_RDSR; // transmit RDSR opcode
state = WR_S12; // advance to next state
break;
case WR_S12: // transmit dummy write to read Status Register
SPI0DAT = 0; // dummy write (after this completes,
// SPI0DAT will contain Read Status
// Register contents, which are decoded
// in WR_S15 below)
state = WR_S13; // advance to next state
break;
case WR_S13: // wait 250ns (CS hold time)
// set Timer0 to interrupt 250ns from now
ET0 = 0; // disable Timer0 interrupts
TCON &= ~0x30; // STOP Timer0 and clear overflow flag
TH0 = (-SYSCLK/4000000) >> 8; // set Timer0 to overflow in 250ns
TL0 = -SYSCLK/4000000;
ET0 = 1; // enable Timer0 interrupts
TR0 = 1; // START Timer0
state = WR_S14; // advance to next state
break;
case WR_S14: // deassert CS and wait 500ns (CS disable time)
EE_CS = 1; // deassert CS
// set Timer0 to interrupt 500ns from now
ET0 = 0; // disable Timer0 interrupts
TCON &= ~0x30; // STOP Timer0 and clear overflow flag
TH0 = (-SYSCLK/2000000) >> 8; // set Timer0 to overflow in 500ns
TL0 = -SYSCLK/2000000;
ET0 = 1; // enable Timer0 interrupts
TR0 = 1; // START Timer0
state = WR_S15; // advance to next state
break;
case WR_S15: // check WIP bit (LSB of RDSR): if '1', then poll again;
// otherwise, RESET and post Write Complete
if (SPI0DAT & 0x01) { // TRUE if write in progress
state = WR_S10; // poll RDSR again
SPIF = 1; // initiate new polling operation
} else { // we're done. clean up.
EE_Ready = TRUE; // indicate EEPROM available
state = RESET; // reset state variable
}
break;
default:
while (1); // error
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -