1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-30 03:38:55 -05:00
sdrangel/liblimesuite/srcmw/lms7002m_mcu/MCU_BD.cpp

1131 lines
31 KiB
C++

/**
@file MCU_BD.cpp
@author Lime Microsystems
@brief Implementation of interacting with on board MCU
*/
#include "MCU_BD.h"
using namespace std;
#include <string>
#include "MCU_File.h"
#include <sstream>
#include <fstream>
#include "LMS64CProtocol.h"
#include <assert.h>
#include <thread>
#include <list>
#include "ErrorReporting.h"
#include "LMS7002M.h"
using namespace lime;
MCU_BD::MCU_BD()
{
mLoadedProgramFilename = "";
m_bLoadedDebug = 0;
m_bLoadedProd = 0;
stepsTotal = 0;
stepsDone = 0;
aborted = false;
callback = nullptr;
mChipID =0;
//ctor
int i=0;
m_serPort=NULL;
//default value,
//must be verified during program exploatation
m_iLoopTries=20;
byte_array_size = cMaxFWSize;
// array initiallization
for (i=0; i<=255; i++){
m_SFR[i]=0x00;
m_IRAM[i]=0x00;
}
for (i=0; i<byte_array_size; i++){
byte_array[i]=0x00;
};
}
MCU_BD::~MCU_BD()
{
//dtor
}
void MCU_BD::Initialize(IConnection* pSerPort, unsigned chipID, unsigned size)
{
m_serPort = pSerPort;
mChipID = chipID;
if (size > 0)
byte_array_size = size;
}
/** @brief Read program code from file into memory
@param inFileName source file path
@param bin binary or hex file
@return 0:success, -1:file not found
*/
int MCU_BD:: GetProgramCode(const char* inFileName, bool bin)
{
unsigned char ch=0x00;
bool find_byte=false;
int i=0;
if(!bin)
{
MCU_File inFile(inFileName, "rb");
if (inFile.FileOpened() == false)
return -1;
mLoadedProgramFilename = inFileName;
try
{
inFile.ReadHex(byte_array_size-1);
}
catch (...)
{
return -1;
}
for (i=0; i<byte_array_size; i++)
{
find_byte=inFile.GetByte(i, ch);
if (find_byte==true)
byte_array[i]=ch;
else
byte_array[i]=0x00;
};
}
else
{
char inByte = 0;
fstream fin;
fin.open(inFileName, ios::in | ios::binary);
if (fin.good() == false)
return -1;
mLoadedProgramFilename = inFileName;
memset(byte_array, 0, byte_array_size);
for(int i=0; i<byte_array_size && !fin.eof(); ++i)
{
inByte = 0;
fin.read(&inByte, 1);
byte_array[i]=inByte;
}
}
return 0;
}
void MCU_BD:: mSPI_write(
unsigned short addr_reg, // takes 16 bit address
unsigned short data_reg) // takes 16 bit value
{
if(m_serPort == nullptr)
return;
uint32_t wrdata = addr_reg << 16 | data_reg;
m_serPort->WriteLMS7002MSPI(&wrdata, 1, mChipID);
}
unsigned short MCU_BD:: mSPI_read(
unsigned short addr_reg) // takes 16 bit address
{// returns 16 bit value
if(m_serPort == nullptr)
return 0;
uint32_t wrdata = addr_reg << 16;
uint32_t rddata = 0;
if(m_serPort->ReadLMS7002MSPI(&wrdata, &rddata, 1, mChipID)!=0)
return 0;
return rddata & 0xFFFF;
}
int MCU_BD::WaitUntilWritten(){
// waits if WRITE_REQ (REG3[2]) flag is equal to '1'
// this means that write operation is in progress
unsigned short tempi=0x0000;
int countDown=m_iLoopTries; // Time out value
tempi=mSPI_read(0x0003); // REG3 read
while (( (tempi&0x0004) == 0x0004) && (countDown>0))
{
tempi=mSPI_read(0x0003); // REG3 read
countDown--;
}
if (countDown==0)
return -1; // an error occured, timer elapsed
else
return 0; // Finished regularly
// pass if WRITE_REQ is '0'
}
int MCU_BD::ReadOneByte(unsigned char * data)
{
unsigned short tempi=0x0000;
int countDown=m_iLoopTries;
// waits when READ_REQ (REG3[3]) flag is equal to '0'
// this means that there is nothing to read
tempi=mSPI_read(0x0003); // REG3 read
while (((tempi&0x0008)==0x0000) && (countDown>0))
{
// wait if READ_REQ is '0'
tempi=mSPI_read(0x0003); // REG3 read
countDown--;
}
if (countDown>0)
{ // Time out has not occured
tempi=mSPI_read(0x0005); // REG5 read
// return the read byte
(* data) = (unsigned char) (tempi);
}
else
(* data) =0;
// return the zero, default value
if (countDown==0)
return -1; // an error occured
else
return 0; // finished regularly
}
int MCU_BD::One_byte_command(unsigned short data1, unsigned char * rdata1)
{
unsigned char tempc=0x00;
int retval=0;
*rdata1=0x00; //default return value
// sends the one byte command
mSPI_write(0x8004, data1); //REG4 write
retval=WaitUntilWritten();
if (retval==-1) return -1;
// error if operation executes too long
// gets the one byte answer
retval=ReadOneByte(&tempc);
if (retval==-1) return -1;
// error if operation takes too long
*rdata1=tempc;
return 0;
}
int MCU_BD::Three_byte_command(
unsigned char data1,unsigned char data2,unsigned char data3,
unsigned char * rdata1,unsigned char * rdata2,unsigned char * rdata3){
int retval=0;
*rdata1=0x00;
*rdata2=0x00;
*rdata3=0x00;
mSPI_write(0x8004, (unsigned short)(data1)); //REG4 write
retval=WaitUntilWritten();
if (retval==-1) return -1;
mSPI_write(0x8004, (unsigned short)(data2)); //REG4 write
retval=WaitUntilWritten();
if (retval==-1) return -1;
mSPI_write(0x8004, (unsigned short)(data3)); //REG4 write
retval=WaitUntilWritten();
if (retval==-1) return -1;
retval= ReadOneByte(rdata1);
if (retval==-1) return -1;
retval= ReadOneByte(rdata2);
if (retval==-1) return -1;
retval= ReadOneByte(rdata3);
if (retval==-1) return -1;
return 0;
}
int MCU_BD::Change_MCUFrequency(unsigned char data) {
unsigned char tempc1, tempc2, tempc3=0x00;
int retval=0;
// code 0x7E is for writing the SFR registers
retval=Three_byte_command(0x7E, 0x8E, data, &tempc1, &tempc2, &tempc3);
// PMSR register, address 0x8E
return retval;
}
int MCU_BD::Read_IRAM()
{
unsigned char tempc1, tempc2, tempc3=0x00;
int i=0;
int retval=0;
//default
//IRAM array initialization
for (i=0; i<=255; i++)
m_IRAM[i]=0x00;
stepsTotal.store(256);
stepsDone.store(0);
aborted.store(false);
for (i=0; i<=255; i++)
{
// code 0x78 is for reading the IRAM locations
retval=Three_byte_command(0x78, ((unsigned char)(i)), 0x00,&tempc1, &tempc2, &tempc3);
if (retval==0)
m_IRAM[i]=tempc3;
else
{
i=256; // error, stop
aborted.store(true);
}
++stepsDone;
#ifndef NDEBUG
printf("MCU reading IRAM: %2i/256\r", stepsDone.load());
#endif
Wait_CLK_Cycles(64);
}
#ifndef NDEBUG
printf("\nMCU reading IRAM finished\n");
#endif
return retval;
}
int MCU_BD::Erase_IRAM()
{
unsigned char tempc1, tempc2, tempc3=0x00;
int retval=0;
int i=0;
//default ini.
for (i=0; i<=255; i++)
m_IRAM[i]=0x00;
stepsTotal.store(256);
stepsDone.store(0);
aborted.store(false);
for (i=0; i<=255; i++)
{
m_IRAM[i]=0x00;
// code 0x7C is for writing the IRAM locations
retval=Three_byte_command(0x7C, ((unsigned char)(i)), 0x00,&tempc1, &tempc2, &tempc3);
if (retval == -1)
{
i = 256;
aborted.store(true);
}
++stepsDone;
#ifndef NDEBUG
printf("MCU erasing IRAM: %2i/256\r", stepsDone.load());
#endif
}
#ifndef NDEBUG
printf("\nMCU erasing IRAM finished\n");
#endif
return retval;
}
int MCU_BD::Read_SFR()
{
int i=0;
unsigned char tempc1, tempc2, tempc3=0x00;
int retval=0;
stepsTotal.store(48);
stepsDone.store(0);
aborted.store(false);
//default m_SFR array initialization
for (i=0; i<=255; i++)
m_SFR[i]=0x00;
// code 0x7A is for reading the SFR registers
retval=Three_byte_command(0x7A, 0x80, 0x00, &tempc1, &tempc2, &tempc3); // P0
if (retval==-1) return -1;
m_SFR[0x80]=tempc3;
retval=Three_byte_command(0x7A, 0x81, 0x00, &tempc1, &tempc2, &tempc3); // SP
if (retval==-1) return -1;
m_SFR[0x81]=tempc3;
retval=Three_byte_command(0x7A, 0x82, 0x00, &tempc1, &tempc2, &tempc3); // DPL0
if (retval==-1) return -1;
m_SFR[0x82]=tempc3;
retval=Three_byte_command(0x7A, 0x83, 0x00, &tempc1, &tempc2, &tempc3); // DPH0
if (retval==-1) return -1;
m_SFR[0x83]=tempc3;
retval=Three_byte_command(0x7A, 0x84, 0x00, &tempc1, &tempc2, &tempc3); // DPL1
if (retval==-1) return -1;
m_SFR[0x84]=tempc3;
retval=Three_byte_command(0x7A, 0x85, 0x00, &tempc1, &tempc2, &tempc3); // DPH1
if (retval==-1) return -1;
m_SFR[0x85]=tempc3;
stepsDone.store(6);
retval=Three_byte_command(0x7A, 0x86, 0x00, &tempc1, &tempc2, &tempc3); // DPS
if (retval==-1) return -1;
m_SFR[0x86]=tempc3;
retval=Three_byte_command(0x7A, 0x87, 0x00, &tempc1, &tempc2, &tempc3); // PCON
if (retval==-1) return -1;
m_SFR[0x87]=tempc3;
retval=Three_byte_command(0x7A, 0x88, 0x00, &tempc1, &tempc2, &tempc3); // TCON
if (retval==-1) return -1;
m_SFR[0x88]=tempc3;
retval=Three_byte_command(0x7A, 0x89, 0x00, &tempc1, &tempc2, &tempc3); // TMOD
if (retval==-1) return -1;
m_SFR[0x89]=tempc3;
retval=Three_byte_command(0x7A, 0x8A, 0x00, &tempc1, &tempc2, &tempc3); // TL0
if (retval==-1) return -1;
m_SFR[0x8A]=tempc3;
retval=Three_byte_command(0x7A, 0x8B, 0x00, &tempc1, &tempc2, &tempc3); // TL1
if (retval==-1) return -1;
m_SFR[0x8B]=tempc3;
stepsDone.store(12);
retval=Three_byte_command(0x7A, 0x8C, 0x00, &tempc1, &tempc2, &tempc3); // TH0
if (retval==-1) return -1;
m_SFR[0x8C]=tempc3;
retval=Three_byte_command(0x7A, 0x8D, 0x00, &tempc1, &tempc2, &tempc3); // TH1
if (retval==-1) return -1;
m_SFR[0x8D]=tempc3;
retval=Three_byte_command(0x7A, 0x8E, 0x00, &tempc1, &tempc2, &tempc3); // PMSR
if (retval==-1) return -1;
m_SFR[0x8E]=tempc3;
retval=Three_byte_command(0x7A, 0x90, 0x00, &tempc1, &tempc2, &tempc3); // P1
if (retval==-1) return -1;
m_SFR[0x90]=tempc3;
retval=Three_byte_command(0x7A, 0x91, 0x00, &tempc1, &tempc2, &tempc3); // DIR1
if (retval==-1) return -1;
m_SFR[0x91]=tempc3;
retval=Three_byte_command(0x7A, 0x98, 0x00, &tempc1, &tempc2, &tempc3); // SCON
if (retval==-1) return -1;
m_SFR[0x98]=tempc3;
stepsDone.store(18);
retval=Three_byte_command(0x7A, 0x99, 0x00, &tempc1, &tempc2, &tempc3); // SBUF
if (retval==-1) return -1;
m_SFR[0x99]=tempc3;
retval=Three_byte_command(0x7A, 0xA0, 0x00, &tempc1, &tempc2, &tempc3); // P2
if (retval==-1) return -1;
m_SFR[0xA0]=tempc3;
retval=Three_byte_command(0x7A, 0xA1, 0x00, &tempc1, &tempc2, &tempc3); // DIR2
if (retval==-1) return -1;
m_SFR[0xA1]=tempc3;
retval=Three_byte_command(0x7A, 0xA2, 0x00, &tempc1, &tempc2, &tempc3); // DIR0
if (retval==-1) return -1;
m_SFR[0xA2]=tempc3;
retval=Three_byte_command(0x7A, 0xA8, 0x00, &tempc1, &tempc2, &tempc3); // IEN0
if (retval==-1) return -1;
m_SFR[0xA8]=tempc3;
stepsDone.store(24);
retval=Three_byte_command(0x7A, 0xA9, 0x00, &tempc1, &tempc2, &tempc3); // IEN1
if (retval==-1) return -1;
m_SFR[0xA9]=tempc3;
retval=Three_byte_command(0x7A, 0xB0, 0x00, &tempc1, &tempc2, &tempc3); // EECTRL
if (retval==-1) return -1;
m_SFR[0xB0]=tempc3;
retval=Three_byte_command(0x7A, 0xB1, 0x00, &tempc1, &tempc2, &tempc3); // EEDATA
if (retval==-1) return -1;
m_SFR[0xB1]=tempc3;
retval=Three_byte_command(0x7A, 0xB8, 0x00, &tempc1, &tempc2, &tempc3); // IP0
if (retval==-1) return -1;
m_SFR[0xB8]=tempc3;
retval=Three_byte_command(0x7A, 0xB9, 0x00, &tempc1, &tempc2, &tempc3); // IP1
if (retval==-1) return -1;
m_SFR[0xB9]=tempc3;
retval=Three_byte_command(0x7A, 0xBF, 0x00, &tempc1, &tempc2, &tempc3); // USR2
if (retval==-1) return -1;
m_SFR[0xBF]=tempc3;
stepsDone.store(30);
retval=Three_byte_command(0x7A, 0xC0, 0x00, &tempc1, &tempc2, &tempc3); // IRCON
if (retval==-1) return -1;
m_SFR[0xC0]=tempc3;
retval=Three_byte_command(0x7A, 0xC8, 0x00, &tempc1, &tempc2, &tempc3); // T2CON
if (retval==-1) return -1;
m_SFR[0xC8]=tempc3;
retval=Three_byte_command(0x7A, 0xCA, 0x00, &tempc1, &tempc2, &tempc3); // RCAP2L
if (retval==-1) return -1;
m_SFR[0xCA]=tempc3;
retval=Three_byte_command(0x7A, 0xCB, 0x00, &tempc1, &tempc2, &tempc3); // RCAP2H
if (retval==-1) return -1;
m_SFR[0xCB]=tempc3;
retval=Three_byte_command(0x7A, 0xCC, 0x00, &tempc1, &tempc2, &tempc3); // TL2
if (retval==-1) return -1;
m_SFR[0xCC]=tempc3;
retval=Three_byte_command(0x7A, 0xCD, 0x00, &tempc1, &tempc2, &tempc3); // TH2
if (retval==-1) return -1;
m_SFR[0xCD]=tempc3;
stepsDone.store(36);
retval=Three_byte_command(0x7A, 0xD0, 0x00, &tempc1, &tempc2, &tempc3); // PSW
if (retval==-1) return -1;
m_SFR[0xD0]=tempc3;
retval=Three_byte_command(0x7A, 0xE0, 0x00, &tempc1, &tempc2, &tempc3); // ACC
if (retval==-1) return -1;
m_SFR[0xE0]=tempc3;
retval=Three_byte_command(0x7A, 0xF0, 0x00, &tempc1, &tempc2, &tempc3); // B
if (retval==-1) return -1;
m_SFR[0xF0]=tempc3;
retval=Three_byte_command(0x7A, 0xEC, 0x00, &tempc1, &tempc2, &tempc3); // REG0
if (retval==-1) return -1;
m_SFR[0xEC]=tempc3;
retval=Three_byte_command(0x7A, 0xED, 0x00, &tempc1, &tempc2, &tempc3); // REG1
if (retval==-1) return -1;
m_SFR[0xED]=tempc3;
retval=Three_byte_command(0x7A, 0xEE, 0x00, &tempc1, &tempc2, &tempc3); // REG2
if (retval==-1) return -1;
m_SFR[0xEE]=tempc3;
stepsDone.store(42);
retval=Three_byte_command(0x7A, 0xEF, 0x00, &tempc1, &tempc2, &tempc3); // REG3
if (retval==-1) return -1;
m_SFR[0xEF]=tempc3;
retval=Three_byte_command(0x7A, 0xF4, 0x00, &tempc1, &tempc2, &tempc3); // REG4
if (retval==-1) return -1;
m_SFR[0xF4]=tempc3;
retval=Three_byte_command(0x7A, 0xF5, 0x00, &tempc1, &tempc2, &tempc3); // REG5
if (retval==-1) return -1;
m_SFR[0xF5]=tempc3;
retval=Three_byte_command(0x7A, 0xF6, 0x00, &tempc1, &tempc2, &tempc3); // REG6
if (retval==-1) return -1;
m_SFR[0xF6]=tempc3;
retval=Three_byte_command(0x7A, 0xF7, 0x00, &tempc1, &tempc2, &tempc3); // REG7
if (retval==-1) return -1;
m_SFR[0xF7]=tempc3;
retval=Three_byte_command(0x7A, 0xFC, 0x00, &tempc1, &tempc2, &tempc3); // REG8
if (retval==-1) return -1;
m_SFR[0xFC]=tempc3;
retval=Three_byte_command(0x7A, 0xFD, 0x00, &tempc1, &tempc2, &tempc3); // REG9
if (retval==-1) return -1;
m_SFR[0xFD]=tempc3;
stepsDone.store(48);
return 0;
}
void MCU_BD::Wait_CLK_Cycles(int delay)
{
//// some delay
int i=0;
for (i=0;i<(delay/64);i++)
mSPI_read(0x0003);
}
/** @brief Upload program code from memory into MCU
@return 0:success, -1:failed
*/
int MCU_BD::Program_MCU(int m_iMode1, int m_iMode0)
{
IConnection::MCU_PROG_MODE mode;
switch(m_iMode1 << 1 | m_iMode0)
{
case 0: mode = IConnection::MCU_PROG_MODE::RESET; break;
case 1: mode = IConnection::MCU_PROG_MODE::EEPROM_AND_SRAM; break;
case 2: mode = IConnection::MCU_PROG_MODE::SRAM; break;
case 3: mode = IConnection::MCU_PROG_MODE::BOOT_SRAM_FROM_EEPROM; break;
default: mode = IConnection::MCU_PROG_MODE::RESET; break;
}
return Program_MCU(byte_array,mode);
}
int MCU_BD::Program_MCU(const uint8_t* buffer, const IConnection::MCU_PROG_MODE mode)
{
if(!m_serPort)
return ReportError(ENOLINK, "Device not connected");
if (byte_array_size <= 8192)
return m_serPort->ProgramMCU(buffer, byte_array_size, mode, callback);
#ifndef NDEBUG
auto timeStart = std::chrono::high_resolution_clock::now();
#endif
const auto timeout = std::chrono::milliseconds(100);
const uint32_t controlAddr = 0x0002 << 16;
const uint32_t statusReg = 0x0003 << 16;
const uint32_t addrDTM = 0x0004 << 16; //data to MCU
const uint16_t EMTPY_WRITE_BUFF = 1 << 0;
const uint16_t PROGRAMMED = 1 << 6;
const uint8_t fifoLen = 64;
uint32_t wrdata[fifoLen];
uint32_t rddata = 0;
int status;
bool abort = false;
//reset MCU, set mode
wrdata[0] = controlAddr | 0;
wrdata[1] = controlAddr | (mode & 0x3);
if((status = m_serPort->WriteLMS7002MSPI(wrdata, 2, mChipID))!=0)
return status;
if(callback)
abort = callback(0, byte_array_size, "");
for(uint16_t i=0; i<byte_array_size && !abort; i+=fifoLen)
{
//wait till EMPTY_WRITE_BUFF = 1
bool fifoEmpty = false;
wrdata[0] = statusReg;
auto t1 = std::chrono::high_resolution_clock::now();
auto t2 = t1;
do{
if((status = m_serPort->ReadLMS7002MSPI(wrdata, &rddata, 1, mChipID))!=0)
return status;
fifoEmpty = rddata & EMTPY_WRITE_BUFF;
t2 = std::chrono::high_resolution_clock::now();
}while( (!fifoEmpty) && (t2-t1)<timeout);
if(!fifoEmpty)
return ReportError(ETIMEDOUT, "MCU FIFO full");
//write 32 bytes into FIFO
for(uint8_t j=0; j<fifoLen; ++j)
wrdata[j] = addrDTM | buffer[i+j];
if((status = m_serPort->WriteLMS7002MSPI(wrdata,fifoLen, mChipID))!=0)
return status;
if(callback)
abort = callback(i+fifoLen, byte_array_size, "");
#ifndef NDEBUG
printf("MCU programming : %4i/%4li\r", i+fifoLen, long(byte_array_size));
#endif
};
if(abort)
return ReportError(-1, "operation aborted by user");
//wait until programmed flag
wrdata[0] = statusReg;
bool programmed = false;
auto t1 = std::chrono::high_resolution_clock::now();
auto t2 = t1;
do{
if((status = m_serPort->ReadLMS7002MSPI(wrdata, &rddata, 1, mChipID))!=0)
return status;
programmed = rddata & PROGRAMMED;
t2 = std::chrono::high_resolution_clock::now();
}while( (!programmed) && (t2-t1)<timeout);
#ifndef NDEBUG
auto timeEnd = std::chrono::high_resolution_clock::now();
printf("\nMCU Programming finished, %li ms\n",
std::chrono::duration_cast<std::chrono::milliseconds>
(timeEnd-timeStart).count());
#endif
if(!programmed)
return ReportError(ETIMEDOUT, "MCU not programmed");
return 0;
}
void MCU_BD::Reset_MCU()
{
unsigned short tempi=0x0000; // was 0x0000
mSPI_write(0x8002, tempi);
tempi=0x0000;
mSPI_write(0x8000, tempi);
}
int MCU_BD::RunProductionTest_MCU()
{
string temps;
unsigned short tempi = 0x0080; // was 0x0000
int m_iMode1_ = 0;
int m_iMode0_ = 0;
if (m_bLoadedProd == 0)
{
if (GetProgramCode("lms7suite_mcu/ptest.hex", false) != 0)
return -1;
}
//MCU gets control over SPI switch
mSPI_write(0x0006, 0x0001); //REG6 write
// reset MCU
tempi = 0x0080;
mSPI_write(0x8002, tempi); // REG2
tempi = 0x0000;
mSPI_write(0x8000, tempi); // REG0
if (m_bLoadedProd == 0)
{
//select programming mode "01" for SRAM and EEPROM
m_iMode1_ = 0; m_iMode0_ = 1;
}
else
{
//boot from EEPROM
m_iMode1_ = 1; m_iMode0_ = 1;
}
//upload hex file
if (Program_MCU(m_iMode1_, m_iMode0_) != 0)
return -1; //failed to program
if (m_bLoadedProd == 0)
{
Wait_CLK_Cycles(256 * 100); // for programming mode, prog.code has been already loaded into MCU
m_iMode1_ = 0; m_iMode0_ = 1;
}
else
{
Wait_CLK_Cycles(256 * 400);
// for booting from EEPROM mode, must wait for some longer delay, at least 8kB/(80kb/s)=0.1s
m_iMode1_ = 1; m_iMode0_ = 1;
}
// global variable
m_bLoadedProd = 1; // the ptest.hex has been loaded
m_bLoadedDebug = 0;
//tempi = 0x0000;
// EXT_INT2=1, external interrupt 2 is raised
mSPI_write(0x8002, formREG2command(0, 0, 0, 1, m_iMode1_, m_iMode0_)); // EXT_INT2=1
// here you can put any Delay function
Wait_CLK_Cycles(256);
// EXT_INT2=0, external interrupt 2 is pulled down
mSPI_write(0x8002, formREG2command(0, 0, 0, 0, m_iMode1_, m_iMode0_)); // EXT_INT2=0
// wait for some time MCU to execute the tests
// the time is approximately 20ms
// here you can put any Delay function
Wait_CLK_Cycles(256 * 100);
unsigned short retval = 0;
retval = mSPI_read(1); //REG1 read
// show the return value at the MCU Control Panel
//int temps = wxString::Format("Result is: 0x%02X", retval);
//ReadResult->SetLabel(temps);
if (retval == 0x10)
{
tempi = 0x0055;
mSPI_write(0x8000, tempi); // P0=0x55;
// EXT_INT3=1, external interrupt 3 is raised
mSPI_write(0x8002, formREG2command(0, 0, 1, 0, m_iMode1_, m_iMode0_)); // EXT_INT3=1
// here you can put any Delay function
Wait_CLK_Cycles(256);
// EXT_INT3=0, external interrupt 3 is pulled down
mSPI_write(0x8002, formREG2command(0, 0, 0, 0, m_iMode1_, m_iMode0_)); // EXT_INT3=0
Wait_CLK_Cycles(256 * 5);
retval = mSPI_read(1); //REG1 read
if (retval != 0x55)
temps = "Ext. interrupt 3 test failed.";
else
{
tempi = 0x00AA;
mSPI_write(0x8000, tempi); // P0=0xAA;
// EXT_INT4=1, external interrupt 4 is raised
mSPI_write(0x8002, formREG2command(0, 1, 0, 0, m_iMode1_, m_iMode0_)); // EXT_INT4=1
// here you can put any Delay function
Wait_CLK_Cycles(256);
// EXT_INT4=0, external interrupt 4 is pulled down
mSPI_write(0x8002, formREG2command(0, 0, 0, 0, m_iMode1_, m_iMode0_)); // EXT_INT4=0
Wait_CLK_Cycles(256 * 5);
retval = mSPI_read(1); //REG1 read
if (retval != 0xAA) temps = "Ext. interrupt 4 test failed.";
else {
tempi = 0x0055;
mSPI_write(0x8000, tempi); // P0=0x55;
// EXT_INT5=1, external interrupt 5 is raised
mSPI_write(0x8002, formREG2command(1, 0, 0, 0, m_iMode1_, m_iMode0_)); // EXT_INT5=1
// here you can put any Delay function
Wait_CLK_Cycles(256);
// EXT_INT5=0, external interrupt 5 is pulled down
mSPI_write(0x8002, formREG2command(0, 0, 0, 0, m_iMode1_, m_iMode0_)); // EXT_INT5=0
Wait_CLK_Cycles(256 * 5);
retval = mSPI_read(1); //REG1 read
if (retval != 0x55)
{
temps = "Ext. interrupt 5 test failed.";
return -1;
}
else
{
temps = "Production test finished. MCU is OK.";
return 0;
}
}
}
}
else
{
if ((retval & 0xF0) == 0x30)
{ // detected error code
if ((retval & 0x0F) > 0)
{
char ctemp[64];
sprintf(ctemp, "Test %i failed", (retval & 0x0F));
temps = ctemp;
return -1;
}
else
{
temps = "Test failed";
return -1;
}
}
else
{
// test too long. Failure.
temps = "Test failed.";
return -1;
}
}
//Baseband gets back the control over SPI switch
mSPI_write(0x0006, 0x0000); //REG6 write
return 0;
}
void MCU_BD::RunTest_MCU(int m_iMode1, int m_iMode0, unsigned short test_code, int m_iDebug) {
int i=0;
int limit=0;
unsigned short tempi=0x0000;
unsigned short basei=0x0000;
if (test_code<=15) basei=(test_code<<4);
else basei=0x0000;
basei=basei&0xFFF0; // not necessery
// 4 LSBs are zeros
// variable basei contains test no. value at bit positions 7-4
// used for driving the P0 input
// P0 defines the test no.
if ((test_code>7)||(test_code==0))
limit=1;
else
limit=50;
// tests 8 to 14 have short duration
if (m_iDebug==1) return; // normal MCU operating mode required
// EXT_INT2=1, external interrupt 2 is raised
tempi=0x0000; // changed
int m_iExt2=1;
if (m_iExt2==1) tempi=tempi|0x0004;
if (m_iMode1==1) tempi=tempi|0x0002;
if (m_iMode0==1) tempi=tempi|0x0001;
// tempi variable is driving the mspi_REG2
mSPI_write(0x8002, tempi); // REG2 write
// generating waveform
for (i=0; i<=limit; i++)
{
tempi=basei|0x000C;
mSPI_write(0x8000, tempi);
// REG0 write
Wait_CLK_Cycles(256);
tempi=basei|0x000D;
mSPI_write(0x8000, tempi);
// REG0 write - P0(0) set
Wait_CLK_Cycles(256);
tempi=basei|0x000C;
mSPI_write(0x8000, tempi);
// REG0 write
Wait_CLK_Cycles(256);
tempi=basei|0x000E;
mSPI_write(0x8000, tempi);
// REG0 write - PO(1) set
Wait_CLK_Cycles(256);
if (i==0) {
// EXT_INT2=0
// external interrupt 2 is pulled down
tempi=0x0000; // changed
m_iExt2=0;
if (m_iExt2==1) tempi=tempi|0x0004;
if (m_iMode1==1) tempi=tempi|0x0002;
if (m_iMode0==1) tempi=tempi|0x0001;
mSPI_write(0x8002, tempi);
// REG2 write
}
}
}
void MCU_BD::RunFabTest_MCU(int m_iMode1, int m_iMode0, int m_iDebug) {
unsigned short tempi=0x0000;
if (m_iDebug==1) return; // normal MCU operating mode required
// EXT_INT2=1, external interrupt 2 is raised
tempi=0x0000; // changed
int m_iExt2=1;
if (m_iExt2==1) tempi=tempi|0x0004;
if (m_iMode1==1) tempi=tempi|0x0002;
if (m_iMode0==1) tempi=tempi|0x0001;
mSPI_write(0x8002, tempi); // REG2 write
Wait_CLK_Cycles(256);
// EXT_INT2=0, external interrupt 2 is pulled down
tempi=0x0000; // changed
m_iExt2=0;
if (m_iExt2==1) tempi=tempi|0x0004;
if (m_iMode1==1) tempi=tempi|0x0002;
if (m_iMode0==1) tempi=tempi|0x0001;
mSPI_write(0x8002, tempi);
Wait_CLK_Cycles(256);
}
void MCU_BD::DebugModeSet_MCU(int m_iMode1, int m_iMode0)
{
unsigned short tempi=0x00C0;
// bit DEBUG is set
int m_iExt2=0;
if (m_iExt2==1) tempi=tempi|0x0004;
if (m_iMode1==1) tempi=tempi|0x0002;
if (m_iMode0==1) tempi=tempi|0x0001;
// Select debug mode
mSPI_write(0x8002, tempi);
// REG2 write
}
void MCU_BD::DebugModeExit_MCU(int m_iMode1, int m_iMode0)
{
unsigned short tempi=0x0000; // bit DEBUG is zero
int m_iExt2=0;
if (m_iExt2==1) tempi=tempi|0x0004;
if (m_iMode1==1) tempi=tempi|0x0002;
if (m_iMode0==1) tempi=tempi|0x0001;
// To run mode
mSPI_write(0x8002, tempi); // REG2 write
}
int MCU_BD::ResetPC_MCU()
{
unsigned char tempc1=0x00;
int retval=0;
retval=One_byte_command(0x70, &tempc1);
return retval;
}
int MCU_BD::RunInstr_MCU(unsigned short * pPCVAL)
{
unsigned char tempc1, tempc2, tempc3=0x00;
int retval=0;
retval=Three_byte_command(0x74, 0x00, 0x00, &tempc1, &tempc2, &tempc3);
if (retval==-1) (*pPCVAL)=0;
else (*pPCVAL)=tempc2*256+tempc3;
return retval;
}
void MCU_BD::Log(const char* msg)
{
printf("%s", msg);
}
/** @brief Returns information about programming or reading data progress
*/
MCU_BD::ProgressInfo MCU_BD::GetProgressInfo() const
{
ProgressInfo info;
info.stepsDone = stepsDone.load();
info.stepsTotal = stepsTotal.load();
info.aborted = aborted.load();
return info;
}
unsigned int MCU_BD::formREG2command(int m_iExt5, int m_iExt4, int m_iExt3, int m_iExt2, int m_iMode1, int m_iMode0) {
unsigned int tempi = 0x0000;
if (m_iExt5 == 1) tempi = tempi | 0x0020;
if (m_iExt4 == 1) tempi = tempi | 0x0010;
if (m_iExt3 == 1) tempi = tempi | 0x0008;
if (m_iExt2 == 1) tempi = tempi | 0x0004;
if (m_iMode1 == 1) tempi = tempi | 0x0002;
if (m_iMode0 == 1) tempi = tempi | 0x0001;
return(tempi);
}
std::string MCU_BD::GetProgramFilename() const
{
return mLoadedProgramFilename;
}
/** @brief Starts algorithm in MCU
*/
void MCU_BD::RunProcedure(uint8_t id)
{
mSPI_write(0x0006, id != 0);
mSPI_write(0x0000, id);
uint8_t x0002reg = mSPI_read(0x0002);
const uint8_t interupt6 = 0x08;
mSPI_write(0x0002, x0002reg | interupt6);
mSPI_write(0x0002, x0002reg & ~interupt6);
std::this_thread::sleep_for(std::chrono::microseconds(10));
}
/** @brief Waits for MCU to finish executing program
@return 0 success, 255 idle, 244 running, else algorithm status
*/
int MCU_BD::WaitForMCU(uint32_t timeout_ms)
{
auto t1 = std::chrono::high_resolution_clock::now();
auto t2 = t1;
unsigned short value = 0;
std::this_thread::sleep_for(std::chrono::microseconds(50));
do {
value = mSPI_read(0x0001) & 0xFF;
if (value != 0xFF) //working
break;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
t2 = std::chrono::high_resolution_clock::now();
}while (std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count() < timeout_ms);
mSPI_write(0x0006, 0); //return SPI control to PC
//if((value & 0x7f) != 0)
std::printf("MCU algorithm time: %li ms\n", std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count());
return value & 0x7F;
}
void MCU_BD::SetParameter(MCU_Parameter param, float value)
{
uint8_t inputRegs[3];
value /= 1e6;
inputRegs[0] = (uint8_t)value; //frequency integer part
uint16_t fracPart = value * 1000.0 - inputRegs[0]*1000.0;
inputRegs[1] = (fracPart >> 8) & 0xFF;
inputRegs[2] = fracPart & 0xFF;
const uint8_t x0002reg = mSPI_read(0x0002);
const uint8_t interupt7 = 0x04;
for(uint8_t i = 0; i < 3; ++i)
{
mSPI_write(0, inputRegs[2-i]);
mSPI_write(0x0002, x0002reg | interupt7);
mSPI_write(0x0002, x0002reg & ~interupt7);
this_thread::sleep_for(chrono::microseconds(5));
}
if(param==MCU_REF_CLK)
RunProcedure(4);
if(param == MCU_BW)
RunProcedure(3);
}
/** @brief Switches MCU into debug mode, MCU program execution is halted
@param mode MCU memory initialization mode
@return Operation status
*/
MCU_BD::OperationStatus MCU_BD::SetDebugMode(bool enabled, IConnection::MCU_PROG_MODE mode)
{
uint8_t regValue = 0;
switch (mode)
{
case IConnection::MCU_PROG_MODE::RESET:
break;
case IConnection::MCU_PROG_MODE::EEPROM_AND_SRAM:
regValue |= 0x01; break;
case IConnection::MCU_PROG_MODE::SRAM:
regValue |= 0x02; break;
case IConnection::MCU_PROG_MODE::BOOT_SRAM_FROM_EEPROM:
regValue |= 0x03; break;
}
if (enabled)
regValue |= 0xC0;
mSPI_write(0x8002, regValue);
return SUCCESS;
}
MCU_BD::OperationStatus MCU_BD::readIRAM(const uint8_t *addr, uint8_t* values, const uint8_t count)
{
uint8_t cmd = 0x78; //
int retval;
for (int i = 0; i < count; ++i)
{
mSPI_write(0x8004, cmd); //REG4 write cmd
retval = WaitUntilWritten();
if (retval == -1) return FAILURE;
mSPI_write(0x8004, addr[i]); //REG4 write IRAM address
retval = WaitUntilWritten();
if (retval == -1) return FAILURE;
mSPI_write(0x8004, 0); //REG4 nop
retval = WaitUntilWritten();
if (retval == -1) return FAILURE;
uint8_t result = 0;
retval = ReadOneByte(&result);
if (retval == -1) return FAILURE;
retval = ReadOneByte(&result);
if (retval == -1) return FAILURE;
retval = ReadOneByte(&result);
if (retval == -1) return FAILURE;
values[i] = result;
}
return SUCCESS;
}
MCU_BD::OperationStatus MCU_BD::writeIRAM(const uint8_t *addr, const uint8_t* values, const uint8_t count)
{
return FAILURE;
}
uint8_t MCU_BD::ReadMCUProgramID()
{
RunProcedure(255);
auto statusMcu = WaitForMCU(10);
return statusMcu & 0x7F;
}