1 // 2 // Copyright (c) 2010-2022 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 8 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Core.Structure.Registers; 10 using Antmicro.Renode.Logging; 11 12 namespace Antmicro.Renode.Peripherals.Miscellaneous 13 { 14 public class STM32L0_PWR : BasicDoubleWordPeripheral, IKnownSize 15 { STM32L0_PWR(IMachine machine)16 public STM32L0_PWR(IMachine machine) : base(machine) 17 { 18 IRQ = new GPIO(); 19 20 Registers.PowerControl.Define(this, 0x1000) 21 // The LPSDSR flag has no functionality because low-power run mode is not implemented 22 .WithFlag(0, name: "LPSDSR") 23 .WithTaggedFlag("PDDS", 1) 24 .WithFlag(2, FieldMode.WriteOneToClear, writeCallback: (_, __) => wakeupFlag.Value = false, name: "CWUF") 25 .WithFlag(3, FieldMode.WriteOneToClear, writeCallback: (_, __) => standbyFlag.Value = false, name: "CSBF") 26 .WithFlag(4, out pvdEnableFlag, name: "PVDE") 27 .WithEnumField<DoubleWordRegister, PvdLevelSelection>(5, 3, out pvdLevel, writeCallback: (_, value) => 28 { 29 if(value == PvdLevelSelection.ExternalInput) 30 { 31 this.Log(LogLevel.Warning, "External PVD input selected, this is not supported"); 32 } 33 }, name: "PLS") 34 .WithFlag(8, name: "DBP") 35 .WithTaggedFlag("ULP", 9) 36 .WithTaggedFlag("FWU", 10) 37 .WithEnumField<DoubleWordRegister, VoltageScalingRangeSelection>(11, 2, out vosValue, name: "VOS", writeCallback: (oldValue, value) => 38 { 39 if(value == VoltageScalingRangeSelection.Forbidden) 40 { 41 this.Log(LogLevel.Warning, "Trying to set forbidden VOS value, ignoring write"); 42 vosValue.Value = oldValue; 43 } 44 }) 45 .WithTaggedFlag("DS_EE_KOFF", 13) 46 .WithTaggedFlag("LPRUN", 14) 47 .WithReservedBits(15, 1) 48 .WithTaggedFlag("LPDS", 16) 49 .WithReservedBits(17, 15); 50 51 Registers.PowerControlStatus.Define(this, 0x8) 52 .WithFlag(0, out wakeupFlag, FieldMode.Read, name: "WUF") 53 .WithFlag(1, out standbyFlag, FieldMode.Read, name: "SBF") 54 .WithFlag(2, out pvdoFlag, FieldMode.Read, name: "PVDO") 55 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => true, name: "VREFINTRDYF") 56 .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => false, name: "VOSF") 57 .WithFlag(5, FieldMode.Read, valueProviderCallback: _ => false, name: "REGLPF") 58 .WithReservedBits(6, 2) 59 .WithTaggedFlag("EWUP1", 8) 60 .WithTaggedFlag("EWUP2", 9) 61 .WithTaggedFlag("EWUP3", 10) 62 .WithReservedBits(11, 21); 63 64 Reset(); 65 } 66 Reset()67 public override void Reset() 68 { 69 base.Reset(); 70 IRQ.Unset(); 71 Voltage = 3.3; 72 prevPvdo = false; 73 } 74 75 public long Size => 0x400; 76 public GPIO IRQ { get; } 77 78 public double? ThresholdVoltage 79 { 80 get 81 { 82 if(pvdLevel.Value == PvdLevelSelection.ExternalInput) 83 { 84 return null; 85 } 86 else 87 { 88 return 1.9 + (int)pvdLevel.Value * 0.2; 89 } 90 } 91 } 92 93 public double Voltage 94 { 95 get 96 { 97 return voltage; 98 } 99 set 100 { 101 voltage = value; 102 UpdatePvd(); 103 } 104 } 105 106 public PvdLevelSelection PvdLevel 107 { 108 get 109 { 110 return pvdLevel.Value; 111 } 112 set 113 { 114 pvdLevel.Value = value; 115 UpdatePvd(); 116 } 117 } 118 UpdatePvd()119 private void UpdatePvd() 120 { 121 bool pvdo; 122 if(prevPvdo && Voltage > ThresholdVoltage + Hysteresis) 123 { 124 // PVDO should be false if the voltage was below and is above the threshold 125 pvdo = false; 126 } 127 else if(!prevPvdo && Voltage < ThresholdVoltage - Hysteresis) 128 { 129 // PVDO should be true if the voltage was above and is below the threshold 130 pvdo = true; 131 } 132 else 133 { 134 // No change (within hysteresis) 135 pvdo = prevPvdo; 136 } 137 prevPvdo = pvdo; 138 pvdo &= pvdEnableFlag.Value; 139 140 pvdoFlag.Value = pvdo; 141 IRQ.Set(pvdo); 142 } 143 144 private IFlagRegisterField wakeupFlag; 145 private IFlagRegisterField standbyFlag; 146 private IFlagRegisterField pvdoFlag; 147 private IFlagRegisterField pvdEnableFlag; 148 private IEnumRegisterField<PvdLevelSelection> pvdLevel; 149 private IEnumRegisterField<VoltageScalingRangeSelection> vosValue; 150 private double voltage; 151 private bool prevPvdo; 152 153 private const double Hysteresis = 0.1; 154 155 public enum PvdLevelSelection 156 { 157 V1_9, 158 V2_1, 159 V2_3, 160 V2_5, 161 V2_7, 162 V2_9, 163 V3_1, 164 ExternalInput, 165 } 166 167 private enum Registers 168 { 169 PowerControl = 0x00, 170 PowerControlStatus = 0x04, 171 } 172 173 private enum VoltageScalingRangeSelection 174 { 175 Forbidden, 176 Range1_V1_8, 177 Range2_V1_5, 178 Range3_V1_2, 179 } 180 } 181 } 182