1783 lines
60 KiB
C++
1783 lines
60 KiB
C++
#include "fpgaflashoperation.h"
|
|
#include <qstring.h>
|
|
|
|
//***********************************************************************
|
|
// Reset Transaction
|
|
// Input parameters:
|
|
// Returns:
|
|
//
|
|
// Note 1: bit 0 reset to 0, no request begin transaction
|
|
// bit 1 reset to 0, no start previous transaction
|
|
//***********************************************************************
|
|
void FlashOperation::resetTransaction()
|
|
{
|
|
cx.ctrl[r_spicr]= //0
|
|
spicr_req_no
|
|
|(spicr_start_no<<1);
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Prepare Transaction
|
|
// Input parameters:
|
|
// Returns:
|
|
//
|
|
// Note 1: bit 0 reset to 1, It requires to the IP to begin with a transaction
|
|
// bit 1 reset to 0, no start previous transaction
|
|
//***********************************************************************
|
|
void FlashOperation::prepareTransaction()
|
|
{
|
|
cx.ctrl[r_spicr]= //1
|
|
spicr_req_begin_trans
|
|
|(spicr_start_no<<1);
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Start Transaction
|
|
// Input parameters:
|
|
// Returns:
|
|
//
|
|
// Note 1: bit 0 reset to 1, It requires to the IP to begin with a transaction
|
|
// bit 1 reset to 1, It starts a previously required transaction
|
|
//***********************************************************************
|
|
void FlashOperation::startTransaction()
|
|
{
|
|
cx.ctrl[r_spicr]= //3;
|
|
spicr_req_begin_trans
|
|
|(spicr_start_prev_trans<<1);
|
|
}
|
|
|
|
//***********************************************************************
|
|
// End Transaction
|
|
// Input parameters:
|
|
// Returns:
|
|
//
|
|
// Note 1: bit 0 reset to 1, It requires to the IP to begin with a transaction
|
|
// bit 1 reset to 1, //no start previous transaction
|
|
//***********************************************************************
|
|
void FlashOperation::endTransaction()
|
|
{
|
|
cx.ctrl[r_spicr]= //1;
|
|
spicr_req_begin_trans
|
|
|(spicr_start_no<<1);
|
|
}
|
|
|
|
|
|
//*****************************************
|
|
// INITIALIZE operations, 2.4.1.1 Inizializzazione
|
|
// Inizialize mode register, set engine
|
|
// Input parameters: engine_ = fpga flash engine
|
|
// a_moder_spimode = SPI mode x1 mode,x2 mode,x4 mode
|
|
// a_moder_byteaddress = 3 bytes address/4 bytes address
|
|
// a_moder_qspiport = primary Spi Port/secondary Spi Port
|
|
// Returns:
|
|
//
|
|
// Note 1: set register r_moder with correct configuration
|
|
//***********************************************************************
|
|
void FlashOperation::init(FpgaFlashEngine* engine_,
|
|
reg_moder_spimode_t a_moder_spimode,
|
|
reg_moder_byteaddress_t a_moder_byteaddress,
|
|
reg_moder_qspiport_t a_moder_qspiport)
|
|
{
|
|
memset(&cx, 0, sizeof cx);
|
|
engine=engine_;
|
|
|
|
moder_spimode = a_moder_spimode;
|
|
moder_byteaddress = a_moder_byteaddress;
|
|
moder_qspiport = a_moder_qspiport;
|
|
|
|
//configure mode registert
|
|
cx.ctrl[r_moder]=
|
|
moder_spimode<<0
|
|
|(moder_byteaddress<<2)
|
|
|(moder_qspiport<<3);
|
|
}
|
|
|
|
//*****************************************
|
|
// INITIALIZE operations, 2.4.1.1 Inizializzazione
|
|
// Inizialize mode register, set engine
|
|
// Input parameters: a_moder_spimode = SPI mode x1 mode,x2 mode,x4 mode
|
|
// a_moder_byteaddress = 3 bytes address/4 bytes address
|
|
// a_moder_qspiport = primary Spi Port/secondary Spi Port
|
|
// Returns:
|
|
//
|
|
// Note 1: set register r_moder with correct configuration
|
|
//***********************************************************************
|
|
void FlashOperation::init(reg_moder_spimode_t a_moder_spimode,
|
|
reg_moder_byteaddress_t a_moder_byteaddress,
|
|
reg_moder_qspiport_t a_moder_qspiport)
|
|
{
|
|
memset(&cx, 0, sizeof cx);
|
|
|
|
moder_spimode = a_moder_spimode;
|
|
moder_byteaddress = a_moder_byteaddress;
|
|
moder_qspiport = a_moder_qspiport;
|
|
|
|
//configure mode register
|
|
cx.ctrl[r_moder]=
|
|
moder_spimode<<0
|
|
|(moder_byteaddress<<2)
|
|
|(moder_qspiport<<3);
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Confirm flash operation
|
|
// Input parameters:
|
|
// Returns: true = no errors, ready for another command
|
|
// false = error, there is a problem or not responds.
|
|
//
|
|
// Note 1: set register r_moder with correct configuration
|
|
//***********************************************************************
|
|
bool FlashOperation::confirmFlashOperation()
|
|
{
|
|
// Set the timeout value [system ticks]
|
|
// max sector erase time from data sheet is 3[s]
|
|
|
|
fif->log(type_log_info, "-> MACRO - Confirm flash operation");
|
|
|
|
uint8_t sts = 0;
|
|
|
|
//unsigned long t_start=fif->timeNowMs();
|
|
//unsigned long t_stop=fif->timeNowMs();
|
|
|
|
//char st[32];
|
|
|
|
//int count = 5;
|
|
do
|
|
{
|
|
cx.ctrl[r_addrr]=0;
|
|
cx.ctrl[r_nbr]=0x01;
|
|
bool ok=sendCommand(cmdr_read_st_reg, //=0x05, read status register
|
|
//&st[0], //SPI Receive FIFO Register
|
|
&cx.ctrl[r_spirr],
|
|
256 , //Number of elements into the "TX FIFO"
|
|
cmd_read);
|
|
if (!ok)
|
|
{
|
|
fif->log(type_log_error, "MACRO - Confirm flash operation, ERROR");
|
|
return false;
|
|
}
|
|
//sts=status_register[0];
|
|
sts = cx.ctrl[r_spirr];
|
|
|
|
//count--;
|
|
//fif->log(0, "MACRO - Confirm flash operation read %d times, read 0x%02X", count, sts);
|
|
fif->log(type_log_info, "MACRO - Confirm flash operation read 0x%02X", sts);
|
|
// Repeat until bit #0 (read from FLASH) is != 0 , bit di "Write In Progress"
|
|
}while ((sts & 0x01) != 0);//((count==0) && ((sts & 0x01) != 0));
|
|
|
|
//t_stop = fif->timeNowMs();
|
|
|
|
/*if (count==0)
|
|
{
|
|
fif->log(0, "TIMEOUT - wait until operation not terminated");
|
|
return false;
|
|
}*/
|
|
|
|
//unsigned long t_now=(t_stop-t_start)/1000.0;
|
|
|
|
//fif->log(0, "MACRO - Confirm flash operation, in %lusecs", int(t_now));
|
|
|
|
return true;
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Core reset
|
|
// Input parameters:
|
|
// Returns: true = no error
|
|
// false = error into reset operation
|
|
//
|
|
// Note 1: set register r_srr with value 0x12ABCDEF, wait 10 us and set
|
|
// register r_srr with value 0
|
|
//***********************************************************************
|
|
bool FlashOperation::reset()
|
|
{
|
|
fif->notify(FpgaFlashInterface::s_reset, 1, "Start reset");
|
|
|
|
fif->log(type_log_info, "-> MACRO - Resetting FPGA interface");
|
|
|
|
memset(&cx, 0, sizeof cx);
|
|
|
|
cx.ctrl[r_srr]=SRR_KEYCODE; //0x12ABCDEF;
|
|
|
|
if (!fpgaWrite(r_base, &cx.ctrl, 256,"reset"))
|
|
{
|
|
fif->notify(FpgaFlashInterface::s_reset, -1, "ERROR, reset not completed");
|
|
fif->log(type_log_error, "MACRO - ERROR, reset not completed");
|
|
return false;
|
|
}
|
|
|
|
fif->rtgWaitEvent(WAIT_TIME_INIT_OPERATION);
|
|
|
|
cx.ctrl[r_srr]=0;
|
|
|
|
if (!fpgaWrite(r_base, &cx.ctrl, 256,"reset"))
|
|
{
|
|
fif->notify(FpgaFlashInterface::s_reset, -1, "ERROR, reset not completed");
|
|
fif->log(type_log_error, "MACRO - ERROR - reset not completed");
|
|
return false;
|
|
}
|
|
|
|
fif->rtgWaitEvent(WAIT_TIME_INIT_OPERATION*5);
|
|
|
|
fif->notify(FpgaFlashInterface::s_reset, -1, "Ok, reset completed");
|
|
|
|
fif->log(type_log_success, "MACRO - DONE - reset");
|
|
return true;
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Fpga write
|
|
// Input parameters: address = address to write
|
|
// data = buffer to write
|
|
// len = buffer's length
|
|
// mess = message to write into debug log
|
|
// Returns: true, no error
|
|
// false, generic error into write function
|
|
//***********************************************************************
|
|
bool FlashOperation::fpgaWrite(uint32_t address, const void* data, unsigned int len, const char* mess)
|
|
{
|
|
|
|
fif->log(type_log_info, "WRITE: 0x%X*%u CMD=0x%02X MOD=0x%02X ADR=0x%02X LEN=0x%02X SPICR=0x%02X SRR=0x%02X CMD=(%s)(%s)",
|
|
address*4,
|
|
len,
|
|
cx.ctrl[r_cmdr],
|
|
cx.ctrl[r_moder],
|
|
cx.ctrl[r_addrr],
|
|
cx.ctrl[r_nbr],
|
|
cx.ctrl[r_spicr],
|
|
cx.ctrl[r_srr],
|
|
retCommand(cx.ctrl[r_cmdr]),
|
|
mess);
|
|
|
|
bool ok=fif->rtgWrite(address*4, data, len);
|
|
|
|
return ok;
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Fpga Read
|
|
// Input parameters: address = address to read
|
|
// data = ouput buffer
|
|
// len = buffer's length
|
|
// mess = message to write into debug log
|
|
// Returns: true, no error
|
|
// false, generic error into read function
|
|
//***********************************************************************
|
|
bool FlashOperation::fpgaRead(uint32_t address, void* data, unsigned int len, const char* mess)
|
|
{
|
|
//fif->rtgWaitEvent(WAIT_TIME_MS);
|
|
fif->log(type_log_info, "READ request: 0x%X*%u CMD=0x%02X MOD=0x%02X ADR=0x%02X LEN=0x%02X SPICR=0x%02X SRR=0x%02X SPISR=0x%02X CMD=(%s)(%s)",
|
|
address*4,
|
|
len,
|
|
cx.ctrl[r_cmdr],
|
|
cx.ctrl[r_moder],
|
|
cx.ctrl[r_addrr],
|
|
cx.ctrl[r_nbr],
|
|
cx.ctrl[r_spicr],
|
|
cx.ctrl[r_srr],
|
|
cx.ctrl[r_spisr],
|
|
retCommand(cx.ctrl[r_cmdr]),
|
|
mess);
|
|
|
|
bool ok=fif->rtgRead(address*4, data, len);
|
|
|
|
fif->log(type_log_info, "READ response: 0x%X*%u CMD=0x%02X MOD=0x%02X ADR=0x%02X LEN=0x%02X SPICR=0x%02X SRR=0x%02X SPISR=0x%02X CMD=(%s)(%s)",
|
|
address*4,
|
|
len,
|
|
cx.ctrl[r_cmdr],
|
|
cx.ctrl[r_moder],
|
|
cx.ctrl[r_addrr],
|
|
cx.ctrl[r_nbr],
|
|
cx.ctrl[r_spicr],
|
|
cx.ctrl[r_srr],
|
|
cx.ctrl[r_spisr],
|
|
retCommand(cx.ctrl[r_cmdr]),
|
|
mess);
|
|
|
|
return ok;
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Fpga Read
|
|
// Input parameters: address = address to read
|
|
// data = ouput buffer
|
|
// len = buffer's length
|
|
// mess = message to write into debug log
|
|
// Returns: true, no error
|
|
// false, generic error into read function
|
|
//***********************************************************************
|
|
bool FlashOperation::fpgaReadFPGAFWIBC(uint32_t address, void* data, unsigned int len, const char* mess)
|
|
{
|
|
fif->rtgWaitEvent(WAIT_TIME_INIT_OPERATION);
|
|
bool ok=fif->rtgReadDirect(address, data, len);
|
|
|
|
|
|
fif->log(type_log_info, "READ: 0x%X*%u CMD=%s",
|
|
address,
|
|
len,
|
|
mess);
|
|
|
|
return ok;
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Send command
|
|
// Input parameters: cmd = address to send command
|
|
// data = buffer that contains register value
|
|
// len = buffer's length
|
|
// type_cmd = nc/write/read
|
|
// Returns: false = error in sendCommand function
|
|
// true = No error
|
|
//***********************************************************************
|
|
bool FlashOperation::sendCommand(unsigned int cmd, void *data, unsigned int len, type_cmd_t type_cmd)
|
|
{
|
|
bool res = false;
|
|
|
|
//1. Set the MODER register.
|
|
//2. Set the CMDR register.
|
|
//3. Set the ADDRR register (this register setting depends by the command set into CMDR. Refer to Table 25 to know if this setting is requested or not).
|
|
//4. Set the NBR register (this register setting depends by the command set into CMDR. Refer to Table 25 to know if this setting is requested or not)
|
|
cx.ctrl[r_cmdr]=cmd;
|
|
|
|
//5. Set the "SPI request" bit into the SPICR register
|
|
prepareTransaction();
|
|
res = fpgaWrite(r_base, cx.ctrl, len,"prepare transaction");
|
|
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, "ERROR - fpgaWrite - prepare transaction");
|
|
return false;
|
|
}
|
|
|
|
//6. Wait until "SPI core Acknowledge" bit into the SPISR is raised by the core.
|
|
unsigned int spisr = 0;
|
|
|
|
unsigned long t_start=fif->timeNowMs();
|
|
unsigned long t_stop=fif->timeNowMs();
|
|
|
|
bool timeout = false;
|
|
|
|
bool is_spi_core_ack = false;
|
|
bool is_spi_core_error = false;
|
|
counterRepeat = 0;
|
|
|
|
do
|
|
{
|
|
res = fpgaRead(r_spi_status_base, &cx.ctrl[r_spi_status_base], len,"wait until Ack SPI is set, first");
|
|
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, "ERROR - fpgaRead - wait until Ack SPI is set, first");
|
|
return false;
|
|
}
|
|
|
|
spisr = cx.ctrl[r_spisr];
|
|
|
|
//QString tst = QString("fpgaRead SPISR=%1 - wait until Ack SPI is set, first").arg(spisr, 0, 16);
|
|
//fif->log(type_log_debug, tst.toStdString().c_str());
|
|
|
|
t_stop = fif->timeNowMs();
|
|
timeout = !(t_stop-t_start<TIMEOUT_SPI);
|
|
|
|
is_spi_core_ack = decodeSPISR(spisr, spi_core_ack);
|
|
is_spi_core_error = decodeSPISR(spisr, spi_core_error);
|
|
if(!is_spi_core_ack && !is_spi_core_error)
|
|
{
|
|
incrCounterRepeat();
|
|
|
|
QString msg = QString("REPEAT %1 - fpgaRead - wait until Ack SPI is set, first").arg(counterRepeat);
|
|
fif->log(type_log_error, msg.toStdString().c_str());
|
|
fif->rtgWaitEvent(WAIT_TIME_BEFORE_NEW_RD);
|
|
}
|
|
} while (!is_spi_core_ack && !is_spi_core_error && (!timeout));
|
|
|
|
//7. Check "SPI Core Error" bit is not raised (core error can be raised if currently requested command is not supported).
|
|
if (decodeSPISR(spisr, spi_core_error))
|
|
{
|
|
//error in spi transaction
|
|
fif->log(type_log_error, "ERROR: SPI_CORE CMD=0x%02X MOD=0x%02X ADR=0x%02X LEN=0x%02X SPICR=0x%02X SRR=0x%02X SPISR=0x%02X CMD=(%s)",
|
|
cx.ctrl[r_cmdr],
|
|
cx.ctrl[r_moder],
|
|
cx.ctrl[r_addrr],
|
|
cx.ctrl[r_nbr],
|
|
cx.ctrl[r_spicr],
|
|
cx.ctrl[r_srr],
|
|
cx.ctrl[r_spisr],
|
|
retCommand(cx.ctrl[r_cmdr]));
|
|
|
|
decodeSPIRError(spisr);
|
|
return false;
|
|
}
|
|
|
|
if (timeout)
|
|
{
|
|
fif->log(type_log_error, "TIMEOUT wait until Ack SPI is set, first ");
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
//8. In case currently requested command requires to fill the TX FIFO (refers to Table 25), fill the trasmission buffer by writing data @ the SPIDTR register
|
|
if(type_cmd==cmd_write)
|
|
{
|
|
//riempio il buffer da scrivere
|
|
res = fpgaWrite(adr_fifo, data, len, "write buffer into fifo");
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, "ERROR - fpgaWrite - write buffer into fifo");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//9. Set the "SPI start" bit into the SPICR register (maintaining the "SPI request" bit set)
|
|
startTransaction();
|
|
res = fpgaWrite(r_base, cx.ctrl, len, "set SPI Start, start transaction ");
|
|
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, "ERROR - fpgaWrite - set SPI Start, start transaction");
|
|
return false;
|
|
}
|
|
|
|
//10. Wait until "SPI busy" into the SPISR is set
|
|
t_start=fif->timeNowMs();
|
|
timeout = false;
|
|
|
|
counterRepeat = 0;
|
|
|
|
bool is_spi_core_busy = false;
|
|
do
|
|
{
|
|
res = fpgaRead(r_spi_status_base, &cx.ctrl[r_spi_status_base], len, "wait until busy SPI is set, first");
|
|
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, "ERROR - fpgaRead - wait until busy SPI is set, first");
|
|
return false;
|
|
}
|
|
|
|
spisr = cx.ctrl[r_spisr];
|
|
t_stop=fif->timeNowMs();
|
|
timeout = !(t_stop-t_start<TIMEOUT_SPI);
|
|
|
|
//QString tst = QString("fpgaRead SPISR=%1 - wait until busy SPI is set, first").arg(spisr, 0, 16);
|
|
//fif->log(type_log_debug, tst.toStdString().c_str());
|
|
|
|
is_spi_core_busy = decodeSPISR(spisr, spi_core_busy);
|
|
is_spi_core_error = decodeSPISR(spisr, spi_core_error);
|
|
if(!is_spi_core_busy && !is_spi_core_error)
|
|
{
|
|
incrCounterRepeat();
|
|
|
|
QString msg = QString("REPEAT %1 - fpgaRead - wait until busy SPI is set, first").arg(counterRepeat);
|
|
fif->log(type_log_error, msg.toStdString().c_str());
|
|
fif->rtgWaitEvent(WAIT_TIME_BEFORE_NEW_RD);
|
|
}
|
|
|
|
} while (!is_spi_core_busy && !is_spi_core_error && (!timeout));
|
|
|
|
if (decodeSPISR(spisr, spi_core_error))
|
|
{
|
|
//error in spi transaction
|
|
fif->log(type_log_error, "ERROR: SPI_CORE CMD=0x%02X MOD=0x%02X ADR=0x%02X LEN=0x%02X SPICR=0x%02X SRR=0x%02X SPISR=0x%02X CMD=(%s)",
|
|
cx.ctrl[r_cmdr],
|
|
cx.ctrl[r_moder],
|
|
cx.ctrl[r_addrr],
|
|
cx.ctrl[r_nbr],
|
|
cx.ctrl[r_spicr],
|
|
cx.ctrl[r_srr],
|
|
cx.ctrl[r_spisr],
|
|
retCommand(cx.ctrl[r_cmdr]));
|
|
|
|
decodeSPIRError(spisr);
|
|
|
|
return false;
|
|
}
|
|
|
|
if (timeout)
|
|
{
|
|
fif->log(type_log_error, "TIMEOUT wait until busy SPI is set, first ");
|
|
return false;
|
|
}
|
|
|
|
//11. Reset "SPI start" bit
|
|
endTransaction();
|
|
res = fpgaWrite(r_base, cx.ctrl, len, "reset SPI Start");
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, "ERROR - fpgaWrite - reset SPI Start");
|
|
return false;
|
|
}
|
|
|
|
//12. Wait until "SPI busy" into the SPISR is reset
|
|
t_start=fif->timeNowMs();
|
|
timeout = false;
|
|
is_spi_core_busy = false;
|
|
counterRepeat = 0;
|
|
do
|
|
{
|
|
res = fpgaRead(r_spi_status_base, &cx.ctrl[r_spi_status_base], len, "wait until busy SPI is reset");
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, "ERROR - fpgaRead - wait until busy SPI is reset");
|
|
return false;
|
|
}
|
|
spisr = cx.ctrl[r_spisr];
|
|
|
|
//QString tst = QString("fpgaRead SPISR=%1 - wait until busy SPI is reset").arg(spisr, 0, 16);
|
|
//fif->log(type_log_debug, tst.toStdString().c_str());
|
|
|
|
t_stop=fif->timeNowMs();
|
|
timeout = !(t_stop-t_start<TIMEOUT_SPI);
|
|
|
|
is_spi_core_busy = decodeSPISR(spisr, spi_core_busy);
|
|
is_spi_core_error = decodeSPISR(spisr, spi_core_error);
|
|
if(is_spi_core_busy && !is_spi_core_error)
|
|
{
|
|
incrCounterRepeat();
|
|
|
|
QString msg = QString("REPEAT %1 - fpgaRead - wait until busy SPI is reset").arg(counterRepeat);
|
|
fif->log(type_log_error, msg.toStdString().c_str());
|
|
fif->rtgWaitEvent(WAIT_TIME_BEFORE_NEW_RD);
|
|
}
|
|
|
|
} while (is_spi_core_busy && !is_spi_core_error && (!timeout));
|
|
|
|
//13. Check "SPI Core Error" bit is not raised (core error can be raised if currently requested command generates an underflow or overflow error).
|
|
if (decodeSPISR(spisr, spi_core_error))
|
|
{
|
|
//error in spi transaction
|
|
//error in spi transaction
|
|
fif->log(type_log_error, "ERROR: SPI_CORE CMD=0x%02X MOD=0x%02X ADR=0x%02X LEN=0x%02X SPICR=0x%02X SRR=0x%02X SPISR=0x%02X CMD=(%s)",
|
|
cx.ctrl[r_cmdr],
|
|
cx.ctrl[r_moder],
|
|
cx.ctrl[r_addrr],
|
|
cx.ctrl[r_nbr],
|
|
cx.ctrl[r_spicr],
|
|
cx.ctrl[r_srr],
|
|
cx.ctrl[r_spisr],
|
|
retCommand(cx.ctrl[r_cmdr]));
|
|
|
|
decodeSPIRError(spisr);
|
|
|
|
return false;
|
|
}
|
|
|
|
if (timeout)
|
|
{
|
|
fif->log(type_log_error, "TIMEOUT wait until busy SPI is reset");
|
|
return false;
|
|
}
|
|
|
|
//14. In case a read command has been requested, readout read data @ SPIDRR
|
|
//READDATA IF NECESSARY
|
|
bool is_rx_fifo_valid= false;
|
|
if(type_cmd==cmd_read)
|
|
{
|
|
//controllo se ho un dato valido nella fifo
|
|
if (decodeSPISR(spisr, rx_fifo_valid))
|
|
{
|
|
counterRepeat = 0;
|
|
|
|
do
|
|
{
|
|
//leggo il buffer che mi è stato spedito
|
|
res = fpgaRead(r_base+r_spirr, data, len, "read data from FIFO");
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, "ERROR - fpgaRead - read data from FIFO");
|
|
return false;
|
|
}
|
|
|
|
fif->rtgWaitEvent(WAIT_TIME_BETWEEN_2_OP);
|
|
|
|
//leggo lo stato del registro spi per capire se ho ancora dati validi da leggere
|
|
res = fpgaRead(r_spi_status_base, &cx.ctrl[r_spi_status_base], len, "check if rx is still valid");
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, "ERROR - fpgaRead - check if rx is still valid");
|
|
return false;
|
|
}
|
|
spisr = cx.ctrl[r_spisr];
|
|
|
|
//QString tst = QString("fpgaRead SPISR=%1 - check if rx is still valid").arg(spisr, 0, 16);
|
|
//fif->log(type_log_debug, tst.toStdString().c_str());
|
|
|
|
is_rx_fifo_valid = decodeSPISR(spisr, rx_fifo_valid);
|
|
is_spi_core_error = decodeSPISR(spisr, spi_core_error);
|
|
if (is_rx_fifo_valid && !is_spi_core_error)
|
|
{
|
|
incrCounterRepeat();
|
|
QString msg = QString("REPEAT %1 - fpgaRead - check if rx is still valid").arg(counterRepeat);
|
|
fif->log(type_log_error, msg.toStdString().c_str());
|
|
fif->rtgWaitEvent(WAIT_TIME_BEFORE_NEW_RD);
|
|
}
|
|
} while (is_rx_fifo_valid && !is_spi_core_error); //ciclo per controllare che ilbit rx valid sia a 1
|
|
|
|
if (decodeSPISR(spisr, spi_core_error))
|
|
{
|
|
//error in spi transaction
|
|
//error in spi transaction
|
|
fif->log(type_log_error, "ERROR: SPI_CORE CMD=0x%02X MOD=0x%02X ADR=0x%02X LEN=0x%02X SPICR=0x%02X SRR=0x%02X SPISR=0x%02X CMD=(%s)",
|
|
cx.ctrl[r_cmdr],
|
|
cx.ctrl[r_moder],
|
|
cx.ctrl[r_addrr],
|
|
cx.ctrl[r_nbr],
|
|
cx.ctrl[r_spicr],
|
|
cx.ctrl[r_srr],
|
|
cx.ctrl[r_spisr],
|
|
retCommand(cx.ctrl[r_cmdr]));
|
|
|
|
decodeSPIRError(spisr);
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//15. De-assert "SPI request" bit.
|
|
resetTransaction();
|
|
res = fpgaWrite(r_base, cx.ctrl, len, "reset SPI request");
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, "ERROR - fpgaWrite - reset SPI request");
|
|
return false;
|
|
}
|
|
|
|
//16. Wait until "SPI core Acknowledge" bit into the SPISR is de-asserted by the core
|
|
t_start=fif->timeNowMs();
|
|
timeout = false;
|
|
is_spi_core_ack = false;
|
|
counterRepeat = 0;
|
|
do
|
|
{
|
|
res = fpgaRead(r_spi_status_base, &cx.ctrl[r_spi_status_base], len, "wait if spi core ack de-asserted, second");
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, "ERROR - fpgaRead - wait if spi core ack de-asserted, second");
|
|
return false;
|
|
}
|
|
spisr = cx.ctrl[r_spisr];
|
|
t_stop=fif->timeNowMs();
|
|
timeout = !(t_stop-t_start<TIMEOUT_SPI);
|
|
|
|
//QString tst = QString("fpgaRead SPISR=%1 - wait if spi core ack de-asserted, second").arg(spisr, 0, 16);
|
|
//fif->log(type_log_debug, tst.toStdString().c_str());
|
|
|
|
is_spi_core_ack = decodeSPISR(spisr, spi_core_ack);
|
|
is_spi_core_error = decodeSPISR(spisr, spi_core_error);
|
|
if (is_spi_core_ack && !is_spi_core_error)
|
|
{
|
|
incrCounterRepeat();
|
|
QString msg = QString("REPEAT %1 - fpgaRead - wait if spi core ack de-asserted, second").arg(counterRepeat);
|
|
fif->log(type_log_error, msg.toStdString().c_str());
|
|
fif->rtgWaitEvent(WAIT_TIME_BEFORE_NEW_RD);
|
|
}
|
|
} while (is_spi_core_ack && !is_spi_core_error && (!timeout));
|
|
|
|
if (decodeSPISR(spisr, spi_core_error))
|
|
{
|
|
//error in spi transaction
|
|
fif->log(type_log_error, "ERROR: SPI_CORE CMD=0x%02X MOD=0x%02X ADR=0x%02X LEN=0x%02X SPICR=0x%02X SRR=0x%02X SPISR=0x%02X CMD=(%s)",
|
|
cx.ctrl[r_cmdr],
|
|
cx.ctrl[r_moder],
|
|
cx.ctrl[r_addrr],
|
|
cx.ctrl[r_nbr],
|
|
cx.ctrl[r_spicr],
|
|
cx.ctrl[r_srr],
|
|
cx.ctrl[r_spisr],
|
|
retCommand(cx.ctrl[r_cmdr]));
|
|
|
|
decodeSPIRError(spisr);
|
|
|
|
return false;
|
|
}
|
|
|
|
if (timeout)
|
|
{
|
|
fif->log(type_log_error, "TIMEOUT wait if spi core ack");
|
|
return false;
|
|
}
|
|
|
|
fif->log(type_log_success, "MACRO FINISHED");
|
|
|
|
return true;
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Read Flash ID
|
|
// Input parameters:
|
|
// Returns: "" if no able to read flash ID
|
|
// "<flashid string" contains the flash id
|
|
// Note 1: ATTENTION! this fuction is required to Unlock FPGA interface
|
|
// Note 2: r_moder = 0x08 if secondary FLASH, 0x00 if primary FLASH
|
|
//***********************************************************************
|
|
bool FlashOperation::readFlashID(reg_moder_qspiport_t spi_port)
|
|
{
|
|
fif->log(type_log_info, "-> MACRO - Unlocking FPGA interface, read FLASH ID, first step");
|
|
|
|
char flash_id[32]; //flash id
|
|
char fw_id[32]; //fpga firmware IBC
|
|
|
|
for (int i = 0;i< FLASH_ID_SIZE; i++)
|
|
FLASH_ID[i] = 0x0;
|
|
|
|
init(moder_spimode_x1mode, moder_byteaddress/*bytes3address*/, spi_port);
|
|
|
|
cx.ctrl[r_nbr] = FLASH_ID_NUMBER_OF_BYTES; //dimension of flash id in bytes
|
|
|
|
//sprintf (fw_id, "Flash ID - before first step =%.4s%.4s%.4s%.4s", (char *)&FLASH_ID[0], (char *)&FLASH_ID[1], (char *)&FLASH_ID[2], (char *)&FLASH_ID[3]);
|
|
//fif->log(0, "read FLASH ID = %s", fw_id);
|
|
|
|
if (!sendCommand(cmdr_read_id, &FLASH_ID[0],256,cmd_read))//cmd_read_flashID)) //Command Register: "x9E"
|
|
{
|
|
fif->notify(FpgaFlashInterface::s_read_id, -1, "ERROR, read Flash ID, first step, NOT completed");
|
|
return false;
|
|
}
|
|
|
|
fif->rtgWaitEvent(WAIT_TIME_INIT_OPERATION);
|
|
|
|
//sprintf (fw_id, "Flash ID - before second step =%.4s%.4s%.4s%.4s", (char *)&FLASH_ID[0], (char *)&FLASH_ID[1], (char *)&FLASH_ID[2], (char *)&FLASH_ID[3]);
|
|
//fif->log(0, "read FLASH ID = %s", fw_id);
|
|
|
|
fif->log(type_log_info, "MACRO - DONE - read FLASH ID, first step");
|
|
|
|
//(NOTA: a causa di un funzionamento anomalo della primitiva STARTUPE dichiarata dalla xilinx stessa,
|
|
//la prima operazione è da considerare dummy e va ripetuta una seconda volta per essere eseguita).
|
|
|
|
fif->log(type_log_info, " ->MACRO - Unlocking FPGA interface, read FLASH ID, second step");
|
|
|
|
if (!sendCommand(cmdr_read_id, &FLASH_ID[0],256,cmd_read)) //Command Register: "x9E"
|
|
{
|
|
fif->notify(FpgaFlashInterface::s_read_id, -1, "ERROR, read Flash ID, second step, NOT completed");
|
|
return false;
|
|
}
|
|
|
|
fif->rtgWaitEvent(WAIT_TIME_INIT_OPERATION);
|
|
|
|
sprintf (flash_id, "0x%8.8lX", FLASH_ID[0]);
|
|
|
|
/*for (int i = 0; i < sizeof(FLASH_ID)/sizeof(uint32_t); i++)
|
|
{
|
|
sprintf (fw_id, "0x%8.8lX", FLASH_ID[i]);
|
|
fif->log(0, "FLASH ID %d = %s", i, fw_id);
|
|
}*/
|
|
|
|
//fif->log(0, "FLASH ID = %s", FlashIDRead);
|
|
|
|
for (int i = 0;i< FLASH_ID_SIZE; i++)
|
|
FLASH_ID[i] = 0x0;
|
|
|
|
if (!readFPGAFWIBC(&FLASH_ID[0], 256))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
sprintf (fw_id, "%.4s%.4s%.4s", (char *)&FLASH_ID[0], (char *)&FLASH_ID[1], (char *)&FLASH_ID[2]);
|
|
fif->log(type_log_info, "FPGA fw IBC = %s", fw_id);
|
|
|
|
fif->notify(FpgaFlashInterface::s_read_id, -1, "Ok, read FlashID %s, FPGA fw IBC %s completed", flash_id, fw_id);
|
|
|
|
fif->log(type_log_success, "MACRO - DONE - read FLASH ID, second step");
|
|
|
|
return true;
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Sets the FPGA FLASH addressing mode
|
|
// Input parameters: spi_port = primary/secondary spi port
|
|
// byteaddress = 3/4 bytes address
|
|
// Returns: true if ok
|
|
// false if error
|
|
//***********************************************************************
|
|
bool FlashOperation::setByteAddress(reg_moder_qspiport_t spi_port,reg_moder_byteaddress_t byteaddress)
|
|
{
|
|
fif->log(type_log_info, "-> MACRO - Sets the FPGA FLASH addressing mode");
|
|
|
|
bool res = false;
|
|
//abilito la scrittura
|
|
res = writeEnable(true);
|
|
if (!res)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//setEnableMsgBlk(true);
|
|
|
|
init(moder_spimode_x1mode, byteaddress, spi_port);
|
|
|
|
unsigned int cmd = 0;
|
|
|
|
if (byteaddress==bytes4address)
|
|
{
|
|
//enter 4b address mode
|
|
cmd = cmdr_4b_add_enter;
|
|
}
|
|
else
|
|
{
|
|
//exit 4b address mode
|
|
cmd = cmdr_4b_add_exit;
|
|
}
|
|
|
|
cx.ctrl[r_nbr] = 0;
|
|
|
|
if (!sendCommand(cmd, 0, 256, cmd_nc))
|
|
{
|
|
fif->log(type_log_error, "MACRO - ERROR - Sets the FPGA FLASH addressing mode");
|
|
return false;
|
|
}
|
|
|
|
fif->rtgWaitEvent(WAIT_TIME_INIT_OPERATION);
|
|
|
|
fif->log(type_log_success, "MACRO - DONE - Sets the FPGA FLASH addressing mode");
|
|
return true;
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Erase sector
|
|
// Input parameters: sector = n. sector to erase
|
|
//
|
|
// Returns: true if ok
|
|
// false if error
|
|
//***********************************************************************
|
|
bool FlashOperation::eraseSector(unsigned long sector_address)
|
|
{
|
|
fif->log(type_log_info, "-> MACRO - Sector address to erase : @0x%lX", sector_address);
|
|
|
|
bool res = false;
|
|
//abilito la scrittura
|
|
res = writeEnable(true);
|
|
if (!res)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
cx.ctrl[r_addrr] = sector_address;
|
|
cx.ctrl[r_nbr] = 0;
|
|
|
|
//sendCommand(0xD8);
|
|
|
|
res=sendCommand(cmdr_erase_sector,0,256,cmd_nc); //0xd8, sector erase
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, "MACRO - ERROR - Erase sector");
|
|
return false;
|
|
}
|
|
fif->log(type_log_success, "MACRO - DONE - Erase sector");
|
|
|
|
//fif->rtgWaitEvent(WAIT_TIME_BETWEEN_2_MACRO);
|
|
|
|
return true;
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Write enable
|
|
// Input parameters: enable = if true enable write, otherwise disable write
|
|
//
|
|
// Returns: true if ok
|
|
// false if error
|
|
//***********************************************************************
|
|
bool FlashOperation::writeEnable(bool enable)
|
|
{
|
|
bool res = false;
|
|
cx.ctrl[r_addrr]=0;
|
|
cx.ctrl[r_nbr]=0;
|
|
|
|
if (enable)
|
|
fif->log(type_log_info, "-> SUB - Write Enable");
|
|
else
|
|
fif->log(type_log_info, "-> SUB - Write Disable");
|
|
|
|
res = sendCommand(enable ? cmdr_write_enable : cmdr_write_disable, 0, 256,cmd_nc);
|
|
if (!res)
|
|
{
|
|
if (enable)
|
|
fif->log(type_log_error, "ERROR - Write Enable");
|
|
else
|
|
fif->log(type_log_error, "ERROR - Write Disable");
|
|
return false;
|
|
}
|
|
|
|
if (enable)
|
|
fif->log(type_log_success, "SUB - Write Enable, DONE");
|
|
else
|
|
fif->log(type_log_success, "SUB - Write Disable, DONE");
|
|
|
|
fif->rtgWaitEvent(WAIT_TIME_BETWEEN_2_MACRO);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//***********************************************************************
|
|
// Write block
|
|
// Input parameters: address = address where buffer is must be write down
|
|
// data = buffer to write
|
|
// len = lenght of the buffer
|
|
// Returns: true if ok
|
|
// false if error
|
|
//***********************************************************************
|
|
bool FlashOperation::writeBlock(unsigned int address, const char* data, unsigned int len)
|
|
{
|
|
bool res = false;
|
|
//abilito la scrittura
|
|
res = writeEnable(true);
|
|
if (!res)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
unsigned int w_len=len/4;
|
|
const uint32_t* p=reinterpret_cast<const uint32_t*>(data);
|
|
|
|
{//Fill Write FIFO. TODO: byte or word? endianess?
|
|
for(unsigned int i=0; i<w_len; ++i)
|
|
{
|
|
cx.buffer[i]=p[i];
|
|
}
|
|
//fpgaWrite(adr_fifo, cx.buffer, w_len*sizeof(p[0]));
|
|
}
|
|
{//Write block
|
|
cx.ctrl[r_addrr]=address; //5.5.1.3 Address Register (ADDRR), Flash Address on which core will access.
|
|
cx.ctrl[r_nbr]=len; //5.5.1.4 Number of Bytes Register (NBR),Number of bytes on which core shall transact.
|
|
//cx.ctrl[r_spicr]=1; //5.5.1.6 SPI Control Register (SPICR), It starts a previously required transaction
|
|
//cx.ctrl[r_spidtr]=cx.buffer[0]; //5.5.1.7 SPI Transmit FIFO Register (SPIDTR), Data To Be transmitted through the SPI Core.
|
|
res = sendCommand(cmdr_prog_quad_inp, &cx.buffer[0], w_len*sizeof(p[0]), cmd_write); //0x32, quad input fast program
|
|
}
|
|
|
|
if (!res)
|
|
{
|
|
fif->notify(FpgaFlashInterface::s_end, -1, "Fail write Block");
|
|
return false;
|
|
}
|
|
|
|
fif->rtgWaitEvent(WAIT_TIME_BETWEEN_2_MACRO);
|
|
|
|
if (!confirmFlashOperation())
|
|
{
|
|
fif->notify(FpgaFlashInterface::s_end, -1, "Fail confirm write Block");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
//fif->notify(FpgaFlashInterface::s_end, -1, "Ok, write Block");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Set/unset QuadSPI communication between FPGA and Flash
|
|
// Input parameters: _flag = true is set quadSPI
|
|
// false is set normalSPI
|
|
// Returns: true if ok
|
|
// false if error
|
|
//***********************************************************************
|
|
bool FlashOperation::setQuadSpiMode(bool _flag)
|
|
{
|
|
bool res = false;
|
|
|
|
if (_flag)
|
|
{
|
|
fif->log(type_log_info, "-> MACRO - Enable QuadSPI");
|
|
}
|
|
else
|
|
{
|
|
fif->log(type_log_info, "-> MACRO - Enable NormalSPI");
|
|
}
|
|
|
|
res = writeEnable(true);
|
|
if (!res)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
setEnableMsgBlk(true);
|
|
MyDebug.setLevel(log_level_max);
|
|
|
|
if (_flag)
|
|
{
|
|
//Set FLASH Volatile Config. Register (modalità SPI 4x)->
|
|
char data[256] ;
|
|
data[0]=0x6F; //Data Transmit Reg: 0x"6F"
|
|
cx.ctrl[r_nbr]=1;
|
|
|
|
res = sendCommand(cmdr_write_enhan,&data[0],256,cmd_write); //0x61, write enhanced volatile configuration register
|
|
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, " MACRO - ERROR - set QuadSPI not completed");
|
|
return false;
|
|
}
|
|
|
|
//configure mode register
|
|
cx.ctrl[r_moder]=
|
|
moder_spimode_x4mode<<0 //quad spi
|
|
|(moder_byteaddress<<2)
|
|
|(moder_qspiport<<3);
|
|
|
|
}
|
|
else
|
|
{
|
|
//Set FLASH Volatile Config. Register (modalità SPI 1x)->
|
|
|
|
char data[256] ;
|
|
data[0]=0xFF;//Data Transmit Reg: 0x"FF"
|
|
cx.ctrl[r_nbr]=1;
|
|
|
|
res = sendCommand(cmdr_write_enhan,&data[0],256,cmd_write); //=0x61, write enhanced volatile configuration register);
|
|
|
|
if (!res)
|
|
{
|
|
fif->log(type_log_error, " MACRO - ERROR - set NormalSPI not completed");
|
|
return false;
|
|
}
|
|
|
|
//configure mode register
|
|
cx.ctrl[r_moder]=
|
|
moder_spimode_x1mode<<0 //normal spi
|
|
|(moder_byteaddress<<2)
|
|
|(moder_qspiport<<3);
|
|
|
|
|
|
}
|
|
|
|
/*res = writeEnable(false);
|
|
if (!res)
|
|
{
|
|
return false;
|
|
}*/
|
|
|
|
fif->rtgWaitEvent(WAIT_TIME_BETWEEN_2_MACRO);
|
|
|
|
|
|
if (_flag)
|
|
{
|
|
fif->log(type_log_success, "MACRO - DONE - Enable QuadSPI");
|
|
}
|
|
else
|
|
{
|
|
fif->log(type_log_success, "MACRO - DONE - Enable NormalSPI");
|
|
}
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Program FLASH with data buffer
|
|
// Input parameters: data = buffer to write on flash
|
|
// size = dimension of data buffer
|
|
// Returns: true if ok
|
|
// false if error
|
|
//***********************************************************************
|
|
bool FlashOperation::program(const void* data, unsigned int size)
|
|
{
|
|
//reset counterRepeat
|
|
counterRepeat = 0;
|
|
|
|
//reg_moder_qspiport_t spi_port = primarySpiPort;
|
|
//reg_moder_byteaddress_t byteaddress = bytes4address;
|
|
|
|
//moder_spimode = a_moder_spimode;
|
|
//moder_byteaddress = a_moder_byteaddress;
|
|
moder_qspiport = profile.spiport;
|
|
moder_byteaddress = profile.byteddress;
|
|
|
|
//disable confirm message in write tftp operation
|
|
setEnableMsgBlk(false);
|
|
|
|
//Resetting FPGA interface...
|
|
if (!reset())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!setByteAddress(moder_qspiport, moder_byteaddress))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//Unlocking FPGA interface...
|
|
// r_moder = 0x08 if secondary FLASH, 0x00 if primary FLASH
|
|
|
|
if (!readFlashID(moder_qspiport))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//setEnableMsgBlk(true);
|
|
//Sets the FPGA FLASH addressing mode
|
|
|
|
/*if (!setByteAddress(moder_qspiport, moder_byteaddress))
|
|
{
|
|
return false;
|
|
}*/
|
|
|
|
//set volatile configuration register
|
|
if (!setQuadSpiMode(true))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
fif->log(type_log_info , "MACRO - prima di confirm");
|
|
|
|
if (!confirmFlashOperation())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
fif->log(type_log_info, "MACRO - before erase");
|
|
|
|
// setEnableMsgBlk(true);
|
|
|
|
//********************************************
|
|
//START of erase function
|
|
|
|
//dimensione del singolo blocco da cancellare
|
|
const unsigned int block_bytes=profile.SectorSize_KBytes*1024; //usually 64kbytes
|
|
|
|
//indirizzo del primo blocco da cancellare, base degli indirizzi
|
|
const unsigned long boffset = (profile.BaseOffset);
|
|
|
|
unsigned int blocks = 0;
|
|
|
|
if (size!=1)
|
|
{
|
|
//si tratta di una programmazione non simulata,
|
|
//quindi il size rappresenta effettivamente la dimensione del buffer da scrivere nella flash
|
|
//numero di blocchi di dimensione SectorSize_KBytes in totale nella memoria
|
|
blocks = profile.address_stop_area / block_bytes; //per una memoria da 128 MBit sono 256 blocchi totali
|
|
//per una memoria da 256 MBit sono 512 blocchi totali
|
|
}
|
|
else
|
|
{
|
|
//si tratta della simulazione
|
|
//numero di blocchi di dimensione SectorSize_KBytes in totale nella memoria
|
|
blocks=(size+(block_bytes-1))/block_bytes;
|
|
}
|
|
|
|
//blocco di partenza
|
|
unsigned int block_start=boffset/block_bytes; //blocco 128 per una memoria da 128MBit
|
|
//blocco 256 per una memoria da 256MBit
|
|
|
|
//blocchi che mancano alla fine dello spazio "user" della flash
|
|
unsigned int blocks_to_delete = blocks - block_start - 1; //128 blocchi da cancellare per una memoria da 128MBit
|
|
//256 blocchi da cancellare per una memoria da 256M
|
|
|
|
//faccio l'erase dei blocchi coninvolti nella programmazione
|
|
fif->log(type_log_info, "-> MACRO - Blocks to Erase: start block %u, at address @0x%lX + next %u block(s)" , block_start, boffset , blocks_to_delete);
|
|
|
|
unsigned long t_start=fif->timeNowMs();
|
|
unsigned long t_erase=fif->timeNowMs();
|
|
float t_now = 0;
|
|
|
|
bool ok = false;
|
|
unsigned long baddress = 0;
|
|
int progress = 0;
|
|
|
|
#ifndef NO_WRITE_ERASE
|
|
|
|
#ifdef NUM_BLOCKS_ERASE
|
|
blocks_to_delete = NUM_BLOCKS_ERASE;
|
|
#else
|
|
|
|
#endif
|
|
|
|
for(unsigned int i=0; i<blocks_to_delete; ++i)
|
|
{
|
|
progress=100*(float(i+1)/blocks_to_delete);
|
|
baddress=boffset+i*block_bytes;
|
|
fif->notify(FpgaFlashInterface::s_erase, progress, "Erasing block %u/%u at address @0x%lX", i+block_start,blocks , baddress);
|
|
ok=eraseSector(baddress);
|
|
if (!ok)
|
|
{
|
|
fif->notify(FpgaFlashInterface::s_erase, -1, "Fail %u", i);
|
|
return false;
|
|
}
|
|
|
|
fif->rtgWaitEvent(WAIT_TIME_BETWEEN_2_MACRO);
|
|
|
|
ok = confirmFlashOperation();
|
|
if (!ok)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//t_now=(fif->timeNowMs()-t_erase)/1000;
|
|
t_now=(fif->timeNowMs()-t_erase);
|
|
|
|
//fif->notify(FpgaFlashInterface::s_erase, 100, "Ok, Erased %u sector(s) (%lusecs)", blocks_to_delete, int(t_now));
|
|
fif->notify(FpgaFlashInterface::s_erase, 100, "Ok, Erased %u sector(s) (%s)", blocks_to_delete, QTime::fromMSecsSinceStartOfDay(t_now).toString("hh:mm:ss"));
|
|
|
|
//return false;
|
|
|
|
#endif
|
|
|
|
//setEnableMsgBlk(true);
|
|
|
|
//********************************************
|
|
//END of erase function
|
|
|
|
//********************************************
|
|
//START of program function
|
|
|
|
//calcolo i blocchi da scrivere in base alle dimensioni da programmare e la dimensione del singolo blocco
|
|
const unsigned int frag_size=256;
|
|
blocks=(size+(block_bytes-1))/block_bytes;
|
|
unsigned int psize=((size+(frag_size-1))/frag_size)*frag_size;
|
|
unsigned int frags=psize/frag_size;
|
|
|
|
fif->notify(FpgaFlashInterface::s_init, -1, "Programming %.2fKiB, %u blocks, %u frags", float(size)/1024, blocks, frags);
|
|
|
|
//TODO: multi bank support
|
|
fif->log(type_log_info, "-> MACRO - Writing %u frags...", frags);
|
|
const char* p=reinterpret_cast<const char*>(data);
|
|
|
|
t_start=fif->timeNowMs();
|
|
|
|
unsigned int progr_frags=0;
|
|
progress = 0;
|
|
|
|
int num_block = psize / frag_size;
|
|
|
|
for(unsigned int i=0; i<psize; i+=frag_size, ++progr_frags)
|
|
{
|
|
unsigned long baddress=boffset+i;
|
|
if (i>0)
|
|
{
|
|
progress=100*(float(i)/psize);
|
|
t_now=(fif->timeNowMs()-t_start)/1000;
|
|
float kbytes=i/1024.0;
|
|
float prate=float(kbytes)/t_now;
|
|
|
|
/*fif->notify(FpgaFlashInterface::s_write, progress, "Writing %u/%u @0x%lX (%usec, %fKiBps)",
|
|
progr_frags, num_block, baddress,
|
|
int(t_now), prate);*/
|
|
fif->notify(FpgaFlashInterface::s_write, progress, "Writing %u/%u @0x%lX (%s, %fKiBps)",
|
|
progr_frags, num_block, baddress,
|
|
QTime::fromMSecsSinceStartOfDay(t_now*1000).toString("hh:mm:ss"), prate);
|
|
}
|
|
else
|
|
{
|
|
fif->notify(FpgaFlashInterface::s_write, progress, "Writing %u @0x%lX", progr_frags, baddress);
|
|
}
|
|
bool ok=writeBlock(baddress, &p[i], frag_size);
|
|
if (!ok)
|
|
{
|
|
fif->notify(FpgaFlashInterface::s_write, -1, "Fail %u @0x%lX", progr_frags, baddress);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
//t_now=(fif->timeNowMs()-t_erase)/1000;
|
|
t_now=(fif->timeNowMs()-t_erase);
|
|
|
|
fif->notify(FpgaFlashInterface::s_write, 100, "Ok, Written %u frags = %fMiB (%s)",
|
|
frags,
|
|
float(psize)/(1024*1024),
|
|
QTime::fromMSecsSinceStartOfDay(t_now).toString("hh:mm:ss"));
|
|
|
|
|
|
//********************************************
|
|
//END of program function
|
|
|
|
//riconfiguro l'indirizzamento a 3 byte per tutte le flash anche se quelle da 256 mbit.
|
|
if (!setByteAddress(moder_qspiport, bytes3address))
|
|
{
|
|
//errori nella configurazione dell'indirizzamento a 3 byte
|
|
return false;
|
|
}
|
|
|
|
/*if (!writeEnable(false))
|
|
{
|
|
//errori nella chiusura delle operazioni (disable write)
|
|
return false;
|
|
}*/
|
|
|
|
#ifndef NO_WRITE_ERASE
|
|
float kbytes=psize/1024.0;
|
|
float prate=kbytes/t_now;
|
|
fif->notify(FpgaFlashInterface::s_end, -1, "Completed. %fKiBps", prate);
|
|
#endif
|
|
|
|
//set volatile configuration register
|
|
if (!setQuadSpiMode(false))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//fif->notify(FpgaFlashInterface::s_end, -1, "Ok, write finished");
|
|
return true;
|
|
}
|
|
|
|
//2.4.1.4 Read (singolo data chunk di 256 byte)
|
|
void FlashOperation::readDataChunk(int size, void* data)
|
|
{
|
|
init(moder_spimode, moder_byteaddress, moder_qspiport); //Mode Register: "x06"
|
|
sendCommand(cmdr_mem_fast_read); //0x0b, fast read memory, Command Register: "x0B"
|
|
|
|
do
|
|
{
|
|
sendCommand(cmdr_read_st_reg); //READ REGISTER OPERATION, READ STATUS REGISTER
|
|
} while (getSpiCoreBusy()); //"spi busy" bit del registro SPISR = 0,
|
|
|
|
//unsigned int nElements = cx.ctrl[r_rxfifoocy];
|
|
data = &cx.ctrl[r_spirr];
|
|
|
|
fif->notify(FpgaFlashInterface::s_end, -1, "Ok, read DataChunk completed");
|
|
}
|
|
|
|
|
|
|
|
char* FlashOperation::retCommand(unsigned int cmd)
|
|
{
|
|
const char* res = "";
|
|
switch(cmd)
|
|
{
|
|
//software reset operations,
|
|
case cmdr_reset_enable: //=0x66, //reset enable
|
|
res = "Reset enable";
|
|
break;
|
|
case cmdr_reset_mem: //=0x99, //reset mem
|
|
res = "Reset mem";
|
|
break;
|
|
|
|
//read id operations,
|
|
case cmdr_read_id: //=0x9e,
|
|
res = "read id";
|
|
break;
|
|
case cmdr_multi_io_read_id: //=0xaf,
|
|
res = "multiple I/O read id";
|
|
break;
|
|
case cmdr_read_serial: //=0x05a
|
|
res = "read serial flash discovery parameter";
|
|
break;
|
|
|
|
//read memory operations,
|
|
case cmdr_mem_read: //=0x03,
|
|
res = "read memory";
|
|
break;
|
|
case cmdr_mem_fast_read: //=0x0b,
|
|
res = "fast read memory";
|
|
break;
|
|
case cmdr_mem_dual_read: //=0x3b,
|
|
res = "dual output fast read";
|
|
break;
|
|
case cmdr_mem_quad_read: //=0x6b,
|
|
res = "quad output fast read";
|
|
break;
|
|
|
|
//write operations,
|
|
case cmdr_write_enable: //=0x06,
|
|
res = "write enable";
|
|
break;
|
|
case cmdr_write_disable: //=0x04,
|
|
res = "write disable";
|
|
break;
|
|
|
|
//read register operation,
|
|
case cmdr_read_st_reg: //=0x05,
|
|
res = "read status register";
|
|
break;
|
|
case cmdr_read_flag_st: //=0x70,
|
|
res = "read flag status register";
|
|
break;
|
|
case cmdr_read_non_vol: //=0xb5,
|
|
res = "read non-volatile config register";
|
|
break;
|
|
case cmdr_read_vol: //=0x85,
|
|
res = "read volatile config register";
|
|
break;
|
|
case cmdr_read_enhan: //=0x65,
|
|
res = "read enhanced volatile config register";
|
|
break;
|
|
case cmdr_read_gen_purp: //=0x96,
|
|
res = "read general purpose read register";
|
|
break;
|
|
|
|
//write register operation,
|
|
case cmdr_write_st_reg: //=0x01,
|
|
res = "write status register";
|
|
break;
|
|
case cmdr_write_non_vol: //=0xb1,
|
|
res = "write non-volatile configuration register";
|
|
break;
|
|
case cmdr_write_vol: //=0x81,
|
|
res = "write volatile configuration register";
|
|
break;
|
|
case cmdr_write_enhan: //=0x61,
|
|
res = "write enhanced volatile configuration register";
|
|
break;
|
|
case cmdr_write_ext: //=0xc5,
|
|
res = "write extended address register";
|
|
break;
|
|
case cmdr_clear_st_reg: //=0x50,
|
|
res = "clear flag status register";
|
|
break;
|
|
|
|
//program operation,
|
|
case cmdr_prog_page: //=0x02,
|
|
res = "page program";
|
|
break;
|
|
case cmdr_prog_dual_inp: //=0xa2,
|
|
res = "dual input fast program";
|
|
break;
|
|
case cmdr_prog_ext_dual: //=0xd2,
|
|
res = "extended dual input fast program";
|
|
break;
|
|
case cmdr_prog_quad_inp: //=0x32,
|
|
res = "quad input fast program";
|
|
break;
|
|
case cmdr_prog_ext_quad: //=0x38,
|
|
res = "extended quad input fast program";
|
|
break;
|
|
|
|
//erase operation,
|
|
case cmdr_erase_32kb: //=0x52,
|
|
res = "32 kb subsector erase";
|
|
break;
|
|
case cmdr_erase_4kb: //=0x20,
|
|
res = "4kb subsector erase";
|
|
break;
|
|
case cmdr_erase_sector: //=0xd8,
|
|
res = "sector erase";
|
|
break;
|
|
case cmdr_erase_bulk: //=0xc7,
|
|
res = "bulk erase";
|
|
break;
|
|
|
|
//4-byte address mode operations
|
|
case cmdr_4b_add_enter: //=0xb7,
|
|
res = "enter 4b address mode";
|
|
break;
|
|
case cmdr_4b_add_exit: //=0xe9,
|
|
res = "exit 4b address mode";
|
|
break;
|
|
|
|
//quad protocol operations
|
|
case cmdr_quad_io_enter: //=0x35,
|
|
res = "enter quad io mode";
|
|
break;
|
|
case cmdr_quad_io_exit: //=0xf5,
|
|
res = "exit quad io mode";
|
|
break;
|
|
|
|
//power down
|
|
case cmdr_pwr_enter: //=0xb9,
|
|
res = "enter deep power down";
|
|
break;
|
|
case cmdr_pwr_release: //=0xab,
|
|
res = "release deep power down";
|
|
break;
|
|
|
|
//advanced sector protection
|
|
case cmdr_sect_read: //=0x2d,
|
|
res = "read sector protection";
|
|
break;
|
|
case cmdr_sect_progr: //=0x2c,
|
|
res = "program sector protection";
|
|
break;
|
|
case cmdr_sect_read_vol: //=0xe8,
|
|
res = "read volatile lock bits";
|
|
break;
|
|
case cmdr_sect_write_vol: //=0xe5,
|
|
res = "write volatile lock bits";
|
|
break;
|
|
case cmdr_sect_read_non_vol: //=0xe2,
|
|
res = "read nonvolatile lock bits";
|
|
break;
|
|
case cmdr_sect_write_non_vol: //=0xe3,
|
|
res = "write nonvolatile lock bits";
|
|
break;
|
|
case cmdr_sect_erase_non_vol: //=0xe4,
|
|
res = "erase nonvolatile lock bits";
|
|
break;
|
|
case cmdr_sect_read_freez: //=0xa7,
|
|
res = "read global freeze bit";
|
|
break;
|
|
case cmdr_sect_write_freez: //=0xa6,
|
|
res = "write global freeze bit";
|
|
break;
|
|
case cmdr_sect_red_pwd: //=0x27,
|
|
res = "read password";
|
|
break;
|
|
case cmdr_sect_write_pwd: //=0x28,
|
|
res = "write password";
|
|
break;
|
|
case cmdr_sect_unlock_pwd: //=0x29,
|
|
res = "unlock password";
|
|
break;
|
|
|
|
//advanced function interface
|
|
case cmdr_int_activation: //=0x9b
|
|
res = "interface activation";
|
|
break;
|
|
}
|
|
|
|
return (char*)res;
|
|
}
|
|
|
|
/*2.4.1.2 Erase
|
|
For (i=0; i++; i==(Flash Sectors)/2)) Loop
|
|
FLASH Write Enable (modalità SPI 4X, 4 Byte Addressing)->
|
|
Command Register: "x06" //WRITE OPERATIONS, WRITE ENABLE
|
|
Mode Register: "x06" //110, 4 bytes address, SPI in x4 mode
|
|
Erase Sector (modalità SPI 4X, 4 Byte Addressing) ->
|
|
Command Register: "xD8" //ERASE OPERATION, SECTOR ERASE
|
|
Mode Register: "x06" //110, 4 bytes address, SPI in x4 mode
|
|
Address Register: (Flash Half Address + i * Sector Size) "
|
|
Questo comando effettua un erase del settore appartenente all'indirizzo specificato.
|
|
Loop
|
|
READ Flash Status Register (modalità SPI 4X, 4 Byte Addressing) ->
|
|
Command Register: "x05" //READ REGISTER OPERATION, READ STATUS REGISTER
|
|
Mode Register: "x06" //110, 4 bytes address, SPI in x4 mode
|
|
Questo comando legge lo stato del registro di stato della Flash al fine di aspettare l'avvenuto erase del settore tramite il bit di "Write In Progress"
|
|
Until (SPIDRR & "x01") == 0
|
|
End Loop*/
|
|
|
|
|
|
// Erase from profile.BaseOffset for size
|
|
bool FlashOperation::eraseForSize(unsigned int size)
|
|
{
|
|
//unsigned long t_erase=fif->timeNowMs();
|
|
|
|
const unsigned int block_bytes=profile.SectorSize_KBytes*1024;
|
|
const unsigned long boffset=profile.BaseOffset;
|
|
unsigned int blocks=(size+(block_bytes-1))/block_bytes;
|
|
unsigned int block_start=boffset/block_bytes;
|
|
|
|
fif->log(type_log_info, "Blocks to Erase: %u+%u", block_start, blocks);
|
|
|
|
//for all sector
|
|
for(unsigned int i=0; i<blocks; ++i)
|
|
{
|
|
//FLASH Write Enable (modalità SPI 4X, 4 Byte Addressing)
|
|
int progress=100*(float(i+1)/blocks);
|
|
unsigned long baddress=boffset+i*block_bytes;
|
|
fif->notify(FpgaFlashInterface::s_erase, progress, "Erasing %u @0x%lX", i+block_start, baddress);
|
|
init(moder_spimode, moder_byteaddress, moder_qspiport); //Mode Register: "x06"
|
|
if (eraseSector(i+block_start)) //ERASE OPERATION, SECTOR ERASE
|
|
{
|
|
do
|
|
{
|
|
sendCommand(cmdr_read_st_reg); //READ REGISTER OPERATION, READ STATUS REGISTER
|
|
} while ((cx.ctrl[r_spisr] & 0x01) == 0); //erase is ok -> info is RX_FIFO_VALID bit 0 register SPISR
|
|
}
|
|
else
|
|
{
|
|
writeEnable(false);
|
|
fif->notify(FpgaFlashInterface::s_erase, -1, "Fail %u", i);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//float t_now=(fif->timeNowMs()-t_erase)/1000;
|
|
fif->notify(FpgaFlashInterface::s_erase, -1, "Ok, Erased completed");
|
|
|
|
writeEnable(false);
|
|
return true;
|
|
}
|
|
|
|
|
|
//***********************************************************************
|
|
// readStatusRegisterSPISR
|
|
// Read status register SPISR and put info into cmdr_read_st_reg struct"
|
|
// Input parameters:
|
|
//
|
|
// Returns:
|
|
//***********************************************************************
|
|
bool FlashOperation::readStatusRegisterSPISR()
|
|
{
|
|
//reset status register struct
|
|
memset(&status_register_spisr, 0, sizeof status_register_spisr);
|
|
//reset command struct
|
|
|
|
init(moder_spimode, moder_byteaddress,moder_qspiport);
|
|
sendCommand(cmdr_read_st_reg); //READ REGISTER OPERATION, READ STATUS REGISTER
|
|
|
|
unsigned int spisr = cx.ctrl[r_spisr];
|
|
|
|
status_register_spisr.rx_fifo_valid = decodeSPISR(spisr, rx_fifo_valid); //bit 0, This bit flags that data present into SPIRR is valid
|
|
status_register_spisr.rx_fifo_overrun = decodeSPISR(spisr, rx_fifo_overrun); //bit 1, This bit flags that an overrun error occurred during data reception into the RX FIFO.
|
|
status_register_spisr.tx_fifo_almost_full = decodeSPISR(spisr, tx_fifo_almost_full); //bit 4, This bit flags that an almost full condition occurred loading the TX FIFO. In particular this condition is activated when the number of bytes into the FIFO differs from respect the FIFO size.
|
|
status_register_spisr.tx_fifo_overrun = decodeSPISR(spisr, tx_fifo_overrun); //bit 5, This bit flags that an overrun error occurred loading data into the TX FIFO.
|
|
status_register_spisr.tx_fifo_underrun = decodeSPISR(spisr, tx_fifo_underrun); //bit 6, This bit flags that an underrun error occurred into the TX FIFO during data transmission.
|
|
status_register_spisr.spi_core_error = decodeSPISR(spisr, spi_core_error); //bit 10, The SPI Core error flags an error condition during transaction. This condition can be activated: - when an overrun or underrun is detected (on both "TX FIFO" or "RX FIFO") - when the required command is not implemented
|
|
status_register_spisr.spi_core_ack = decodeSPISR(spisr, spi_core_ack); //bit 11, This bit is activated when a previously required transaction required with the "SPI request" on the SPICR register has been accepted
|
|
status_register_spisr.spi_core_busy = decodeSPISR(spisr, spi_core_busy); //bit 12, This bit is activated when the core is executing the current transaction after that it has been run with the "SPI start" bit on the SPICR register.
|
|
|
|
fif->notify(FpgaFlashInterface::s_status, -1, "Ok, read StatusRegister SPISR completed");
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool FlashOperation::getRxFifoValid()
|
|
{
|
|
readStatusRegisterSPISR();
|
|
return status_register_spisr.rx_fifo_valid;
|
|
}
|
|
|
|
bool FlashOperation::getRxFifoOverrun()
|
|
{
|
|
readStatusRegisterSPISR();
|
|
return status_register_spisr.rx_fifo_overrun;
|
|
}
|
|
|
|
bool FlashOperation::getTxFifoFull()
|
|
{
|
|
readStatusRegisterSPISR();
|
|
return status_register_spisr.tx_fifo_almost_full;
|
|
}
|
|
|
|
bool FlashOperation::getTxFifoOverrun()
|
|
{
|
|
readStatusRegisterSPISR();
|
|
return status_register_spisr.tx_fifo_overrun;
|
|
}
|
|
|
|
bool FlashOperation::getTxFifoUnderrun()
|
|
{
|
|
readStatusRegisterSPISR();
|
|
return status_register_spisr.tx_fifo_underrun;
|
|
}
|
|
|
|
bool FlashOperation::getSpiCoreBusy()
|
|
{
|
|
readStatusRegisterSPISR();
|
|
return status_register_spisr.spi_core_busy;
|
|
}
|
|
|
|
bool FlashOperation::getSpiCoreError()
|
|
{
|
|
readStatusRegisterSPISR();
|
|
return status_register_spisr.spi_core_error;
|
|
}
|
|
|
|
bool FlashOperation::getSpiCoreAck()
|
|
{
|
|
readStatusRegisterSPISR();
|
|
return status_register_spisr.spi_core_ack;
|
|
}
|
|
|
|
//***********************************************************************
|
|
// getWriteInProgress
|
|
// Questo comando legge lo stato del registro di stato della Flash al fine di aspettare
|
|
// l'avvenuta scrittura del pacchetto dati tramite il bit di "Write In Progress"
|
|
// Input parameters:
|
|
//
|
|
// Returns:
|
|
//***********************************************************************
|
|
bool FlashOperation::getWriteInProgress()
|
|
{
|
|
//(SPIDRR & "x01") == 0, che corrisponde al bit 0 del registro SPISR a 1
|
|
return getRxFifoValid();
|
|
}
|
|
|
|
//***********************************************************************
|
|
// get enable message confirm in tftp write operation
|
|
// Input parameters:
|
|
//
|
|
// Returns: true = if is enable
|
|
// false = if is disable
|
|
//***********************************************************************
|
|
bool FlashOperation::getEnableMsgBlk()
|
|
{
|
|
return enabledMsgBlk;
|
|
}
|
|
|
|
//***********************************************************************
|
|
// set enable message confirm in tftp write operation
|
|
// Input parameters: _enable = true if display confirm message
|
|
// = false if not display confirm message
|
|
//
|
|
// Returns:
|
|
//***********************************************************************
|
|
void FlashOperation::setEnableMsgBlk(bool _enabled)
|
|
{
|
|
enabledMsgBlk = _enabled;
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Read Fpga FW IBC
|
|
// Input parameters:
|
|
//
|
|
// Returns: true = success, into data buffer there is the correct value
|
|
// false = error in read FW IBC
|
|
//***********************************************************************
|
|
bool FlashOperation::readFPGAFWIBC(void* data, const int _len)
|
|
{
|
|
return fpgaReadFPGAFWIBC(FPGA_C_MEM_RD_ADD, data, _len,"Read Flash Fw IBC");
|
|
}
|
|
|
|
//***********************************************************************
|
|
// Decode SPIR and diplay all bit status with info
|
|
// Input parameters: _spir = return from SPI status
|
|
//
|
|
// Returns:
|
|
//
|
|
//***********************************************************************
|
|
void FlashOperation::decodeSPIRError(unsigned int _spisr)
|
|
{
|
|
QString msg = "";
|
|
if ((_spisr & rx_fifo_valid)!=0)
|
|
msg.append( "RX fifo valid - ");
|
|
else
|
|
msg.append( "RX fifo NOT valid - ");
|
|
|
|
if ((_spisr & rx_fifo_overrun)!=0)
|
|
msg.append( "overrun - ");
|
|
else
|
|
msg.append( "NOT overrun - ");
|
|
|
|
if ((_spisr & tx_fifo_almost_full)!=0)
|
|
msg.append( "TX fifo almost full - ");
|
|
else
|
|
msg.append( "TX fifo not almost full - ");
|
|
|
|
if ((_spisr & tx_fifo_overrun)!=0)
|
|
msg.append( "overrun - ");
|
|
else
|
|
msg.append( "NOT overrun - ");
|
|
|
|
if ((_spisr & tx_fifo_underrun)!=0)
|
|
msg.append( "underrun - ");
|
|
else
|
|
msg.append( "NOT underrun - ");
|
|
|
|
if ((_spisr & spi_core_error)!=0)
|
|
msg.append( "SPI core error - ");
|
|
else
|
|
msg.append( "SPI core NOT error - ");
|
|
|
|
if ((_spisr & spi_core_ack)!=0)
|
|
msg.append( "ack - ");
|
|
else
|
|
msg.append( "NOT ack - ");
|
|
|
|
if ((_spisr & spi_core_busy)!=0)
|
|
msg.append( "busy.");
|
|
else
|
|
msg.append( "NOT busy.");
|
|
|
|
fif->log(type_log_error, "SPISR=0x%02X -> %s", _spisr ,msg.toStdString().c_str());
|
|
}
|
|
|
|
//***********************************************************************
|
|
// increment counter repeater
|
|
// Input parameters:
|
|
// Returns:
|
|
//***********************************************************************
|
|
void FlashOperation::incrCounterRepeat()
|
|
{
|
|
if (counterRepeat>MAX_COUNTER_REPEAT)
|
|
{
|
|
counterRepeat = 0;
|
|
return;
|
|
}
|
|
counterRepeat++;
|
|
}
|