1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Threading; 9 using Antmicro.Renode.Peripherals.Bus; 10 using Antmicro.Renode.Logging; 11 using Antmicro.Renode.Core; 12 using System.Collections.Generic; 13 using Antmicro.Renode.Core.Structure.Registers; 14 using Antmicro.Migrant; 15 using Antmicro.Renode.Time; 16 17 namespace Antmicro.Renode.Peripherals.UART 18 { 19 [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)] 20 public sealed class STM32F7_USART : UARTBase, IUARTWithBufferState, IDoubleWordPeripheral, IKnownSize 21 { STM32F7_USART(IMachine machine, uint frequency, bool lowPowerMode = false)22 public STM32F7_USART(IMachine machine, uint frequency, bool lowPowerMode = false) : base(machine) 23 { 24 IRQ = new GPIO(); 25 ReceiveDmaRequest = new GPIO(); 26 RegistersCollection = new DoubleWordRegisterCollection(this); 27 this.frequency = frequency; 28 this.lowPowerMode = lowPowerMode; 29 DefineRegisters(); 30 } 31 Reset()32 public override void Reset() 33 { 34 base.Reset(); 35 RegistersCollection.Reset(); 36 IRQ.Unset(); 37 receiverTimeoutCancellationTokenSrc?.Cancel(); 38 ReceiveDmaRequest.Unset(); 39 } 40 ReadDoubleWord(long offset)41 public uint ReadDoubleWord(long offset) 42 { 43 return RegistersCollection.Read(offset); 44 } 45 WriteDoubleWord(long offset, uint value)46 public void WriteDoubleWord(long offset, uint value) 47 { 48 RegistersCollection.Write(offset, value); 49 } 50 51 public override uint BaudRate => BaudRateMultiplier * frequency / (uint)baudRateDivisor.Value; 52 53 public override Bits StopBits 54 { 55 get 56 { 57 switch(stopBits.Value) 58 { 59 case 0: 60 return Bits.One; 61 case 1: 62 return Bits.Half; 63 case 2: 64 return Bits.Two; 65 case 3: 66 return Bits.OneAndAHalf; 67 default: 68 throw new InvalidOperationException("Should not reach here."); 69 } 70 } 71 } 72 73 public override Parity ParityBit 74 { 75 get 76 { 77 if(!parityControlEnabled.Value) 78 { 79 return Parity.None; 80 } 81 return paritySelection.Value ? Parity.Odd : Parity.Even; 82 } 83 } 84 85 public BufferState BufferState 86 { 87 get 88 { 89 return bufferState; 90 } 91 92 private set 93 { 94 if(bufferState == value) 95 { 96 return; 97 } 98 bufferState = value; 99 UpdateInterrupt(); 100 BufferStateChanged?.Invoke(value); 101 ReceiveDmaRequest.Set(receiveDmaEnabled.Value && value != BufferState.Empty); 102 } 103 } 104 105 public event Action<BufferState> BufferStateChanged; 106 107 public GPIO IRQ { get; } 108 public GPIO ReceiveDmaRequest { get; } 109 110 public long Size => 0x400; 111 112 public DoubleWordRegisterCollection RegistersCollection { get; } 113 CharWritten()114 protected override void CharWritten() 115 { 116 BufferState = BufferState.Ready; 117 if(receiverTimeoutOccurred != null && receiverTimeoutInterruptEnable.Value) 118 { 119 // We just got a character - cancel the previous action 120 // If it has already executed - then it's alright, since the timeout held 121 receiverTimeoutCancellationTokenSrc?.Cancel(); 122 // Set up a new action to fire after specified time if no characters are received 123 // again, if it receives any, this should be cancelled too, in the exact same way 124 receiverTimeoutCancellationTokenSrc = new CancellationTokenSource(); 125 // Receiver timeout is specified in bits of inactivity, so divide by the baud rate to calculate time 126 // and multiply by 8 since it's a baud rate (measures bits), and by million to convert to microseconds 127 var timeoutIn = (receiverTimeout.Value * 8000000) / BaudRate; 128 Machine.ScheduleAction(TimeInterval.FromMicroseconds(timeoutIn), _ => ReportRxTimeout(receiverTimeoutCancellationTokenSrc.Token), name: $"{nameof(STM32F7_USART)} Receiver timeout"); 129 } 130 } 131 QueueEmptied()132 protected override void QueueEmptied() 133 { 134 BufferState = BufferState.Empty; 135 } 136 137 protected override bool IsReceiveEnabled => receiveEnabled.Value && enabled.Value; 138 DefineRegisters()139 private void DefineRegisters() 140 { 141 var cr1 = Registers.ControlRegister1.Define(RegistersCollection) 142 .WithFlag(0, out enabled, name: "UE") 143 .WithTaggedFlag("UESM", 1) 144 .WithFlag(2, out receiveEnabled, name: "RE") 145 .WithFlag(3, out transmitEnabled, writeCallback: (_, value) => 146 { 147 if(!value) 148 { 149 transferComplete.Value = true; 150 } 151 }, name: "TE") 152 .WithTaggedFlag("IDLEIE", 4) 153 .WithFlag(5, out readRegisterNotEmptyInterruptEnabled, name: "RXNEIE") 154 .WithFlag(6, out transferCompleteInterruptEnabled, name: "TCIE") 155 .WithFlag(7, out transmitRegisterEmptyInterruptEnabled, name: "TXEIE") 156 .WithFlag(8, name: "PEIE") 157 .WithFlag(9, out paritySelection, name: "PS") 158 .WithFlag(10, out parityControlEnabled, name: "PCE") 159 .WithTaggedFlag("WAKE", 11) 160 .WithTaggedFlag("MO", 12) 161 .WithTaggedFlag("MME", 13) 162 .WithTaggedFlag("CMIE", 14) 163 .WithTag("DEDT", 16, 5) 164 .WithTag("DEAT", 21, 5) 165 .WithTaggedFlag("M1", 28) 166 .WithReservedBits(29, 3) 167 .WithWriteCallback((_, __) => UpdateInterrupt()); 168 169 var cr2 = Registers.ControlRegister2.Define(RegistersCollection) 170 .WithReservedBits(0, 4) 171 .WithTaggedFlag("ADDM7", 4) 172 .WithReservedBits(7, 1) 173 .WithValueField(12, 2, out stopBits) 174 .WithTaggedFlag("SWAP", 15) 175 .WithTaggedFlag("RXINV", 16) 176 .WithTaggedFlag("TXINV", 17) 177 .WithTaggedFlag("DATAINV", 18) 178 .WithTaggedFlag("MSBFIRST", 19) 179 .WithTag("ADD", 24, 8); 180 181 var cr3 = Registers.ControlRegister3.Define(RegistersCollection) 182 .WithTaggedFlag("EIE", 0) 183 .WithTaggedFlag("HDSEL", 3) 184 .WithFlag(6, out receiveDmaEnabled, name: "DMAR") 185 .WithFlag(7, name: "DMAT") 186 .WithTaggedFlag("RTSE", 8) 187 .WithTaggedFlag("CTSE", 9) 188 .WithTaggedFlag("CTSIE", 10) 189 .WithTaggedFlag("OVRDIS", 12) 190 .WithTaggedFlag("DDRE", 13) 191 .WithTaggedFlag("DEM", 14) 192 .WithTaggedFlag("DEP", 15) 193 .WithReservedBits(16, 1) 194 .WithTag("WUS", 20, 2) 195 .WithTaggedFlag("WUFIE", 22) 196 .WithTaggedFlag("UCESM", 23) 197 .WithReservedBits(25, 7); 198 199 if(lowPowerMode) 200 { 201 Registers.BaudRate.Define(RegistersCollection) 202 .WithValueField(0, 20, out baudRateDivisor, name: "BRR") 203 .WithReservedBits(20, 12); 204 } 205 else 206 { 207 Registers.BaudRate.Define(RegistersCollection) 208 .WithValueField(0, 16, out baudRateDivisor, name: "BRR") 209 .WithReservedBits(16, 16); 210 } 211 212 var request = Registers.Request.Define(RegistersCollection) 213 .WithFlag(1, FieldMode.Write, name: "SBKRQ") 214 .WithFlag(2, FieldMode.Write, name: "MMRQ") 215 .WithFlag(3, FieldMode.Write, writeCallback: (_, value) => 216 { 217 if(value) 218 { 219 ClearBuffer(); 220 } 221 }, name: "RXFRQ") 222 .WithReservedBits(6, 26); 223 224 var isr = Registers.InterruptAndStatus.Define(RegistersCollection, lowPowerMode ? 0xC0u : 0x200000C0u) 225 .WithTaggedFlag("PE", 0) 226 .WithTaggedFlag("FE", 1) 227 .WithTaggedFlag("NF", 2) 228 .WithTaggedFlag("ORE", 3) 229 .WithTaggedFlag("IDLE", 4) 230 .WithFlag(5, FieldMode.Read, valueProviderCallback: _ => (Count != 0), name: "RXNE") 231 .WithFlag(6, out transferComplete, FieldMode.Read, name: "TC") 232 .WithFlag(7, FieldMode.Read, name: "TXE", valueProviderCallback: _ => true) 233 .WithTaggedFlag("CTSIF", 9) 234 .WithTaggedFlag("CTS", 10) 235 .WithReservedBits(13, 1) 236 .WithTaggedFlag("BUSY", 16) 237 .WithTaggedFlag("CMF", 17) 238 .WithTaggedFlag("SBKF", 18) 239 .WithTaggedFlag("RWU", 19) 240 .WithTaggedFlag("WUF", 20) 241 .WithFlag(21, FieldMode.Read, name: "TEACK", valueProviderCallback: _ => transmitEnabled.Value) 242 .WithFlag(22, FieldMode.Read, name: "REACK", valueProviderCallback: _ => receiveEnabled.Value) 243 .WithReservedBits(23, 2) 244 .WithReservedBits(26, 6); 245 246 var icr = Registers.InterruptFlagClear.Define(RegistersCollection) 247 .WithTaggedFlag("PECF", 0) 248 .WithTaggedFlag("FECF", 1) 249 .WithTaggedFlag("NCF", 2) 250 .WithTaggedFlag("ORECF", 3) 251 .WithTaggedFlag("IDLECF", 4) 252 .WithReservedBits(5, 1) 253 // the TC flag is cleared by writing 1 to TCCF 254 .WithFlag(6, FieldMode.Read | FieldMode.WriteOneToClear, name: "TCCF", 255 writeCallback: (_, val) => { if(val) transferComplete.Value = false; }) 256 .WithTaggedFlag("CTSCF", 9) 257 .WithReservedBits(10, 1) 258 .WithReservedBits(13, 4) 259 .WithTaggedFlag("CMCF", 17) 260 .WithReservedBits(18, 2) 261 .WithTaggedFlag("WUCF", 20) 262 .WithReservedBits(21, 11) 263 .WithWriteCallback((_, __) => UpdateInterrupt()); 264 265 Registers.ReceiveData.Define(RegistersCollection) 266 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => HandleReceiveData(), name: "RDR") 267 .WithReservedBits(8, 24); 268 269 Registers.TransmitData.Define(RegistersCollection) 270 .WithValueField(0, 8, 271 // reading this register will intentionally return the last written value 272 writeCallback: (_, val) => HandleTransmitData((uint)val), name: "TDR") 273 .WithReservedBits(8, 24); 274 275 if(lowPowerMode) 276 { 277 cr1 278 .WithReservedBits(15, 1) 279 .WithReservedBits(26, 2); 280 281 cr2 282 .WithReservedBits(5, 2) 283 .WithReservedBits(8, 4) 284 .WithReservedBits(14, 1) 285 .WithReservedBits(20, 4); 286 287 cr3 288 .WithReservedBits(1, 2) 289 .WithReservedBits(4, 2) 290 .WithReservedBits(11, 1) 291 .WithReservedBits(17, 3) 292 .WithReservedBits(24, 1); 293 294 request 295 .WithReservedBits(0, 1) 296 .WithReservedBits(5, 1); 297 298 isr 299 .WithReservedBits(8, 1) 300 .WithReservedBits(11, 2) 301 .WithReservedBits(14, 2) 302 .WithReservedBits(25, 1); 303 304 icr 305 .WithReservedBits(7, 2) 306 .WithReservedBits(11, 2); 307 } 308 else 309 { 310 Registers.ReceiverTimeout.Define(RegistersCollection) 311 .WithValueField(0, 24, out receiverTimeout, name: "RTO (Receiver Timeout value)") 312 .WithTag("BLEN (Block length)", 24, 8); 313 314 cr1 315 .WithFlag(15, out over8, name: "OVER8") 316 .WithFlag(26, out receiverTimeoutInterruptEnable, name: "RTOIE") 317 .WithTaggedFlag("EOBIE", 27) 318 .WithWriteCallback((_, __) => 319 { 320 // Need to cancel the previous receiverTimeout here 321 if(!enabled.Value || !receiveEnabled.Value || !receiverTimeoutInterruptEnable.Value) 322 { 323 receiverTimeoutCancellationTokenSrc?.Cancel(); 324 } 325 } 326 ); 327 328 cr2 329 .WithTaggedFlag("LBDL", 5) 330 .WithTaggedFlag("LBDIE", 6) 331 .WithTaggedFlag("LBCL", 8) 332 .WithTaggedFlag("CPHA", 9) 333 .WithTaggedFlag("CPOL", 10) 334 .WithTaggedFlag("CLKEN", 11) 335 .WithTaggedFlag("LINEN", 14) 336 .WithTaggedFlag("ABREN", 20) 337 .WithTag("ABRMOD", 21, 2) 338 .WithTaggedFlag("RTOEN", 23); 339 340 cr3 341 .WithTaggedFlag("IREN", 1) 342 .WithTaggedFlag("IRLP", 2) 343 .WithTaggedFlag("NACK", 4) 344 .WithTaggedFlag("SCEN", 5) 345 .WithTaggedFlag("ONEBIT", 11) 346 .WithTag("SCARCNT", 17, 3) 347 .WithTaggedFlag("TCBGTIE", 24); 348 349 request 350 .WithTaggedFlag("ABRRQ", 0) 351 .WithTaggedFlag("TXFRQ", 5); 352 353 isr 354 .WithTaggedFlag("LBDF", 8) 355 .WithFlag(11, FieldMode.Read, valueProviderCallback: _ => receiverTimeoutInterruptEnable.Value && (receiverTimeoutOccurred?.Value ?? false), name: "RTOF") 356 .WithTaggedFlag("EOBF", 12) 357 .WithTaggedFlag("ABRE", 14) 358 .WithTaggedFlag("ABRF", 15) 359 .WithTaggedFlag("TCBGT", 25); 360 361 icr 362 .WithTaggedFlag("TCBGTCF", 7) 363 .WithTaggedFlag("LBDCF", 8) 364 .WithFlag(11, out receiverTimeoutOccurred, FieldMode.WriteOneToClear, name: "RTOCF") 365 .WithTaggedFlag("EOBCF", 12) 366 .WithWriteCallback((_, __) => UpdateInterrupt()); 367 } 368 } 369 HandleTransmitData(uint value)370 private void HandleTransmitData(uint value) 371 { 372 if(transmitEnabled.Value && enabled.Value) 373 { 374 base.TransmitCharacter((byte)value); 375 transferComplete.Value = true; 376 UpdateInterrupt(); 377 } 378 else 379 { 380 this.Log(LogLevel.Warning, "Char was to be sent, but the transmitter (or the whole USART) is not enabled. Ignoring."); 381 } 382 } 383 HandleReceiveData()384 private uint HandleReceiveData() 385 { 386 if(!TryGetCharacter(out var result)) 387 { 388 this.Log(LogLevel.Warning, "No characters in queue."); 389 } 390 return result; 391 } 392 UpdateInterrupt()393 private void UpdateInterrupt() 394 { 395 var transmitRegisterEmptyInterrupt = transmitRegisterEmptyInterruptEnabled.Value; // we assume that transmit register is always empty 396 var transferCompleteInterrupt = transferComplete.Value && transferCompleteInterruptEnabled.Value; 397 var readRegisterNotEmptyInterrupt = Count != 0 && readRegisterNotEmptyInterruptEnabled.Value; 398 399 // This interrupt is expected to fire if there are not additional bits incoming after some specified time after last reception 400 var receiverTimeoutInterrupt = (receiverTimeoutOccurred?.Value ?? false) && receiverTimeoutInterruptEnable.Value; 401 402 IRQ.Set(transmitRegisterEmptyInterrupt || transferCompleteInterrupt || readRegisterNotEmptyInterrupt || receiverTimeoutInterrupt); 403 } 404 ReportRxTimeout(CancellationToken ct)405 private void ReportRxTimeout(CancellationToken ct) 406 { 407 if(!ct.IsCancellationRequested) 408 { 409 receiverTimeoutOccurred.Value = true; 410 UpdateInterrupt(); 411 } 412 } 413 414 private CancellationTokenSource receiverTimeoutCancellationTokenSrc; 415 416 private IFlagRegisterField parityControlEnabled; 417 private IFlagRegisterField paritySelection; 418 private IFlagRegisterField transmitRegisterEmptyInterruptEnabled; 419 private IFlagRegisterField transferCompleteInterruptEnabled; 420 private IFlagRegisterField transferComplete; 421 private IFlagRegisterField readRegisterNotEmptyInterruptEnabled; 422 private IFlagRegisterField transmitEnabled; 423 private IFlagRegisterField receiveEnabled; 424 private IFlagRegisterField receiveDmaEnabled; 425 private IFlagRegisterField enabled; 426 private IValueRegisterField baudRateDivisor; 427 private IValueRegisterField stopBits; 428 private IFlagRegisterField over8; 429 private IFlagRegisterField receiverTimeoutInterruptEnable; 430 private IFlagRegisterField receiverTimeoutOccurred; 431 private IValueRegisterField receiverTimeout; 432 433 private BufferState bufferState; 434 435 private readonly uint frequency; 436 private readonly bool lowPowerMode; 437 438 private uint BaudRateMultiplier => lowPowerMode ? 256u : over8.Value ? 2u : 1u; 439 440 private enum Registers 441 { 442 ControlRegister1 = 0x0, 443 ControlRegister2 = 0x4, 444 ControlRegister3 = 0x8, 445 BaudRate = 0xC, 446 ReceiverTimeout = 0x14, 447 Request = 0x18, 448 InterruptAndStatus = 0x1C, 449 InterruptFlagClear = 0x20, 450 ReceiveData = 0x24, 451 TransmitData = 0x28, 452 } 453 } 454 } 455 456