#include // For memcpy and memset #include "sci.h" #include "sys_dma.h" #include "Comm.h" #include "Download.h" #include "FPGA.h" #include "Timers.h" #include "SystemComm.h" #include "Utilities.h" /** * @addtogroup FPGA * @{ */ // ********** private definitions ********** #define QUEUE_MAX_SIZE 20 ///< Max queue size. #if BL_STACK_ID == 1 #define FPGA_PAGE_SIZE 512 ///< FPGA register pages are 256 bytes. #define FPGA_WRITE_CMD_HDR_LEN 5 ///< FPGA write command header byte length. #define FPGA_READ_CMD_HDR_LEN 5 ///< FPGA read command header byte length. #define FPGA_BULK_READ_START_ADDR 0x0200 ///< Start address for FPGA continuous priority reads. #else #define FPGA_PAGE_SIZE 256 ///< FPGA register pages are 256 bytes. #define FPGA_WRITE_CMD_HDR_LEN 4 ///< FPGA write command header byte length. #define FPGA_READ_CMD_HDR_LEN 4 ///< FPGA read command header byte length. #define FPGA_BULK_READ_START_ADDR 0x0100 ///< Start address for FPGA continuous priority reads. #endif #define FPGA_MAX_READ_SIZE ( FPGA_PAGE_SIZE - 1 ) ///< FGPA max read size. #define FPGA_WRITE_CMD_BUFFER_LEN ( FPGA_PAGE_SIZE + 8 ) ///< FPGA write command buffer byte length. #define FPGA_READ_CMD_BUFFER_LEN 8 ///< FPGA read command buffer byte length. #define FPGA_WRITE_RSP_BUFFER_LEN 8 ///< FPGA write command response buffer byte length. #define FPGA_READ_RSP_BUFFER_LEN ( FPGA_PAGE_SIZE + 8 ) ///< FPGA read command response buffer byte length. #define SCI2_RECEIVE_DMA_REQUEST 28 ///< Serial port 2 receive DMA request line. #define SCI2_TRANSMIT_DMA_REQUEST 29 ///< Serial port 2 transmit DMA request line. #define FPGA_CRC_LEN 2 ///< FPGA CRC byte length. #define FPGA_WRITE_RSP_HDR_LEN 3 ///< FPGA write command response header byte length. #define FPGA_READ_RSP_HDR_LEN 3 ///< FPGA read command response header byte length. #define FPGA_WRITE_CMD_CODE 0x55 ///< FPGA write command code. #define FPGA_WRITE_CMD_ACK 0xA5 ///< FPGA write command ACK code. #define FPGA_READ_CMD_CODE 0x5A ///< FPGA read command code. #define FPGA_READ_CMD_ACK 0xAA ///< FPGA read command ACK code. #define FPGA_HEADER_START_ADDR 0x0000 ///< Start address for FPGA header data. #if BL_STACK_ID == 1 #define FPGA_FLASH_CONTROL_REG_ADDR 0x120E ///< FPGA flash control register address. #define FPGA_MULTI_BOOT_STATUS_ADDR 0x1200 ///< FPGA multi boot status register address. #define FPGA_ICAP2_REG_ADDR 0x1209 ///< FPGA ICAP 2 command register address. #define FPGA_FLASH_DATA_REG_ADDR 0x1400 ///< FPGA flash data register address. #else #define FPGA_FLASH_CONTROL_REG_ADDR 0x090E ///< FPGA flash control register address. #define FPGA_MULTI_BOOT_STATUS_ADDR 0x0900 ///< FPGA multi boot status register address. #define FPGA_ICAP2_REG_ADDR 0x0909 ///< FPGA ICAP 2 command register address. #define FPGA_FLASH_DATA_REG_ADDR 0x0A00 ///< FPGA flash data register address. #endif #define FPGA_FLASH_STATUS_REG_ADDR 0x0900 ///< FPGA flash status register address. // TODO remove #define FPGA_FIFO_COUNT_REG_ADDR 0x0902 ///< FPGA FIFO count register address. // TODO remove #define FPGA_WRITE_START_ADDR 0x000B ///< Start address for FPGA continuous priority writes. // TODO remove #define FPGA_UPDATE_REGISTER_ADDR ( FPGA_WRITE_START_ADDR + 4 ) ///< FPGA update register address. // TODO remove since FFU will broadcast #define FPGA_UPDATE_REQUEST_INDEX ( FPGA_READ_RSP_HDR_LEN + 1 ) ///< FPGA update request index. // TODO remove #define FPGA_FLASH_STATUS_INDEX ( FPGA_READ_RSP_HDR_LEN + 1 ) ///< FPGA flash status index. // TODO remove #define FPGA_FIFO_COUNT_INDEX ( FPGA_READ_RSP_HDR_LEN + 1 ) ///< FPGA FIFO count index. // TODO remove #define UPDATE_REQUESTED_VALUE 1 // TODO remove FFU will broadcast ///< The value that indicates and update has been requested. #define FPGA_FIFO_SIZE_BYTES 1024 ///< FPGA FIFO size in bytes. #define FPGA_FIFO_COUNT_MASK 0x03FF ///< FPGA FIFO count in FIFO mask. #define FPGA_INIT_STAGE_TIMEOUT_MS 6000 ///< FPGA initialization stage timeout in milliseconds. #define FPGA_PRE_SELF_CONFIG_TIMEOUT_MS 10000 ///< FPGA pre self configure timeout in milliseconds. /// FPGA communication status enumeration typedef enum { FPGA_COMM_IDLE = 0, ///< FPGA communication idle. FPGA_COMM_READ_IN_PROGRESS, ///< FPGA communication read in progress. FPGA_COMM_READ_RESP_RECEIVED, ///< FPGA communication read response received. FPGA_COMM_WRITE_IN_PROGRESS, ///< FPGA communication write in progress. FPGA_COMM_WRITE_RESP_RECEIVED, ///< FPGA communication write response received. NUM_OF_FPGA_COMM_STATUS ///< Number of FPGA communication status. } FPGA_COMM_STATE_T; typedef enum { FPGA_UPDATE_STAGE_INIT = 0, FPGA_UPDATE_STAGE_CHECK_UPDATE_INIT, FPGA_UPDATE_STAGE_UPDATE, FPGA_UPDATE_STAGE_SELF_CONFIGURE, NUM_OF_FPGA_UPDATE_STAGES } FPGA_UPDATE_STAGE_T; /// FPGA queue jobs enumeration typedef enum { FPGA_READ_HEADER = 0, ///< FPGA read header. FPGA_READ_UPDATE_REG, // TODO remove related to using FPGA as communication but FFU will broadcast ///< FPGA read update request register. FPGA_WRITE_UPDATE_REG, // TODO remove related to using FPGA as communication but FFU will broadcast ///< FPGA write to update request register. FPGA_RESET_FLASH, ///< FPGA reset flash. FPGA_ERASE_FIFO, ///< FPGA erase FIFO. FPGA_ENABLE_FLASH, ///< FPGA enable flash. FPGA_READ_MULTI_BOOT_STATUS, ///< FPGA read multi-boot status. FPGA_FLASH_WRITE_DATA, ///< FPGA write flash data. FPGA_SELF_CONFIGURE, ///< FPGA self configure. NUM_OF_FPGA_JOBS, ///< Number of the FPGA jobs. } FPGA_JOBS_T; /// FPGA state machine states enumeration typedef enum { FPGA_IDLE_STATE = 0, ///< FPGA idle state. FPGA_WRITE_TO_FPGA_STATE, ///< FPGA write to FPGA state. FPGA_RCV_WRITE_RESP_FROM_FPGA_STATE, ///< FPGA receive write response from FPGA state. FPGA_READ_FROM_FPGA_STATE, ///< FPGA read from FPGA state. FPGA_RCV_READ_RESP_FROM_FPGA_STATE, ///< FPGA received read response from FPGA state. NUM_OF_FPGA_STATES ///< Number of FPGA states. } FPGA_STATE_T; //#pragma pack(push,1) /// FPGA queue job specification structure typedef struct { U16 fpgaJobAddress; ///< FPGA job address. U16 fpgaJobSize; ///< FPGA job size. BOOL fpgaIsJobWrite; ///< FPGA boolean flag to indicate this is a write job or not. U08* fpgaWriteStartAddress; ///< FPGA write buffer start address. } FPGA_JOB_SPECS_T; /// FPGA jobs queue status structure typedef struct { U08 fpgaJobsQueue[ QUEUE_MAX_SIZE ]; ///< FPGA jobs queue. U08 fpgaJobRearIndex; ///< FPGA job queue rear index. U08 fpgaJobFrontIndex; ///< FPGA job queue front index. U08 fpgaJobsQueueCount; ///< FPGA job queue count. U08 fpgaCurrentJob; ///< FPGA queue current job. FPGA_COMM_STATE_T fpgaCommRead; ///< FPGA DMA read command state. FPGA_COMM_STATE_T fpgaCommWrite; ///< FPGA DMA write command state. } FPGA_JOBS_Q_STATUS_T; /// FPGA read registers status structure typedef struct { U16 flashStatus; ///< FPGA flash status. U16 fifoCount; ///< FPGA FIFO count. U32 icape2DataIn; ///< FPGA ICAPE2 datain. U08 icape2Address; ///< FPGA ICAPE2 address. U08 icape2Cmd; ///< FPGA ICAPE2 command. U32 icape2DataOut; ///< FPGA ICAPE2 dataout. U08 flashIntCtrlReg; ///< FPGA flash interface control register. } FPGA_READ_REGS_T; /// FPGA flash status structure typedef struct { U16 fpgaRemainingFIFOCountBytes; ///< Remaining FIFO size in bytes. U16 fpgaInitStatus; U16 fpgaCheckIDStatus; U16 fpgaEraseStatus; U16 fpgaProgramImageStatus; U16 fpgaReadyForDataStatus; FPGA_UPDATE_STAGE_T fpgaUpdateStage; U32 preSelfConfigureStartTimeMS; ///< Pre self configure start time in milliseconds. U32 startTimeMS; ///< Start time in milliseconds. } FPGA_FLASH_STATUS_T; /// Record structure for FPGA header read. typedef struct { U08 fpgaId; ///< Reg 0. FPGA ID code. Checked against expected value at power up to verify basic FPGA communication and operation. U08 fpgaRev; ///< Reg 1. FPGA revision (minor) being reported. U08 fpgaRevMajor; ///< Reg 2. FPGA revision (major) being reported. U08 fpgaRevLab; ///< Reg 3. FPGA revision (lab) being reported. } FPGA_HEADER_T; // Read only on FPGA //#pragma pack(pop) // ********** private data ********** // FPGA comm buffers static U08 fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_BUFFER_LEN ]; ///< FPGA write command buffer. Holds the next FPGA write command to be transmitted. static U08 fpgaReadCmdBuffer[ FPGA_READ_CMD_BUFFER_LEN ]; ///< FPGA read command buffer. Holds the next FPGA read command to be transmitted. static U08 fpgaWriteResponseBuffer[ FPGA_WRITE_RSP_BUFFER_LEN ]; ///< FPGA write command response buffer. Memory reserved to capture the response to the last FPGA write command. static U08 fpgaReadResponseBuffer[ FPGA_READ_RSP_BUFFER_LEN ]; ///< FPGA read command response buffer. Memory reserved to capture the response to the last FPGA read command. // DMA control records static g_dmaCTRL fpgaDMAWriteControlRecord; ///< DMA record for controlling a DMA write command transmission from buffer. static g_dmaCTRL fpgaDMAWriteRespControlRecord; ///< DMA record for controlling a DMA write command reception to buffer. static g_dmaCTRL fpgaDMAReadControlRecord; ///< DMA record for controlling a DMA read command transmission from buffer. static g_dmaCTRL fpgaDMAReadRespControlRecord; ///< DMA record for controlling a DMA read command reception to buffer. static FPGA_HEADER_T fpgaHeader; ///< Record of last received FPGA header data. static FPGA_STATE_T fpgaState; ///< FPGA current state. static U08 fpgaUpdateRegisterStatus; // TODO remove FFU will broadcast ///< FPGA update register status. static FPGA_JOBS_Q_STATUS_T fpgaJobsQStatus; ///< FPGA jobs queue status. static FPGA_FLASH_STATUS_T fpgaFlashStatus; ///< FPGA flash status. static FPGA_READ_REGS_T fpgaReadRegsStatus; ///< FGPA read registers status. static U32 fpgaOperationStartTimeMS; ///< FPGA operation start time in milliseconds (read/write). static U08 fpgaDataToWriteBuffer[ SW_UPDATE_FLASH_BUFFER_SIZE ]; ///< FPGA data to write to FPGA flash buffer. static U32 fpgaDataLenToWrite; ///< FPGA data length to write to FPGA. static U08 tempPrevJob; static U16 tempPrevFlash; static U16 tempPrevFIFO; /// FPGA stack ID for TD, DD //static const U08 STACK_FPGA_ID[ NUM_OF_FW_STACKS ] = { 0x5A, 0x61 }; // TODO update with the real FPGA IDs // TODO remove // TODO what is this value? 0? //static const U16 DISABLE_UPDATE_REG_CMD = 5; ///< FPGA disable update register command. // TODO remove FFU will broadcast static const U08 FPGA_RESET_FLASH_CMD = 0x01; ///< FPGA reset flash command. static const U08 FPGA_ERASE_FIFO_CMD = 0x08; ///< FPGA erase FIFO command. static const U08 FPGA_ENABLE_FLASH_CMD = 0x00; ///< FPGA enable flash command. static const U08 FPGA_SELF_CONFIG_CMD = 0x03; ///< FPGA self configure command. static const U08 DUMMY_ADDRESS1 = 0x03; static const U08 DUMMY_ADDRESS2 = 0x03; static const U08 DUMMY_ADDRESS3 = 0x03; static const U08 DUMMY_ADDRESS4 = 0x03; static const U32 FPGA_FLASH_INIT_STATUS = ( 1 << 8 ); static const U32 FPGA_FLASH_ERASE_STATUS = ( 1 << 11 ); static const U32 FPGA_FLASH_PROG_IMAGE_STATUS = ( 1 << 12 ); static const U32 FPGA_FLASH_READY_FOR_UPDATE_STATUS = ( 1 << 15 ); /// FPGA jobs specifications. static const FPGA_JOB_SPECS_T JOBS_SPECS[ NUM_OF_FPGA_JOBS ] = { { FPGA_HEADER_START_ADDR, sizeof( FPGA_HEADER_T ), FALSE, (U08*)&DUMMY_ADDRESS1, }, // FPGA_READ_HEADER { FPGA_BULK_READ_START_ADDR, FPGA_MAX_READ_SIZE, FALSE, (U08*)&DUMMY_ADDRESS1, }, // TODO remove with the enum at the top // FPGA_READ_UPDATE_REG { FPGA_UPDATE_REGISTER_ADDR, sizeof( U16 ), TRUE , (U08*)&DUMMY_ADDRESS1, }, // TODO remove // FPGA_WRITE_UPDATE_REG { FPGA_FLASH_CONTROL_REG_ADDR, sizeof( U08 ), TRUE , (U08*)&FPGA_RESET_FLASH_CMD, }, // FPGA_RESET_FLASH { FPGA_FLASH_CONTROL_REG_ADDR, sizeof( U08 ), TRUE , (U08*)&FPGA_ERASE_FIFO_CMD, }, // FPGA_ERASE_FIFO { FPGA_FLASH_CONTROL_REG_ADDR, sizeof( U08 ), TRUE , (U08*)&FPGA_ENABLE_FLASH_CMD, }, // FPGA_ENABLE_FLASH { FPGA_MULTI_BOOT_STATUS_ADDR, sizeof( FPGA_READ_REGS_T ), FALSE, (U08*)&DUMMY_ADDRESS1, }, // FPGA_READ_MULTI_BOOT_STATUS { FPGA_FLASH_DATA_REG_ADDR, SW_UPDATE_FLASH_BUFFER_SIZE, TRUE , (U08*)&fpgaDataToWriteBuffer, }, // FPGA_FLASH_WRITE_DATA { FPGA_ICAP2_REG_ADDR, sizeof( U08 ), TRUE , (U08*)&FPGA_SELF_CONFIG_CMD, } // FPGA_SELF_CONFIGURE }; // ********** private function prototypes ********** static void initDMA( void ); static void consumeUnexpectedData( void ); static void processFPGAFlashRegistersRead( void ); static void processFPGAUpdateInitStatus( void ); static void setupDMAForReadResp( U32 bytes2Receive ); static void setupDMAForReadCmd( U32 bytes2Transmit ); static void startDMAReceiptOfReadResp( void ); static void startDMAReadCmd( void ); static void setupDMAForWriteCmd( U32 bytes2Transmit ); static void startDMAWriteCmd( void ); static void setupDMAForWriteResp( U32 bytes2Receive ); static void startDMAReceiptOfWriteResp( void ); static void resetFPGACommFlags( void ); static void enqueue( FPGA_JOBS_T job ); static void dequeue( void ); static FPGA_JOBS_T peekFromQueue( void ); static BOOL isQueueFull( void ); static void publishDataTemp( void ); static FPGA_STATE_T handleFPGAIdleState( void ); static FPGA_STATE_T handleFPGAWriteToFPGAState( void ); static FPGA_STATE_T handleFPGAReceiveWriteRespFromFPGAState( void ); static FPGA_STATE_T handleFPGAReadFromFPGAState( void ); static FPGA_STATE_T handleFPGAReceiveReadRespFromFPGAState( void ); /*********************************************************************//** * @brief * The initFPGA function initializes the FPGA unit. * @details \b Inputs: none * @details \b Outputs: FPGA unit initialized. * @return none *************************************************************************/ void initFPGA( void ) { memset( &fpgaHeader, 0x0, sizeof( FPGA_HEADER_T ) ); memset( &fpgaJobsQStatus, 0x0, sizeof( FPGA_JOBS_Q_STATUS_T ) ); memset( &fpgaFlashStatus, 0x0, sizeof( FPGA_FLASH_STATUS_T ) ); memset( &fpgaReadRegsStatus, 0x0, sizeof( FPGA_READ_REGS_T ) ); memset( &fpgaDataToWriteBuffer, 0x0, SW_UPDATE_FLASH_BUFFER_SIZE ); // initialize fpga comm buffers memset( &fpgaWriteCmdBuffer, 0, FPGA_WRITE_CMD_BUFFER_LEN ); memset( &fpgaReadCmdBuffer, 0, FPGA_READ_CMD_BUFFER_LEN ); memset( &fpgaWriteResponseBuffer, 0, FPGA_WRITE_RSP_BUFFER_LEN ); memset( &fpgaReadResponseBuffer, 0, FPGA_READ_RSP_BUFFER_LEN ); fpgaState = FPGA_IDLE_STATE; fpgaUpdateRegisterStatus = 0; fpgaOperationStartTimeMS = 0; fpgaDataLenToWrite = 0; tempPrevJob = 0; tempPrevFlash = 0; tempPrevFIFO = 0; initDMA(); consumeUnexpectedData(); enqueue( FPGA_READ_HEADER ); enqueue( FPGA_READ_MULTI_BOOT_STATUS ); } /*********************************************************************//** * @brief * The execFPGA function the FPGA state machine. * @details \b Inputs: fpgaState * @details \b Outputs: fpgaState * @return none *************************************************************************/ void execFPGA( void ) { switch( fpgaState ) { case FPGA_IDLE_STATE: fpgaState = handleFPGAIdleState(); break; case FPGA_WRITE_TO_FPGA_STATE: fpgaState = handleFPGAWriteToFPGAState(); break; case FPGA_RCV_WRITE_RESP_FROM_FPGA_STATE: fpgaState = handleFPGAReceiveWriteRespFromFPGAState(); break; case FPGA_READ_FROM_FPGA_STATE: fpgaState = handleFPGAReadFromFPGAState(); break; case FPGA_RCV_READ_RESP_FROM_FPGA_STATE: fpgaState = handleFPGAReceiveReadRespFromFPGAState(); break; default: // Do nothing break; } publishDataTemp(); } /*********************************************************************//** * @brief * The signalFPGAReceiptCompleted function increments a counter to indicate * that another DMA receipt from the FPGA has completed and sets comm flags * indicating pending response from FPGA is completed. * @details \b Inputs: fpgaJobsQStatus * @details \b Outputs: fpgaJobsQStatus * @return none *************************************************************************/ void signalFPGAReceiptCompleted( void ) { if ( FPGA_COMM_WRITE_IN_PROGRESS == fpgaJobsQStatus.fpgaCommWrite ) { fpgaJobsQStatus.fpgaCommWrite = FPGA_COMM_WRITE_RESP_RECEIVED; } else if ( FPGA_COMM_READ_IN_PROGRESS == fpgaJobsQStatus.fpgaCommRead ) { fpgaJobsQStatus.fpgaCommRead = FPGA_COMM_READ_RESP_RECEIVED; } } /*********************************************************************//** * @brief * The hasUpdateBeenRequested function checks whether an update has been * requested through the FPGA read registers. * @details \b Inputs: fpgaState, fpgaUpdateRegisterStatus * @details \b Outputs: fpgaUpdateRegisterStatus * @return TRUE if an update has been requested otherwise, FALSE *************************************************************************/ BOOL hasUpdateBeenRequested( void ) { BOOL status = FALSE; if ( ( FPGA_IDLE_STATE == fpgaState ) && ( UPDATE_REQUESTED_VALUE == fpgaUpdateRegisterStatus ) ) { status = TRUE; fpgaUpdateRegisterStatus = 0; enqueue( FPGA_WRITE_UPDATE_REG ); } return status; } /*********************************************************************//** * @brief * The isFPGAIDValid function checks whether the FPGA header is valid. * @details \b Inputs: fpgaHeader * @details \b Outputs: none * @return TRUE if the FPGA header is valid otherwise, FALSE *************************************************************************/ BOOL isFPGAIDValid( void ) { //BOOL status = ( STACK_FPGA_ID[ BL_STACK_ID ] == fpgaHeader.fpgaId ? TRUE : FALSE ); BOOL status = FALSE; return status; } /*********************************************************************//** * @brief * The isFPGAFlashComplete function returns the status of FPGA flash. So * TRUE if the flash is complete, otherwise, FALSE. * @details \b Inputs: fpgaFlashStatus * @details \b Outputs: none * @return TRUE if flash is complete otherwise, FALSE *************************************************************************/ BOOL isFPGAFlashComplete( void ) { //return fpgaFlashStatus.isFPGAFlashComplete; // TODO clean this up return TRUE; } /*********************************************************************//** * @brief * The signalFPGAToPrepareForUpdate function enqueues the FPGA update * initialization jobs if the queue is not full. * @details \b Inputs: none * @details \b Outputs: none * @return none *************************************************************************/ void signalFPGAToPrepareForUpdate( void ) { if ( FALSE == isQueueFull() ) { enqueue( FPGA_RESET_FLASH ); enqueue( FPGA_ERASE_FIFO ); enqueue( FPGA_ENABLE_FLASH ); } } /*********************************************************************//** * @brief * The signalFPGAToWriteToFlash function enqueues the FPGA write to flash * job if the queue is not full. * @details \b Inputs: none * @details \b Outputs: fpgaDataLenToWrite, fpgaDataToWriteBuffer * @return TURE if the buffer was enqueued successfully otherwise, FALSE *************************************************************************/ BOOL signalFPGAToWriteToFlash( U08* data, U32 len ) { BOOL status = FALSE; BOOL isFIFOReady = FALSE; // Check if the next job in the queue is a flash write. // If there is a flash write, only dequeue it if: // 1. There are enough number of bytes available in the FIFO for the next data (e.g. 256) // 2. The flash status is okay if ( ( fpgaFlashStatus.fpgaRemainingFIFOCountBytes > SW_UPDATE_FLASH_BUFFER_SIZE ) && ( FPGA_FLASH_READY_FOR_UPDATE_STATUS == fpgaFlashStatus.fpgaReadyForDataStatus ) ) { isFIFOReady = TRUE; } if ( ( FALSE == isQueueFull() ) && ( TRUE == isFIFOReady ) ) { fpgaDataLenToWrite = len; status = TRUE; memset( &fpgaDataToWriteBuffer, 0x0, SW_UPDATE_FLASH_BUFFER_SIZE ); memcpy( &fpgaDataToWriteBuffer, data, len ); enqueue( FPGA_FLASH_WRITE_DATA ); } return status; } /*********************************************************************//** * @brief * The signalFPGAToSelfConfigure function enqueues the FPGA self configure * job if the queue is not full. * @details \b Inputs: none * @details \b Outputs: fpgaFlashStatus * @return none *************************************************************************/ void signalFPGAToSelfConfigure( void ) { if ( FALSE == isQueueFull() ) { fpgaFlashStatus.preSelfConfigureStartTimeMS = getMSTimerCount(); enqueue( FPGA_SELF_CONFIGURE ); } } // ********** private functions ********** /*********************************************************************//** * @brief * The initDMA function initializes the DMA communication. * @details \b Inputs: none * @details \b Outputs: FPGA DMA unit initialized. * @return none *************************************************************************/ static void initDMA( void ) { // Enable interrupt notifications for FPGA serial port sciEnableNotification( scilinREG, SCI_OE_INT | SCI_FE_INT ); // Assign DMA channels to h/w DMA requests dmaReqAssign( DMA_CH0, SCI2_RECEIVE_DMA_REQUEST ); dmaReqAssign( DMA_CH2, SCI2_TRANSMIT_DMA_REQUEST ); // Set DMA channel priorities dmaSetPriority( DMA_CH0, HIGHPRIORITY ); dmaSetPriority( DMA_CH2, LOWPRIORITY ); // Enable DMA block transfer complete interrupts dmaEnableInterrupt( DMA_CH0, BTC ); dmaEnableInterrupt( DMA_CH2, BTC ); // Initialize FPGA DMA Write Control Record fpgaDMAWriteControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) fpgaDMAWriteControlRecord.SADD = (U32)fpgaWriteCmdBuffer; // Transfer source address fpgaDMAWriteControlRecord.DADD = (U32)(&(scilinREG->TD)); // Dest. is SCI2 xmit register fpgaDMAWriteControlRecord.CHCTRL = 0; // No chaining fpgaDMAWriteControlRecord.ELCNT = 1; // Frame is 1 element fpgaDMAWriteControlRecord.FRCNT = 0; // Block is TBD frames - will be populated later when known fpgaDMAWriteControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte fpgaDMAWriteControlRecord.WRSIZE = ACCESS_8_BIT; // fpgaDMAWriteControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer fpgaDMAWriteControlRecord.ADDMODERD = ADDR_INC1; // Source addressing mode is post-increment fpgaDMAWriteControlRecord.ADDMODEWR = ADDR_FIXED; // Dest. addressing mode is fixed fpgaDMAWriteControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off fpgaDMAWriteControlRecord.ELSOFFSET = 0; // Not used fpgaDMAWriteControlRecord.ELDOFFSET = 0; // Not used fpgaDMAWriteControlRecord.FRSOFFSET = 0; // Not used fpgaDMAWriteControlRecord.FRDOFFSET = 0; // Not used // Initialize FPGA DMA Write Response Control Record fpgaDMAWriteRespControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) fpgaDMAWriteRespControlRecord.SADD = (U32)(&(scilinREG->RD)); // Source is SCI2 recv register fpgaDMAWriteRespControlRecord.DADD = (U32)fpgaWriteResponseBuffer; // Transfer destination address fpgaDMAWriteRespControlRecord.CHCTRL = 0; // No chaining fpgaDMAWriteRespControlRecord.ELCNT = 1; // Frame is 1 element fpgaDMAWriteRespControlRecord.FRCNT = 0; // Block is TBD frames - will be populated later when known fpgaDMAWriteRespControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte fpgaDMAWriteRespControlRecord.WRSIZE = ACCESS_8_BIT; // fpgaDMAWriteRespControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer fpgaDMAWriteRespControlRecord.ADDMODERD = ADDR_FIXED; // Source addressing mode is fixed fpgaDMAWriteRespControlRecord.ADDMODEWR = ADDR_INC1; // Dest. addressing mode is post-increment fpgaDMAWriteRespControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off fpgaDMAWriteRespControlRecord.ELDOFFSET = 0; // Not used fpgaDMAWriteRespControlRecord.ELSOFFSET = 0; // Not used fpgaDMAWriteRespControlRecord.FRDOFFSET = 0; // Not used fpgaDMAWriteRespControlRecord.FRSOFFSET = 0; // Not used // Initialize FPGA DMA Read Control Record fpgaDMAReadControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) fpgaDMAReadControlRecord.SADD = (U32)fpgaReadCmdBuffer; // Transfer source address fpgaDMAReadControlRecord.DADD = (U32)(&(scilinREG->TD)); // Dest. is SCI2 xmit register fpgaDMAReadControlRecord.CHCTRL = 0; // No chaining fpgaDMAReadControlRecord.ELCNT = 1; // Frame is 1 element fpgaDMAReadControlRecord.FRCNT = 0; // Block is TBD frames - will be populated later when known fpgaDMAReadControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte fpgaDMAReadControlRecord.WRSIZE = ACCESS_8_BIT; // fpgaDMAReadControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer fpgaDMAReadControlRecord.ADDMODERD = ADDR_INC1; // Source addressing mode is post-increment fpgaDMAReadControlRecord.ADDMODEWR = ADDR_FIXED; // Dest. addressing mode is fixed fpgaDMAReadControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off fpgaDMAReadControlRecord.ELSOFFSET = 0; // Not used fpgaDMAReadControlRecord.ELDOFFSET = 0; // Not used fpgaDMAReadControlRecord.FRSOFFSET = 0; // Not used fpgaDMAReadControlRecord.FRDOFFSET = 0; // Not used // Initialize FPGA DMA Read Response Control Record fpgaDMAReadRespControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) fpgaDMAReadRespControlRecord.SADD = (U32)(&(scilinREG->RD)); // Source is SCI2 recv register fpgaDMAReadRespControlRecord.DADD = (U32)fpgaReadResponseBuffer; // Transfer destination address fpgaDMAReadRespControlRecord.CHCTRL = 0; // No chaining fpgaDMAReadRespControlRecord.ELCNT = 1; // Frame is 1 element fpgaDMAReadRespControlRecord.FRCNT = 0; // Block is TBD frames - will be populated later when known fpgaDMAReadRespControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte fpgaDMAReadRespControlRecord.WRSIZE = ACCESS_8_BIT; // fpgaDMAReadRespControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer fpgaDMAReadRespControlRecord.ADDMODERD = ADDR_FIXED; // Source addressing mode is fixed fpgaDMAReadRespControlRecord.ADDMODEWR = ADDR_INC1; // Dest. addressing mode is post-increment fpgaDMAReadRespControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off fpgaDMAReadRespControlRecord.ELDOFFSET = 0; // Not used fpgaDMAReadRespControlRecord.ELSOFFSET = 0; // Not used fpgaDMAReadRespControlRecord.FRDOFFSET = 0; // Not used fpgaDMAReadRespControlRecord.FRSOFFSET = 0; // Not used } /*********************************************************************//** * @brief * The consumeUnexpectedData function checks to see if a byte is sitting in * the SCI2 received data register and consumes the byte if found. * @details \b Inputs: SCI FLR register * @details \b Outputs: SCI errors cleared, unexpected byte consumed * @return none *************************************************************************/ static void consumeUnexpectedData( void ) { // Clear any errors sciRxError( scilinREG ); // If a byte is pending read, read it if ( sciIsRxReady( scilinREG ) != 0 ) { sciReceiveByte( scilinREG ); } } /*********************************************************************//** * @brief * The processFPGAFlashRegistersRead function processes the read flash readings. * @details \b Inputs: fpgaReadResponseBuffer[] * @details \b Outputs: fpgaFlashStatus * @return none *************************************************************************/ static void processFPGAFlashRegistersRead( void ) { fpgaFlashStatus.fpgaRemainingFIFOCountBytes = FPGA_FIFO_SIZE_BYTES - ( fpgaReadRegsStatus.fifoCount & FPGA_FIFO_COUNT_MASK ); fpgaFlashStatus.fpgaInitStatus = fpgaReadRegsStatus.flashStatus & FPGA_FLASH_INIT_STATUS; fpgaFlashStatus.fpgaEraseStatus = fpgaReadRegsStatus.flashStatus & FPGA_FLASH_ERASE_STATUS; fpgaFlashStatus.fpgaProgramImageStatus = fpgaReadRegsStatus.flashStatus & FPGA_FLASH_PROG_IMAGE_STATUS; fpgaFlashStatus.fpgaReadyForDataStatus = fpgaReadRegsStatus.flashStatus & FPGA_FLASH_READY_FOR_UPDATE_STATUS; } static void processFPGAUpdateInitStatus( void ) { if ( TRUE == didTimeout( fpgaFlashStatus.startTimeMS, FPGA_INIT_STAGE_TIMEOUT_MS ) ) { BOOL initStatus = TRUE; ACK_NACK_STATUS_T ackStatus = NACK; fpgaFlashStatus.fpgaUpdateStage = FPGA_UPDATE_STAGE_INIT; initStatus &= ( FPGA_FLASH_INIT_STATUS == fpgaFlashStatus.fpgaInitStatus ? TRUE : FALSE ); initStatus &= ( FPGA_FLASH_READY_FOR_UPDATE_STATUS == fpgaFlashStatus.fpgaReadyForDataStatus ? TRUE : FALSE ); initStatus &= ( fpgaFlashStatus.fpgaRemainingFIFOCountBytes > SW_UPDATE_FLASH_BUFFER_SIZE ? TRUE : FALSE ); if ( TRUE == initStatus ) { ackStatus = ACK; fpgaFlashStatus.fpgaUpdateStage = FPGA_UPDATE_STAGE_UPDATE; } ackStatus = ( TRUE == initStatus ? ACK : NACK ); sendFPGAAckNackStatus( ackStatus, FALSE ); } } /*********************************************************************//** * @brief * The setupDMAForReadResp function sets the expected byte count for the * next DMA read command response from the FPGA. * @details \b Inputs: none * @details \b Outputs: fpgaDMAReadRespControlRecord * @param bytes2Receive number of expected bytes to be transmitted via * DMA from the FPGA * @return none *************************************************************************/ static void setupDMAForReadResp( U32 bytes2Receive ) { // Verify # of bytes does not exceed buffer length if ( bytes2Receive <= FPGA_READ_RSP_BUFFER_LEN ) { fpgaDMAReadRespControlRecord.FRCNT = bytes2Receive; } } /*********************************************************************//** * @brief * The setupDMAForReadCmd function sets the byte count for the next DMA * read command to the FPGA. * @details \b Inputs: none * @details \b Outputs: fpgaDMAReadControlRecord * @param bytes2Transmit number of bytes to be transmitted via DMA to the FPGA * @return none *************************************************************************/ static void setupDMAForReadCmd( U32 bytes2Transmit ) { // Verify # of bytes does not exceed buffer length if ( bytes2Transmit <= FPGA_READ_CMD_BUFFER_LEN ) { fpgaDMAReadControlRecord.FRCNT = bytes2Transmit; } } /*********************************************************************//** * @brief * The startDMAReceiptOfReadResp function initiates readiness of the DMA * receiver for the next DMA read command response from the FPGA. * @details \b Inputs: fpgaDMAReadRespControlRecord * @details \b Outputs: DMA read command response is ready to be received * from the FPGA * @return none *************************************************************************/ static void startDMAReceiptOfReadResp( void ) { dmaSetCtrlPacket( DMA_CH0, fpgaDMAReadRespControlRecord ); dmaSetChEnable( DMA_CH0, DMA_HW ); setSCI2DMAReceiveInterrupt(); } /*********************************************************************//** * @brief * The startDMAReadCmd function initiates the DMA transmit for the next * DMA read command to the FPGA. * @details \b Inputs: fpgaDMAReadControlRecord * @details \b Outputs: DMA read command to FPGA is initiated * @return none *************************************************************************/ static void startDMAReadCmd( void ) { dmaSetCtrlPacket( DMA_CH2, fpgaDMAReadControlRecord ); dmaSetChEnable( DMA_CH2, DMA_HW ); setSCI2DMATransmitInterrupt(); } /*********************************************************************//** * @brief * The setupDMAForWriteCmd function sets the byte count for the next DMA * write command to the FPGA. * @details Inputs: none * @details Outputs: number of bytes for next FPGA write command is set * @param bytes2Transmit number of bytes to be transmitted via DMA to the FPGA * @return none *************************************************************************/ static void setupDMAForWriteCmd( U32 bytes2Transmit ) { // Verify # of bytes does not exceed buffer length if ( bytes2Transmit <= FPGA_WRITE_CMD_BUFFER_LEN ) { fpgaDMAWriteControlRecord.FRCNT = bytes2Transmit; } } /*********************************************************************//** * @brief * The startDMAWriteCmd function initiates the DMA transmit for the next * DMA write command to the FPGA. * @details Inputs: none * @details Outputs: DMA write command to FPGA is initiated * @return none *************************************************************************/ static void startDMAWriteCmd( void ) { dmaSetCtrlPacket( DMA_CH2, fpgaDMAWriteControlRecord ); dmaSetChEnable( DMA_CH2, DMA_HW ); setSCI2DMATransmitInterrupt(); } /*********************************************************************//** * @brief * The setupDMAForWriteResp function sets the expected byte count for the * next DMA write command response from the FPGA. * @details Inputs: none * @details Outputs: number of expected bytes for next FPGA write command response is set * @param bytes2Receive number of bytes expected to be transmitted via DMA from the FPGA * @return none *************************************************************************/ static void setupDMAForWriteResp( U32 bytes2Receive ) { // Verify # of bytes does not exceed buffer length if ( bytes2Receive <= FPGA_WRITE_RSP_BUFFER_LEN ) { fpgaDMAWriteRespControlRecord.FRCNT = bytes2Receive; } } /*********************************************************************//** * @brief * The startDMAReceiptOfWriteResp function initiates readiness of the DMA * receiver for the next DMA write command response from the FPGA. * @details Inputs: none * @details Outputs: DMA write command response is ready to be received from the FPGA * @return none *************************************************************************/ static void startDMAReceiptOfWriteResp( void ) { dmaSetCtrlPacket( DMA_CH0, fpgaDMAWriteRespControlRecord ); dmaSetChEnable( DMA_CH0, DMA_HW ); setSCI2DMAReceiveInterrupt(); } /*********************************************************************//** * @brief * The resetFPGACommFlags function resets the various fpga comm flags and * counters. * @details \b Inputs: none * @details \b Outputs: fpgaJobsQStatus * @return none *************************************************************************/ static void resetFPGACommFlags( void ) { fpgaJobsQStatus.fpgaCommRead = FPGA_COMM_IDLE; fpgaJobsQStatus.fpgaCommWrite = FPGA_COMM_IDLE; } /*********************************************************************//** * @brief * The enqueue function enqueues a new job into the queue. * @details \b Inputs: none * @details \b Outputs: fpgaJobsQStatus * @return none *************************************************************************/ static void enqueue( FPGA_JOBS_T job ) { U08 currentRearIndex = fpgaJobsQStatus.fpgaJobRearIndex; fpgaJobsQStatus.fpgaJobsQueue[ currentRearIndex ] = job; fpgaJobsQStatus.fpgaJobsQueueCount++; fpgaJobsQStatus.fpgaJobRearIndex = INC_WRAP( currentRearIndex, 0, QUEUE_MAX_SIZE - 1 ); } /*********************************************************************//** * @brief * The enqueue function dequeues a job from the queue. This function is thread * safe. Prior to dequeuing a job, the IRQ interrupt is stopped. * @details \b Inputs: fpgaJobsQStatus * @details \b Outputs: fpgaJobsQStatus * @return none *************************************************************************/ static void dequeue( void ) { U08 tempIndex; _disable_IRQ(); tempIndex = fpgaJobsQStatus.fpgaJobFrontIndex; if ( fpgaJobsQStatus.fpgaJobsQueueCount > 0 ) { U08 frontIndex = fpgaJobsQStatus.fpgaJobFrontIndex; fpgaJobsQStatus.fpgaJobFrontIndex = INC_WRAP( frontIndex, 0, QUEUE_MAX_SIZE - 1 ); fpgaJobsQStatus.fpgaCurrentJob = fpgaJobsQStatus.fpgaJobsQueue[ tempIndex ]; } if ( fpgaJobsQStatus.fpgaJobsQueueCount > 0 ) { fpgaJobsQStatus.fpgaJobsQueueCount--; } _enable_IRQ(); } /*********************************************************************//** * @brief * The peekFromQueue function just reports what is the next job in the queue. * This function does not do the actual dequeue. This function is thread * safe. Prior to peeking into the next job, the IRQ interrupt is stopped. * @details \b Inputs: fpgaJobsQStatus * @details \b Outputs: none * @return the next job that is in the queue *************************************************************************/ static FPGA_JOBS_T peekFromQueue( void ) { _disable_IRQ(); U08 frontIndex = fpgaJobsQStatus.fpgaJobFrontIndex; FPGA_JOBS_T nextJob = (FPGA_JOBS_T)fpgaJobsQStatus.fpgaJobsQueue[ frontIndex ]; _enable_IRQ(); return nextJob; } /*********************************************************************//** * @brief * The isQueueFull function checks whether the queue is full or not. * @details \b Inputs: fpgaJobsQStatus * @details \b Outputs: none * @return TRUE if the queue is full otherwise, FALSE *************************************************************************/ static BOOL isQueueFull( void ) { BOOL isFull = FALSE; if ( fpgaJobsQStatus.fpgaJobsQueueCount >= ( QUEUE_MAX_SIZE - 1 ) ) { isFull = TRUE; } return isFull; } static void publishDataTemp( void ) { // TODO test code remove //if ( ( tempPrevJob != fpgaJobsQStatus.fpgaCurrentJob ) || ( tempPrevFlash != fpgaReadRegsStatus.flashStatus ) || ( tempPrevFIFO != fpgaFlashStatus.fpgaRemainingFIFOCountBytes ) ) { U08 data[8]; data[0] = GET_MSB_OF_WORD( getCurrentUpdateMessageID() ); data[1] = GET_LSB_OF_WORD( getCurrentUpdateMessageID() ); data[2] = GET_MSB_OF_WORD( fpgaFlashStatus.fpgaRemainingFIFOCountBytes ); data[3] = GET_LSB_OF_WORD( fpgaFlashStatus.fpgaRemainingFIFOCountBytes ); data[4] = GET_MSB_OF_WORD( fpgaReadRegsStatus.flashStatus ); data[5] = GET_LSB_OF_WORD( fpgaReadRegsStatus.flashStatus ); data[6] = fpgaJobsQStatus.fpgaCurrentJob; data[7] = (U08)fpgaState; broadcastDataTestRemove(data); //tempPrevJob = fpgaJobsQStatus.fpgaCurrentJob; //tempPrevFlash = fpgaReadRegsStatus.flashStatus; //tempPrevFIFO = fpgaFlashStatus.fpgaRemainingFIFOCountBytes; } // TODO test code remove } /*********************************************************************//** * @brief * The handleFPGAIdleState function handles the FPGA idle state. This state * checks whether there are any jobs in the queue and processes them. This * state also requests the flash update registers. * @details \b Inputs: fpgaJobsQStatus, fpgaFlashStatus * @details \b Outputs: none * @return next state of the FPGA state machine *************************************************************************/ static FPGA_STATE_T handleFPGAIdleState( void ) { FPGA_STATE_T state = FPGA_IDLE_STATE; switch( fpgaFlashStatus.fpgaUpdateStage ) { case FPGA_UPDATE_STAGE_CHECK_UPDATE_INIT: processFPGAUpdateInitStatus(); break; } if ( FALSE == isQueueFull() ) { // If queue is not full enqueue a multi-boot status read enqueue( FPGA_READ_MULTI_BOOT_STATUS ); } if ( fpgaJobsQStatus.fpgaJobsQueueCount > 0 ) { BOOL isDequeueAllowed = TRUE; // TODO remove //if ( FPGA_FLASH_WRITE_DATA == peekFromQueue() ) //{ // // Check if the next job in the queue is a flash write. // // If there is a flash write, only dequeue it if: // // 1. There are at least 256 bytes available in the FIFO // // 2. The flash status is okay // // 3. The FIFO erase is okay // if ( ( fpgaFlashStatus.fpgaRemainingFIFOCountBytes < SW_UPDATE_FLASH_BUFFER_SIZE ) || // ( FALSE == fpgaFlashStatus.isFlashStatusOk ) || // ( FALSE == fpgaFlashStatus.isFIFOEraseOk ) ) // { // isDequeueAllowed = FALSE; // } //} // TODO remove //if ( FPGA_SELF_CONFIGURE == peekFromQueue() ) //{ // // Check if the next job in the queue is the self configure. Then make sure: // // 1. The delay has timed out // // 2. The flash status is okay // if ( ( FALSE == didTimeout( fpgaFlashStatus.preSelfConfigureStartTimeMS, FPGA_PRE_SELF_CONFIG_TIMEOUT_MS ) ) || // ( FALSE == fpgaFlashStatus.isFlashStatusOk ) ) // { // isDequeueAllowed = FALSE; // } //} if ( TRUE == isDequeueAllowed ) { dequeue(); // After dequeue based on the job specs transition to either write or read states state = ( FALSE == JOBS_SPECS[ fpgaJobsQStatus.fpgaCurrentJob ].fpgaIsJobWrite ? FPGA_READ_FROM_FPGA_STATE : FPGA_WRITE_TO_FPGA_STATE ); } } return state; } /*********************************************************************//** * @brief * The handleFPGAWriteToFPGAState function handles the FPGA write to FPGA * state. This state prepares the buffer to write to FPGA and sets the DMA * to write to the FPGA. * @details \b Inputs: fpgaJobsQStatus, fpgaDataLenToWrite * @details \b Outputs: fpgaFlashStatus, fpgaWriteCmdBuffer[] * @return next state of the FPGA state machine *************************************************************************/ static FPGA_STATE_T handleFPGAWriteToFPGAState( void ) { FPGA_STATE_T state = FPGA_RCV_WRITE_RESP_FROM_FPGA_STATE; U16 crc = 0; U16 jobAddress = JOBS_SPECS[ fpgaJobsQStatus.fpgaCurrentJob ].fpgaJobAddress; U16 jobSize = JOBS_SPECS[ fpgaJobsQStatus.fpgaCurrentJob ].fpgaJobSize; if ( ( fpgaDataLenToWrite != SW_UPDATE_FLASH_BUFFER_SIZE ) && ( FPGA_FLASH_WRITE_DATA == fpgaJobsQStatus.fpgaCurrentJob ) ) { // Set the write length from the buffer length provided jobSize = (U16)fpgaDataLenToWrite; } if ( FPGA_SELF_CONFIGURE == fpgaJobsQStatus.fpgaCurrentJob ) { // Once self configure is sent the FPGA will be unresponsive so there will be no ack back // Signal FPGA is completed state = FPGA_IDLE_STATE; } U08* value2Write = JOBS_SPECS[ fpgaJobsQStatus.fpgaCurrentJob ].fpgaWriteStartAddress; U16 firstCRCIndex = FPGA_WRITE_CMD_HDR_LEN + jobSize; U16 secondCRCIndex = FPGA_WRITE_CMD_HDR_LEN + jobSize + 1; memset( &fpgaWriteCmdBuffer, 0x0, FPGA_WRITE_CMD_BUFFER_LEN ); // TODO a better place for this memcpy( &fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_HDR_LEN ], value2Write, jobSize ); // Construct bulk read command to read sensor data registers starting at address 8 fpgaWriteCmdBuffer[ 0 ] = FPGA_WRITE_CMD_CODE; fpgaWriteCmdBuffer[ 1 ] = GET_LSB_OF_WORD( jobAddress ); fpgaWriteCmdBuffer[ 2 ] = GET_MSB_OF_WORD( jobAddress ); #if BL_STACK_ID == 1 fpgaWriteCmdBuffer[ 3 ] = GET_LSB_OF_WORD( jobSize ); fpgaWriteCmdBuffer[ 4 ] = GET_MSB_OF_WORD( jobSize ); #else fpgaWriteCmdBuffer[ 3 ] = jobSize % SW_UPDATE_FLASH_BUFFER_SIZE; #endif crc = crc16( fpgaWriteCmdBuffer, FPGA_WRITE_CMD_HDR_LEN + jobSize ); fpgaWriteCmdBuffer[ firstCRCIndex ] = GET_MSB_OF_WORD( crc ); fpgaWriteCmdBuffer[ secondCRCIndex ] = GET_LSB_OF_WORD( crc ); // Prep DMA for sending the read cmd and receiving the response fpgaJobsQStatus.fpgaCommWrite = FPGA_COMM_WRITE_IN_PROGRESS; // Prep DMA for sending the bulk write cmd and receiving its response setupDMAForWriteCmd( FPGA_WRITE_CMD_HDR_LEN + jobSize + FPGA_CRC_LEN ); setupDMAForWriteResp( FPGA_WRITE_RSP_HDR_LEN + FPGA_CRC_LEN ); // Initiate bulk write command and its receipt - read will follow startDMAReceiptOfWriteResp(); startDMAWriteCmd(); return state; } /*********************************************************************//** * @brief * The handleFPGAReceiveWriteRespFromFPGAState function handles the FPGA * receive write to FPGA response. * @details \b Inputs: fpgaJobsQStatus, fpgaWriteResponseBuffer[] * @details \b Outputs: fpgaWriteResponseBuffer[] * @return next state of the FPGA state machine *************************************************************************/ static FPGA_STATE_T handleFPGAReceiveWriteRespFromFPGAState( void ) { FPGA_STATE_T state = FPGA_RCV_WRITE_RESP_FROM_FPGA_STATE; if ( FPGA_COMM_WRITE_RESP_RECEIVED == fpgaJobsQStatus.fpgaCommWrite ) { if ( FPGA_WRITE_CMD_ACK == fpgaWriteResponseBuffer[ 0 ] ) { // Message is an ack - check CRC U32 rspSize = FPGA_READ_RSP_HDR_LEN; U32 crcPos = rspSize; U16 crc = MAKE_WORD_OF_BYTES( fpgaWriteResponseBuffer[ crcPos ], fpgaWriteResponseBuffer[ crcPos + 1 ] ); // Does the FPGA response CRC checkout? if ( crc == crc16( fpgaWriteResponseBuffer, rspSize ) ) { // TODO switch case or a function here if ( FPGA_FLASH_WRITE_DATA == fpgaJobsQStatus.fpgaCurrentJob ) { sendFPGAAckNackStatus( ACK, TRUE ); } if ( FPGA_ENABLE_FLASH == fpgaJobsQStatus.fpgaCurrentJob ) { fpgaFlashStatus.fpgaUpdateStage = FPGA_UPDATE_STAGE_CHECK_UPDATE_INIT; fpgaFlashStatus.startTimeMS = getMSTimerCount(); } // CRC passed state = FPGA_IDLE_STATE; } else { // TODO error handling BOOL test = FALSE; } } } return state; } /*********************************************************************//** * @brief * The handleFPGAReadFromFPGAState function handles the FPGA read from FPGA. * @details \b Inputs: none * @details \b Outputs: fpgaReadCmdBuffer[], fpgaJobsQStatus, fpgaFlashStatus * @return next state of the FPGA state machine *************************************************************************/ static FPGA_STATE_T handleFPGAReadFromFPGAState( void ) { FPGA_STATE_T state = FPGA_RCV_READ_RESP_FROM_FPGA_STATE; U16 crc = 0; U16 jobAddress = JOBS_SPECS[ fpgaJobsQStatus.fpgaCurrentJob ].fpgaJobAddress; U08 jobSize = JOBS_SPECS[ fpgaJobsQStatus.fpgaCurrentJob ].fpgaJobSize; // Construct read command to read 3 registers starting at address 0 fpgaReadCmdBuffer[ 0 ] = FPGA_READ_CMD_CODE; fpgaReadCmdBuffer[ 1 ] = GET_LSB_OF_WORD( jobAddress ); fpgaReadCmdBuffer[ 2 ] = GET_MSB_OF_WORD( jobAddress ); #if BL_STACK_ID == 1 fpgaReadCmdBuffer[ 3 ] = jobSize; fpgaReadCmdBuffer[ 4 ] = 0; #else fpgaReadCmdBuffer[ 3 ] = jobSize; #endif crc = crc16( fpgaReadCmdBuffer, FPGA_READ_CMD_HDR_LEN ); #if BL_STACK_ID == 1 fpgaReadCmdBuffer[ 5 ] = GET_MSB_OF_WORD( crc ); fpgaReadCmdBuffer[ 6 ] = GET_LSB_OF_WORD( crc ); #else fpgaReadCmdBuffer[ 4 ] = GET_MSB_OF_WORD( crc ); fpgaReadCmdBuffer[ 5 ] = GET_LSB_OF_WORD( crc ); #endif // Prep DMA for sending the read cmd and receiving the response fpgaJobsQStatus.fpgaCommRead = FPGA_COMM_READ_IN_PROGRESS; fpgaOperationStartTimeMS = getMSTimerCount(); setupDMAForReadResp( FPGA_READ_RSP_HDR_LEN + jobSize + sizeof( U16 ) ); setupDMAForReadCmd( FPGA_READ_CMD_HDR_LEN + sizeof( U16 ) ); startDMAReceiptOfReadResp(); startDMAReadCmd(); return state; } /*********************************************************************//** * @brief * The handleFPGAReceiveReadRespFromFPGAState function handles the FPGA * read response from FPGA. * @details \b Inputs: fpgaJobsQStatus, fpgaReadResponseBuffer[] * @details \b Outputs: fpgaReadResponseBuffer[], fpgaHeader, * fpgaUpdateRegisterStatus * @return next state of the FPGA state machine *************************************************************************/ static FPGA_STATE_T handleFPGAReceiveReadRespFromFPGAState( void ) { FPGA_STATE_T state = FPGA_RCV_READ_RESP_FROM_FPGA_STATE; if ( FPGA_COMM_READ_RESP_RECEIVED == fpgaJobsQStatus.fpgaCommRead ) { if ( FPGA_READ_CMD_ACK == fpgaReadResponseBuffer[ 0 ] ) { U16 jobSize = JOBS_SPECS[ fpgaJobsQStatus.fpgaCurrentJob ].fpgaJobSize; U32 rspSize = FPGA_READ_RSP_HDR_LEN + jobSize; U32 crcPos = rspSize; U16 crc = MAKE_WORD_OF_BYTES( fpgaReadResponseBuffer[ crcPos ], fpgaReadResponseBuffer[ crcPos + 1 ] ); // Does the FPGA response CRC check out? if ( crc == crc16( fpgaReadResponseBuffer, rspSize ) ) { switch( fpgaJobsQStatus.fpgaCurrentJob ) { case FPGA_READ_HEADER: memcpy( &fpgaHeader, &fpgaReadResponseBuffer[ FPGA_READ_RSP_HDR_LEN ], jobSize ); break; case FPGA_READ_UPDATE_REG: fpgaUpdateRegisterStatus = fpgaReadResponseBuffer[ FPGA_UPDATE_REQUEST_INDEX ]; break; case FPGA_READ_MULTI_BOOT_STATUS: memcpy( &fpgaReadRegsStatus, &fpgaReadResponseBuffer[ FPGA_READ_RSP_HDR_LEN ], jobSize ); processFPGAFlashRegistersRead(); break; default: // Do nothing break; } memset( &fpgaReadResponseBuffer, 0x0, FPGA_READ_RSP_BUFFER_LEN ); state = FPGA_IDLE_STATE; } } } if ( TRUE == didTimeout( fpgaFlashStatus.startTimeMS, 100 ) ) { state = FPGA_IDLE_STATE; } resetFPGACommFlags(); // Should not be any data received at this time consumeUnexpectedData(); return state; } /**@}*/