180 lines
6.3 KiB
Python
180 lines
6.3 KiB
Python
import math
|
|
|
|
from ScEpTIC import ConfigurationException
|
|
from ScEpTIC.emulator.energy import energy_utils
|
|
from ScEpTIC.emulator.energy.mcu import MCUEnergyModel
|
|
from ScEpTIC.emulator.energy.mcu.options import MCUClockCycleAction
|
|
from ScEpTIC.emulator.energy.mcu.datasheets.msp430g2553_utils.lookup_table import resistance_lookup_table
|
|
from ScEpTIC.emulator.energy.mcu.datasheets.msp430g2553_utils.voltage_lookup_hash import voltage_lookup_hash
|
|
|
|
class MSP430GEnergyModel(MCUEnergyModel):
|
|
"""
|
|
MCU energy model for MSP430-G series from Texas Instruments
|
|
"""
|
|
|
|
def _get_MCU_frequency(self, frequency_data):
|
|
"""
|
|
:param frequency_data: MCU datasheet information of a specific clock frequency
|
|
:return: clock frequency
|
|
"""
|
|
return energy_utils.str_to_float(frequency_data["frequency"])
|
|
|
|
|
|
def _get_MCU_nominal_v(self, frequency_data):
|
|
"""
|
|
:param frequency_data: MCU datasheet information of a specific clock frequency
|
|
:return: the nominal voltage at which the current draws of the MCU were measured
|
|
"""
|
|
return energy_utils.str_to_float(frequency_data['V'])
|
|
|
|
|
|
def _get_MCU_min_v(self, frequency_data):
|
|
"""
|
|
:param frequency_data: MCU datasheet information of a specific clock frequency
|
|
:return: the minimum operating voltage of the MCU at a given clock frequency
|
|
"""
|
|
return energy_utils.str_to_float(frequency_data['V_min'])
|
|
|
|
|
|
def _calculate_MCU_equivalent_r(self, frequency_name, frequency_data):
|
|
"""
|
|
:param frequency_name: operating frequency name
|
|
:param frequency_data: MCU datasheet information of a specific clock frequency
|
|
:return: the equivalent resistance of the MCU in the various operating conditions.
|
|
"""
|
|
data = {}
|
|
|
|
nominal_v = self._get_MCU_nominal_v(frequency_data)
|
|
current_draws = self._calculate_MCU_I(frequency_data)
|
|
|
|
for operating_mode, current_draw in current_draws.items():
|
|
data[operating_mode] = energy_utils.equivalent_resistance(nominal_v, current_draw)
|
|
|
|
return data
|
|
|
|
|
|
def _calculate_MCU_I(self, frequency_data):
|
|
"""
|
|
Calculates the current draw of the MCU in the various operating conditions.
|
|
:param frequency_data: MCU datasheet information of a specific clock frequency
|
|
"""
|
|
i = energy_utils.str_to_float(frequency_data['I'])
|
|
# the datasheet does not provide sufficient information to differentiate clock cycles accessing SRAM from clock cycles that doesn't.
|
|
|
|
data = {
|
|
MCUClockCycleAction.NO_MEMORY_ACCESS: i,
|
|
MCUClockCycleAction.I2C_ACCESS: i,
|
|
MCUClockCycleAction.SPI_ACCESS: i,
|
|
MCUClockCycleAction.LPM_ENTER: i,
|
|
MCUClockCycleAction.LPM_EXIT: i,
|
|
MCUClockCycleAction.VOLATILE_MEMORY_ACCESS: i,
|
|
}
|
|
|
|
return data
|
|
|
|
|
|
def _calculate_ADC_equivalent_r(self, adc_data):
|
|
"""
|
|
:param adc_data: ADC datasheet information
|
|
:return: the equivalent resistance of the ADC
|
|
"""
|
|
nominal_v = self._get_ADC_nominal_v(adc_data)
|
|
current_draw = self._get_ADC_I(adc_data)
|
|
return energy_utils.equivalent_resistance(nominal_v, current_draw)
|
|
|
|
|
|
def _calculate_MCU_LPM_R(self, lpm_data):
|
|
"""
|
|
:param lpm_data: LPM datasheet information
|
|
:return: the equivalent resistance of the MCU in LPM
|
|
"""
|
|
v_lpm = energy_utils.str_to_float(lpm_data['V'])
|
|
i_lpm = energy_utils.str_to_float(lpm_data['I'])
|
|
|
|
return energy_utils.equivalent_resistance(v_lpm, i_lpm)
|
|
|
|
|
|
def _get_MCU_LPM_V_min(self, lpm_data):
|
|
"""
|
|
:param lpm_data: LPM datasheet information
|
|
:return: the minimum voltage required in LPM
|
|
"""
|
|
return energy_utils.str_to_float(lpm_data['V_min'])
|
|
|
|
|
|
def _get_MCU_LPM_t_wakeup(self, lpm_data):
|
|
"""
|
|
:param lpm_data: LPM datasheet information
|
|
:return: the wakeup time from LPM to active mode
|
|
"""
|
|
return energy_utils.str_to_float(lpm_data['t_wakeup'])
|
|
|
|
|
|
def _get_ADC_nominal_v(self, adc_data):
|
|
"""
|
|
:param adc_data: ADC datasheet information
|
|
:return: the nominal voltage at which the current draw of the ADC was measured
|
|
"""
|
|
return energy_utils.str_to_float(adc_data['V'])
|
|
|
|
|
|
def _get_ADC_min_v(self, adc_data):
|
|
"""
|
|
:param adc_data: ADC datasheet information
|
|
:return: the minimum operating voltage of the ADC
|
|
"""
|
|
return energy_utils.str_to_float(adc_data['V_min'])
|
|
|
|
|
|
def _calculate_ADC_wait_cycles(self, adc_data, frequency):
|
|
"""
|
|
Calculates the number of cycles to activate the ADC, wait for its operativity, retrieve data, and turn it off
|
|
:param adc_data: ADC datasheet information
|
|
:param frequency: MCU frequency
|
|
:return: the wait cycles
|
|
"""
|
|
# Time to start the ADC
|
|
t_off_on = energy_utils.str_to_float(adc_data['T_off_on'])
|
|
|
|
# Time to sample data
|
|
t_sample = energy_utils.str_to_float(adc_data['T_sampling'])
|
|
|
|
n_off_on = math.ceil(t_off_on * frequency)
|
|
n_sample = math.ceil(t_sample * frequency)
|
|
|
|
return int(n_off_on + n_sample)
|
|
|
|
|
|
def _get_ADC_instructions(self, adc_data):
|
|
"""
|
|
:param adc_data: ADC datasheet information
|
|
:return: the instructions executed to turn on the ADC, retrieve data, and turn it off
|
|
"""
|
|
# Instructions to init the ADC
|
|
n_init = energy_utils.str_to_int(adc_data['N_init'])
|
|
|
|
# Instructions to transfer data
|
|
n_transfer = energy_utils.str_to_int(adc_data['N_transfer_ops'])
|
|
|
|
# Instructions to turn off the ADC
|
|
n_off = energy_utils.str_to_int(adc_data['N_off'])
|
|
|
|
return {"on": n_init, "transfer": n_transfer, "off": n_off}
|
|
|
|
|
|
def _get_ADC_I(self, adc_data):
|
|
"""
|
|
:param adc_data: ADC datasheet information
|
|
:return: the current draw of the ADC
|
|
"""
|
|
if self.ADC_I_TO_CONSIDER == 'min':
|
|
return energy_utils.str_to_float(adc_data['I_min'])
|
|
|
|
elif self.ADC_I_TO_CONSIDER == 'max':
|
|
return energy_utils.str_to_float(adc_data['I_max'])
|
|
|
|
elif self.ADC_I_TO_CONSIDER == 'avg':
|
|
I_min = energy_utils.str_to_float(adc_data['I_min'])
|
|
I_max = energy_utils.str_to_float(adc_data['I_max'])
|
|
return (I_min + I_max) / 2.0
|