/************************************************************************** * * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file FPGA.c * * @author (last) Sean Nash * @date (last) 14-Oct-2020 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 * ***************************************************************************/ #include // For memset(), memcpy() #include "sci.h" #include "sys_dma.h" #include "FPGA.h" #include "Comm.h" #include "SystemCommMessages.h" #include "Utilities.h" /** * @addtogroup FPGA * @{ */ // ********** private definitions ********** /// Enumeration of FPGA states. typedef enum FPGA_States { FPGA_STATE_START = 0, ///< Start state for the FPGA. FPGA_STATE_READ_HEADER, ///< Read header command state for the FPGA. FPGA_STATE_RCV_HEADER, ///< Receive header state for the FPGA. FPGA_STATE_WRITE_ALL_ACTUATORS, ///< Write actuators command state for the FPGA. FPGA_STATE_RCV_ALL_SENSORS, ///< Receive sensors state for the FPGA. FPGA_STATE_READ_ALL_SENSORS_ASYNC, ///< Read async sensors state for the FPGA. FPGA_STATE_RCV_ALL_SENSORS_ASYNC, ///< Receive async sensors state for the FPGA. FPGA_STATE_FAILED, ///< Failed state for the FPGA. NUM_OF_FPGA_STATES ///< Number of FPGA states. } FPGA_STATE_T; #define FPGA_PAGE_SIZE 256 ///< FPGA register pages are 256 bytes. #define FPGA_EXPECTED_ID 0x5A ///< Expected ID for HD FPGA. #define FPGA_HEADER_START_ADDR 0x0000 ///< Start address for FPGA header data. #define FPGA_BULK_READ_START_ADDR 0x0100 ///< Start address for FPGA continuous priority reads. #define FPGA_BULK_WRITE_START_ADDR 0x000C ///< Start address for FPGA continuous priority writes. #define FPGA_BULK_ASYNC_READ_START_ADDR 0x0200 ///< Start address for FPGA async reads. #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 FPGA_WRITE_CMD_CODE 0x55 ///< FPGA write command code. #define FPGA_READ_CMD_CODE 0x5A ///< FPGA read command code. #define FPGA_WRITE_CMD_ACK 0xA5 ///< FPGA write command ACK code. #define FPGA_READ_CMD_ACK 0xAA ///< FPGA read command ACK code. #define FPGA_CMD_NAK 0xEE ///< FPGA command NAK code. #define FPGA_CRC_LEN 2 ///< FPGA CRC byte length. #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_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 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 MAX_COMM_ERROR_RETRIES 5 ///< Maximum consecutive FPGA communication error retries. #define FPGA_ADC1_AUTO_READ_ENABLE 0x01 ///< Auto-read enable bit for ADC1 control register. #define FPGA_AIRTRAP_LEVEL_LOW_MASK 0x0008 ///< Bit mask for air trap lower level sensor. #define FPGA_AIRTRAP_LEVEL_HIGH_MASK 0x0004 ///< Bit mask for air trap upper level sensor. // FPGA Sensors Record #pragma pack(push,1) /// 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. U16 fpgaStatus; ///< Reg 4. FPGA status register. U08 fpgaDiag; ///< Reg 6. FPGA diagnostic (R/W) register. U08 adc1Control; ///< Reg 7. ADC1 control register. Bit 0=auto read enable. U08 flowDAQ1Cmd; ///< Reg 8. Command passed to flow DAQ #1. U08 flowDAQ2Cmd; ///< Reg 9. Command passed to flow DAQ #2. U08 accelCmd; ///< Reg 10. Command passed to accelerometer. U08 fpgaSensorTest; ///< Reg 11. Blood leak and bubble detector sensor test register. U16 fpgaPIDControl; ///< Reg 12. Valve PID enables. } FPGA_HEADER_T; // Read only on FPGA /// Record structure for FPGA continuous priority reads. typedef struct // TODO - add all sensor readings to this structure per FPGA register map { U08 errorCountProcessor; ///< Reg 256. TBD. U08 errorCountPC; ///< Reg 257. TBD. U08 bloodFlowMeterDataPktCount; ///< Reg 258. Blood flow sensor data packet count. U08 bloodFlowMeterSlowPktCounts; ///< Reg 259. Blood flow sensor slow data packet count. F32 bloodFlowLast; ///< Reg 260. Blood flow rate data. U08 bloodFlowMeterDeviceStatus; ///< Reg 264. Blood flow sensor status. U08 bloodFlowMeterResponse; ///< Reg 265. TBD. U08 dialysateFlowMeterDataPktCount; ///< Reg 266. Dialysate flow sensor data packet count. U08 dialysateFlowMeterSlowPckCounts; ///< Reg 267. Dialysate flow sensor slow data packet count. F32 dialysateFlowLast; ///< Reg 268. Dialysate flow rate data. U08 dialysateFlowMeterDeviceStatus; ///< Reg 272. Dialysate flow sensor status. U08 dialysateFlowMeterResponse; ///< Reg 273. TBD. U08 bloodFlowMeterErrorCount; ///< Reg 274. Blood flow sensor error count. U08 dialysateFlowMeterErrorCount; ///< Reg 275. Dialysate flow sensor error count. U16 bloodOcclusionData; ///< Reg 276. Blood pump occlusion sensor data. U08 bloodOcclusionReadCount; ///< Reg 278. Blood pump occlusion sensor read count. U08 bloodOcclusionErrorCount; ///< Reg 279. Blood pump occlusion sensor error count. U16 dialysateInOcclusionData; ///< Reg 280. Dialysate inlet pump occlusion sensor data. U08 dialysateInOcclusionReadCount; ///< Reg 282. Dialysate inlet pump occlusion sensor read count. U08 dialysateInOcclusionErrorCount; ///< Reg 283. Dialysate inlet pump occlusion sensor error count. U16 dialysateOutOcclusionData; ///< Reg 284. Dialysate outlet pump occlusion sensor data. U08 dialysateOutOcclusionReadCount; ///< Reg 286. Dialysate outlet pump occlusion sensor read count. U08 dialysateOutOcclusionErrorCount; ///< Reg 287. Dialysate outlet pump occlusion sensor error count. U16 bloodPumpHallSensorCount; ///< Reg 288. Blood pump hall sensor count. U08 bloodPumpHallSensorStatus; ///< Reg 290. Blood pump hall sensor status. U08 dialInPumpHallSensorStatus; ///< Reg 291. Dialysate inlet pump hall sensor status. U32 adc1Channel0; ///< Reg 292. ADC1 channel 0 data. U32 adc1Channel1; ///< Reg 296. ADC1 channel 1 data. U32 bloodFlowSoundSpeedData; ///< Reg 300. Blood flow sensor - sound speed data. U32 bloodFlowAccFlowData; ///< Reg 304. Blood flow sensor - accumualted flow data. F32 bloodFlowSignalStrength; ///< Reg 308. Blood flow sensor - signal strength. U08 adc1SequenceCount; ///< Reg 312. ADC1 round robin channel sequence count. U08 adc1ErrorCount; ///< Reg 313. ADC1 error count. U16 accelX; ///< Reg 314. Accelerometer X axis data. U16 accelY; ///< Reg 316. Accelerometer Y axis data. U16 accelZ; ///< Reg 318. Accelerometer Z axis data. U16 accelXMax; ///< Reg 320. Accelerometer X axis max data (since last read). U16 accelYMax; ///< Reg 322. Accelerometer Y axis max data (since last read). U16 accelZMax; ///< Reg 324. Accelerometer Z axis max data (since last read). U16 accelFaultRegister; ///< Reg 326. Accelerometer fault register. U16 accelSampleCounter; ///< Reg 328. Accelerometer sample count. U16 venousPressure; ///< Reg 330. Venous pressure sensor data. U16 venousTemperature; ///< Reg 332. Venous pressure sensor temperature. U08 venousReadCounter; ///< Reg 334. Venous pressure sensor read count. U08 dialOutPumpSensorStatus; ///< Reg 335. Dialysate outlet pump hall sensor status. U16 dialInPumpHallSensorCount; ///< Reg 336. Dialysate inlet pump hall sensor count. U16 dialOutPumpHallSensorCount; ///< Reg 338. Dialysate outlet pump hall sensor count. U32 dialysateFlowSoundSpeedData; ///< Reg 340. Dialysate flow sensor - sound speed data. U32 dialysateFlowAccFlowData; ///< Reg 344. Dialysate flow sensor - accumualted flow data. F32 dialysateFlowSignalStrength; ///< Reg 348. Dialysate flow sensor - signal strength. U16 fan1PulseTime; ///< Reg 352. Fan 1 pulse time in 2.5 uSec resolution. 0xFFFF if fan RPM < 500 RPM. U16 fan2PUlseTime; ///< Reg 354. Fan 2 pulse time in 2.5 uSec resolution. 0xFFFF if fan RPM < 500 RPM. U16 fpgaGPIO; ///< Reg 356. FPGA GPIO register. S16 VBAPosition; ///< Reg 358. Encoder position from VBA pinch valve. 0 until PID interface is enabled. S16 VBVPosition; ///< Reg 360. Encoder position from VBV pinch valve. 0 until PID interface is enabled. S16 VDiPosition; ///< Reg 362. Encoder position from VDi pinch valve. 0 until PID interface is enabled. S16 VDoPosition; ///< Reg 364. Encoder position from VDo pinch valve. 0 until PID interface is enabled. S16 VSparePosition; ///< Reg 366. Encoder position from VSpare pinch valve. 0 until PID interface is enabled. U16 valveStatus; ///< Reg 368. Valve status register. U16 VBAPWMTarget; ///< Reg 370. PWM target duty cycle for VBA pinch valve. U16 VBVPWMTarget; ///< Reg 372. PWM target duty cycle for VBV pinch valve. U16 VDiPWMTarget; ///< Reg 374. PWM target duty cycle for VDi pinch valve. U16 VDoPWMTarget; ///< Reg 376. PWM target duty cycle for VDo pinch valve. U16 VSparePWMTarget; ///< Reg 378. PWM target duty cycle for Vspare pinch valve. U16 SyringePumpStatus; ///< Reg 380. Syringe pump status register U16 SyringePumpEncStatus; ///< Reg 382. Syringe pump encoder status U32 SyringePumpEncPosition; ///< Reg 384. Syringe pump encoder position U16 sPumpAdcDataReadChannel0; ///< Reg 388. U16 sPumpAdcDataReadCh1; ///< Reg 390. U16 sPumpAdcDataReadCh2; ///< Reg 392. U16 sPumpAdcDataReadCh3; ///< Reg 394. U16 VBASpeed; ///< Reg 396. VBA pinch valve speed (Register VAUX0) U16 VBVSpeed; ///< Reg 398. VBV pinch valve speed (Register VAUX1) U16 VBVCurrent; ///< Reg 400. VBV pinch valve current (Register VAUX2) U16 VDoCurrent; ///< Reg 402. VDo pinch valve current (Register VAUX3) U16 VBACurrent; ///< Reg 404. VBA pinch valve current (Register VAUX8) U16 VDiSpeed; ///< Reg 406. VDi pinch valve current (Register VAUX9) U16 VDoSpeed; ///< Reg 408. VDo pinch valve speed (Register VAUX10) U16 VDiCurrent; ///< Reg 410. VDi pinch valve current (Register VAUX11) U16 VSpareSpeed; ///< Reg 412. VSpare speed (Register VAUX5) U16 VSpareCurrent; ///< Reg 414. VSpare current (Register VAUX13) } FPGA_SENSORS_T; /// Record structure for FPGA continuous priority writes. typedef struct // TODO - add all actuator set points to this structure per FPGA register map { U16 fpgaPIDControl; ///< Reg 12. Valve PID enables. S16 VBASetPoint; ///< Reg 14. VBA pinch valve is commanded to this set point position. S16 VBVSetPoint; ///< Reg 16. VBV pinch valve is commanded to this set point position. S16 VDiSetPoint; ///< Reg 18. VDi pinch valve is commanded to this set point position. S16 VDoSetPoint; ///< Reg 20. VDo pinch valve is commanded to this set point position. S16 VSpareSetPoint; ///< Reg 22. VSpare pinch valve is commanded to this set point position. U16 VBAPWMFixed; ///< Reg 24. VBA PWM set to fixed current by setting fixed PWM duty cycle. Range 750 to 4250. < 2500 is reverse direction. U16 VBVPWMFixed; ///< Reg 26. VBV PWM set to fixed current by setting fixed PWM duty cycle. Range 750 to 4250. < 2500 is reverse direction. U16 VDiPWMFixed; ///< Reg 28. VDi PWM set to fixed current by setting fixed PWM duty cycle. Range 750 to 4250. < 2500 is reverse direction. U16 VDoPWMFixed; ///< Reg 30. VDo PWM set to fixed current by setting fixed PWM duty cycle. Range 750 to 4250. < 2500 is reverse direction. U16 VSparePWMFixed; ///< Reg 32. Vspare PWM set to fixed current by setting fixed PWM duty cycle. Range 750 to 4250. < 2500 is reverse direction. U08 AlarmControl; ///< Reg 34. Alarm (audio) control register. } FPGA_ACTUATORS_T; // TODO clean up the struct /// Record structure for FPGA async (as needed) reads. typedef struct // TODO - add all sensor readings to this structure per FPGA register map { U16 fpgaDieTemp; ///< Reg 512. Internal FPGA die temperature. U16 fpgaADCVccVoltage; ///< Reg 514. Internal FPGA Vcc voltage. U16 fpgaADCVccAuxVoltage; ///< Reg 516. Internal FPGA Vcc aux voltage. U16 fpgaADCVpvnVoltage; ///< Reg 518. Internal FPGA VPVN voltage. U16 fpgaVAux0Voltage; ///< Reg 520. Aux. voltage 0. U16 fpgaVAux1Voltage; ///< Reg 522. Aux. voltage 1. U16 fpgaVAux2Voltage; ///< Reg 524. Aux. voltage 2. U16 fpgaVAux3Voltage; ///< Reg 526. Aux. voltage 3. U16 fpgaVAux8Voltage; ///< Reg 528. Aux. voltage 8. U16 fpgaVAux9Voltage; ///< Reg 530. Aux. voltage 9. U16 fpgaVAux10Voltage; ///< Reg 532. Aux. voltage 10. U16 fpgaVAux11Voltage; ///< Reg 534. Aux. voltage 11. F32 bloodFlowSoundSpeed; ///< Reg 536. Blood flow sound speed. F32 bloodFlowAccFlow; ///< Reg 540. Blood flow accumulated flow. F32 bloodFlowSignalStrength; ///< Reg 544. Blood flow signal strength. F32 dialysateInFlowSoundSpeed; ///< Reg 548. Dialysate inlet flow sound speed. F32 dialysateInFlowAccFlow; ///< Reg 552. Dialysate inlet flow accumulated flow. F32 dialysateInFlowSignalStrength; ///< Reg 556. Dialysate inlet flow signal strength. U16 fpgaVAux5Voltage; ///< Reg 560. Aux. voltage 5. } FPGA_SENSORS_ASYNC_T; #pragma pack(pop) // ********** private data ********** // FPGA state static FPGA_STATE_T fpgaState = FPGA_STATE_START; ///< Current FPGA state. static U32 fpgaCommRetryCount = 0; ///< FPGA communication retry counter. static U32 fpgaReceiptCounter = 0; ///< FPGA response receipt counter. static U32 fpgaTransmitCounter = 0; ///< FPGA command transmit counter. static BOOL fpgaWriteCommandInProgress = FALSE; ///< Flag indicating an FPGA write command is in progress. static BOOL fpgaReadCommandInProgress = FALSE; ///< Flag indicating an FPGA read command is in progress. static BOOL fpgaBulkWriteAndReadInProgress = FALSE; ///< Flag indicating an FPGA bulk write and read command are in progress. static BOOL fpgaWriteCommandResponseReceived = FALSE; ///< Flag indicating a response to an FPGA write command has been received. static BOOL fpgaReadCommandResponseReceived = FALSE; ///< Flag indicating a response to an FPGA read command has been received. // 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. // FPGA data static FPGA_HEADER_T fpgaHeader; ///< Record of last received FPGA header data. static FPGA_SENSORS_T fpgaSensorReadings; ///< Record of last received FPGA priority sensor data. static FPGA_ACTUATORS_T fpgaActuatorSetPoints; ///< Record of next transmitted FPGA priority actuator data. #ifdef READ_FPGA_ASYNC_DATA static FPGA_SENSORS_ASYNC_T fpgaSensorReadingsAsync; ///< Record of last received async (as needed) FPGA sensor data. #endif // ********** private function prototypes ********** static FPGA_STATE_T handleFPGAReadHeaderState( void ); static FPGA_STATE_T handleFPGAReceiveHeaderState( void ); static FPGA_STATE_T handleFPGAWriteAllActuatorsState( void ); static FPGA_STATE_T handleFPGAReceiveAllSensorsState( void ); #ifdef READ_FPGA_ASYNC_DATA static FPGA_STATE_T handleFPGAReceiveAllSensorsAsyncState( void ); static FPGA_STATE_T handleFPGAReadAllSensorsAsyncState( void ); #endif static void resetFPGACommFlags( void ); static void setupDMAForWriteCmd( U32 bytes2Transmit ); static void startDMAWriteCmd( void ); static void setupDMAForWriteResp( U32 bytes2Receive ); static void startDMAReceiptOfWriteResp( void ); static void setupDMAForReadCmd( U32 bytes2Transmit ); static void startDMAReadCmd( void ); static void setupDMAForReadResp( U32 bytes2Receive ); static void startDMAReceiptOfReadResp( void ); static void consumeUnexpectedData( void ); /*********************************************************************//** * @brief * The initFPGA function initializes the FPGA module. * @details Inputs: none * @details Outputs: FPGA module initialized. * @return none *************************************************************************/ void initFPGA( void ) { // Initialize fpga data structures memset( &fpgaHeader, 0, sizeof(FPGA_HEADER_T) ); memset( &fpgaSensorReadings, 0, sizeof(FPGA_SENSORS_T) ); memset( &fpgaActuatorSetPoints, 0, sizeof(FPGA_ACTUATORS_T) ); fpgaActuatorSetPoints.AlarmControl = (U08)MIN_ALARM_VOLUME_ATTENUATION << 2; // Start alarm audio volume at maximum // 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 ); // 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 // There should not be any data pending yet consumeUnexpectedData(); } /*********************************************************************//** * @brief * The resetFPGACommFlags function resets the various fpga comm flags and * counters. * @details Inputs: none * @details Outputs: fpga comm flags & counters reset * @return none *************************************************************************/ static void resetFPGACommFlags( void ) { fpgaWriteCommandResponseReceived = FALSE; fpgaReadCommandResponseReceived = FALSE; fpgaWriteCommandInProgress = FALSE; fpgaReadCommandInProgress = FALSE; fpgaBulkWriteAndReadInProgress = FALSE; fpgaTransmitCounter = 0; fpgaReceiptCounter = 0; } /*********************************************************************//** * @brief * The signalFPGAReceiptCompleted function increments a counter to indicate * that another DMA receipt from the FPGA has completed. * @details Inputs: none * @details Outputs: fpgaReceiptCounter * @return none *************************************************************************/ void signalFPGAReceiptCompleted( void ) { fpgaReceiptCounter++; // Did FPGA Ack last command? if ( TRUE == fpgaWriteCommandInProgress ) { fpgaWriteCommandInProgress = FALSE; fpgaWriteCommandResponseReceived = TRUE; } else if ( TRUE == fpgaReadCommandInProgress ) { fpgaReadCommandInProgress = FALSE; fpgaReadCommandResponseReceived = TRUE; } // See if we want to follow up with a bulk read command if ( TRUE == fpgaBulkWriteAndReadInProgress ) { fpgaBulkWriteAndReadInProgress = FALSE; fpgaReadCommandInProgress = TRUE; // Initiate bulk read command startDMAReceiptOfReadResp(); startDMAReadCmd(); } } /*********************************************************************//** * @brief * The signalFPGATransmitCompleted function increments a counter to indicate * that another DMA transmit to the FPGA has completed. * @details Inputs: none * @details Outputs: fpgaReceiptCounter * @return none *************************************************************************/ void signalFPGATransmitCompleted( void ) { fpgaTransmitCounter++; } /*********************************************************************//** * @brief * The execFPGA function manages incoming data exchanges with the FPGA. * @details Inputs: fpgaState * @details Outputs: fpgaState * @return none *************************************************************************/ void execFPGAIn( void ) { // FPGA incoming state machine switch ( fpgaState ) { case FPGA_STATE_START: fpgaState = FPGA_STATE_READ_HEADER; break; case FPGA_STATE_RCV_HEADER: fpgaState = handleFPGAReceiveHeaderState(); break; // TODO - sensor/ADC init/configuration states case FPGA_STATE_RCV_ALL_SENSORS: fpgaState = handleFPGAReceiveAllSensorsState(); break; #ifdef READ_FPGA_ASYNC_DATA case FPGA_STATE_RCV_ALL_SENSORS_ASYNC: fpgaState = handleFPGAReceiveAllSensorsAsyncState(); break; #endif case FPGA_STATE_FAILED: // Do nothing - we will be stuck here break; default: if ( fpgaState >= NUM_OF_FPGA_STATES ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_INVALID_IN_STATE, fpgaState ) } else { // Ok, some states handled in the outgoing state machine } break; } // If retries for commands exceeds limit, fault if ( fpgaCommRetryCount > MAX_COMM_ERROR_RETRIES ) { activateAlarmNoData( ALARM_ID_FPGA_COMM_TIMEOUT ); } // Reset comm flags after processing incoming responses resetFPGACommFlags(); } /*********************************************************************//** * @brief * The execFPGAOut function manages outgoing data exchanges with the FPGA. * @details Inputs: fpgaState * @details Outputs: fpgaState * @return none *************************************************************************/ void execFPGAOut( void ) { // FPGA outgoing state machine switch ( fpgaState ) { case FPGA_STATE_READ_HEADER: fpgaState = handleFPGAReadHeaderState(); break; // TODO - sensor/ADC init/configuration states case FPGA_STATE_WRITE_ALL_ACTUATORS: fpgaState = handleFPGAWriteAllActuatorsState(); break; case FPGA_STATE_FAILED: // Do nothing - we will be stuck here break; #ifdef READ_FPGA_ASYNC_DATA case FPGA_STATE_READ_ALL_SENSORS_ASYNC: fpgaState = handleFPGAReadAllSensorsAsyncState(); break; #endif default: if ( fpgaState >= NUM_OF_FPGA_STATES ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_INVALID_OUT_STATE, fpgaState ) } else { // Ok, some states handled in the incoming state machine } break; } } /*********************************************************************//** * @brief * The handleFPGAReadHeaderState function handles the FPGA state where * the read header registers command is sent to the FPGA. * @details Inputs: none * @details Outputs: read command sent to FPGA * @return next FPGA state *************************************************************************/ static FPGA_STATE_T handleFPGAReadHeaderState( void ) { FPGA_STATE_T result = FPGA_STATE_RCV_HEADER; U16 crc; // Construct read command to read 3 registers starting at address 0 fpgaReadCmdBuffer[ 0 ] = FPGA_READ_CMD_CODE; fpgaReadCmdBuffer[ 1 ] = GET_LSB_OF_WORD( FPGA_HEADER_START_ADDR ); fpgaReadCmdBuffer[ 2 ] = GET_MSB_OF_WORD( FPGA_HEADER_START_ADDR ); fpgaReadCmdBuffer[ 3 ] = sizeof(FPGA_HEADER_T); crc = crc16( fpgaReadCmdBuffer, FPGA_READ_CMD_HDR_LEN ); fpgaReadCmdBuffer[ 4 ] = GET_MSB_OF_WORD( crc ); fpgaReadCmdBuffer[ 5 ] = GET_LSB_OF_WORD( crc ); // Prep DMA for sending the read cmd and receiving the response fpgaReadCommandInProgress = TRUE; setupDMAForReadResp( FPGA_READ_RSP_HDR_LEN + sizeof(FPGA_HEADER_T) + FPGA_CRC_LEN ); setupDMAForReadCmd( FPGA_READ_CMD_HDR_LEN + FPGA_CRC_LEN ); startDMAReceiptOfReadResp(); startDMAReadCmd(); return result; } /*********************************************************************//** * @brief * The handleFPGAReceiveHeaderState function handles the FPGA state * where the header registers read response should be ready to take in. * @details Inputs: none * @details Outputs: header register values updated * @return next FPGA state *************************************************************************/ static FPGA_STATE_T handleFPGAReceiveHeaderState( void ) { FPGA_STATE_T result = FPGA_STATE_READ_HEADER; // Did we get an FPGA response? if ( TRUE == fpgaReadCommandResponseReceived ) { // Did FPGA Ack the read command? if ( fpgaReadResponseBuffer[ 0 ] == FPGA_READ_CMD_ACK ) { U32 rspSize = FPGA_READ_RSP_HDR_LEN + sizeof(FPGA_HEADER_T); 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 ) ) { fpgaCommRetryCount = 0; // Capture the read values memcpy( &fpgaHeader, &fpgaReadResponseBuffer[ FPGA_READ_RSP_HDR_LEN ], sizeof( FPGA_HEADER_T ) ); result = FPGA_STATE_WRITE_ALL_ACTUATORS; } else { fpgaCommRetryCount++; } } else // Header read was NAK'd { fpgaCommRetryCount++; } } else // No response to read command { fpgaCommRetryCount++; } // Should not be any data received at this time consumeUnexpectedData(); return result; } /*********************************************************************//** * @brief * The handleFPGAWriteAllActuatorsState function handles the FPGA state * where the bulk write command is sent to the FPGA. * @details Inputs: actuator set points * @details Outputs: actuator set points sent to FPGA * @return next FPGA state *************************************************************************/ static FPGA_STATE_T handleFPGAWriteAllActuatorsState( void ) { FPGA_STATE_T result = FPGA_STATE_RCV_ALL_SENSORS; U16 crc; // Construct bulk write command to write actuator data registers starting at address 3 (TODO - change address later) fpgaWriteCmdBuffer[ 0 ] = FPGA_WRITE_CMD_CODE; fpgaWriteCmdBuffer[ 1 ] = GET_LSB_OF_WORD( FPGA_BULK_WRITE_START_ADDR ); fpgaWriteCmdBuffer[ 2 ] = GET_MSB_OF_WORD( FPGA_BULK_WRITE_START_ADDR ); fpgaWriteCmdBuffer[ 3 ] = sizeof(FPGA_ACTUATORS_T); memcpy( &( fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_HDR_LEN ] ), &fpgaActuatorSetPoints, sizeof( FPGA_ACTUATORS_T ) ); crc = crc16( fpgaWriteCmdBuffer, FPGA_WRITE_CMD_HDR_LEN + sizeof( FPGA_ACTUATORS_T ) ); fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_HDR_LEN + sizeof( FPGA_ACTUATORS_T ) ] = GET_MSB_OF_WORD( crc ); fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_HDR_LEN + sizeof( FPGA_ACTUATORS_T ) + 1 ] = GET_LSB_OF_WORD( crc ); // Construct bulk read command to read sensor data registers starting at address 8 fpgaReadCmdBuffer[ 0 ] = FPGA_READ_CMD_CODE; fpgaReadCmdBuffer[ 1 ] = GET_LSB_OF_WORD( FPGA_BULK_READ_START_ADDR ); fpgaReadCmdBuffer[ 2 ] = GET_MSB_OF_WORD( FPGA_BULK_READ_START_ADDR ); fpgaReadCmdBuffer[ 3 ] = sizeof(FPGA_SENSORS_T); crc = crc16( fpgaReadCmdBuffer, FPGA_READ_CMD_HDR_LEN ); fpgaReadCmdBuffer[ 4 ] = GET_MSB_OF_WORD( crc ); fpgaReadCmdBuffer[ 5 ] = GET_LSB_OF_WORD( crc ); // Prep DMA for sending the bulk write cmd and receiving its response setupDMAForWriteCmd( FPGA_WRITE_CMD_HDR_LEN + sizeof( FPGA_ACTUATORS_T ) + FPGA_CRC_LEN ); setupDMAForWriteResp( FPGA_WRITE_RSP_HDR_LEN + FPGA_CRC_LEN ); // Prep DMA for sending the bulk read cmd and receiving its response setupDMAForReadCmd( FPGA_READ_CMD_HDR_LEN + FPGA_CRC_LEN ); setupDMAForReadResp( FPGA_READ_RSP_HDR_LEN + sizeof( FPGA_SENSORS_T ) + FPGA_CRC_LEN ); // Set fpga comm flags for bulk write cmd and follow-up bulk read command fpgaWriteCommandInProgress = TRUE; fpgaBulkWriteAndReadInProgress = TRUE; // Initiate bulk write command and its receipt - read will follow startDMAReceiptOfWriteResp(); startDMAWriteCmd(); return result; } /*********************************************************************//** * @brief * The handleFPGAReceiveAllSensorsState function handles the FPGA state * where the bulk read response should be ready to parse. * @details Inputs: none * @details Outputs: sensor values updated * @return next FPGA state *************************************************************************/ static FPGA_STATE_T handleFPGAReceiveAllSensorsState( void ) { FPGA_STATE_T result = FPGA_STATE_WRITE_ALL_ACTUATORS; // Check bulk write command success if ( ( FALSE == fpgaWriteCommandResponseReceived ) || ( fpgaWriteResponseBuffer[ 0 ] != FPGA_WRITE_CMD_ACK ) ) { fpgaCommRetryCount++; } // If bulk read command is ACK'd, collect the readings if ( TRUE == fpgaReadCommandResponseReceived ) { // Did FPGA Ack the read command? if ( fpgaReadResponseBuffer[ 0 ] == FPGA_READ_CMD_ACK ) { U32 rspSize = FPGA_READ_RSP_HDR_LEN + sizeof(FPGA_SENSORS_T); 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 ) ) { fpgaCommRetryCount = 0; // Capture the read values memcpy( &fpgaSensorReadings, &fpgaReadResponseBuffer[ FPGA_READ_RSP_HDR_LEN ], sizeof( FPGA_SENSORS_T ) ); #ifndef READ_FPGA_ASYNC_DATA result = FPGA_STATE_WRITE_ALL_ACTUATORS; #else result = FPGA_STATE_READ_ALL_SENSORS_ASYNC; #endif } else // Bad CRC { fpgaCommRetryCount++; } } else // Read command was NAK'd { fpgaCommRetryCount++; } } else // No response to read command { fpgaCommRetryCount++; } // Should not be any data received at this time consumeUnexpectedData(); return result; } #ifdef READ_FPGA_ASYNC_DATA /*********************************************************************//** * @brief * The handleFPGAReadAllSensorsAsyncState function handles the FPGA state where * the read async sensors command is sent to the FPGA. * @details Inputs: none * @details Outputs: read async sensors command sent to FPGA * @return next FPGA state *************************************************************************/ static FPGA_STATE_T handleFPGAReadAllSensorsAsyncState( void ) { FPGA_STATE_T result = FPGA_STATE_RCV_ALL_SENSORS_ASYNC; U16 crc; // Construct read command to read low priority async registers starting at address 0x200 fpgaReadCmdBuffer[ 0 ] = FPGA_READ_CMD_CODE; fpgaReadCmdBuffer[ 1 ] = GET_LSB_OF_WORD( FPGA_BULK_ASYNC_READ_START_ADDR ); fpgaReadCmdBuffer[ 2 ] = GET_MSB_OF_WORD( FPGA_BULK_ASYNC_READ_START_ADDR ); fpgaReadCmdBuffer[ 3 ] = sizeof(FPGA_SENSORS_ASYNC_T); crc = crc16( fpgaReadCmdBuffer, FPGA_READ_CMD_HDR_LEN ); fpgaReadCmdBuffer[ 4 ] = GET_MSB_OF_WORD( crc ); fpgaReadCmdBuffer[ 5 ] = GET_LSB_OF_WORD( crc ); // Prep DMA for sending the read cmd and receiving the response fpgaReadCommandInProgress = TRUE; setupDMAForReadResp( FPGA_READ_RSP_HDR_LEN + sizeof(FPGA_SENSORS_ASYNC_T) + FPGA_CRC_LEN ); setupDMAForReadCmd( FPGA_READ_CMD_HDR_LEN + FPGA_CRC_LEN ); startDMAReceiptOfReadResp(); startDMAReadCmd(); return result; } /*********************************************************************//** * @brief * The handleFPGAReceiveAllSensorsAsyncState function handles the FPGA state * where the bulk async read response should be ready to parse. * @details Inputs: none * @details Outputs: async sensor values updated * @return next FPGA state *************************************************************************/ static FPGA_STATE_T handleFPGAReceiveAllSensorsAsyncState( void ) { FPGA_STATE_T result = FPGA_STATE_READ_ALL_SENSORS_ASYNC; // If bulk read command is ACK'd, collect the readings if ( TRUE == fpgaReadCommandResponseReceived ) { // Did FPGA Ack the read command? if ( fpgaReadResponseBuffer[ 0 ] == FPGA_READ_CMD_ACK ) { U32 rspSize = FPGA_READ_RSP_HDR_LEN + sizeof(FPGA_SENSORS_ASYNC_T); 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 ) ) { fpgaCommRetryCount = 0; // Capture the read values memcpy( &fpgaSensorReadingsAsync, &fpgaReadResponseBuffer[ FPGA_READ_RSP_HDR_LEN ], sizeof( FPGA_SENSORS_ASYNC_T ) ); result = FPGA_STATE_WRITE_ALL_ACTUATORS; } else // Bad CRC { fpgaCommRetryCount++; } } else // Read command was NAK'd { fpgaCommRetryCount++; } } else // No response to read command { fpgaCommRetryCount++; } // Should not be any data received at this time consumeUnexpectedData(); return result; } #endif /*********************************************************************//** * @brief * The execFPGATest function executes the FPGA self-test. * @details Inputs: fpgaHeader * @details Outputs: none * @return passed, or failed *************************************************************************/ SELF_TEST_STATUS_T execFPGATest( void ) { SELF_TEST_STATUS_T result; // Check FPGA reported correct ID if ( FPGA_EXPECTED_ID == fpgaHeader.fpgaId ) { result = SELF_TEST_STATUS_PASSED; } else { result = SELF_TEST_STATUS_FAILED; SET_ALARM_WITH_1_U32_DATA( ALARM_ID_FPGA_POST_TEST_FAILED, (U32)fpgaHeader.fpgaId ) } return result; } /*********************************************************************//** * @brief * The consumeUnexpectedData function checks to see if a byte is sitting in * the SCI2 received data register. * @details Inputs: fpgaHeader * @details Outputs: none * @return fpgaDiag *************************************************************************/ 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 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; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_WRITE_CMD_TOO_MUCH_DATA, 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; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_WRITE_RSP_TOO_MUCH_DATA, 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 setupDMAForReadCmd function sets the byte count for the next DMA * read command to the FPGA. * @details Inputs: none * @details Outputs: number of bytes for next FPGA read command is set * @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; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_READ_CMD_TOO_MUCH_DATA, bytes2Transmit ) } } /*********************************************************************//** * @brief * The startDMAReadCmd function initiates the DMA transmit for the next * DMA read command to the FPGA. * @details Inputs: none * @details 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 setupDMAForReadResp function sets the expected byte count for the * next DMA read command response from the FPGA. * @details Inputs: none * @details Outputs: number of expected bytes for next FPGA read command response is set * @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; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_READ_RSP_TOO_MUCH_DATA, bytes2Receive ) } } /*********************************************************************//** * @brief * The startDMAReceiptOfReadResp function initiates readiness of the DMA * receiver for the next DMA read command response from the FPGA. * @details Inputs: none * @details 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 getFPGAVersions function gets the fpga version numbers. * @details Inputs: fpgaHeader * @details Outputs: none * @return none *************************************************************************/ void getFPGAVersions( U08 *Id, U08 *Maj, U08 *Min, U08 *Lab ) { *Id = fpgaHeader.fpgaId; *Min = fpgaHeader.fpgaRev; *Maj = fpgaHeader.fpgaRevMajor; *Lab = fpgaHeader.fpgaRevLab; } /*********************************************************************//** * @brief * The setAlarmAudioState function sets the fpga audio control to the given * state and volume. * @details Inputs: none * @details Outputs: alarm audio state and attenuation set * @param state the state of alarm audio to command: * 0 - No alarm tone * 1 - Low priority alarm tone (c e) * 2 - Medium priority alarm tone (c f# c) * 3 - High priority alarm tone (c f# c - c f#) * @param volumeLevel the level of attenuation to command (0..4) * 4 - 3 dB gain * 3 - 6 dB gain * 2 - 9 dB gain * 1 - 12 dB gain * 0 - 15 dB gain * @return none *************************************************************************/ void setAlarmAudioState( ALARM_PRIORITY_T state, U32 volumeLevel ) { if ( ( state < NUM_OF_ALARM_PRIORITIES ) && ( volumeLevel <= MAX_ALARM_VOLUME_ATTENUATION ) ) { U08 audioCmd = (U08)state; audioCmd |= ( (U08)volumeLevel << 2 ); fpgaActuatorSetPoints.AlarmControl = audioCmd; } else { U08 audioCmd = (U08)ALARM_PRIORITY_HIGH; // Set alarm audio to high priority, max volume for safety since s/w seems to be having trouble setting audio correctly audioCmd |= ( (U08)MIN_ALARM_VOLUME_ATTENUATION << 2 ); fpgaActuatorSetPoints.AlarmControl = audioCmd; // S/w fault to indicate issue w/ s/w SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_INVALID_ALARM_AUDIO_PARAM, volumeLevel ) } } /*********************************************************************//** * @brief * The getFPGABloodFlowSignalStrength function gets the latest blood flow * signal strength reading. * @details Inputs: fpgaSensorReadings2 * @details Outputs: none * @return last blood flow signal strength reading *************************************************************************/ F32 getFPGABloodFlowSignalStrength( void ) { return fpgaSensorReadings.bloodFlowSignalStrength; } /*********************************************************************//** * @brief * The getFPGADialysateFlowSignalStrength function gets the latest dialysate * flow signal strength reading. * @details Inputs: fpgaSensorReadings2 * @details Outputs: none * @return last dialysate flow signal strength reading *************************************************************************/ F32 getFPGADialysateFlowSignalStrength( void ) { return fpgaSensorReadings.dialysateFlowSignalStrength; } /*********************************************************************//** * @brief * The getFPGABloodFlow function gets the latest blood flow reading. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last blood flow reading *************************************************************************/ F32 getFPGABloodFlow( void ) { return fpgaSensorReadings.bloodFlowLast; } /*********************************************************************//** * @brief * The getFPGADialysateFlow function gets the latest dialysate flow reading. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last dialysate flow reading *************************************************************************/ F32 getFPGADialysateFlow( void ) { return fpgaSensorReadings.dialysateFlowLast; } /*********************************************************************//** * @brief * The getFPGABloodPumpHallSensorCount function gets the latest blood pump * hall sensor count. Count is a 16 bit free running counter. If counter is * counting up, indicates motor is running in forward direction. If counter is * counting down, indicates motor is running in reverse direction. Counter will * wrap at 0/65535. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last blood pump hall sensor count reading. *************************************************************************/ U16 getFPGABloodPumpHallSensorCount( void ) { return fpgaSensorReadings.bloodPumpHallSensorCount; } /*********************************************************************//** * @brief * The getFPGABloodPumpHallSensorStatus function gets the latest blood pump * hall sensor status. * Bit 0 - Derived direction of the blood pump motor (0=Fwd, 1=Rev) * Bit 1 - A direction error was detected in the current hall sensor phase * Bit 2 - A direction error was detected since the last read of this register * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last blood pump hall sensor status reading. *************************************************************************/ U08 getFPGABloodPumpHallSensorStatus( void ) { return fpgaSensorReadings.bloodPumpHallSensorStatus; } /*********************************************************************//** * @brief * The getFPGADialInPumpHallSensorCount function gets the latest dialysate inlet pump * hall sensor count. Count is a 16 bit free running counter. If counter is * counting up, indicates motor is running in forward direction. If counter is * counting down, indicates motor is running in reverse direction. Counter will * wrap at 0/65535. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last dialysate inlet pump hall sensor count reading. *************************************************************************/ U16 getFPGADialInPumpHallSensorCount( void ) { return fpgaSensorReadings.dialInPumpHallSensorCount; } /*********************************************************************//** * @brief * The getFPGADialInPumpHallSensorStatus function gets the latest dialysate inlet pump * hall sensor status. * Bit 0 - Derived direction of the dialyste inlet pump motor (0=Fwd, 1=Rev) * Bit 1 - A direction error was detected in the current hall sensor phase * Bit 2 - A direction error was detected since the last read of this register * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last dialysate inlet pump hall sensor status reading. *************************************************************************/ U08 getFPGADialInPumpHallSensorStatus( void ) { return fpgaSensorReadings.dialInPumpHallSensorStatus; } /*********************************************************************//** * @brief * The getFPGADialOutPumpHallSensorCount function gets the latest dialysate outlet pump * hall sensor count. Count is a 16-bit free running counter. If counter is * counting up, indicates motor is running in forward direction. If counter is * counting down, indicates motor is running in reverse direction. Counter will * wrap at 0/65535. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last dialysate outlet pump hall sensor count reading. *************************************************************************/ U16 getFPGADialOutPumpHallSensorCount( void ) { return fpgaSensorReadings.dialOutPumpHallSensorCount; } /*********************************************************************//** * @brief * The getFPGADialOutPumpHallSensorStatus function gets the latest dialysate outlet pump * hall sensor status. * Bit 0 - Derived direction of the dialysate outlet pump motor (0=Fwd, 1=Rev) * Bit 1 - A direction error was detected in the current hall sensor phase * Bit 2 - A direction error was detected since the last read of this register * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last dialysate outlet pump hall sensor status reading. *************************************************************************/ U08 getFPGADialOutPumpHallSensorStatus( void ) { return fpgaSensorReadings.dialOutPumpSensorStatus; } /*********************************************************************//** * @brief * The getFPGABloodPumpOcclusion function gets the latest blood occlusion reading. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last blood occlusion reading *************************************************************************/ U16 getFPGABloodPumpOcclusion( void ) { return fpgaSensorReadings.bloodOcclusionData; } /*********************************************************************//** * @brief * The getFPGADialInPumpOcclusion function gets the latest dialysate * inlet occlusion reading. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last dialysate inlet occlusion reading *************************************************************************/ U16 getFPGADialInPumpOcclusion( void ) { return fpgaSensorReadings.dialysateInOcclusionData; } /*********************************************************************//** * @brief * The getFPGADialOutPumpOcclusion function gets the latest dialysate * outlet occlusion reading. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last dialysate outlet occlusion reading *************************************************************************/ U16 getFPGADialOutPumpOcclusion( void ) { return fpgaSensorReadings.dialysateOutOcclusionData; } /*********************************************************************//** * @brief * The getFPGAArterialPressure function gets the latest arterial pressure reading. * High byte indicates alarm status for ADC channel. * Low 24-bits are channel reading. Subtract 2^23 from low 24 bits to get * signed channel reading. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last arterial pressure reading *************************************************************************/ U32 getFPGAArterialPressure( void ) { return fpgaSensorReadings.adc1Channel0; } /*********************************************************************//** * @brief * The getFPGAVenousPressure function gets the venous arterial pressure reading. * The high 2 bits are status bits: 00=ok, 01=cmd mode, 10=stale data, 11=diag * The low 14 bits are data. Zero is at 1638. Values above are positive, * below are negative. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last venous pressure reading *************************************************************************/ U16 getFPGAVenousPressure( void ) { return fpgaSensorReadings.venousPressure; } /*********************************************************************//** * @brief * The getFPGAAccelAxes function gets the accelerometer axis readings. * Axis readings are in ADC counts. 0.004 g per LSB. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @param x Populate this param with X axis reading * @param y Populate this param with Y axis reading * @param z Populate this param with Z axis reading * @return none *************************************************************************/ void getFPGAAccelAxes( S16 *x, S16 *y, S16 *z ) { *x = (S16)fpgaSensorReadings.accelX; *y = (S16)fpgaSensorReadings.accelY; *z = (S16)fpgaSensorReadings.accelZ; } /*********************************************************************//** * @brief * The getFPGAAccelMaxes function gets the maximum accelerometer axis readings. * from last FPGA read (every 10ms). * Axis readings are in ADC counts. 0.004 g per LSB. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @param x Populate this param with maximum X axis reading * @param y Populate this param with maximum Y axis reading * @param z Populate this param with maximum Z axis reading * @return none *************************************************************************/ void getFPGAAccelMaxes( S16 *xmax, S16*ymax, S16*zmax ) { *xmax = (S16)fpgaSensorReadings.accelXMax; *ymax = (S16)fpgaSensorReadings.accelYMax; *zmax = (S16)fpgaSensorReadings.accelZMax; } /*********************************************************************//** * @brief * The getFPGAAccelStatus function gets the accelerometer reading count * and error register values. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @param cnt Populate this param with latest sample counter value * @param err Populate this param with latest error * @return none *************************************************************************/ void getFPGAAccelStatus( U16 *cnt, U16 *err ) { *cnt = fpgaSensorReadings.accelSampleCounter; *err = fpgaSensorReadings.accelFaultRegister; } /*********************************************************************//** * @brief * The getFPGAAirTrapLevels function gets the latest air trap level sensor * readings. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return none *************************************************************************/ void getFPGAAirTrapLevels( BOOL *airAtLower, BOOL *airAtUpper ) { U16 fpgaGPIO = fpgaSensorReadings.fpgaGPIO; U16 lower = fpgaGPIO & FPGA_AIRTRAP_LEVEL_LOW_MASK; U16 upper = fpgaGPIO & FPGA_AIRTRAP_LEVEL_HIGH_MASK; *airAtLower = ( 0 == lower ? FALSE : TRUE ); *airAtUpper = ( 0 == upper ? FALSE : TRUE ); } /*********************************************************************//** * @brief * The setFPGAValvesControlMode function sets the valves control mode. * @details Inputs: fpgaActuatorSetPoints * @details Outputs: fpgaActuatorSetPoints * @param bits : The bits to enable the PID controller of a valve * @return none *************************************************************************/ void setFPGAValvesControlMode( U16 bits ) { fpgaActuatorSetPoints.fpgaPIDControl = bits; } /*********************************************************************//** * @brief * The getValvesStatus function reads the status of the valves * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return The status of the valves *************************************************************************/ U16 getFPGAValvesStatus( void ) { return fpgaSensorReadings.valveStatus; } /*********************************************************************//** * @brief * The setValveDialyzerInletPosition function sets the position of VDi * in counts * @details Inputs: fpgaActuatorSetPoints * @details Outputs: fpgaActuatorSetPoints * @param setPoint : Next position of the valve in counts * @return none *************************************************************************/ void setFPGAValveDialyzerInletPosition( S16 setPoint ) { fpgaActuatorSetPoints.VDiSetPoint = setPoint; } /*********************************************************************//** * @brief * The getValveDialyzerInletPosition function reads the current position * of VDi in counts * @details Inputs: none * @details Outputs: fpgaSensorReadings * @return The current position of VDi *************************************************************************/ S16 getFPGAValveDialyzerInletPosition( void ) { return fpgaSensorReadings.VDiPosition; } /*********************************************************************//** * @brief * The getFPGAValveDialyzerInletCurrentCounts function reads the current \n * of VDi in counts * @details Inputs: none * @details Outputs: fpgaSensorReadings * @return The current of VDi *************************************************************************/ U16 getFPGAValveDialyzerInletCurrentCounts( void ) { return fpgaSensorReadings.VDiCurrent; } #ifdef DEBUG_ENABLED /*********************************************************************//** * @brief * The setFPGAValveDialyzerInletPWM function sets the PWM of VDI in counts. * @details Inputs: fpgaActuatorSetPoints * @details Outputs: fpgaActuatorSetPoints * @param count which is the PWM of VDI in counts * @return none *************************************************************************/ void setFPGAValveDialyzerInletPWM( U16 count ) { fpgaActuatorSetPoints.VDiPWMFixed = count; } /*********************************************************************//** * @brief * The getFPGAValveDialyzerInletPWM function reads the current PWM target * of VDI. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return current PWM of VDI *************************************************************************/ U16 getFPGAValveDialyzerInletPWM( void ) { return fpgaSensorReadings.VDiPWMTarget; } #endif /*********************************************************************//** * @brief * The setFPGAValveDialyzerOutletPosition function sets the position of VDo * in counts * @details Inputs: fpgaActuatorSetPoints * @details Outputs: fpgaActuatorSetPoints * @param setPoint : Next position of the valve in counts * @return none *************************************************************************/ void setFPGAValveDialyzerOutletPosition( S16 setPoint ) { fpgaActuatorSetPoints.VDoSetPoint = setPoint; } /*********************************************************************//** * @brief * The getFPGAValveDialyzerOutletPosition function reads the current position * of VDo in counts * @details Inputs: none * @details Outputs: fpgaSensorReadings * @return The current position of VDo *************************************************************************/ S16 getFPGAValveDialyzerOutletPosition( void ) { return fpgaSensorReadings.VDoPosition; } /*********************************************************************//** * @brief * The getFPGAValveDialyzerOutletCurrentCounts function reads the current * of VDo in counts * @details Inputs: none * @details Outputs: fpgaSensorReadings * @return The current of VDo *************************************************************************/ U16 getFPGAValveDialyzerOutletCurrentCounts( void ) { return fpgaSensorReadings.VDoCurrent; } #ifdef DEBUG_ENABLED /*********************************************************************//** * @brief * The setFPGAValveDialyzerOutletPWM function sets the PWM of VDO in counts. * @details Inputs: fpgaActuatorSetPoints * @details Outputs: fpgaActuatorSetPoints * @param count which is the PWM of VDO in counts * @return none *************************************************************************/ void setFPGAValveDialyzerOutletPWM( U16 count ) { fpgaActuatorSetPoints.VDoPWMFixed = count; } /*********************************************************************//** * @brief * The getFPGAValveDialyzerOutletPWM function reads the current PWM target * of VDO. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return current PWM of VDO *************************************************************************/ U16 getFPGAValveDialyzerOutletPWM( void ) { return fpgaSensorReadings.VDoPWMTarget; } #endif /*********************************************************************//** * @brief * The setValveBloodVenousPosition function sets the position of VBV * in counts * @details Inputs: fpgaActuatorSetPoints * @details Outputs: fpgaActuatorSetPoints * @param setPoint : Next position of the valve in counts * @return none *************************************************************************/ void setFPGAValveBloodVenousPosition( S16 setPoint ) { fpgaActuatorSetPoints.VBVSetPoint = setPoint; } /*********************************************************************//** * @brief * The getValveBloodVenousPosition function reads the current position * of VBV in counts * @details Inputs: none * @details Outputs: fpgaSensorReadings * @return The current position of VBV *************************************************************************/ S16 getFPGAValveBloodVenousPosition( void ) { return fpgaSensorReadings.VBVPosition; } /*********************************************************************//** * @brief * The getFPGAValveBloodVenousCurrentCounts function reads the current * of VBV in counts * @details Inputs: none * @details Outputs: fpgaSensorReadings * @return The current of VBV *************************************************************************/ U16 getFPGAValveBloodVenousCurrentCounts( void ) { return fpgaSensorReadings.VBVCurrent; } #ifdef DEBUG_ENABLED /*********************************************************************//** * @brief * The setFPGAValveBloodVenousPWM function sets the PWM of VBV in counts. * @details Inputs: fpgaActuatorSetPoints * @details Outputs: fpgaActuatorSetPoints * @param count which is the PWM of VBV in counts * @return none *************************************************************************/ void setFPGAValveBloodVenousPWM( U16 count ) { fpgaActuatorSetPoints.VBVPWMFixed = count; } /*********************************************************************//** * @brief * The getFPGAValveBloodVenousPWM function returns the PWM of VBV in counts. * @details Inputs: fpgaActuatorSetPoints * @details Outputs: none * @return returns the PWM of VBV in counts *************************************************************************/ U16 getFPGAValveBloodVenousPWM( void ) { return fpgaSensorReadings.VBVPWMTarget; } #endif /*********************************************************************//** * @brief * The setValveBloodArterialPosition function sets the position of VBA * in counts * @details Inputs: fpgaActuatorSetPoints * @details Outputs: fpgaActuatorSetPoints * @param setPoint : Next position of the valve in counts * @return none *************************************************************************/ void setFPGAValveBloodArterialPosition( S16 setPoint ) { fpgaActuatorSetPoints.VBASetPoint = setPoint; } /*********************************************************************//** * @brief * The getValveBloodArterialPosition function reads the current position * of VBA in counts * @details Inputs: none * @details Outputs: fpgaSensorReadings * @return The current position of VBA *************************************************************************/ S16 getFPGAValveBloodArterialPosition( void ) { return fpgaSensorReadings.VBAPosition; } /*********************************************************************//** * @brief * The getFPGAValveBloodArterialCurrentCounts function reads the current * of VBA in counts * @details Inputs: none * @details Outputs: fpgaSensorReadings * @return The current of VBA *************************************************************************/ U16 getFPGAValveBloodArterialCurrentCounts( void ) { return fpgaSensorReadings.VBACurrent; } #ifdef DEBUG_ENABLED /*********************************************************************//** * @brief * The setFPGAValveBloodArterialPWM function sets a PWM for VBA in counts. * @details Inputs: fpgaActuatorSetPoints * @details Outputs: fpgaActuatorSetPoints * @param count which is the PWM of VBA in counts * @return none *************************************************************************/ void setFPGAValveBloodArterialPWM( U16 count ) { fpgaActuatorSetPoints.VBAPWMFixed = count; } /*********************************************************************//** * @brief * The getFPGAValveBloodArterialPWM function returns the current PWM of * VBA in counts. * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return current PWM of VBA in counts *************************************************************************/ U16 getFPGAValveBloodArterialPWM( void ) { return fpgaSensorReadings.VBAPWMTarget; } #endif /**@}*/