627 lines
21 KiB
C#
627 lines
21 KiB
C#
|
|
// <20><><EFBFBD>ϵز<CFB5><D8B2>жϸ<D0B6><CFB8>İ汾
|
|||
|
|
//author:liuwenbo
|
|||
|
|
// <20><EFBFBD>Ϊ<EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϴ<D0B6><CFB4><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
|
|||
|
|
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.Time;
|
|||
|
|
|
|||
|
|
namespace Antmicro.Renode.Peripherals.CustomPeripherals
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// UART_771_RUHW_2CFG <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
/// <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD>1024B<34><42><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD>2048B<38><42>ʱ<EFBFBD><CAB1>24MHz
|
|||
|
|
/// <20>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>汾 - ʹ<><CAB9>machine.ScheduleAction<6F><6E>ȷģ<C8B7>Ⲩ<EFBFBD><E2B2A8><EFBFBD><EFBFBD>
|
|||
|
|
/// </summary>
|
|||
|
|
public class UART_771_RUHW_2CFG4 : IDoubleWordPeripheral, IKnownSize, IUART
|
|||
|
|
{
|
|||
|
|
private readonly IMachine machine;
|
|||
|
|
private readonly object txFifoLock = new object();
|
|||
|
|
private readonly object rxFifoLock = new object();
|
|||
|
|
|
|||
|
|
public UART_771_RUHW_2CFG4(IMachine machine)
|
|||
|
|
{
|
|||
|
|
this.clockFrequency = 24000000;
|
|||
|
|
this.machine = machine;
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD> FIFO
|
|||
|
|
rxFifo = new Queue<byte>();
|
|||
|
|
txFifo = new Queue<byte>();
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><D0B6><EFBFBD>
|
|||
|
|
IRQ = new GPIO();
|
|||
|
|
|
|||
|
|
// <20><>ʼ<EFBFBD><CABC><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD>
|
|||
|
|
DefineRegisters();
|
|||
|
|
Reset();
|
|||
|
|
|
|||
|
|
this.Log(LogLevel.Info, "771 UART initialized (event-driven), clock: {0} Hz", clockFrequency);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void Reset()
|
|||
|
|
{
|
|||
|
|
lock(txFifoLock)
|
|||
|
|
{
|
|||
|
|
txFifo.Clear();
|
|||
|
|
}
|
|||
|
|
lock(rxFifoLock)
|
|||
|
|
{
|
|||
|
|
rxFifo.Clear();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ucr = 0x00;
|
|||
|
|
usr = USR_TFE; // <20><>ʼFIFO<46><4F>
|
|||
|
|
mcr = 0x00;
|
|||
|
|
brsr = 0;
|
|||
|
|
fsta = (byte)(FSTA_TEMP | FSTA_REMP);
|
|||
|
|
tbr = 0;
|
|||
|
|
rbr = 0;
|
|||
|
|
rstr = 0x00;
|
|||
|
|
|
|||
|
|
RxfifoEnabled = true;
|
|||
|
|
TxfifoEnabled = true;
|
|||
|
|
fifoTriggerLevel = 1;
|
|||
|
|
|
|||
|
|
transmissionScheduled = false;
|
|||
|
|
transmissionGeneration++;
|
|||
|
|
|
|||
|
|
IRQ.Set(false);
|
|||
|
|
UpdateInterrupts();
|
|||
|
|
|
|||
|
|
this.Log(LogLevel.Info, "UART reset");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void DefineRegisters()
|
|||
|
|
{
|
|||
|
|
// <20>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8> ReadDoubleWord/WriteDoubleWord ʵ<><CAB5>
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ========================================
|
|||
|
|
// IBusPeripheral <20>ӿ<EFBFBD>ʵ<EFBFBD><CAB5>
|
|||
|
|
// ========================================
|
|||
|
|
public uint ReadDoubleWord(long offset)
|
|||
|
|
{
|
|||
|
|
return ReadRegisters(offset);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void WriteDoubleWord(long offset, uint value)
|
|||
|
|
{
|
|||
|
|
WriteRegisters(offset, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ========================================
|
|||
|
|
// <20>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD>ȡ
|
|||
|
|
// ========================================
|
|||
|
|
public uint ReadRegisters(long offset)
|
|||
|
|
{
|
|||
|
|
uint value = 0;
|
|||
|
|
|
|||
|
|
switch (offset)
|
|||
|
|
{
|
|||
|
|
case (long)Registers.TBR_RBR:
|
|||
|
|
value = ReadRBR();
|
|||
|
|
this.Log(LogLevel.Info, "Read RBR: 0x{0:X2}", value);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case (long)Registers.UCR_USR:
|
|||
|
|
value = (byte)(usr & 0xFF);
|
|||
|
|
this.Log(LogLevel.Info, "Read USR: 0x{0:X2}", value);
|
|||
|
|
// <20><>ȡUSR<53><52><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϱ<D0B6>־
|
|||
|
|
usr = (byte)(usr & (~(USR_RBFI | USR_TCMP)));
|
|||
|
|
UpdateInterrupts();
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case (long)Registers.MCR:
|
|||
|
|
value = (byte)(mcr & 0xFF);
|
|||
|
|
this.Log(LogLevel.Info, "Read MCR: 0x{0:X2}", value);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case (long)Registers.BRSR:
|
|||
|
|
value = (uint)(brsr);
|
|||
|
|
this.Log(LogLevel.Debug, "Read BRSR: {0}", value);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case (long)Registers.FSTA:
|
|||
|
|
value = (byte)(fsta & 0xFF);
|
|||
|
|
this.Log(LogLevel.Debug, "Read FSTA: 0x{0:X2}", value);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case (long)Registers.TBR_FreeBytes:
|
|||
|
|
lock(txFifoLock)
|
|||
|
|
{
|
|||
|
|
tbr = (ushort)txFifo.Count;
|
|||
|
|
}
|
|||
|
|
value = (uint)tbr;
|
|||
|
|
this.Log(LogLevel.Debug, "Read TBR_FreeBytes: {0}", value);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case (long)Registers.RBR_FreeBytes:
|
|||
|
|
lock(rxFifoLock)
|
|||
|
|
{
|
|||
|
|
rbr = (ushort)rxFifo.Count;
|
|||
|
|
}
|
|||
|
|
value = (uint)rbr;
|
|||
|
|
this.Log(LogLevel.Debug, "Read RBR_FreeBytes: {0}", value);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case (long)Registers.RSTR:
|
|||
|
|
value = (uint)rstr;
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
default:
|
|||
|
|
this.Log(LogLevel.Warning, "Read to unknown offset: 0x{0:X}", offset);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return value;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ========================================
|
|||
|
|
// <20>Ĵ<EFBFBD><C4B4><EFBFBD>д<EFBFBD><D0B4>
|
|||
|
|
// ========================================
|
|||
|
|
public void WriteRegisters(long offset, uint value)
|
|||
|
|
{
|
|||
|
|
switch (offset)
|
|||
|
|
{
|
|||
|
|
case (long)Registers.TBR_RBR:
|
|||
|
|
WriteTBR((byte)value);
|
|||
|
|
this.Log(LogLevel.Info, "Write TBR: 0x{0:X2}", value);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case (long)Registers.UCR_USR:
|
|||
|
|
ucr = (byte)(value & 0xFF);
|
|||
|
|
this.Log(LogLevel.Info, "Write UCR: 0x{0:X2}", ucr);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case (long)Registers.MCR:
|
|||
|
|
mcr = (byte)(value & 0xFF);
|
|||
|
|
this.Log(LogLevel.Info, "Write MCR: 0x{0:X2}", mcr);
|
|||
|
|
UpdateModemControl();
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case (long)Registers.BRSR:
|
|||
|
|
if(value != 0)
|
|||
|
|
{
|
|||
|
|
currentBaudRate = (uint)(clockFrequency / value);
|
|||
|
|
brsr = (ushort)value;
|
|||
|
|
this.Log(LogLevel.Info, "Write BRSR: {0}, BaudRate: {1}", brsr, currentBaudRate);
|
|||
|
|
}
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ========================================
|
|||
|
|
// <20>жϹ<D0B6><CFB9><EFBFBD>
|
|||
|
|
// ========================================
|
|||
|
|
private void UpdateInterrupts()
|
|||
|
|
{
|
|||
|
|
bool interrupt = false;
|
|||
|
|
|
|||
|
|
if ((mcr & MCR_BEN) != 0)
|
|||
|
|
{
|
|||
|
|
if ((usr & USR_TCMP) != 0) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>
|
|||
|
|
interrupt = true;
|
|||
|
|
else if ((usr & USR_RBFI) != 0) // <20><><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>
|
|||
|
|
interrupt = true;
|
|||
|
|
else if ((usr & (USR_PE | USR_FE | USR_OE | USR_BI)) != 0)
|
|||
|
|
interrupt = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
IRQ.Set(interrupt);
|
|||
|
|
|
|||
|
|
if (interrupt)
|
|||
|
|
{
|
|||
|
|
this.Log(LogLevel.Info, "UART interrupt triggered: USR=0x{0:X2}", usr);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void UpdateModemControl()
|
|||
|
|
{
|
|||
|
|
if((mcr & MCR_REN) == 0)
|
|||
|
|
{
|
|||
|
|
RxfifoEnabled = false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.Log(LogLevel.Info, "Modem control: INT_EN={0}, RX_EN={1}",
|
|||
|
|
(mcr & MCR_BEN) != 0, (mcr & MCR_REN) != 0);
|
|||
|
|
|
|||
|
|
UpdateInterrupts();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ========================================
|
|||
|
|
// CPUдTBR<42>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD>- <20>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
// ========================================
|
|||
|
|
public void WriteTBR(byte value)
|
|||
|
|
{
|
|||
|
|
this.Log(LogLevel.Info, "Write TBR: 0x{0:X2} ('{1}')", value,
|
|||
|
|
(value >= 32 && value < 127) ? (char)value : '.');
|
|||
|
|
|
|||
|
|
lock(txFifoLock)
|
|||
|
|
{
|
|||
|
|
if (TxfifoEnabled)
|
|||
|
|
{
|
|||
|
|
if (txFifo.Count < TX_FIFO_SIZE)
|
|||
|
|
{
|
|||
|
|
bool wasEmpty = (txFifo.Count == 0);
|
|||
|
|
|
|||
|
|
txFifo.Enqueue(value);
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD>FIFO״̬
|
|||
|
|
fsta = (byte)(fsta & (~FSTA_TEMP)); // FIFO<46>ǿ<EFBFBD>
|
|||
|
|
usr = (byte)(usr & (~USR_TFE)); // <20><><EFBFBD><EFBFBD>FIFO<46>ձ<EFBFBD>־
|
|||
|
|
|
|||
|
|
// FIFO<46>ӿձ<D3BF>Ϊ<EFBFBD>ǿգ<C7BF><D5A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>
|
|||
|
|
if (wasEmpty)
|
|||
|
|
{
|
|||
|
|
usr = (byte)(usr & (~USR_TCMP));
|
|||
|
|
this.Log(LogLevel.Info, "FIFO: Empty->NonEmpty, clearing TCMP");
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȣ<EFBFBD><C8A3>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
ScheduleNextByteTransmit();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (txFifo.Count == TX_FIFO_SIZE)
|
|||
|
|
{
|
|||
|
|
fsta = (byte)(fsta | FSTA_TFUL);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
fsta = (byte)(fsta | FSTA_TFUL);
|
|||
|
|
usr = (byte)(usr | USR_OE); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
this.Log(LogLevel.Warning, "TX FIFO overflow");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
txFifo.Clear();
|
|||
|
|
txFifo.Enqueue(value);
|
|||
|
|
fsta = (byte)(fsta & (~FSTA_TEMP));
|
|||
|
|
usr = (byte)(usr & (~USR_TFE));
|
|||
|
|
usr = (byte)(usr & (~USR_TCMP));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateInterrupts();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ========================================
|
|||
|
|
// <20><><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5>ȷ<EFBFBD><C8B7>ͣ<EFBFBD><CDA3>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
// ========================================
|
|||
|
|
private void ScheduleNextByteTransmit()
|
|||
|
|
{
|
|||
|
|
lock(txFifoLock)
|
|||
|
|
{
|
|||
|
|
// <20><>ֹ<EFBFBD>ظ<EFBFBD><D8B8><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
if (transmissionScheduled)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (txFifo.Count == 0)
|
|||
|
|
{
|
|||
|
|
// FIFO<46>գ<EFBFBD><D5A3><EFBFBD><EFBFBD>÷<EFBFBD><C3B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɱ<EFBFBD>־
|
|||
|
|
fsta = (byte)((fsta & 0xF0) | FSTA_TEMP);
|
|||
|
|
usr = (byte)(usr | USR_TFE);
|
|||
|
|
usr = (byte)(usr | USR_TCMP); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>
|
|||
|
|
|
|||
|
|
this.Log(LogLevel.Info, "TX FIFO empty, setting TCMP interrupt");
|
|||
|
|
|
|||
|
|
UpdateInterrupts();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD>㴫<EFBFBD><E3B4AB>ʱ<EFBFBD>䣨ʹ<E4A3A8>ùٷ<C3B9>IUART<52><54>չ<EFBFBD><D5B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><DFBC><EFBFBD>
|
|||
|
|
int bitsPerByte = 1; // <20><>ʼλ
|
|||
|
|
bitsPerByte += 8; // <20><><EFBFBD><EFBFBD>λ
|
|||
|
|
|
|||
|
|
// У<><D0A3>λ<EFBFBD>ж<EFBFBD>
|
|||
|
|
byte parityBits = (byte)((ucr & UCR_PB) >> 1); // <20><>ȡbits 1-3
|
|||
|
|
if (parityBits != 0x07)
|
|||
|
|
{
|
|||
|
|
bitsPerByte += 1; // ?<3F><>У<EFBFBD><D0A3>λ<EFBFBD><CEBB><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD>żУ<C5BC>飩
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD>
|
|||
|
|
// ucrӦ<72>ñ<EFBFBD><C3B1><EFBFBD><EFBFBD><EFBFBD>Ϊ 0x02 (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: 00000010)
|
|||
|
|
// parityBits = (0x02 & 0x0E) >> 1 = 0x02 >> 1 = 0x01 (<28><>У<EFBFBD><D0A3>)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֹͣλ
|
|||
|
|
if ((ucr & UCR_STB) != 0)
|
|||
|
|
{
|
|||
|
|
bitsPerByte += 2; // 2ֹͣλ
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
bitsPerByte += 1; // 1ֹͣλ
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD>㴫<EFBFBD><E3B4AB>ʱ<EFBFBD>䣨<EFBFBD>룩
|
|||
|
|
double secondsPerByte = (double)bitsPerByte / currentBaudRate;
|
|||
|
|
long microsecondsPerByte = (long)(secondsPerByte * 1000000);
|
|||
|
|
|
|||
|
|
this.Log(LogLevel.Debug,
|
|||
|
|
"Scheduling byte transmission: {0} bits @ {1} bps = {2}<7D><>s",
|
|||
|
|
bitsPerByte, currentBaudRate, microsecondsPerByte);
|
|||
|
|
|
|||
|
|
transmissionScheduled = true;
|
|||
|
|
var currentGeneration = transmissionGeneration;
|
|||
|
|
|
|||
|
|
// ʹ<><CAB9>Renode<64><65><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
machine.ScheduleAction(
|
|||
|
|
TimeInterval.FromMicroseconds(microsecondsPerByte),
|
|||
|
|
_ => TransmitOneByte(currentGeneration)
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void TransmitOneByte(ulong generation)
|
|||
|
|
{
|
|||
|
|
lock(txFifoLock)
|
|||
|
|
{
|
|||
|
|
transmissionScheduled = false;
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>Resetȡ<74><C8A1>
|
|||
|
|
if (generation != transmissionGeneration)
|
|||
|
|
{
|
|||
|
|
this.Log(LogLevel.Debug, "Transmission cancelled (reset)");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (txFifo.Count > 0)
|
|||
|
|
{
|
|||
|
|
byte data = txFifo.Dequeue();
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD>CharReceived<65>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>ⲿBackend<6E>ɶ<EFBFBD><C9B6><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD><D0BC><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC>ķ<EFBFBD>ʽ<EFBFBD><CABD>
|
|||
|
|
TransmitCharacter(data);
|
|||
|
|
|
|||
|
|
this.Log(LogLevel.Info,
|
|||
|
|
"Transmitted: 0x{0:X2} ('{1}'), Remaining: {2}",
|
|||
|
|
data,
|
|||
|
|
(data >= 32 && data < 127) ? (char)data : '.',
|
|||
|
|
txFifo.Count);
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ֽ<EFBFBD>
|
|||
|
|
ScheduleNextByteTransmit();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ʵ<><CAB5>IUART<52>ӿڵ<D3BF>TransmitCharacter<65><72><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>
|
|||
|
|
protected void TransmitCharacter(byte character)
|
|||
|
|
{
|
|||
|
|
CharReceived?.Invoke(character);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ========================================
|
|||
|
|
// <20><>ѡ<EFBFBD><D1A1><EFBFBD>ṩ<EFBFBD><E1B9A9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD>ӿڣ<D3BF><DAA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD>
|
|||
|
|
// ========================================
|
|||
|
|
public string GetTXFIFODataString()
|
|||
|
|
{
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD>Ƕ<EFBFBD>ȡ<EFBFBD>ӿڣ<D3BF><DAA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><F0B4A5B7>ж<EFBFBD>
|
|||
|
|
// <20>ж<EFBFBD><D0B6><EFBFBD><DFBC><EFBFBD>ȫ<EFBFBD><C8AB>ScheduleNextByteTransmit<69><74><EFBFBD><EFBFBD>
|
|||
|
|
|
|||
|
|
string data = "110118"; // Э<><D0AD>ͷ
|
|||
|
|
|
|||
|
|
lock(txFifoLock)
|
|||
|
|
{
|
|||
|
|
if (txFifo.Count == 0)
|
|||
|
|
{
|
|||
|
|
return "0x001800"; // <20><><EFBFBD><EFBFBD><EFBFBD>ݱ<EFBFBD>ʶ
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>紫<EFBFBD><E7B4AB><EFBFBD>Ż<EFBFBD><C5BB><EFBFBD>
|
|||
|
|
int bytesToRead = Math.Min(txFifo.Count, 128);
|
|||
|
|
|
|||
|
|
for (int i = 0; i < bytesToRead; i++)
|
|||
|
|
{
|
|||
|
|
if (txFifo.Count > 0)
|
|||
|
|
{
|
|||
|
|
byte tmp = txFifo.Dequeue();
|
|||
|
|
data += tmp.ToString("X2");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.Log(LogLevel.Debug, "Batch read: {0} bytes, Remaining: {1}",
|
|||
|
|
bytesToRead, txFifo.Count);
|
|||
|
|
|
|||
|
|
return data;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ========================================
|
|||
|
|
// RX<52><58><EFBFBD><EFBFBD><F2A3BABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
// ========================================
|
|||
|
|
public byte ReadRBR()
|
|||
|
|
{
|
|||
|
|
byte value = 0;
|
|||
|
|
|
|||
|
|
lock(rxFifoLock)
|
|||
|
|
{
|
|||
|
|
if (rxFifo.Count > 0)
|
|||
|
|
{
|
|||
|
|
value = rxFifo.Dequeue();
|
|||
|
|
this.Log(LogLevel.Info, "Read RBR: 0x{0:X2} ('{1}')", value,
|
|||
|
|
(value >= 32 && value < 127) ? (char)value : '.');
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
this.Log(LogLevel.Warning, "Read from empty RBR");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (rxFifo.Count == 0)
|
|||
|
|
{
|
|||
|
|
fsta = (byte)(fsta | FSTA_REMP);
|
|||
|
|
usr = (byte)(usr & (~USR_OE));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateInterrupts();
|
|||
|
|
return value;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ʵ<><CAB5>IUART<52>ӿڵ<D3BF>WriteChar<61><72><EFBFBD>ⲿд<E2B2BF>룩
|
|||
|
|
public void WriteChar(byte value)
|
|||
|
|
{
|
|||
|
|
WriteRXFIFOData(value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void WriteRXFIFOData(byte value)
|
|||
|
|
{
|
|||
|
|
lock(rxFifoLock)
|
|||
|
|
{
|
|||
|
|
if(RxfifoEnabled)
|
|||
|
|
{
|
|||
|
|
if(rxFifo.Count < RX_FIFO_SIZE)
|
|||
|
|
{
|
|||
|
|
rxFifo.Enqueue(value);
|
|||
|
|
fsta = (byte)(fsta & (~FSTA_REMP));
|
|||
|
|
this.Log(LogLevel.Info, "External Write RXFIFO: 0x{0:X2} ('{1}')", value,
|
|||
|
|
(value >= 32 && value < 127) ? (char)value : '.');
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
fsta = (byte)(fsta | FSTA_RFUL);
|
|||
|
|
this.Log(LogLevel.Warning, "RX FIFO full");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
usr = (byte)(usr | USR_RBFI);
|
|||
|
|
UpdateInterrupts();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ========================================
|
|||
|
|
// IUART<52>ӿ<EFBFBD>ʵ<EFBFBD><CAB5>
|
|||
|
|
// ========================================
|
|||
|
|
public uint BaudRate => currentBaudRate;
|
|||
|
|
|
|||
|
|
public Bits StopBits => ((ucr & UCR_STB) != 0) ? Bits.Two : Bits.One;
|
|||
|
|
|
|||
|
|
public Parity ParityBit
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
// <20><>ȡUCR<43><52>bits 1-3
|
|||
|
|
byte parityBits = (byte)((ucr & UCR_PB) >> 1);
|
|||
|
|
|
|||
|
|
if (parityBits == 0x07) // 111b = 0x07 = <20><>У<EFBFBD><D0A3>
|
|||
|
|
return Parity.None;
|
|||
|
|
|
|||
|
|
if (parityBits == 0x01) // 001b = 0x01 = <20><>У<EFBFBD><D0A3>
|
|||
|
|
return Parity.Odd;
|
|||
|
|
|
|||
|
|
if (parityBits == 0x00) // 000b = 0x00 = żУ<C5BC><D0A3>
|
|||
|
|
return Parity.Even;
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD>ֵĬ<D6B5><C4AC>Ϊ<EFBFBD><CEAA>У<EFBFBD><D0A3>
|
|||
|
|
return Parity.None;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[field: Transient]
|
|||
|
|
public event Action<byte> CharReceived; // <20>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>ⲿ<EFBFBD>ɶ<EFBFBD><C9B6><EFBFBD>
|
|||
|
|
|
|||
|
|
public long Size => 0x28;
|
|||
|
|
public GPIO IRQ { get; }
|
|||
|
|
|
|||
|
|
// ========================================
|
|||
|
|
// <20>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
// ========================================
|
|||
|
|
private enum Registers : long
|
|||
|
|
{
|
|||
|
|
TBR_RBR = 0x00,
|
|||
|
|
UCR_USR = 0x04,
|
|||
|
|
MCR = 0x08,
|
|||
|
|
BRSR = 0x0C,
|
|||
|
|
FSTA = 0x10,
|
|||
|
|
TBR_FreeBytes = 0x14,
|
|||
|
|
RBR_FreeBytes = 0x18,
|
|||
|
|
RSTR = 0x20,
|
|||
|
|
EXTI = 0x24
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// λ<><CEBB><EFBFBD><EFBFBD>
|
|||
|
|
private const byte UCR_STB = 0x01;
|
|||
|
|
private const byte USR_PE = 0x01;
|
|||
|
|
private const byte USR_FE = 0x02;
|
|||
|
|
private const byte USR_OE = 0x04;
|
|||
|
|
private const byte USR_BI = 0x08;
|
|||
|
|
private const byte USR_TCMP = 0x20;
|
|||
|
|
private const byte USR_TFE = 0x40;
|
|||
|
|
private const byte USR_RBFI = 0x80;
|
|||
|
|
private const byte MCR_BEN = 0x04;
|
|||
|
|
private const byte MCR_REN = 0x20;
|
|||
|
|
private const byte FSTA_TEMP = 0x01;
|
|||
|
|
private const byte FSTA_TFUL = 0x04;
|
|||
|
|
private const byte FSTA_REMP = 0x10;
|
|||
|
|
private const byte FSTA_RFUL = 0x40;
|
|||
|
|
private const byte RSTR_RES = 0x55;
|
|||
|
|
private const int RX_FIFO_SIZE = 1024;
|
|||
|
|
private const int TX_FIFO_SIZE = 2048;
|
|||
|
|
|
|||
|
|
// ˽<><CBBD><EFBFBD>ֶ<EFBFBD>
|
|||
|
|
private readonly uint clockFrequency;
|
|||
|
|
private uint currentBaudRate = 115200;
|
|||
|
|
private byte ucr;
|
|||
|
|
private byte usr;
|
|||
|
|
private byte mcr;
|
|||
|
|
private ushort brsr;
|
|||
|
|
private byte fsta;
|
|||
|
|
private ushort tbr;
|
|||
|
|
private ushort rbr;
|
|||
|
|
private byte rstr;
|
|||
|
|
private readonly Queue<byte> rxFifo;
|
|||
|
|
private readonly Queue<byte> txFifo;
|
|||
|
|
private bool RxfifoEnabled;
|
|||
|
|
private bool TxfifoEnabled;
|
|||
|
|
private int fifoTriggerLevel;
|
|||
|
|
private bool transmissionScheduled;
|
|||
|
|
private ulong transmissionGeneration;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
// // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD>α<EFBFBD><CEB1><EFBFBD>룩
|
|||
|
|
// class UDPNetworkLayer
|
|||
|
|
// {
|
|||
|
|
// private List<byte> buffer = new List<byte>();
|
|||
|
|
|
|||
|
|
// public void Initialize(UART_771_RUHW_2CFG4 uart)
|
|||
|
|
// {
|
|||
|
|
// // <20><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>25Hz<48><7A>ʱ<EFBFBD><CAB1>
|
|||
|
|
// uart.CharReceived += OnUartDataReceived;
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
// private void OnUartDataReceived(byte data)
|
|||
|
|
// {
|
|||
|
|
// buffer.Add(data);
|
|||
|
|
|
|||
|
|
// // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD>Ż<EFBFBD><C5BB><EFBFBD>
|
|||
|
|
// if (buffer.Count >= 128 || bufferTimeout)
|
|||
|
|
// {
|
|||
|
|
// SendToUDP(buffer.ToArray());
|
|||
|
|
// buffer.Clear();
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
// }
|