Files
simulation_Peripheral/UART_kx12A6_event.cs
yangyanqing 1bad9fd8ce 更新 UART_kx12A6_event.cs
修改TransmitCharacter函数
2026-05-07 10:26:26 +08:00

502 lines
17 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// UART 外设实现
// 基于 UART 规格,包含完整的 FIFO、中断和调制解调器控制功能
//
using System;
using System.Collections.Generic;
using Antmicro.Renode.Core;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Peripherals.UART;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Time;
using Antmicro.Migrant;
namespace Antmicro.Renode.Peripherals.CustomPeripherals
{
/// <summary>
/// UART_771_RUHW_2CFG 控制器:同步串口、遥测、有中断
/// 接收缓存0B发送缓存2048B输入时钟24MHz
/// </summary>
public class UART_771_RUHW_2CFG6 : IDoubleWordPeripheral, IKnownSize
{
private readonly IMachine machine;
private readonly object txFifoLock = new object();
private readonly object rxFifoLock = new object();
public UART_771_RUHW_2CFG6(IMachine machine)
{
this.clockFrequency = 24000000;
this.machine = machine;
transmissionGeneration = 0;
// 创建 FIFO
txFifo = new Queue<byte>();
rxFifo = new Queue<byte>();
// 创建中断线
IRQ = new GPIO();
// 初始化寄存器
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "771 UART initialized, clock: {0} Hz", clockFrequency);
}
public void Reset()
{
lock(txFifoLock)
{
txFifo.Clear();
}
lock(rxFifoLock)
{
rxFifo.Clear();
}
fsta = FSTA_TEMP; // FIFO状态寄存器
frm_cnt = 0; // 帧计数
byte_cnt = 0;
tbr = 0; // 发送FIFO剩余字节数
currentBaudRate = 16384; // 时钟配置缺省为16384Hz
clk_set = (ushort)(clockFrequency / (2 * currentBaudRate) - 1);
scramble_ctrl = 0x00; // 加解扰使能禁止
rstr = 0x00; // 复位/使能寄存器
RxfifoEnabled = true;
TxfifoEnabled = true; //发送fifo使能
transmissionScheduled = false;
transmissionGeneration++;
InterruptTriggerCondition = false; //重置后不满足条件
IRQ.Set(false);
UpdateInterrupts();
this.Log(LogLevel.Info, "TX_FIFO_SIZE reset");
}
private void DefineRegisters()
{
// 寄存器访问通过 ReadDoubleWord/WriteDoubleWord 实现
}
// ========================================
// IBusPeripheral 接口实现
// ========================================
public uint ReadDoubleWord(long offset)
{
return ReadRegisters(offset);
}
public void WriteDoubleWord(long offset, uint value)
{
WriteRegisters(offset, value);
}
// ========================================
// 自定义
// ========================================
public uint ReadRegisters(long offset)
{
uint value = 0;
switch (offset)
{
case (long)Registers.FSTA: // FIFO状态寄存器
value = (byte)(fsta & 0xFF);
this.Log(LogLevel.Info, "Read FSTA: 0x{0:X2}", value);
break;
case (long)Registers.FRM_CNT: //帧计数,待定
value = (uint)frm_cnt;
this.Log(LogLevel.Info, "Read TBR_FreeBytes: {0}", value);
break;
case (long)Registers.TBR_FreeBytes: //发送FIFO剩余字节数
lock(txFifoLock)
{
tbr = (ushort)txFifo.Count;
}
value = (uint)tbr;
this.Log(LogLevel.Info, "Read TBR_FreeBytes: {0}", value);
break;
case (long)Registers.CLK_SET: //时钟配置,暂无读操作
value = (uint)clk_set;
this.Log(LogLevel.Info, "Read CLK_SET: {0}", value);
break;
case (long)Registers.SCRAMBLE_CTRL: //加解扰使能禁止,暂无读操作
value = (uint)(scramble_ctrl & 0xFF);
this.Log(LogLevel.Info, "Read SCRAMBLE_CTRL: 0x{0}", value);
break;
case (long)Registers.RSTR: // 复位/使能,暂无读操作
value = (uint)(rstr & 0xFF);
this.Log(LogLevel.Info, "Read RSTR: 0x{0}", value);
break;
default:
this.Log(LogLevel.Warning, "Read to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
return value;
}
public void WriteRegisters(long offset, uint value)
{
switch (offset)
{
case (long)Registers.TBR_RBR: // 发送FIFO
WriteTBR(value);
//this.Log(LogLevel.Info, "Write TBR_RBR: {0}", value);
break;
case (long)Registers.CLK_SET: // 时钟配置
clk_set = (ushort)value;
currentBaudRate = (ushort)(clockFrequency / 2 / (1 + value));
this.Log(LogLevel.Info, "Write CLK_SET: {0}, currentBaudRate: {1}", value, currentBaudRate);
// 计算传输速率
ComputeTransRate();
break;
case (long)Registers.SCRAMBLE_CTRL: // 加解扰使能禁止
scramble_ctrl = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write SCRAMBLE_CTRL: 0x{0:X2}", value);
break;
case (long)Registers.RSTR: // 复位/使能
rstr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write RSTR: 0x{0:X2}", rstr);
if ((rstr & 0XFF) == RSTR_RES)
{
Reset();
}
break;
default:
this.Log(LogLevel.Warning, "Write to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
}
// ========================================
// 按波特率计算传输速率,同步串口无起始位、停止位、奇偶校验位
// ========================================
public void ComputeTransRate()
{
// 计算传输时间
int bitsPerByte = 8; // 数据位
// 计算传输时间(秒),16384hz->488.24us
if(currentBaudRate == 0)
{
return;
}
double secondsPerByte = (double)bitsPerByte / currentBaudRate;
microsecondsPerByte = (ulong)(secondsPerByte * 1000000);
this.Log(LogLevel.Debug,
"Scheduling byte transmission: {0} bits @ {1} bps = {2}μs",
bitsPerByte, currentBaudRate, microsecondsPerByte);
}
private void UpdateInterrupts()
{
if(InterruptTriggerCondition == false)
{
// FIFO空 → 必须先写满>64期间绝对不触发中断
IRQ.Set(false);
return;
}
lock(txFifoLock)
{
// <64 中断,>96 清除,中间保持
if (txFifo.Count < IRQ_MINBYTES)
{
IRQ.Set(true);
this.Log(LogLevel.Info, "Interrupt asserted");
}
else if (txFifo.Count > IRQ_MAXBYTES)
{
IRQ.Set(false);
}
}
}
public void WriteTBR(uint value)
{
// 从星务接收数据 操作txFifo
// value 低16位有效
this.Log(LogLevel.Info, "Write TBR: 0x{0:X2}", value);
lock(txFifoLock)
{
if (TxfifoEnabled)
{
if ((txFifo.Count + 2) <= TX_FIFO_SIZE)
{
bool wasEmpty = (txFifo.Count == 0);
byte tmp = (byte)(value >> 8);
txFifo.Enqueue(tmp);
tmp = (byte)value;
txFifo.Enqueue(tmp);
fsta = (byte)(fsta & (~FSTA_TEMP)); // 发送缓冲区不为空D0置0
// 更新帧计数
byte_cnt += 2;
frm_cnt = (ushort)(byte_cnt / FRAME_LONG); // 遥测帧固定1024字节
// FIFO从空变为非空
if(wasEmpty)
{
this.Log(LogLevel.Info, "FIFO: Empty->NonEmpty");
// 启动传输调度(事件驱动)
ScheduleNextByteTransmit();
}
if (txFifo.Count >= (TX_FIFO_SIZE / 2))
{
// 置半满标志
fsta = (byte)(fsta | FSTA_TLHF); // 发送FIFO半满,D2置1
}
if((InterruptTriggerCondition == false) && (txFifo.Count > IRQ_MINBYTES))
{
InterruptTriggerCondition = true;
UpdateInterrupts();
}
}
else
{
fsta = (byte)(fsta | FSTA_TFUL); // 发送FIFO满
this.Log(LogLevel.Warning, "TX FIFO overflow");
}
}
else
{
// 非 FIFO 模式,待定
txFifo.Clear();
txFifo.Enqueue((byte)value);
fsta = (byte)(fsta & (~FSTA_TEMP)); // 发送缓冲区不为空D0置0
}
}
}
// ========================================
// 核心:按波特率调度发送(事件驱动)
// ========================================
private void ScheduleNextByteTransmit()
{
lock(txFifoLock)
{
// 防止重复调度
if (transmissionScheduled)
{
return;
}
if (txFifo.Count == 0)
{
// FIFO空
fsta = (byte)((fsta & 0xF0) | FSTA_TEMP);
fsta |= FSTA_THHF; //空闲置1
this.Log(LogLevel.Info, "TX FIFO empty");
InterruptTriggerCondition = false;
return;
}
if (txFifo.Count < (TX_FIFO_SIZE / 2))
{
// 清半满标志
fsta = (byte)(fsta & (~FSTA_TLHF)); // 发送FIFO非半满D2清0
}
transmissionScheduled = true;
fsta = (byte)(fsta & (~FSTA_THHF)); //正在发送置0
var currentGeneration = transmissionGeneration;
// 使用Renode虚拟时间调度
machine.ScheduleAction(
TimeInterval.FromMicroseconds(microsecondsPerByte),
_ => TransmitOneByte(currentGeneration)
);
}
}
private void TransmitOneByte(ulong generation)
{
lock(txFifoLock)
{
transmissionScheduled = false;
// 检查是否被Reset取消
if (generation != transmissionGeneration)
{
this.Log(LogLevel.Debug, "Transmission cancelled (reset)");
return;
}
if (txFifo.Count > 0)
{
byte data = txFifo.Dequeue();
// 触发CharReceived事件外部Backend可订阅 网络中间层改为订阅这个事件的方式)
TransmitCharacter(data);
this.Log(LogLevel.Info,
"Transmitted: 0x{0:X2} ('{1}'), Remaining: {2}",
data,
(data >= 32 && data < 127) ? (char)data : '.',
txFifo.Count);
// 继续调度下一个字节
UpdateInterrupts();
ScheduleNextByteTransmit();
}
}
}
public string GetTXFIFODataString()
{
string data = "0x";
byte tmp;
// 从 TX FIFO 发送数据中间层获取txfifo接口
if(txFifo.Count == 0)
{
this.Log(LogLevel.Info, "TXFIFO Null");
return "0x00";
}
while (txFifo.Count > 0)
{
tmp = txFifo.Dequeue();
data += tmp.ToString("X2"); // 转换为16进制字符串
}
this.Log(LogLevel.Info, "Transmitted: 0x{0}, TXFIFO Null", data);
UpdateInterrupts();
return data;
}
// ========================================
// 同步串口属性
// ========================================
public uint BaudRate => 0;
public enum Bits { None }
public Bits StopBits => Bits.None;
public enum Parity { None }
public Parity ParityBit => Parity.None;
public uint GetFSTA() => fsta;
public uint GetByteCount() => byte_cnt;
public ushort GetFrameCount() => frm_cnt;
public event Action<byte> CharReceived;
private void TransmitCharacter(byte data)
{
CharReceived?.Invoke(data);
}
public long Size => 0x80; //uart地址长度总空间
public GPIO IRQ { get; }
// ========================================
// 寄存器定义
// ========================================
private enum Registers : long
{
TBR_RBR = 0x00, // TBR发送FIFO
FSTA = 0x04, // FIFO状态寄存器
FRM_CNT = 0x08, // 帧计数
TBR_FreeBytes = 0x0C, // 发送FIFO剩余字节数
CLK_SET = 0x10, // 时钟配置
SCRAMBLE_CTRL = 0x14, // 加解扰使能禁止
RSTR = 0x7C // 复位/使能 x55复位其他使能
}
// FSTA FIFO状态寄存器
private const byte FSTA_TEMP = 0x01; // 发送FIFO空
private const byte FSTA_TLHF= 0x02; // 发送FIFO半满
private const byte FSTA_TFUL = 0x04; // 发送FIFO满
private const byte FSTA_THHF = 0x08; // 1为空闲0为正在发送
// RSTR 复位/使能寄存器
private const byte RSTR_RES = 0x55; // 0x55复位其他使能
private const byte SCRAMBLE_CTRL_ENABLE = 0x55; // 0x55加解扰使能其他禁止
// 常量
private const int RX_FIFO_SIZE = 0; // 接收FIFO_SIZE
private const int TX_FIFO_SIZE = 2048; // 发送FIFO_SIZE
private const int FRAME_LONG = 1024; // 帧长固定为1024B
private const int IRQ_MINBYTES = 64; // FIFO中的字节数小于64字节时会产生中断
private const int IRQ_MAXBYTES = 96; // FIFO中的字节数大于96字节时会清中断
// ========================================
// 私有字段
// ========================================
private readonly uint clockFrequency;
private uint currentBaudRate;
private uint byte_cnt; // 字节计数,计算帧计数
// 寄存器
private byte fsta; // FIFO状态寄存器
private ushort frm_cnt; // 帧计数
private ushort tbr; // 发送FIFO剩余字节数
private ushort clk_set; // 时钟配置
private byte scramble_ctrl; // 加解扰使能禁止
private byte rstr; // 复位/使能
// FIFO
private readonly Queue<byte> rxFifo;
private readonly Queue<byte> txFifo;
private bool RxfifoEnabled;
private bool TxfifoEnabled;
private bool transmissionScheduled;
private ulong transmissionGeneration;
private ulong microsecondsPerByte;
private bool InterruptTriggerCondition; //FIFO为空后写入64字节才允许触发中断
}
}