Example #1
0
/*! \brief  Send a Reset signal and listen for Presence signal. (software
 *  only driver)
 *
 *  Generates the waveform for transmission of a Reset pulse on the 
 *  1-Wire(R) bus and listens for presence signals.
 *
 *  \param  pins    A bitmask of the buses to send the Reset signal on.
 *
 *  \return A bitmask of the buses where a presence signal was detected.
 */
unsigned char OWI_DetectPresence(unsigned char pins)
{
    unsigned char intState;
    unsigned char presenceDetected;
    
    // Disable interrupts.
    intState = __save_interrupt();
    __disable_interrupt();
    
    // Drive bus low and delay.
    OWI_PULL_BUS_LOW(pins);
    __delay_cycles(OWI_DELAY_H_STD_MODE);
    
    // Release bus and delay.
    OWI_RELEASE_BUS(pins);
    __delay_cycles(OWI_DELAY_I_STD_MODE);
    
    // Sample bus to detect presence signal and delay.
    presenceDetected = ((~OWI_PIN) & pins);
    __delay_cycles(OWI_DELAY_J_STD_MODE);
    
    // Restore interrupts.
    __restore_interrupt(intState);
    
    return presenceDetected;
}
Example #2
0
/*! \brief  Read a bit from the bus(es). (Software only driver)
 *
 *  Generates the waveform for reception of a bit on the 1-Wire(R) bus(es).
 *
 *  \param  pins    A bitmask of the bus(es) to read from.
 *
 *  \return A bitmask of the buses where a '1' was read.
 */
unsigned char OWI_ReadBit(unsigned char pins)
{
    unsigned char intState;
    unsigned char bitsRead;
    
    // Disable interrupts.
    intState = __save_interrupt();
    __disable_interrupt();
    
    // Drive bus low and delay.
    OWI_PULL_BUS_LOW(pins);
    __delay_cycles(OWI_DELAY_A_STD_MODE);
    
    // Release bus and delay.
    OWI_RELEASE_BUS(pins);
    __delay_cycles(OWI_DELAY_E_STD_MODE);
    
    // Sample bus and delay.
    bitsRead = OWI_PIN & pins;
    __delay_cycles(OWI_DELAY_F_STD_MODE);
    
    // Restore interrupts.
    __restore_interrupt(intState);
    
    return bitsRead;
}
Example #3
0
/*! \brief  Write a '0' to the bus(es). (Software only driver)
 *
 *  Generates the waveform for transmission of a '0' bit on the 1-Wire(R)
 *  bus.
 *
 *  \param  pins    A bitmask of the buses to write to.
 */
void OWI_WriteBit0(unsigned char pins)
{
    unsigned char intState;
    
    // Disable interrupts.
    intState = __save_interrupt();
    __disable_interrupt();
    
    // Drive bus low and delay.
    OWI_PULL_BUS_LOW(pins);
    __delay_cycles(OWI_DELAY_C_STD_MODE);
    
    // Release bus and delay.
    OWI_RELEASE_BUS(pins);
    __delay_cycles(OWI_DELAY_D_STD_MODE);
    
    // Restore interrupts.
    __restore_interrupt(intState);
}
Example #4
0
File: main.c Project: ByReaL/AVR474
/*! \brief The main function.
 *
 * This contains initialization and the main loop as described in the
 * application note. Interrupt service routines (ISR) supply all data to be
 * processed in the main loop.
 *
 */
int main( void )
{
	/*
	Initialisation of peripheral modules:
	- Watchdog (timeout must be more than longer than the longest conversion period used for the CC-ADC)
	- Turn of unneeded modules (only SPI atm)
	- Bandgap
	- Set Current protection levels/configuration
	- V-ADC
		- Get cell voltages (requires that interrupts are enabled)
		- Get temperature
		- Estimate capacity ("gas gauging")
	- Check battery voltage and release the device from DUVR mode
	- CC-ADC
		- Get initial current reading (momentary and average).
	- Communication
	*/
	// Initialization.
	wdt_reset();
	
	WDT_SetTimeOut( WDTO_2Kms );  //Set Watchdog timeout to 2 sec

#ifdef DEBUG
	if( FAILURE == Reset_Initialization() ){
		// TODO: The Watchdog has triggered several times - might want to shut down the battery?!
		// POWMAN_Shutdown();
	}
#endif
	// Enable power reduction for SPI
	PRR_DISABLE_SPI();
	// Disable digital input for port a
	DIDR0 = (1<<PA0DID) | (1<<PA1DID);
	// Enable pull-ups for port b to avoid floating pins
	PORTB = (1<<PORTB0) | (1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3) | (1<<PORTB4) | (1<<PORTB5) | (1<<PORTB6) | (1<<PORTB7);
	DDRB = (1<<PORTB0) | (1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3) | (1<<PORTB4);
	
	// Check the CRC checksum of the battery parameters struct
	errorFlags.checksumFailure = (! BATTPARAM_CheckCRC()) | (! CheckSignatureCRC());

	// Initialize Bandgap reference.
	if( FAILURE == BANDGAP_Initialization() ){
		errorFlags.criticalConditionDetected = true;
	}
	
	// Initialize the battery protection module (enabled by default - if default settings are good
	// this is not required).
	BATTPROT_SetShortCircuitDetection( battParams.shortcircuitCurrent, battParams.shortcircuitReactionTime );
	BATTPROT_SetOverCurrentDetection( battParams.overcurrentDischarge, battParams.overcurrentCharge, battParams.overcurrentReactionTime );
	BATTPROT_SetHighCurrentDetection( battParams.highcurrentDischarge, battParams.highcurrentCharge, battParams.highcurrentReactionTime );
	
	BATTPROT_DisableDischargeHighCurrentProtection(); // Don't want a high discharging current to disable the FETs (in this example)
	BATTPROT_EnableAllInterrupts();

	//Enable DUVR from the start, so we are always in DUVR mode.
	FETCTRL_EnableDeepUnderVoltageMode();
	
	// On reset, the device is in DUVR mode depending on the fuse setting DUVRINIT
	stateFlags.inDUVR = true;
	
	// Enable the voltage regulator monitor interrupt
	VREGMON_InterruptEnable();
	
	// Initialize V-ADC and configure a full scan
	VADC_InitializeVadcCoefficients();
	VADC_ScanConfig( (vadcIndex_t)HIGHEST_CELL, (vadcIndex_t)HIGHEST_VADC, (vadcIndex_t)VTEMP );

	// This can only fail if the VADC is set-up with an invalid ScanConfig
	if( FAILURE == VADC_StartScan() ){
		errorFlags.criticalConditionDetected = true;
	} else {
		__enable_interrupt();
		while( VADC_RUNNING == VADC_ScanState() );
		__disable_interrupt();
		
		VADC_ClearReadyFlags();
		
		disableDUVRIfPossible();
		VBSoC_Init();
	}
	
	// Calculate the coefficient numbers for ccadc_ticks to mA and gas_gauging to mAh functions
	BATTCUR_CalculateShuntCoeffient(battParams.shuntResistance, CCADC_VOLTREF);
        uint16_t temp = RCCAL_CalculateUlpRCperiod(coreTemperature/10);
	CCGASG_CalculateShuntCoefficients(temp, battParams.shuntResistance, CCADC_VOLTREF);
	
	// Calculate values for the sram battery parameters struct
	BATTPARAM_InitSramParameters();
	
	// Copy key from eeprom to sram if using AES
#if defined(AUTH_USE_AES)
	AUTH_CopyKeyToSram();
#endif
		
	
	// If a critical condition occured, (either bandgap didn't work or VADC was configured wrong)
	// don't do any of the battery related initialization and disable DUVR mode (so charging is impossible)
	if( errorFlags.criticalConditionDetected ) {
		FETCTRL_DisableDeepUnderVoltageMode();
		FETCTRL_DisableFets();
		
	} else {
		// Initialize the CC-ADC (sample every second and set regular current level)
		CCADC_Init( ACCT_1024, RCCI_1024, 10 mA );
		CCADC_SetMode( CCADC_ACC );
		
		// Set initial remaining capacity in the CCGASG module, it is marked as in-
		// accurate and updated the first time the VBSoC have an accurate reading.
		CCGASG_SetStateofCharge(VBSoC_EstimatedSoC());
		stateFlags.remainingCapacityInaccurate = 1;
		
		__enable_interrupt();
		// Needs to run a conversion before the value is correct
		while( !CCADC_isAccResultReady() );
		wdt_reset();
		__disable_interrupt();
		
		
		// Calculate the CCADC Accumulating conversion offset if it is invalid and
		// DUVR mode is disabled
		if(CCADC_GetRawAccOffset() == 32767 && ! stateFlags.inDUVR) {
			FETCTRL_DisableFets(); // Disable FETs when measuring offset as changes in current not is good
			__enable_interrupt();
			CCADC_CalculateAccOffset();
			__disable_interrupt();
		}
		
		// If two or more cells, init the misbalance corrector
#if BATTPARAM_CELLS_IN_SERIES >= 2
		BATTVMON_InitializeBalancing();
#endif
		
		//Store information about the current (to be able to reply if host asks...)
		BATTCUR_StoreCurrent( CCADC_GetAccResult() );
		BATTCUR_InitializeAverageCurrent( BATTCUR_GetOffsetCalibratedCurrent() );
	}
	
	//init communication bus
	T1init();	// Used for SmBus timeout and LED

	Comm_Init();

	// Ready to run - enable interrupts and enter main loop.
	__enable_interrupt();
	
	
	/*******************************************************************
	Main loop:
	If any of the task flags are set the corresponding task should be run.
	
	The following things are done:
	- Reset watchdog
	- If a new CCADC result is ready, start a VADC conversion
	- If the communication interface have a new byte, handle it
	- and if a whole new command has arrived, handle that
	- Handle new CCADC result if it's ready
	- Check new core temperature if ready, and run a fast RC calibration if needed
	- Check new cell temperature if ready
	- Check new cell voltage if ready
	- Set different sleep modes depending on what's running
	  - If in communication or RC calibration (any timer running) can only enter idle mode
	  - If VADC is running, can't go deeper than ADC noise reduction mode
	  - If "nothing" is running, enter power-save
	- Disable/enable fets depeding on various things
	- Go to sleep
	*/
	while(1) {

		//Tickle the watchdog every cycle
		wdt_reset();
		
		if( CCADC_isAccResultReady() )
		{
			// Start a new VADC scan as fast as possible so that all scans hopefully are
			// ready before the main loop ends, to avoid having to cycle again.
			
			
#if BATTPARAM_CELLS_IN_SERIES >= 2
			// Disable cell balancing if more than one cell
			BATTVMON_DisableCellBalancing();
#endif
			
			// Start a new VADC scan
			configureVADC();
			VADC_StartScan();
			
			taskFlags.newCurrentAvailable = true;
		}
		
		//See if there were any received commands.
		taskFlags.newSbsCommandAvailable = Comm_Handle( &sbs );

		
		//If complete sbs command has been received: process it
		if( taskFlags.newSbsCommandAvailable )
		{
			handleSBSCommand();
			// If authentication is needed, run. It will use and change the values in sbs,
			// make sure the communication interrupt does not write directly to it.
			// Note that this can take long time and communication will not work
			// during that time.
			if(taskFlags.doAuthentication) {
				AUTH_Execute(&sbs);
				taskFlags.doAuthentication = false;
			}
		}
		
		
		/*
		A new CC-ADC conversion is available. Update momentary current, average current,
		and calculate new battery capacity. Update discharge_cycle_accumulator (and increment
		cycle_count if required).
		*/
		if( taskFlags.newCurrentAvailable )
		{
			taskFlags.newCurrentAvailable = false;
			
			// We use the CCADC interrupt as counter for the RTC
			runEverySecond();
			BATTCUR_StoreCurrent( CCADC_GetAccResult() );
			handleNewCCADCResult();
			CCGASG_AccumulateCCADCMeasurements( BATTCUR_GetCurrent(), slowRcOscillatorPeriod );
			
			//Set ledstatus
			SoC_State = GASG_StateOfCharge(BATTCUR_GetAverageCurrent(), battParams_sram.capacityInCCAccumulated);
			SetLEDs((uint8_t)SoC_State);
		}

		/*
		New core temperature reading is available and should be processed. If
		temperature has changed set RC_calibration_required flag.
		*/
		if( VADC_VTempReady() )
		{
			handleNewCoreTemperature();
		}

		/*
		RC oscillator requires calibration (new CC_ADC conversion period time should
		be calculated and stored.
		*/
		if( taskFlags.rcCalibrationRequired )
		{
			taskFlags.rcCalibrationRequired = false;
			RCCAL_StartCalibrateFastRC();
			
			// Calculating slow RC period works on whole kelvins
			slowRcOscillatorPeriod = RCCAL_CalculateSlowRCperiod( coreTemperature/10 );
		}
		
		if( RCCAL_GetState() == RCCAL_CALIB_INIT || RCCAL_GetState() == RCCAL_CALIB_WORKING ) {
			RCCAL_CalibrateFastRCruntime(slowRcOscillatorPeriod);
		}
		
		/*
		Battery cell temperature is available. Check it and disable FETs if too high/low
		*/
		if( VADC_CellTempReady() )
		{
			handleNewCellTemperature();
		}
		
		
		/*
		Check battery voltage cell . Check if critical (high/low voltage)
		*/
		if( VADC_Cell1VoltageReady() )
		{
			handleNewCellVoltage(CELL1);
		}
			
		/*
		Check battery voltage cell . Check if critical (high/low voltage) and misbalance
		*/
#if BATTPARAM_CELLS_IN_SERIES >= 2
		if( VADC_Cell2VoltageReady() )
		{
			handleNewCellVoltage(CELL2);
		}

#if BATTPARAM_CELLS_IN_SERIES >= 3
		if( VADC_Cell3VoltageReady() )
		{
			handleNewCellVoltage(CELL3);
		}

#if BATTPARAM_CELLS_IN_SERIES >= 4
		if( VADC_Cell4VoltageReady() )
		{
			handleNewCellVoltage(CELL4);
		}
#endif
#endif
#endif	
		
		// Check what sleep mode we can enter. Needs disable interrupt because otherwise it might
		// overwrite what interrupts write to SMCR (for example, if external interrupt is triggered and
		// wants the sleep mode to be no higher than idle, it should be run after all those checks)
		uint8_t interruptState = __save_interrupt();
		__disable_interrupt();
		if( Comm_IsIdle() && ! RCCAL_IS_RUNNING() ) {
			if( VADC_RUNNING == VADC_ScanState() ) {
				SLEEP_SET_ADC_NR_MODE();
			} else {
				SLEEP_SET_POWER_SAVE_MODE();
			}
		} else {
			SLEEP_SET_IDLE_MODE();
		}
		__restore_interrupt(interruptState);
		
		/*
		Disable FETs if critical condition have been detected.
		Enable them if that is okey, depending om various factors like
		temperature and voltage.
		*/
		if(   errorFlags.criticalConditionDetected
			 || stateFlags.simulatePowerOff)
		{
			FETCTRL_DisableFets();
		}
		else if( ! errorFlags.cellTemperatureTooHigh &&
		         ! errorFlags.cellTemperatureTooLow &&
		         ! stateFlags.inDUVR)
		{
			if(   ! errorFlags.voltageTooHigh
			   && ! errorFlags.reoccuringChargeProtection
			   && ! stateFlags.chargingProhibited
			   && ! sbsFlags.forceChargeFETDisabled)
			{
				FETCTRL_EnableChargeFet();
			}
			
			if(   ! errorFlags.voltageTooLow
			   && ! stateFlags.dischargingProhibited
			   && ! sbsFlags.forceDischargeFETDisabled)
			{
				FETCTRL_EnableDischargeFet();
			}
		}
		
		// The reason to do this is that on short-circuit, the cell voltage reading can
		// be wrong and if that causes both chargingProhibited and dischargingProhibited
		// to get set, they would never be cleared unless we do this.
		// If they should be set, they will be set again before the FETs are enabled again
		// on next cycle.
		if( stateFlags.chargingProhibited && stateFlags.dischargingProhibited ) {
			stateFlags.chargingProhibited = false;
			stateFlags.dischargingProhibited = false;
		}
		
		// Enter sleep if no new byte just have been received on the communication
		// If a byte is received between the check for Comm_Flag and __sleep is
		// executed, the sleep function will have no effect as the software communication
		// interrupt clears sleep mode enable.
		if( (Comm_Flag() == 0 ) && (ShowLedBusy()==false) ){
			__sleep();
		}
	}
}