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