507 lines
15 KiB
C
507 lines
15 KiB
C
/**
|
||
* @file spise2p.c
|
||
* @brief Неблокирующий драйвер последовательной EEPROM поверх SPI.
|
||
*
|
||
* Высокоуровневые Seeprom_read/Seeprom_write запускают транзакцию, а конечный
|
||
* автомат SPISE2P_DRV_tick продвигается от Timer2. Состояние драйвера единично:
|
||
* новую операцию разрешено начинать только после spiSe2pFree(). Адрес и длина
|
||
* должны укладываться в SEEPROM_LEN и не пересекать ограничения микросхемы.
|
||
*/
|
||
/*=================================================================
|
||
File name : SPISE2PD.C
|
||
|
||
Originator : Settu Duraisamy
|
||
C2000 Applications Team
|
||
Texas Instruments
|
||
|
||
Description : This file contains the SPI bus Serial EEPROM driver
|
||
implemented using Virtual SPI driver
|
||
|
||
Date : 6/30/2003 (DD/MM/YYYY)
|
||
====================================================================*/
|
||
|
||
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
|
||
|
||
#include "spise2p.h"
|
||
|
||
|
||
/* Instance the SPI bus serial EEPROM driver */
|
||
static SPISE2P_DRV se2p=SPISE2P_DRV_DEFAULTS;
|
||
|
||
/* Instance serial EEPROm data transfer structure */
|
||
static SE2P_DATA writeData, readData;
|
||
|
||
// Prototype statements for functions found within this file.
|
||
interrupt void PRD_TICK(void);
|
||
interrupt void cpu_timer2_isr(void);
|
||
|
||
int ccc=0;
|
||
|
||
/********************************************************************/
|
||
/******* SPI bus Serial EEPROM driver Initialization routine ********/
|
||
/********************************************************************/
|
||
|
||
/**
|
||
* @brief Синхронно записывает пользовательский блок через асинхронный драйвер.
|
||
* @param adres Начальный адрес EEPROM.
|
||
* @param buf Источник данных в памяти DSP.
|
||
* @param size Размер блока в байтах.
|
||
* @details Ожидает освобождения драйвера, запускает транзакцию и блокируется до
|
||
* её завершения, которое продвигается прерываниями Timer2.
|
||
*/
|
||
void Seeprom_write( unsigned int adres,
|
||
unsigned int buf[],
|
||
unsigned int size)
|
||
{
|
||
unsigned int len;
|
||
|
||
CpuTimer2.InterruptCount=0;
|
||
CpuTimer2Regs.TCR.all = 0x4020; // Use write-only instruction to set TSS bit = 0
|
||
|
||
while(!spiSe2pFree(&se2p));
|
||
|
||
size = (size / WORD_LEN) + (size % WORD_LEN);
|
||
while(size)
|
||
{
|
||
len = PAGE_LEN - (adres % PAGE_LEN);
|
||
if(len > size) len=size;
|
||
|
||
writeData.dataPtr = buf;
|
||
writeData.nrData = len;
|
||
writeData.se2pAddr = adres * WORD_LEN;
|
||
|
||
spiSe2pWrite(&se2p, &writeData);
|
||
while(!spiSe2pFree(&se2p));
|
||
|
||
buf += len;
|
||
adres += len;
|
||
size -= len;
|
||
}
|
||
CpuTimer2Regs.TCR.all = 0x4010; // Use write-only instruction to set TSS bit = 1
|
||
}
|
||
|
||
/**
|
||
* @brief Синхронно читает блок EEPROM в пользовательский буфер.
|
||
* @param adres Начальный адрес EEPROM.
|
||
* @param buf Приёмный буфер DSP.
|
||
* @param size Размер в байтах.
|
||
*/
|
||
void Seeprom_read( unsigned int adres,
|
||
unsigned int buf[],
|
||
unsigned int size)
|
||
{
|
||
unsigned int len;
|
||
|
||
CpuTimer2.InterruptCount=0;
|
||
CpuTimer2Regs.TCR.all = 0x4020; // Use write-only instruction to set TSS bit = 0
|
||
|
||
while(!spiSe2pFree(&se2p));
|
||
|
||
size = (size / WORD_LEN) + (size % WORD_LEN);
|
||
while(size)
|
||
{
|
||
len = PAGE_LEN - (adres % PAGE_LEN);
|
||
if(len > size) len=size;
|
||
|
||
readData.dataPtr = buf;
|
||
readData.nrData = len;
|
||
readData.se2pAddr = adres * WORD_LEN;
|
||
|
||
spiSe2pRead(&se2p, &readData);
|
||
while(!spiSe2pFree(&se2p));
|
||
|
||
buf += len;
|
||
adres += len;
|
||
size -= len;
|
||
}
|
||
CpuTimer2Regs.TCR.all = 0x4010; // Use write-only instruction to set TSS bit = 1
|
||
}
|
||
|
||
/**
|
||
* @brief Инициализирует SPI, объект драйвера и периодический Timer2.
|
||
* @post se2p находится в свободном состоянии, Timer2 вызывает cpu_timer2_isr().
|
||
*/
|
||
void InitSeeprom()
|
||
{
|
||
se2p.init(&se2p);
|
||
|
||
EALLOW; // This is needed to write to EALLOW protected registers
|
||
PieVectTable.TINT2 = &cpu_timer2_isr;
|
||
EDIS; // This is needed to disable write to EALLOW protected registers
|
||
|
||
InitCpuTimers(); // For this example, only initialize the Cpu Timers
|
||
ConfigCpuTimer(&CpuTimer2, (SYSCLKOUT/1000000), 100);
|
||
|
||
IER |= M_INT14;
|
||
}
|
||
|
||
/** @brief Сбрасывает конечный автомат и программирует регистры SPI-A. */
|
||
void SPISE2P_DRV_init(SPISE2P_DRV *eeprom)
|
||
{
|
||
/* Configure SPI-A pins using GPIO regs*/
|
||
// This specifies which of the possible GPIO pins will be SPI functional pins.
|
||
// Comment out other unwanted lines.
|
||
EALLOW;
|
||
GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 1; // Configure GPIO16 as SPISIMOA
|
||
GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 1; // Configure GPIO17 as SPISOMIA
|
||
GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 1; // Configure GPIO18 as SPICLKA
|
||
GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 0; // General purpose I/O 19 (default) (I/O)
|
||
GpioCtrlRegs.GPADIR.bit.GPIO19 = 1; // Configures the GPIO pin as an output
|
||
GpioDataRegs.GPADAT.bit.GPIO19 = 0;
|
||
EDIS;
|
||
|
||
/* Configure the SPI: 8-bit, Rising edge with delay */
|
||
SpiaRegs.SPICCR.all=0x0007;
|
||
SpiaRegs.SPICTL.all=0x001F;
|
||
SpiaRegs.SPISTS.all=0x00;
|
||
|
||
SpiaRegs.SPIBRR = CLKMULT * 6 + 1;
|
||
|
||
SpiaRegs.SPIFFTX.all=0x8000;
|
||
SpiaRegs.SPIFFRX.all=0x0000;
|
||
SpiaRegs.SPIFFCT.all=0x00;
|
||
SpiaRegs.SPIPRI.all=0x0010;
|
||
|
||
/* Disable Chip Select of Serial EEPROM */
|
||
eeprom->csr=0;
|
||
eeprom->msgPtr=0;
|
||
|
||
SpiaRegs.SPICCR.bit.SPISWRESET=1; // Enable SCI
|
||
}
|
||
|
||
/** @brief Деактивирует chip-select EEPROM. */
|
||
void SPISE2P_DRV_csset()
|
||
{
|
||
GpioDataRegs.GPADAT.bit.GPIO19 = 1;
|
||
}
|
||
|
||
/** @brief Активирует chip-select EEPROM перед транзакцией. */
|
||
void SPISE2P_DRV_csclr()
|
||
{
|
||
GpioDataRegs.GPADAT.bit.GPIO19 = 0;
|
||
}
|
||
|
||
/** @brief Возвращает ненулевое значение, если конечный автомат не занят. */
|
||
unsigned int spiSe2pFree(SPISE2P_DRV *se2p)
|
||
{
|
||
if(se2p->csr&0x3) return(0);
|
||
else return(1);
|
||
}
|
||
|
||
/** @brief Привязывает описание блока и переводит автомат в начало записи. */
|
||
void spiSe2pWrite(SPISE2P_DRV *se2p, SE2P_DATA *msgPtr)
|
||
{
|
||
se2p->msgPtr=msgPtr;
|
||
se2p->csr|=0x1;
|
||
}
|
||
|
||
/** @brief Привязывает описание блока и переводит автомат в начало чтения. */
|
||
void spiSe2pRead(SPISE2P_DRV *se2p, SE2P_DATA *msgPtr)
|
||
{
|
||
se2p->msgPtr=msgPtr;
|
||
se2p->csr|=0x2;
|
||
}
|
||
|
||
/********************************************************************/
|
||
/******* SPI bus Serial EEPROM driver Tick function *****************/
|
||
/********************************************************************/
|
||
|
||
/**
|
||
* @brief ISR Timer2, задающий такт конечному автомату EEPROM.
|
||
* @note Один вызов выполняет только ограниченный шаг SPI-транзакции.
|
||
*/
|
||
interrupt void cpu_timer2_isr(void)
|
||
{ EALLOW;
|
||
CpuTimer2.InterruptCount++;
|
||
|
||
se2p.tick(&se2p);
|
||
|
||
// The CPU acknowledges the interrupt.
|
||
EDIS;
|
||
}
|
||
|
||
/**
|
||
* @brief Выполняет один переход конечного автомата SPI EEPROM.
|
||
* @details Состояния последовательно выдают opcode, адрес и данные, ожидают
|
||
* флаги SPI, управляют CS и проверяют готовность микросхемы после записи.
|
||
* @param eeprom Активный экземпляр драйвера с описанием текущего блока.
|
||
*/
|
||
void SPISE2P_DRV_tick(SPISE2P_DRV *eeprom)
|
||
{
|
||
static unsigned int step=0;
|
||
static unsigned int dataCount=0;
|
||
static volatile unsigned int dummy=0;
|
||
|
||
switch(step)
|
||
{
|
||
case 0:
|
||
/* If write request is SET, then trigger the Write operation
|
||
If read request is SET, then trigger the Read operation
|
||
If Read request is also not SET, then continue to poll */
|
||
|
||
if(eeprom->csr&SPISE2P_WRRQ)
|
||
{ step=1;
|
||
eeprom->csr|=SPISE2P_WRIP; /* Set Write in progress*/
|
||
eeprom->csclr();
|
||
}
|
||
|
||
if(eeprom->csr&SPISE2P_RDRQ)
|
||
{ step=13;
|
||
eeprom->csr|=SPISE2P_RDIP; /* Set Read in progress */
|
||
eeprom->csclr();
|
||
}
|
||
break;
|
||
|
||
case 1:
|
||
/************************************************************
|
||
*********** SPI bus EEPROM Write Starts from here ***********
|
||
*************************************************************
|
||
Prier to any attempt to write data to SPI serial EEPROM
|
||
Write Enable Latch must be set by issuing the WREN command */
|
||
SpiaRegs.SPICCR.all=SPISE2P_TFR8BIT;
|
||
SpiaRegs.SPITXBUF=SPISE2P_WREN_CMD;
|
||
SpiaRegs.SPISTS.bit.BUFFULL_FLAG=1;
|
||
step=2;
|
||
break;
|
||
|
||
case 2:
|
||
/* Wait for VSPI State machine to send the WREN command and
|
||
serial EEPROM Chip Select must be brought to HIGH to set
|
||
the WREN latch */
|
||
|
||
if(SpiaRegs.SPISTS.bit.INT_FLAG) /* Check SPI INT FLAG */
|
||
{
|
||
dummy=SpiaRegs.SPIRXBUF; /* Reset SPI INT FLAG */
|
||
eeprom->csset();
|
||
|
||
step=3;
|
||
}
|
||
break;
|
||
|
||
case 3:
|
||
/* Assert CS of Serial EEPROM and send WRITE command */
|
||
|
||
eeprom->csclr();
|
||
SpiaRegs.SPICCR.all=SPISE2P_TFR8BIT;
|
||
SpiaRegs.SPITXBUF=SPISE2P_WRITE_CMD;
|
||
SpiaRegs.SPISTS.bit.BUFFULL_FLAG=1;
|
||
step=4;
|
||
break;
|
||
|
||
case 4:
|
||
/* Wait for VSPI State machine to send the WRITE command */
|
||
|
||
if(SpiaRegs.SPISTS.bit.INT_FLAG) /* Check SPI INT FLAG */
|
||
{ dummy=SpiaRegs.SPIRXBUF; /* Reset SPI INT FLAG */
|
||
step=5;
|
||
}
|
||
break;
|
||
|
||
case 5:
|
||
/* Send Address */
|
||
|
||
#if(SPISE2P_ADDR_WIDTH==SIXTEEN_BIT)
|
||
SpiaRegs.SPICCR.all= SPISE2P_TFR16BIT;
|
||
SpiaRegs.SPITXBUF=eeprom->msgPtr->se2pAddr;
|
||
#endif
|
||
#if(SPISE2P_ADDR_WIDTH==EIGHT_BIT)
|
||
SpiaRegs.SPICCR.all= SPISE2P_TFR8BIT;
|
||
SpiaRegs.SPITXBUF=eeprom->msgPtr->se2pAddr<<8;
|
||
#endif
|
||
|
||
SpiaRegs.SPISTS.bit.BUFFULL_FLAG=1; /* Set TXBUF FULL FLAG */
|
||
step=6;
|
||
break;
|
||
|
||
case 6:
|
||
/* Wait for VSPI State machine to send the Address */
|
||
|
||
if(SpiaRegs.SPISTS.bit.INT_FLAG) /* Check SPI INT FLAG */
|
||
{ dummy=SpiaRegs.SPIRXBUF; /* Reset SPI INT FLAG */
|
||
step=7;
|
||
}
|
||
break;
|
||
|
||
case 7:
|
||
/* Send Data */
|
||
|
||
#if(SPISE2P_DATA_WIDTH==SIXTEEN_BIT)
|
||
SpiaRegs.SPICCR.all=SPISE2P_TFR16BIT;
|
||
SpiaRegs.SPITXBUF=*(eeprom->msgPtr->dataPtr+dataCount);
|
||
#endif
|
||
|
||
#if(SPISE2P_DATA_WIDTH==EIGHT_BIT)
|
||
SpiaRegs.SPICCR.all=SPISE2P_TFR8BIT;
|
||
SpiaRegs.SPITXBUF=*(eeprom->msgPtr->dataPtr+dataCount)<<8;
|
||
#endif
|
||
|
||
dataCount++;
|
||
SpiaRegs.SPISTS.bit.BUFFULL_FLAG=1; /* Set TXBUF FULL FLAG */
|
||
step=8;
|
||
break;
|
||
|
||
case 8:
|
||
/* Wait for VSPI State machine to send the Data.
|
||
If all the data are sent, then set the CS pin to HIGH
|
||
to program or write the data in EEPROM array */
|
||
|
||
if(SpiaRegs.SPISTS.bit.INT_FLAG) /* Check SPI INT FLAG */
|
||
{ dummy=SpiaRegs.SPIRXBUF; /* Reset SPI INT FLAG */
|
||
|
||
if (dataCount==eeprom->msgPtr->nrData)
|
||
{ eeprom->csset();
|
||
step=9;}
|
||
else
|
||
step=7; /* Write next data */
|
||
}
|
||
break;
|
||
|
||
|
||
case 9:
|
||
/* Read the EEPROM status register to check whether the
|
||
data sent are indeed programmed to the EEPROM array.
|
||
Hence, send RDSR command to EEPROM to read status reg. */
|
||
|
||
eeprom->csclr();
|
||
SpiaRegs.SPICCR.all=SPISE2P_TFR8BIT;
|
||
SpiaRegs.SPITXBUF=SPISE2P_RDSR_CMD;
|
||
SpiaRegs.SPISTS.bit.BUFFULL_FLAG=1; /* Set TXBUF FULL FLAG */
|
||
step=10;
|
||
break;
|
||
|
||
case 10:
|
||
/* Wait for VSPI State machine to send RDSR command */
|
||
|
||
if(SpiaRegs.SPISTS.bit.INT_FLAG) /* Check SPI INT FLAG */
|
||
{ dummy=SpiaRegs.SPIRXBUF; /* Reset SPI INT FLAG */
|
||
step=11;
|
||
}
|
||
break;
|
||
|
||
case 11:
|
||
/* Send dummy Data to read Status reg. */
|
||
|
||
SpiaRegs.SPITXBUF=SPISE2P_DUMMY_DATA;
|
||
SpiaRegs.SPISTS.bit.BUFFULL_FLAG=1; /* Set TXBUF FULL FLAG */
|
||
step=12;
|
||
break;
|
||
|
||
case 12:
|
||
/* Wait for VSPI State machine to clock out status reg.
|
||
Check, whether the data are written to the EEPROM array,
|
||
If written, then reset the WRIP(write in progress) and
|
||
WRRQ(Write request bit) and go back to STATE0 */
|
||
|
||
if(SpiaRegs.SPISTS.bit.INT_FLAG) /* Check SPI INT FLAG */
|
||
{ eeprom->csset();
|
||
|
||
if (SpiaRegs.SPIRXBUF & SPISE2P_BUSY_MASK )
|
||
step=9;
|
||
else
|
||
{ eeprom->csr&=(~SPISE2P_WRIP);
|
||
eeprom->csr&=(~SPISE2P_WRRQ);
|
||
step=0;
|
||
dataCount=0;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case 13:
|
||
/************************************************************
|
||
*********** SPI bus EEPROM Read Starts from here ***********
|
||
*************************************************************
|
||
Send READ Command to SPI bus serail EEPROM */
|
||
|
||
SpiaRegs.SPICCR.all=SPISE2P_TFR8BIT;
|
||
SpiaRegs.SPITXBUF=SPISE2P_READ_CMD;
|
||
SpiaRegs.SPISTS.bit.BUFFULL_FLAG=1; /* Set TXBUF FULL FLAG */
|
||
step=14;
|
||
break;
|
||
|
||
case 14:
|
||
/* Wait for VSPI State machine to send READ command */
|
||
|
||
if(SpiaRegs.SPISTS.bit.INT_FLAG) /* Check SPI INT FLAG */
|
||
{ dummy=SpiaRegs.SPIRXBUF; /* Reset SPI INT FLAG */
|
||
step=15;
|
||
}
|
||
break;
|
||
|
||
case 15:
|
||
/* Send Address */
|
||
|
||
#if(SPISE2P_ADDR_WIDTH==SIXTEEN_BIT)
|
||
SpiaRegs.SPICCR.all= SPISE2P_TFR16BIT;
|
||
SpiaRegs.SPITXBUF=eeprom->msgPtr->se2pAddr;
|
||
#endif
|
||
#if(SPISE2P_ADDR_WIDTH==EIGHT_BIT)
|
||
SpiaRegs.SPICCR.all= SPISE2P_TFR8BIT;
|
||
SpiaRegs.SPITXBUF=eeprom->msgPtr->se2pAddr<<8;
|
||
#endif
|
||
|
||
SpiaRegs.SPISTS.bit.BUFFULL_FLAG=1; /* Set TXBUF FULL FLAG */
|
||
step=16;
|
||
break;
|
||
|
||
case 16:
|
||
/* Wait for VSPI State machine to send Address */
|
||
|
||
if(SpiaRegs.SPISTS.bit.INT_FLAG) /* Check SPI INT FLAG */
|
||
{ dummy=SpiaRegs.SPIRXBUF; /* Reset SPI INT FLAG */
|
||
step=17;
|
||
}
|
||
break;
|
||
|
||
case 17:
|
||
/* Send Dummy value to clock out data from serial EEPROM */
|
||
|
||
#if(SPISE2P_DATA_WIDTH==SIXTEEN_BIT)
|
||
SpiaRegs.SPICCR.all= SPISE2P_TFR16BIT;
|
||
SpiaRegs.SPITXBUF=SPISE2P_DUMMY_DATA;
|
||
#endif
|
||
|
||
#if(SPISE2P_DATA_WIDTH==EIGHT_BIT)
|
||
SpiaRegs.SPICCR.all= SPISE2P_TFR8BIT;
|
||
SpiaRegs.SPITXBUF=SPISE2P_DUMMY_DATA<<8;
|
||
#endif
|
||
|
||
SpiaRegs.SPISTS.bit.BUFFULL_FLAG=1; /* Set TXBUF FULL FLAG */
|
||
step=18;
|
||
break;
|
||
|
||
case 18:
|
||
/* Wait for VSPI State machine to clk out data from EEPROM */
|
||
|
||
if(SpiaRegs.SPISTS.bit.INT_FLAG) /* Check SPI INT FLAG */
|
||
{
|
||
#if(SPISE2P_DATA_WIDTH==SIXTEEN_BIT)
|
||
*(eeprom->msgPtr->dataPtr+dataCount)=SpiaRegs.SPIRXBUF;
|
||
#endif
|
||
|
||
#if(SPISE2P_DATA_WIDTH==EIGHT_BIT)
|
||
*(eeprom->msgPtr->dataPtr+dataCount)=SpiaRegs.SPIRXBUF&0xFF;
|
||
#endif
|
||
dataCount++;
|
||
step=19;
|
||
}
|
||
break;
|
||
|
||
case 19:
|
||
/* If all the data are read, terminate the read operation by
|
||
rising the CS. Then reset the RDIP (Read in progress) bit
|
||
and reset the RDRQ(Read request) bit and go back to STATE0 */
|
||
|
||
if (dataCount==eeprom->msgPtr->nrData)
|
||
{ eeprom->csset();
|
||
step=0;
|
||
dataCount=0;
|
||
eeprom->csr&=(~SPISE2P_RDIP);
|
||
eeprom->csr&=(~SPISE2P_RDRQ);
|
||
}
|
||
else
|
||
step=17;
|
||
break;
|
||
}
|
||
}
|
||
|