spinal.lib.com.uart.UartCtrlTx.scala Maven / Gradle / Ivy
package spinal.lib.com.uart
import spinal.core._
import spinal.lib.com.uart.UartStopType._
import spinal.lib.{Counter, slave}
import spinal.lib.fsm._
object UartCtrlTxState extends SpinalEnum {
val IDLE, START, DATA, PARITY, STOP = newElement()
}
class UartCtrlTx(g : UartCtrlGenerics) extends Component {
import g._
val io = new Bundle {
val configFrame = in(UartCtrlFrameConfig(g))
val samplingTick = in Bool()
val write = slave Stream (Bits(dataWidthMax bit))
val cts = in Bool()
val txd = out Bool()
val break = in Bool()
}
// Provide one clockDivider.tick each rxSamplePerBit pulse of io.samplingTick
// Used by the stateMachine as a baud rate time reference
val clockDivider = new Area {
val counter = Counter(rxSamplePerBit)
val tick = counter.willOverflow
when(io.samplingTick) {
counter.increment()
}
}
// Count up each clockDivider.tick, used by the state machine to count up data bits and stop bits
val tickCounter = new Area {
val value = Reg(UInt(Math.max(log2Up(dataWidthMax), 2) bit))
def reset() = value := 0
when(clockDivider.tick) {
value := value + 1
}
}
val stateMachine = new Area {
import UartCtrlTxState._
val state = RegInit(IDLE)
val parity = Reg(Bool())
val txd = True
when(clockDivider.tick) {
parity := parity ^ txd
}
io.write.ready := io.break
switch(state) {
is(IDLE){
when(io.write.valid && !io.cts && clockDivider.tick){
state := START
}
}
is(START) {
txd := False
when(clockDivider.tick) {
state := DATA
parity := io.configFrame.parity === UartParityType.ODD
tickCounter.reset()
}
}
is(DATA) {
txd := io.write.payload(tickCounter.value)
when(clockDivider.tick) {
when(tickCounter.value === io.configFrame.dataLength) {
io.write.ready := True
tickCounter.reset()
when(io.configFrame.parity === UartParityType.NONE) {
state := STOP
} otherwise {
state := PARITY
}
}
}
}
is(PARITY) {
txd := parity
when(clockDivider.tick) {
state := STOP
tickCounter.reset()
}
}
is(STOP) {
when(clockDivider.tick) {
when(tickCounter.value === toBitCount(io.configFrame.stop)) {
state := io.write.valid ? START | IDLE
}
}
}
}
}
io.txd := RegNext(stateMachine.txd && !io.break) init(True)
}