1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219 |
- /*********************************************************************
- *
- * LTC6803 API File
- *
- *********************************************************************
- * FileName: MBS_LTC.c
- * Processor: PIC18F45K80
- * Compiler: Microchip C18 v3.41
- * Company: KIT - CN - IPE
- *
- * Author Date Comment
- *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * Reiling V. 17.02.2012 Release
- * Reiling V. 27.02.2012 Debug: Odd Voltage = 0V
- * Reiling V. 29.03.2012 Release 2. see change log file
- *********************************************************************/
- #include "BMS_Slave.h"
- /*********************************************************************
- *
- * Globals
- *
- *********************************************************************/
- static LTC_CFG gCFG;
- static LTC_CVAD gCVAD;
- static LTC_TMP gTMP;
- static LTC_DRG gDRG;
- static uint16_t gLTC_SelfTest_Result = LTC_OK;
- static uint16_t gLTC_TimeOut = LTC_OK;
- extern SERIAL_NR_t gSerial;
- extern ERROR_flags gERROR;
- extern LTC_STATUS LTC_Status;
- /*********************************************************************
- * Function: void LTC_Init( void )
- *
- * Overview: API Function
- * Use this function to initialize LTC6803 module
- *
- * PreCondition: None
- *
- * Input: None
- *
- * Output: Return: LTC_OK,
- *
- * Side Effects: Change gCFG
- **********************************************************************/
- void LTC_Init( void )
- {
- int8_t i = 0;
- CAN_CONFIG gCAN_CONFIG ={ SlaveNo_VAL,
- BRP_VAL,
- PROPSEG_VAL,
- PHSEG1_VAL,
- PHSEG2_VAL,
- SJW_VAL,
- PHSEG2_MODE_VAL,
- BUS_SAMPLE_MODE_VAL,
- WAKEUP_MODE_VAL,
- FILTER_MODE_VAL };
-
- OSCCONbits.IRCF0 = 0; // 2MHz Prescaler für SPI
- OSCCONbits.IRCF1 = 1;
- OSCCONbits.IRCF2 = 1;
- OSCTUNEbits.PLLEN = 0; // PLL on
- // 12 Bit ADC Settings
- ADCON0 = 0x00; // Clear ADCON0 register
- ADCON1 = 0x30; // Internal Vref+ = 4,1V, Vreg- = 0V
- ADCON2 = 0x92; // right justifield, 4Tad, Fosc/32
- ANCON0 = 0x0B; // AN0 and AN1 and AN3 as analog inputs
- ANCON1 = 0x00;
- ADCON0bits.ADON = 0x01; //Enable A/D module
- TRISAbits.TRISA0 = 1; // PortA.0 = Analog In
- TRISAbits.TRISA1 = 1; // PortA.1 = Analog In
- TRISAbits.TRISA3 = 1; // PortA.3 = Analog In (Balancing Temperature)
- LATAbits.LATA5 = 1; // LTC SPI CS OFF
- TRISAbits.TRISA5 = 0; // Output LTC SPI CS
- TRISB = 0xFB; // Port B Input (PB.2 = CAN_1_TX Output)
- TRISCbits.TRISC0 = 0; // Output MUX 0,1,2
- TRISCbits.TRISC1 = 0;
- TRISCbits.TRISC2 = 0;
- LATD = 0; // Port D alle Latches off
- TRISD = 0; // Port D Output
- TRISEbits.TRISE0 = 0; // Out LED0
- TRISEbits.TRISE1 = 0; // Out LED1
- LATE |= 3; // LED0 = on; LED1 = on
- LATC = LATC & 0xF8; // Clear C0,C1,C2
- LATC |= 1; // Set MUX Counter = 1 to avoid MUX input = 0
-
- InitSPI();
- InitTimer();
- //gCAN_CONFIG.SlaveNo = ((PORTB >> 2) & 0xC);
- //gCAN_CONFIG.SlaveNo += (PORTB & 0x3);
- //gCAN_CONFIG.SlaveNo <<= 4;
- //gCAN_CONFIG.SlaveNo ^= 0xF0; //!! entfällt bei eWolf
- //gSerial.SLAVE_ID = gCAN_CONFIG.SlaveNo;
- gCAN_CONFIG.SlaveNo = gSerial.EE_BYTE.SLAVE_ID;
- CAN_Init( &gCAN_CONFIG );
- for(i=0;i<24;i++) // Start Voltage and Temperature with 0xFFFF / 0xFF
- {
- gCVAD.CVAD[i] = -1; // init. value for voltage => not connected
- gTMP.ETMP[i] = -51; // init. value for temperature => not connected
- }
- // Config LTC6803, Run Mode, Balancing OFF
- LTC_SetCFG(CDC_1, 0, 0x0FFFFFF );
-
- gDRG.PEC_Counter = 0; // Com Error Counter ini
- INTCONbits.GIE = 1;
- INTCONbits.PEIE = 1;
- }
- /*********************************************************************
- * Function: void LTC_Do( uint16_t *gEvent)
- *
- * Overview: API Function
- * Use this function to run LTC6803 module
- *
- * PreCondition: LTC_Init()
- *
- * Input: Pointer to gEvent
- *
- * Output: None
- *
- * Side Effects: Change gCVAD, gTMP, gDRG
- **********************************************************************/
- void LTC_Do(uint16_t *ptr_gEvent)
- {
- int8_t MUXcopy = 0;
- if(*ptr_gEvent & EV__LTC_V_Start)
- {
- if(PORTC & LTC_ADC_Ready) // ADC not running
- {
- if(LTC_MeasureVoltage( STCVAD_ALL, STCVAD_ALL_PEC, EV__LTC_V_Start ))
- gDRG.PEC_Counter++;
- *ptr_gEvent &= (~EV__LTC_V_Start);
- *ptr_gEvent |= EV__LTC_V_Wait;
- }
- }
- if(*ptr_gEvent & EV__LTC_V_Wait)
- {
- if(PORTC & LTC_ADC_Ready) // ADC not running
- {
- if(LTC_MeasureVoltage( STCVAD_ALL, STCVAD_ALL_PEC, EV__LTC_V_Wait ))
- gDRG.PEC_Counter++;
- *ptr_gEvent &= (~EV__LTC_V_Wait);
- }
- }
- if(*ptr_gEvent & EV__LTC_T_Start)
- {
- if(PORTC & LTC_ADC_Ready) // ADC not running
- {
- if(LTC_MeasureTemperature( STTMPAD_ALL, STTMPAD_ALL_PEC, EV__LTC_T_Start ))
- gDRG.PEC_Counter++;
- *ptr_gEvent |= EV__LTC_T_Wait;
- *ptr_gEvent &= (~EV__LTC_T_Start);
- }
- }
-
- if(*ptr_gEvent & EV__LTC_T_Wait)
- {
- if(PORTC & LTC_ADC_Ready) // ADC not running
- {
- if(LTC_MeasureTemperature( STTMPAD_ALL, STTMPAD_ALL_PEC, EV__LTC_T_Wait ))
- gDRG.PEC_Counter++;
-
- //IMPORTANT: RCT Power Version to avoid MUX INPUT = 0
- MUXcopy = LATC & 0x07; // extract MUX
- LATC = LATC & 0xF8; // clear old MUX
- if( MUXcopy < 6)
- {
- LATC = (LATC | MUXcopy) + 1; // set new MUX
- }
- else
- {
- LATC = 0x01; // Set Mux Counter = 1
- }
-
- *ptr_gEvent &= (~EV__LTC_T_Wait);
- }
- }
- }
- /*********************************************************************
- * Function: void LTC_BalanceOn(uint8_t No)
- *
- * Overview: API Function
- * Use this function to start Balancing Cell No
- * thru LTC6803 module
- *
- * PreCondition: None
- *
- * Input: Number of Cell to Balance
- *
- * Output: None
- *
- * Side Effects: None
- **********************************************************************/
- void LTC_BalanceOn(uint8_t No)
- {
- uint32_t DCC = 1; // Start for Shift
- DCC = DCC << No; // Shift Bitmask into Position
- LTC_SetCFG(CDC_1, DCC, 0);
- }
- /*********************************************************************
- * Function: void LTC_BalanceOff(uint8_t No)
- *
- * Overview: API Function
- * Use this function to stop Balancing Cell(n)
- * thru LTC6803 module
- *
- * PreCondition: None
- *
- * Input: Number of Cell to Balance
- *
- * Output: None
- *
- * Side Effects: None
- **********************************************************************/
- void LTC_BalanceOff(uint8_t No)
- {
- uint32_t DCC = 1; // Start for Shift
- DCC = DCC << No; // Shift Bitmask into Position
- LTC_SetCFG(CDC_1, 0, DCC);
- }
- /*********************************************************************
- * Function: void LTC_Terminate(void)
- *
- * Overview: API Function
- * Use this function to End LTC6803 module
- *
- * PreCondition: None
- *
- * Input: None
- *
- * Output: None
- *
- * Side Effects: None
- ********************************************************************/
- void LTC_Terminate(void)
- {
- LTC_SetCFG(CDC_0, 0, 0x0FFF); // LTC StandBy, Balance OFF
- }
- /*********************************************************************
- * Function: int16_t LTC_GetVoltage(uint8_t No)
- *
- * Overview: API Funktion
- * Use this function to read out one Cell Voltage
- *
- * PreCondition: None
- *
- * Input: Number of Cell to read out Voltage
- *
- * Output: Cell Voltage
- *
- * Side Effects: None
- ********************************************************************/
- int16_t LTC_GetVoltage(uint8_t No)
- {
- int16_t copyCVAD = gCVAD.CVAD[No];
- if (gERROR.LIMITCELLVOLTAGE == 0)
- {
- if(copyCVAD >= CELL_BYPASSED)
- {
- if( !((copyCVAD > VOLTAGE_MIN) && (copyCVAD < VOLTAGE_MAX)) )
- {
- gERROR.LIMITCELLVOLTAGE = 1;
- }
- }
-
- }
-
- gCVAD.CVAD[No] = -1;
- return copyCVAD;
- }
- /*********************************************************************
- * Function: int16_t LTC_GetTemperature(uint8_t No)
- *
- * Overview: API Funktion
- * Use this function to read out one Temperature Sensor
- *
- * PreCondition: None
- *
- * Input: Number of Sensor to read out Temperature
- *
- * Output: Sensor Temperature
- *
- * Side Effects: None
- ********************************************************************/
- int16_t LTC_GetTemperature(uint8_t No)
- {
- int8_t copyETMP = gTMP.ETMP[No];
- if (gERROR.LIMITCELLTEMP == 0)
- {
- if( (copyETMP >= TEMP_NOT_CON) )
- {
- if( !((copyETMP > TEMP_MIN) && (copyETMP < TEMP_MAX)) )
- {
- gERROR.LIMITCELLTEMP = 1;
- }
- }
- }
- gTMP.ETMP[No] = -51;
- return copyETMP;
- }
- /*********************************************************************
- * Function: void LTC_GetStatus( LTC_STATUS *LTC_Status )
- *
- * Overview: API Funktion
- * Show LTC_Status, PEC Counter and LTC_SelfTest
- *
- * PreCondition: None
- *
- * Input: Global gDRG, PEC_Counter, gLTC_SelfTest_Result, gLTC_TimeOut
- *
- * Output: None
- *
- *
- * Side Effects: Reset gDRG.PEC_Counter, change LTC_Status
- ********************************************************************/
- void LTC_GetStatus( LTC_STATUS *LTC_Status )
- {
- // Build LTC_StatusSlave
- LTC_Status->LTC_StatusSlave = LTC_OK;
- if(gTMP.ITMP[0] < WarnLowTemp)
- LTC_Status->LTC_StatusSlave |= LTC1_LowTemp_NOK;
- if(gTMP.ITMP[1] < WarnLowTemp)
- LTC_Status->LTC_StatusSlave |= LTC2_LowTemp_NOK;
-
- if(gTMP.ITMP[0] > WarnHighTemp)
- LTC_Status->LTC_StatusSlave |= LTC1_HighTemp_NOK;
- if(gTMP.ITMP[1] > WarnHighTemp)
- LTC_Status->LTC_StatusSlave |= LTC2_HighTemp_NOK;
-
- if(gTMP.THSD[0])
- LTC_Status->LTC_StatusSlave |= LTC1_THSD_NOK;
- if(gTMP.THSD[1])
- LTC_Status->LTC_StatusSlave |= LTC2_THSD_NOK;
- if(gLTC_TimeOut)
- LTC_Status->LTC_StatusSlave |= LTC_TimeOut;
- gLTC_TimeOut = LTC_OK;
- if(gDRG.PEC_Counter)
- LTC_Status->LTC_StatusSlave |= LTC_PEC_NOK;
- if(!(PORTA & 0x04) )
- LTC_Status->LTC_StatusSlave |= RELAIS_ON;
- // Build LTC_PECFailCounter
- LTC_Status->LTC_PECFailCounter = gDRG.PEC_Counter;
- gDRG.PEC_Counter = 0; // Reset Error Counter after readout
- // Build LTC_SelfTest
- LTC_Status->LTC_SelfTest = gLTC_SelfTest_Result;
- }
- /*********************************************************************
- * Function: void LTC_GetHeatSink( LTC_STATUS *LTC_Status )
- *
- * Overview: API Funktion
- * Show HeatSinkTemperature
- *
- * PreCondition: None
- *
- * Input: Global gDRG
- *
- * Output: None
- *
- *
- * Side Effects: change LTC_Status
- ********************************************************************/
- void LTC_GetHeatSink( LTC_STATUS *LTC_Status )
- {
- int16_t HeatSinkTemp = 0;
- ADCON0bits.CHS = 3; // Set adc channel to read
- ADCON0bits.GO = 1; //Start A/D Conversion
- while(ADCON0bits.GO == 1)
- {
- //Loop here until A/D conversion completes
- };
- HeatSinkTemp = ( (((uint16_t)ADRESH << 8)+ADRESL)); // readout ADC
- HeatSinkTemp -= 500; // correct 0°C Offset
- HeatSinkTemp /= 10; // correct Slope
- LTC_Status->HeatSinkTemperature = (int8_t)HeatSinkTemp;
- }
- /*********************************************************************
- * Function: uint16_t LTC_SelfTest( void )
- *
- * Overview: API Funktion
- * Use this function to Self Test LTC6803
- *
- * PreCondition: LTC_Init()
- *
- * Input: none
- *
- * Output: LTC_OK, LTC1_VST1_NOK, LTC1_VST2_NOK, LTC1_VST1_NOK, LTC1_VST2_NOK,
- * LTC1_TST1_NOK, LTC1_TST2_NOK, LTC2_TST1_NOK, LTC2_TST2_NOK,
- * LTC1_RefL_NOK, LTC1_RefH_NOK, LTC2_RefL_NOK, LTC2_RefH_NOK,
- * LTC1_MUX_NOK, LTC2_MUX_NOK, LTC_PEC_NOK
- *
- * Side Effects: ~85ms stall
- ********************************************************************/
- uint16_t LTC_SelfTest( void )
- {
- int8_t i = 0;
- gLTC_SelfTest_Result = LTC_OK;
- // Spannungsmessung im SelfTest1 dh alle Datenbyte müssen 0x55 sein
- Delay10KTCYx(96);
- LTC_MeasureVoltage( STCVAD_ST1, STCVAD_ST1_PEC, EV__LTC_V_Start );
- Delay10KTCYx(96);
-
- if(LTC_MeasureVoltage( STCVAD_ST1, STCVAD_ST1_PEC, EV__LTC_V_Wait ))
- gLTC_SelfTest_Result |= LTC_PEC_NOK;
- else
- {
- for(i=2; i<20; i++)
- {
- if(gCVAD.LTC_CVAD_RAW[i] == (0x55 || 0xAA ))
- gLTC_SelfTest_Result |= LTC1_VST1_NOK;
- if(gCVAD.LTC_CVAD_RAW[i+19] == (0x55 || 0xAA ))
- gLTC_SelfTest_Result |= LTC2_VST1_NOK;
- }
- }
- // Spannungsmessung im SelfTest2 dh alle Datenbyte müssen 0xAA sein
- LTC_MeasureVoltage( STCVAD_ST2, STCVAD_ST2_PEC, EV__LTC_V_Start );
- Delay10KTCYx(96);
-
- if(LTC_MeasureVoltage( STCVAD_ST2, STCVAD_ST2_PEC, EV__LTC_V_Wait ))
- {
- gLTC_SelfTest_Result |= LTC_PEC_NOK;
- }
- else
- {
- for(i=2; i<20; i++)
- {
- if(gCVAD.LTC_CVAD_RAW[i] == (0x55 || 0xAA ))
- gLTC_SelfTest_Result |= LTC1_VST2_NOK;
- if(gCVAD.LTC_CVAD_RAW[i+19] == (0x55 || 0xAA ))
- gLTC_SelfTest_Result |= LTC2_VST2_NOK;
- }
- }
- // Normale Spannungsmessung um SelfTest zu beenden
- LTC_MeasureVoltage( STCVAD_ALL, STCVAD_ALL_PEC, EV__LTC_V_Start );
- Delay10KTCYx(96);
-
- if(LTC_MeasureVoltage( STCVAD_ALL, STCVAD_ALL_PEC, EV__LTC_V_Wait )) //Reset Self Test
- gLTC_SelfTest_Result |= LTC_PEC_NOK;
- // Temperaturmessung im SelfTest1 dh alle Datenbyte müssen 0x55 sein
- LTC_MeasureTemperature( STTMPAD_ST1, STTMPAD_ST1_PEC, EV__LTC_T_Start );
- Delay10KTCYx(20);
-
- if(LTC_MeasureTemperature( STTMPAD_ST1, STTMPAD_ST1_PEC, EV__LTC_T_Wait ))
- {
- gLTC_SelfTest_Result |= LTC_PEC_NOK;
- }
- else
- {
- for(i=2; i<6; i++)
- {
- if(gTMP.LTC_TMP_RAW[i] == (0x55 || 0xAA ))
- gLTC_SelfTest_Result |= LTC1_TST1_NOK;
- if(gTMP.LTC_TMP_RAW[i+6] == (0x55 || 0xAA ))
- gLTC_SelfTest_Result |= LTC2_TST1_NOK;
- }
- if(gTMP.LTC_TMP_RAW[6] == (0x05 || 0x0A ))
- gLTC_SelfTest_Result |= LTC1_TST1_NOK;
- if(gTMP.LTC_TMP_RAW[12] == (0x05 || 0x0A ))
- gLTC_SelfTest_Result |= LTC2_TST1_NOK;
- }
- // Temperaturmessung im SelfTest2 dh alle Datenbyte müssen 0xAA sein
- LTC_MeasureTemperature( STTMPAD_ST2, STTMPAD_ST2_PEC, EV__LTC_T_Start );
- Delay10KTCYx(20);
-
- if(LTC_MeasureTemperature( STTMPAD_ST2, STTMPAD_ST2_PEC, EV__LTC_T_Wait ))
- {
- gLTC_SelfTest_Result |= LTC_PEC_NOK;
- }
- else
- {
- for(i=2; i<6; i++)
- {
- if(gTMP.LTC_TMP_RAW[i] == (0x55 || 0xAA ))
- gLTC_SelfTest_Result |= LTC1_TST2_NOK;
- if(gTMP.LTC_TMP_RAW[i+6] == (0x55 || 0xAA ))
- gLTC_SelfTest_Result |= LTC2_TST2_NOK;
- }
- if(gTMP.LTC_TMP_RAW[6] == (0x05 || 0x0A ))
- gLTC_SelfTest_Result |= LTC1_TST2_NOK;
- if(gTMP.LTC_TMP_RAW[12] == (0x05 || 0x0A ))
- gLTC_SelfTest_Result |= LTC2_TST2_NOK;
- }
- // Normale Temperaturmessung um SelfTest zu beenden
- LTC_MeasureTemperature( STTMPAD_ALL, STTMPAD_ALL_PEC, EV__LTC_T_Start ); // Reset Self Test
- Delay10KTCYx(20);
- if(LTC_MeasureTemperature( STTMPAD_ALL, STTMPAD_ALL_PEC, EV__LTC_T_Wait ))
- gLTC_SelfTest_Result |= LTC_PEC_NOK;
- // Normale StatusAbfrage
- LTC_MeasureDiag( EV__LTC_S_Start );
- Delay10KTCYx(110);
-
- if(LTC_MeasureDiag( EV__LTC_S_Wait ))
- {
- gLTC_SelfTest_Result |= LTC_PEC_NOK;
- }
- else
- {
- if(gDRG.REF[0]<2100)
- gLTC_SelfTest_Result |= LTC1_RefL_NOK;
- if(gDRG.REF[0]>2900)
- gLTC_SelfTest_Result |= LTC1_RefH_NOK;
- if(gDRG.MUXFAIL[0])
- gLTC_SelfTest_Result |= LTC1_MUX_NOK;
- if(gDRG.REF[1]<2100)
- gLTC_SelfTest_Result |= LTC2_RefL_NOK;
- if(gDRG.REF[1]>2900)
- gLTC_SelfTest_Result |= LTC2_RefH_NOK;
- if(gDRG.MUXFAIL[1])
- gLTC_SelfTest_Result |= LTC2_MUX_NOK;
- }
- return gLTC_SelfTest_Result;
- }
- /*********************************************************************
- * Function: void LTC_SetCFG(uint8_t CDC,
- * uint32_t SetDCC,
- * uint32_t ClearDCC)
- *
- * Overview: Use this function to initialize LTC6803 module
- *
- * PreCondition: None
- *
- * Input: Variable: CDC (Mode), set/clear DCC (Balancing Mask)
- * Fix: CELL10 = 0 (12-Cell Mode)
- * LVLPL = 1 (Level Polling)
- * GPIO = 0 (Pull-Down ON)
- * WDT = 0 (WDT pin al logic '0')
- * MC = 0 (enable interrupts)
- * VUV = 0x77 (~2,1V)
- * VOV = 0xAA (~3,3V)
- *
- * Output: None
- *
- * Side Effects: None
- ********************************************************************/
- void LTC_SetCFG(uint8_t CDC, uint32_t setDCC, uint32_t clearDCC)
- {
- static uint32_t gDCC=0; // dauerhafter Kopie von Balance
- uint8_t DCC1L, DCC1H, DCC2L, DCC2H; // DCC Mask to CFG
- uint8_t LTC_CFG_TxBuffer[16]; // Speicher für Command&PEC Data&PEC
- uint32_t DCC=0; // work copy of gDCC
- gDCC = gDCC | setDCC; // Backup DCC for SetBalance
- gDCC = gDCC & ~clearDCC; // Backup DCC for ClearBalance
- DCC = gDCC; // Load new DCC
- DCC2L = (unsigned char)(DCC & 0x000000FF);
- DCC = DCC>>8;
- DCC2H = (unsigned char)(DCC & 0x0000000F);
- DCC = DCC>>4;
- DCC1L = (unsigned char)(DCC & 0x000000FF);
- DCC = DCC>>8;
- DCC1H = (unsigned char)(DCC & 0x0000000F);
- LTC_CFG_TxBuffer[2] = CDC + LVLPL; // Runmode
- LTC_CFG_TxBuffer[3] = DCC1L; // Balancing
- LTC_CFG_TxBuffer[4] = DCC1H; // 0xX0 = Zellen maskieren; Balancing = 0x0X
- LTC_CFG_TxBuffer[5] = 0x00; // 0xXX Zellen maskieren
- LTC_CFG_TxBuffer[6] = 0x77; // 0xXX = Unterspannung
- LTC_CFG_TxBuffer[7] = 0xAA; // 0xXX = Oberspannung
- LTC_CFG_TxBuffer[8] = LTC_CalcPEC(<C_CFG_TxBuffer[2], 6);
- LTC_CFG_TxBuffer[9] = CDC + LVLPL; // Runmode
- LTC_CFG_TxBuffer[10] = DCC2L; // Balancing
- LTC_CFG_TxBuffer[11] = DCC2H; // 0xX0 = Zellen maskieren; Balancing = 0x0X
- LTC_CFG_TxBuffer[12] = 0x00; // 0xXX Zellen maskieren
- LTC_CFG_TxBuffer[13] = 0x77; // 0xXX = Unterspannung
- LTC_CFG_TxBuffer[14] = 0xAA; // 0xXX = Oberspannung
- LTC_CFG_TxBuffer[15] = LTC_CalcPEC(<C_CFG_TxBuffer[9], 6);
- // Send CFG Buffer to LTC
- LTC_Read(WRCFG, WRCFG_PEC, 16, <C_CFG_TxBuffer[0]);
- }
- /*********************************************************************
- * Function: uint8_t LTC_GetCFG( void )
- *
- * Overview: Use this function to read back LTC6803 module CFG
- * Check PEC
- *
- * PreCondition: None
- *
- * Input: Global gCFG
- *
- * Output: OK = PEC OK, NOK = PEC NOK
- *
- * Side Effects: None
- ********************************************************************/
- uint8_t LTC_GetCFG( void )
- {
- uint8_t PECStatus = LTC_OK;
- // Read CFG
- LTC_Read(RDCFG, RDCFG_PEC, 16, (unsigned char *)&gCFG.LTC_CFG_RAW[0]);
-
- if( LTC_CalcPEC(&gCFG.LTC_CFG_RAW[2], 6) != gCFG.LTC_CFG_RAW[8])
- {
- PECStatus = LTC_NOK;
- }
- else
- {
- if( LTC_CalcPEC(&gCFG.LTC_CFG_RAW[9], 6) != gCFG.LTC_CFG_RAW[15])
- {
- PECStatus = LTC_NOK;
- }
- else
- {
- gCFG.CDC[1] = gCFG.LTC_CFG_RAW[9] & 0x7;
- gCFG.CDC[0] = gCFG.LTC_CFG_RAW[2] & 0x7;
- gCFG.CELL10[1] = (gCFG.LTC_CFG_RAW[9] >> 3) & 0x1;
- gCFG.CELL10[0] = (gCFG.LTC_CFG_RAW[2] >> 3) & 0x1;
- gCFG.LVL_PL[1] = (gCFG.LTC_CFG_RAW[9] >> 4) & 0x1;
- gCFG.LVL_PL[0] = (gCFG.LTC_CFG_RAW[2] >> 4) & 0x1;
- gCFG.GPIO[1] = (gCFG.LTC_CFG_RAW[9] >> 5) & 0x3;
- gCFG.GPIO[0] = (gCFG.LTC_CFG_RAW[2] >> 5) & 0x3;
- gCFG.WDT[1] = (gCFG.LTC_CFG_RAW[9] >> 7) & 0x1;
- gCFG.WDT[0] = (gCFG.LTC_CFG_RAW[2] >> 7) & 0x1;
- gCFG.DCC[1] = gCFG.LTC_CFG_RAW[11] & 0xF;
- gCFG.DCC[1] = (gCFG.DCC[1] << 8) + gCFG.LTC_CFG_RAW[10];
- gCFG.DCC[0] = gCFG.LTC_CFG_RAW[4] & 0xF;
- gCFG.DCC[0] = (gCFG.DCC[0] << 8) + gCFG.LTC_CFG_RAW[3];
- gCFG.MC[1] = gCFG.LTC_CFG_RAW[12];
- gCFG.MC[1] = (gCFG.MC[1] << 4) + (gCFG.LTC_CFG_RAW[11] >> 4);
- gCFG.MC[0] = gCFG.LTC_CFG_RAW[5];
- gCFG.MC[0] = (gCFG.MC[0] << 4) + (gCFG.LTC_CFG_RAW[4] >> 4);
- gCFG.VUV[1] = gCFG.LTC_CFG_RAW[13] - 31;
- gCFG.VUV[1] = gCFG.VUV[1] << 4;
- gCFG.VUV[1] = gCFG.VUV[1] + (gCFG.VUV[1] >> 1);
- gCFG.VUV[0] = gCFG.LTC_CFG_RAW[6] - 31;
- gCFG.VUV[0] = gCFG.VUV[0] << 4;
- gCFG.VUV[0] = gCFG.VUV[0] + (gCFG.VUV[0] >> 1);
- gCFG.VOV[1] = gCFG.LTC_CFG_RAW[14] - 32;
- gCFG.VOV[1] = gCFG.VOV[1] << 4;
- gCFG.VOV[1] = gCFG.VOV[1] + (gCFG.VOV[1] >> 1);
- gCFG.VOV[0] = gCFG.LTC_CFG_RAW[7] - 32;
- gCFG.VOV[0] = gCFG.VOV[0] << 4;
- gCFG.VOV[0] = gCFG.VOV[0] + (gCFG.VOV[0] >> 1);
- }
- }
- return PECStatus;
- }
- /*********************************************************************
- * Function: uint8_t LTC_MeasureDiag( uint16_t Status )
- *
- * Overview: API Funktion
- * Use this function to readout Status of LTC6803
- *
- * PreCondition: None
- *
- * Input: Global gDRG, Status
- * Status = EV__LTC_S_Start, EV__LTC_S_Wait
- *
- * Output: OK = PEC OK, NOK = PEC NOK
- *
- * Side Effects: ~17ms stall of LTC
- ********************************************************************/
- uint8_t LTC_MeasureDiag( uint16_t Status )
- {
- uint8_t PECStatus = LTC_OK;
- if(Status == (unsigned)EV__LTC_S_Start)
- {
- LTC_StartMeasure(DAGN, DAGN_PEC); // S Start
- }
- if(Status == (unsigned)EV__LTC_S_Wait)
- {
- if(PORTC & LTC_ADC_Ready) // ADC not running
- {
- LATAbits.LATA5 = 1; // CS SPI OFF
- // Read Diagnostic Register Group (DRG)
- LTC_Read(RDDGNR, RDDGNR_PEC, 8, (uint8_t *)&gDRG.LTC_DRG_RAW[0]);
- // Check for Errors
- if( LTC_CalcPEC(&gDRG.LTC_DRG_RAW[2], 2) != gDRG.LTC_DRG_RAW[4])
- {
- PECStatus = LTC_NOK;
- }
- else
- {
- if( LTC_CalcPEC(&gDRG.LTC_DRG_RAW[5], 2) != gDRG.LTC_DRG_RAW[7])
- {
- PECStatus = LTC_NOK;
- }
- else
- {
- // Extract Data
- // siehe Applications Note LTC 6803-3 Seite 25
- gDRG.REF[0] = LTC_Field2IntEven( gDRG.LTC_DRG_RAW[2], gDRG.LTC_DRG_RAW[3] );
- gDRG.REF[1] = LTC_Field2IntEven( gDRG.LTC_DRG_RAW[5], gDRG.LTC_DRG_RAW[6] );
- gDRG.MUXFAIL[0] = (gDRG.LTC_DRG_RAW[3] >> 5) & 0x1;
- gDRG.MUXFAIL[1] = (gDRG.LTC_DRG_RAW[6] >> 5) & 0x1;
- gDRG.REV[0] = gDRG.LTC_DRG_RAW[3] >> 6;
- gDRG.REV[1] = gDRG.LTC_DRG_RAW[6] >> 6;
- }
- }
- }
- }
- return PECStatus;
- }
- /*********************************************************************
- * Function: uint8_t LTC_MeasureVoltage( uint16_t Status );
- *
- * Overview: Use this function to start measuring cell voltage
- * with LTC6803 module
- *
- * PreCondition: None
- *
- * Input: Global gCVAD, Status = EV__LTC_V_Start / EV__LTC_V_Wait
- * *
- * Output: OK = PEC OK, NOK = PEC NOK
- *
- * Side Effects: ~13ms stall
- // ********************************************************************/
- uint8_t LTC_MeasureVoltage( uint8_t CMD, uint8_t CMD_PEC, uint16_t Status )
- {
- int8_t i, j; // Laufindex
- uint8_t PECStatus = LTC_OK;
-
- if(Status == (unsigned)EV__LTC_V_Start)
- {
- LTC_SetCFG(CDC_1, 0x00, 0x00FFFFFF); // Set Balancing Off
- LTC_StartMeasure( CMD, CMD_PEC); // Start Voltage Measure
- }
- if(Status == (unsigned)EV__LTC_V_Wait)
- {
- if(PORTC & LTC_ADC_Ready) // ADC not running
- {
- LATAbits.LATA5 = 1; // CS SPI OFF
- LTC_SetCFG(CDC_1, CAN_BAL, ~CAN_BAL); // Set Balancing Outs
- // Read all cell voltage
- LTC_Read(RDCV, RDCV_PEC, 40, (unsigned char *)&gCVAD.LTC_CVAD_RAW[0]);
- if( LTC_CalcPEC(&gCVAD.LTC_CVAD_RAW[2], 18) != gCVAD.LTC_CVAD_RAW[20])
- {
- PECStatus = LTC_NOK;
- }
- else
- {
- if( LTC_CalcPEC(&gCVAD.LTC_CVAD_RAW[21], 18) != gCVAD.LTC_CVAD_RAW[39])
- {
- PECStatus = LTC_NOK;
- }
- else
- {
- //reassemble Data and calc Voltage
- for(i=0; i<24 ; i=i+2) // Loop über alle Zellen
- {
- j = i + (i>>1); // Index j = 1.5 x i
- if(i>11) j++; // jump PEC_L
- // siehe Applications Note LTC 6803-3 Seite 24
- gCVAD.CVAD[i] = LTC_Field2IntEven( gCVAD.LTC_CVAD_RAW[j+2], gCVAD.LTC_CVAD_RAW[j+3]);
- gCVAD.CVAD[i+1] = LTC_Field2IntOdd( gCVAD.LTC_CVAD_RAW[j+3], gCVAD.LTC_CVAD_RAW[j+4]);
- }
- }
- }
- }
- }
- return PECStatus;
- }
- /*********************************************************************
- * Function: uint8_t LTC_runMeasureTemperature( uint8_t CMD,
- * uint8_t CMD_PEC,
- * uint16_t Status );
- *
- * Overview: Use this function to start measuring Temperature
- * with LTC6803 module
- *
- * PreCondition: None
- *
- * Input: CMD & CMD_PEC, Global gTMP, Status
- * Status = EV__LTC_T_Start, EV__LTC_T_Wait
- * CMD = STTMPAD_ALL, STTMPAD_ST1, STTMPAD_ST
- *
- * Output: OK = PEC OK, NOK = PEC NOK
- *
- * Side Effects: ~4ms stall of LTC
- ********************************************************************/
- uint8_t LTC_MeasureTemperature( uint8_t CMD, uint8_t CMD_PEC, uint16_t Status )
- {
- int8_t i, j; // Laufindex
- int16_t iBufTMP; // Zwischenspeicher
- uint8_t Cycle = 0; // Temperature MUX Count
- uint8_t RCT_Cycle = 0; // new runindex for MUX2
- uint8_t PECStatus = LTC_OK;
- // Start Cell Temperature ADC Conversions - poll status
- if(Status == (unsigned)EV__LTC_T_Start)
- {
- LTC_StartMeasure(CMD, CMD_PEC);
- }
- if(Status == (unsigned)EV__LTC_T_Wait)
- {
- if(PORTC & LTC_ADC_Ready) // ADC not running
- {
- LATAbits.LATA5 = 1; // CS SPI OFF
- // Read all cell temperature
- LTC_Read(RDTMP, RDTMP_PEC, 14, (unsigned char *)&gTMP.LTC_TMP_RAW[0]);
- // Check for Errors
- if( LTC_CalcPEC(&gTMP.LTC_TMP_RAW[2], 5) != gTMP.LTC_TMP_RAW[7])
- {
- PECStatus = LTC_NOK;
- }
- else
- {
- if( LTC_CalcPEC(&gTMP.LTC_TMP_RAW[8], 5) != gTMP.LTC_TMP_RAW[13])
- {
- PECStatus = LTC_NOK;
- }
- else
- {
- // Extract Data
- j=2; // Index in RAW
- Cycle = LATC & 0x07; // Extract MUX
- Cycle--;
- RCT_Cycle = 5 - Cycle; // set new Cycle
- for(i=0; i<24; i=i+12) // Loop over LTC Modules*2*TMP
- {
- // siehe Applications Note LTC 6803-3 Seite 25
- iBufTMP = LTC_Field2IntEven( gTMP.LTC_TMP_RAW[j], gTMP.LTC_TMP_RAW[j+1] );
- gTMP.ETMP[2*Cycle+i] = LTC_CONV_UMESS_2_TEMP(iBufTMP);
-
- j++;
- iBufTMP = LTC_Field2IntOdd( gTMP.LTC_TMP_RAW[j], gTMP.LTC_TMP_RAW[j+1] );
- gTMP.ETMP[2*RCT_Cycle+i+1] = LTC_CONV_UMESS_2_TEMP(iBufTMP);
- j = j + 2;
- iBufTMP = LTC_Field2IntEven( gTMP.LTC_TMP_RAW[j], gTMP.LTC_TMP_RAW[j+1] );
- gTMP.ITMP[i/12] = (iBufTMP >> 3) - 273;
-
- j = j + 3;
- }
- gTMP.THSD[0] = (gTMP.LTC_TMP_RAW[6] >> 4) & 0x1;
- gTMP.THSD[1] = (gTMP.LTC_TMP_RAW[12] >> 4) & 0x1;
- }
- }
- }
- }
- return PECStatus;
- }
- /*********************************************************************
- * Function: uint8_t LTC_CalcPEC(uint8_t *Array, uint8_t SizeOf)
- *
- * Overview: Use this function to calculate CRC Checksum (PEC)
- * for LTC6803 module
- *
- * PreCondition: None
- *
- * Input: *Array, SizeOf - Number of Elements
- *
- * Output: PEC
- *
- * Side Effects: None
- **********************************************************************/
- uint8_t LTC_CalcPEC(uint8_t *Array, uint8_t Size_Of)
- {
- uint8_t i; // Laufindex
- int8_t k; // Laufindex
- uint8_t PEC = 0x41; // PEC Startwert
- uint8_t DIN = 0; // Input Buffer
- uint8_t IN0 = 0; // Zwischenspeicher
- uint8_t IN1 = 0; // Zwischenspeicher
- uint8_t IN2 = 0; // Zwischenspeicher
- for(i=0;i<Size_Of;i++) // Loop über alle Elemente
- {
- for(k=0;k<8;k++) // Loop über alle Bits
- {
- DIN = Array[i] & (0x0080 >> k); // Berechnung nach Datenblatt
- DIN = (DIN >> (7 - k));
- IN0 = DIN ^ ((PEC & 0x0080) >> 7);
- IN1 = (PEC & 0x0001) ^ IN0;
- IN2 = ((PEC & 0x0002) >> 1) ^ IN0;
- PEC = (PEC << 1);
- PEC = (PEC & 0x00F8) | ((IN2 << 2) |(IN1 << 1) | IN0);
- }
- }
- return PEC;
- }
- /*********************************************************************
- * Function: void InitSPI( void )
- *
- * Overview: Use this function to config SPI for LTC6803 module
- *
- * PreCondition: None
- *
- * Input: None
- *
- * Output: None
- *
- * Side Effects: None
- **********************************************************************/
- void InitSPI( void )
- {
- // RC3 is connected to SCK: Serial clock input
- TRISCbits.TRISC3 = 0;
- // RC5 is connected to SI: Serial data I/O (MCP23017), Serial data input (MCP23S17)
- TRISCbits.TRISC5 = 0;
- // SSPxCON1: MSSPx CONTROL REGISTER 1 (I2C? MODE)
- // SSPEN=1, 1 = Enables the serial port and configures the SDAx and SCLx pins as the serial port pins
- // SSPM<3:0>=0010, 0010 = SPI Master mode, clock = FOSC/64
- // CKP=1, 1 = Idle state for clock is a high level
- SSPCON1 = 0x32;//SSP1CON1 = 0x32; // 00100010
- // CKE: SPI Clock Select bit
- // 1 = Transmit occurs on transition from active to Idle clock state
- // 0 = Transmit occurs on transition from Idle to active clock state
- SSPSTATbits.CKE = 0;//SSP1STATbits.CKE = 0;
- // SSP1IF: MSSP1 Interrupt Flag bit
- //1 = The transmission/reception is complete (must be cleared in software)
- //0 = Waiting to transmit/receive
- PIR1bits.SSPIF = 0;
- }
- /*********************************************************************
- * Function: int16_t LTC_Field2IntEven( uint8_t ucByteLow,
- * uint8_t ucByteHigh)
- *
- * Overview: Use this function to extract an int Variable
- * out of LTC-Bitfield at known even Address and calculate
- * Voltage
- *
- * PreCondition: None
- *
- * Input: 2 Byte out of LTC_Bitfield
- *
- * Output: Extracted Integer representing Voltage (mV)
- *
- * Side Effects: None
- **********************************************************************/
- int16_t LTC_Field2IntEven( uint8_t ucByteLow, uint8_t ucByteHigh)
- {
- int16_t iBuffer = 0;
- iBuffer = ucByteHigh & 0xF; // H Nibble isolieren
- iBuffer = (iBuffer << 8) + ucByteLow; // H Nibble in Position + M + L
- iBuffer = iBuffer - 512; // Offset 512 Korrektur
- if(iBuffer>=0)
- iBuffer = iBuffer + (iBuffer >> 1); // ADCinc x 1,5 = X mV
- else
- iBuffer = iBuffer + ((iBuffer >> 1) + 0x8000); // ADCinc x 1,5 = X mV (bei negativen Zahlen)
-
- return iBuffer;
- }
- /*********************************************************************
- * Function: int16_t LTC_Field2IntOdd( uint8_t ucByteLow,
- * uint8_t ucByteHigh)
- *
- * Overview: Use this function to extract an int Variable
- * out of LTC-Bitfield at known odd Address and calculate
- * Voltage
- *
- * PreCondition: None
- *
- * Input: 2 Byte out of LTC_Bitfield
- *
- * Output: Extracted Integer representing Voltage (mV)
- *
- * Side Effects: None
- **********************************************************************/
- int16_t LTC_Field2IntOdd( uint8_t ucByteLow, uint8_t ucByteHigh)
- {
- int16_t iBuffer = 0;
- iBuffer = ucByteHigh; // H und M Nibble isolieren
- iBuffer = (iBuffer << 4) + (ucByteLow >> 4); // H und M Nibble in Position + L Nibble
- iBuffer = iBuffer - 512; // Offset 512 Korrektur
- if(iBuffer>=0)
- iBuffer = iBuffer + (iBuffer >> 1); // ADCinc x 1,5 = X mV
- else
- iBuffer = iBuffer + ((iBuffer >> 1) + 0x8000); // ADCinc x 1,5 = X mV (bei negativen Zahlen)
- return iBuffer;
- }
- /*********************************************************************
- * Function: void LTC_StartMeasure(uint8_t COMAND, uint8_t COMAND_PEC);
- *
- * Overview: Use this function sends Command Sequence for Measurment
- *
- * PreCondition: None
- *
- * Input: Command Byte & Command PEC
- *
- * Output: none
- *
- * Side Effects: uses SPI
- **********************************************************************/
- void LTC_StartMeasure(uint8_t COMAND, uint8_t COMAND_PEC)
- {
- LATAbits.LATA5 = 0; // CS SPI ON
- SSPBUF=COMAND; // Send Command Byte
- while(!PIR1bits.SSPIF); // Warten bis die Daten gesendet wurden
- PIR1bits.SSPIF = 0; // clear SSPIF Bit
- SSPBUF=COMAND_PEC; // PEC Byte
- while(!PIR1bits.SSPIF); // Warten bis die Daten gesendet wurden
- PIR1bits.SSPIF = 0; // clear SSPIF Bit
- }
- /*********************************************************************
- * Function: void LTC_Read( uint8_t CMD,
- * uint8_t CMD_PEC,
- * uint8_t Length,
- * uint8_t *ptr),
- *
- * Overview: Use this function read Data from LTC
- *
- * PreCondition: None
- *
- * Input: Command Byte & Command PEC & Data Length & Pointer 2 Start Buffer
- *
- * Output: none
- *
- * Side Effects: uses SPI
- **********************************************************************/
- void LTC_Read(uint8_t CMD, uint8_t CMD_PEC, uint8_t Length, uint8_t *ptr)
- {
- uint8_t i; // Laufindex
- *ptr = CMD; // Load Command to Buffer
- *(ptr+1) = CMD_PEC; // Load Command PEC to Buffer
-
- LATAbits.LATA5 = 0; // CS SPI ON
- for(i=0;i<Length; i++)
- {
- SSPBUF = *(ptr+i); // Send Byte
- while(!PIR1bits.SSPIF); // wait until Send complete
- PIR1bits.SSPIF = 0; // clear SSPIF Bit
- *(ptr+i) = SSPBUF; // store Data to Buffer
- }
- LATAbits.LATA5 = 1; // CS SPI OFF
- }
- /*********************************************************************
- * Function: void InitTimer( void );
- *
- * Overview: Use this function to init Timer 1 for 20ms TimeSlot
- *
- * PreCondition: None
- *
- * Input: -
- *
- * Output: -
- *
- * Side Effects: run Timer 1
- **********************************************************************/
- void InitTimer(void)
- {
- T1CONbits.T1CKPS0 = 1; // Timer 1 prescalar = 0b00
- T1CONbits.T1CKPS1 = 1; // = (Fosc/4) / 8 = 2MHz
- IPR1bits.TMR1IP = 0; // 1 = make this a low priority interrupt
- PIE1bits.TMR1IE = 1; // enable Timer interrupt
- PIR1bits.TMR1IF = 0; // clear any pending events
- T1CONbits.RD16 = 1; // 16 Bit read-write mode
- T1CONbits.TMR1ON = 1; // Timer A run
- }
- /*********************************************************************
- * Function: void Set_LTC_TimeOut( void )
- *
- * Overview: Use this function to set LTC_TimeOut Flag
- *
- * PreCondition: None
- *
- * Input: -
- *
- * Output: -
- *
- * Side Effects: change LTC_TimeOut
- **********************************************************************/
- void Set_LTC_TimeOut( void )
- {
- gLTC_TimeOut |= LTC_TimeOut;
- }
- int16_t ADC_supply_voltage( void )
- {
- int16_t analog_reading = 0;
- ADCON0bits.CHS = 0; // Set adc channel to read
- ADCON0bits.GO = 1; //Start A/D Conversion
- while(ADCON0bits.GO == 1)
- {
- //Loop here until A/D conversion completes
- };
- analog_reading= ( (((uint16_t)ADRESH << 8)+ADRESL)); // readout ADC
- return analog_reading;
- }
|