Compare commits
3 Commits
393499537d
...
2e649e2c86
Author | SHA1 | Date |
---|---|---|
|
2e649e2c86 | |
|
464bd40440 | |
|
d2942fe094 |
|
@ -0,0 +1,115 @@
|
|||
#ifndef _UART_H_
|
||||
#define _UART_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define UART_BASE 0x40004000
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DECL_REG(addr, name) \
|
||||
volatile uint32_t *const(name) = (volatile uint32_t *)(addr)
|
||||
|
||||
#define __time_critical __attribute__((section(".time_critical")))
|
||||
|
||||
typedef volatile uint32_t io_rw_32;
|
||||
|
||||
#endif
|
||||
|
||||
// #include "addressmap.h"
|
||||
#include "uart_regs.h"
|
||||
|
||||
DECL_REG(UART_BASE + UART_CSR_OFFS, UART_CSR);
|
||||
DECL_REG(UART_BASE + UART_DIV_OFFS, UART_DIV);
|
||||
DECL_REG(UART_BASE + UART_FSTAT_OFFS, UART_FSTAT);
|
||||
DECL_REG(UART_BASE + UART_TX_OFFS, UART_TX);
|
||||
DECL_REG(UART_BASE + UART_RX_OFFS, UART_RX);
|
||||
|
||||
static inline void uart_enable(bool en) {
|
||||
*UART_CSR = *UART_CSR & ~UART_CSR_EN_MASK | (!!en << UART_CSR_EN_LSB);
|
||||
}
|
||||
|
||||
// 10.4 fixed point format.
|
||||
// Encodes number of clock cycles per clock enable.
|
||||
// Each baud period is 16 clock enables (default modparam)
|
||||
static inline void uart_clkdiv(uint32_t div) { *UART_DIV = div; }
|
||||
|
||||
// Use constant arguments:
|
||||
#define uart_clkdiv_baud(clk_mhz, baud) \
|
||||
uart_clkdiv((uint32_t)((clk_mhz) * 1e6 * (16.0 / 8.0) / (float)(baud)))
|
||||
|
||||
static inline bool uart_tx_full() {
|
||||
return !!(*UART_FSTAT & UART_FSTAT_TXFULL_MASK);
|
||||
}
|
||||
|
||||
static inline bool uart_tx_empty() {
|
||||
return !!(*UART_FSTAT & UART_FSTAT_TXEMPTY_MASK);
|
||||
}
|
||||
|
||||
static inline size_t uart_tx_level() {
|
||||
return (*UART_FSTAT & UART_FSTAT_TXLEVEL_MASK) >> UART_FSTAT_TXLEVEL_LSB;
|
||||
}
|
||||
|
||||
static inline bool uart_rx_full() {
|
||||
return !!(*UART_FSTAT & UART_FSTAT_RXFULL_MASK);
|
||||
}
|
||||
|
||||
static inline bool uart_rx_empty() {
|
||||
return !!(*UART_FSTAT & UART_FSTAT_RXEMPTY_MASK);
|
||||
}
|
||||
|
||||
static inline size_t uart_rx_level() {
|
||||
return (*UART_FSTAT & UART_FSTAT_RXLEVEL_MASK) >> UART_FSTAT_RXLEVEL_LSB;
|
||||
}
|
||||
|
||||
static inline void uart_put(uint8_t x) {
|
||||
while (uart_tx_full());
|
||||
*(volatile uint8_t *const)UART_TX = x;
|
||||
}
|
||||
|
||||
static inline uint8_t uart_get() {
|
||||
while (uart_rx_empty());
|
||||
return *(volatile uint8_t *const)UART_RX;
|
||||
}
|
||||
|
||||
static inline void uart_puts(const char *s) {
|
||||
while (*s) {
|
||||
if (*s == '\n') uart_put('\r');
|
||||
uart_put((uint8_t)(*s++));
|
||||
}
|
||||
}
|
||||
|
||||
// Have you seen how big printf is?
|
||||
static const char hextable[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
static inline void uart_putint(uint32_t x) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
uart_put((uint8_t)(hextable[x >> 28]));
|
||||
x <<= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void uart_putbyte(uint8_t x) {
|
||||
uart_put((uint8_t)(hextable[x >> 4]));
|
||||
uart_put((uint8_t)(hextable[x & 0xf]));
|
||||
}
|
||||
|
||||
static inline void uart_wait_done() { while (*UART_CSR & UART_CSR_BUSY_MASK); }
|
||||
|
||||
static inline void uart_init() {
|
||||
*UART_CSR = 0;
|
||||
while (*UART_CSR & UART_CSR_BUSY_MASK);
|
||||
while (!uart_rx_empty()) (void)uart_get();
|
||||
uart_enable(true);
|
||||
}
|
||||
|
||||
static inline void uart_enable_cts(bool en) {
|
||||
*UART_CSR = *UART_CSR & ~UART_CSR_CTSEN_MASK | (!!en << UART_CSR_CTSEN_LSB);
|
||||
}
|
||||
|
||||
#endif // _UART_H_
|
|
@ -0,0 +1,142 @@
|
|||
/*******************************************************************************
|
||||
* AUTOGENERATED BY REGBLOCK *
|
||||
* Do not edit manually. *
|
||||
* Edit the source file (or regblock utility) and regenerate. *
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _UART_REGS_H_
|
||||
#define _UART_REGS_H_
|
||||
|
||||
// Block name : uart
|
||||
// Bus type : apb
|
||||
// Bus data width : 32
|
||||
// Bus address width : 16
|
||||
|
||||
#define UART_CSR_OFFS 0
|
||||
#define UART_DIV_OFFS 4
|
||||
#define UART_FSTAT_OFFS 8
|
||||
#define UART_TX_OFFS 12
|
||||
#define UART_RX_OFFS 16
|
||||
|
||||
/*******************************************************************************
|
||||
* CSR *
|
||||
*******************************************************************************/
|
||||
|
||||
// Control and status register
|
||||
|
||||
// Field: CSR_EN Access: RW
|
||||
// UART runs when en is high. Synchronous reset (excluding FIFOs) when low.
|
||||
#define UART_CSR_EN_LSB 0
|
||||
#define UART_CSR_EN_BITS 1
|
||||
#define UART_CSR_EN_MASK 0x1
|
||||
// Field: CSR_BUSY Access: ROV
|
||||
// UART TX is still sending data
|
||||
#define UART_CSR_BUSY_LSB 1
|
||||
#define UART_CSR_BUSY_BITS 1
|
||||
#define UART_CSR_BUSY_MASK 0x2
|
||||
// Field: CSR_TXIE Access: RW
|
||||
// Enable TX FIFO interrupt
|
||||
#define UART_CSR_TXIE_LSB 2
|
||||
#define UART_CSR_TXIE_BITS 1
|
||||
#define UART_CSR_TXIE_MASK 0x4
|
||||
// Field: CSR_RXIE Access: RW
|
||||
// Enable RX FIFO interrupt
|
||||
#define UART_CSR_RXIE_LSB 3
|
||||
#define UART_CSR_RXIE_BITS 1
|
||||
#define UART_CSR_RXIE_MASK 0x8
|
||||
// Field: CSR_CTSEN Access: RW
|
||||
// Enable pausing of TX while CTS is not asserted
|
||||
#define UART_CSR_CTSEN_LSB 4
|
||||
#define UART_CSR_CTSEN_BITS 1
|
||||
#define UART_CSR_CTSEN_MASK 0x10
|
||||
// Field: CSR_LOOPBACK Access: RW
|
||||
// Connect TX -> RX and RTS -> CTS internally (for testing).
|
||||
#define UART_CSR_LOOPBACK_LSB 8
|
||||
#define UART_CSR_LOOPBACK_BITS 1
|
||||
#define UART_CSR_LOOPBACK_MASK 0x100
|
||||
|
||||
/*******************************************************************************
|
||||
* DIV *
|
||||
*******************************************************************************/
|
||||
|
||||
// Clock divider control fields
|
||||
|
||||
// Field: DIV_INT Access: WO
|
||||
#define UART_DIV_INT_LSB 4
|
||||
#define UART_DIV_INT_BITS 10
|
||||
#define UART_DIV_INT_MASK 0x3ff0
|
||||
// Field: DIV_FRAC Access: WO
|
||||
#define UART_DIV_FRAC_LSB 0
|
||||
#define UART_DIV_FRAC_BITS 4
|
||||
#define UART_DIV_FRAC_MASK 0xf
|
||||
|
||||
/*******************************************************************************
|
||||
* FSTAT *
|
||||
*******************************************************************************/
|
||||
|
||||
// FIFO status register
|
||||
|
||||
// Field: FSTAT_TXLEVEL Access: ROV
|
||||
#define UART_FSTAT_TXLEVEL_LSB 0
|
||||
#define UART_FSTAT_TXLEVEL_BITS 8
|
||||
#define UART_FSTAT_TXLEVEL_MASK 0xff
|
||||
// Field: FSTAT_TXFULL Access: ROV
|
||||
#define UART_FSTAT_TXFULL_LSB 8
|
||||
#define UART_FSTAT_TXFULL_BITS 1
|
||||
#define UART_FSTAT_TXFULL_MASK 0x100
|
||||
// Field: FSTAT_TXEMPTY Access: ROV
|
||||
#define UART_FSTAT_TXEMPTY_LSB 9
|
||||
#define UART_FSTAT_TXEMPTY_BITS 1
|
||||
#define UART_FSTAT_TXEMPTY_MASK 0x200
|
||||
// Field: FSTAT_TXOVER Access: W1C
|
||||
#define UART_FSTAT_TXOVER_LSB 10
|
||||
#define UART_FSTAT_TXOVER_BITS 1
|
||||
#define UART_FSTAT_TXOVER_MASK 0x400
|
||||
// Field: FSTAT_TXUNDER Access: W1C
|
||||
#define UART_FSTAT_TXUNDER_LSB 11
|
||||
#define UART_FSTAT_TXUNDER_BITS 1
|
||||
#define UART_FSTAT_TXUNDER_MASK 0x800
|
||||
// Field: FSTAT_RXLEVEL Access: ROV
|
||||
#define UART_FSTAT_RXLEVEL_LSB 16
|
||||
#define UART_FSTAT_RXLEVEL_BITS 8
|
||||
#define UART_FSTAT_RXLEVEL_MASK 0xff0000
|
||||
// Field: FSTAT_RXFULL Access: ROV
|
||||
#define UART_FSTAT_RXFULL_LSB 24
|
||||
#define UART_FSTAT_RXFULL_BITS 1
|
||||
#define UART_FSTAT_RXFULL_MASK 0x1000000
|
||||
// Field: FSTAT_RXEMPTY Access: ROV
|
||||
#define UART_FSTAT_RXEMPTY_LSB 25
|
||||
#define UART_FSTAT_RXEMPTY_BITS 1
|
||||
#define UART_FSTAT_RXEMPTY_MASK 0x2000000
|
||||
// Field: FSTAT_RXOVER Access: W1C
|
||||
#define UART_FSTAT_RXOVER_LSB 26
|
||||
#define UART_FSTAT_RXOVER_BITS 1
|
||||
#define UART_FSTAT_RXOVER_MASK 0x4000000
|
||||
// Field: FSTAT_RXUNDER Access: W1C
|
||||
#define UART_FSTAT_RXUNDER_LSB 27
|
||||
#define UART_FSTAT_RXUNDER_BITS 1
|
||||
#define UART_FSTAT_RXUNDER_MASK 0x8000000
|
||||
|
||||
/*******************************************************************************
|
||||
* TX *
|
||||
*******************************************************************************/
|
||||
|
||||
// TX data FIFO
|
||||
|
||||
// Field: TX Access: WF
|
||||
#define UART_TX_LSB 0
|
||||
#define UART_TX_BITS 8
|
||||
#define UART_TX_MASK 0xff
|
||||
|
||||
/*******************************************************************************
|
||||
* RX *
|
||||
*******************************************************************************/
|
||||
|
||||
// RX data FIFO
|
||||
|
||||
// Field: RX Access: RF
|
||||
#define UART_RX_LSB 0
|
||||
#define UART_RX_BITS 8
|
||||
#define UART_RX_MASK 0xff
|
||||
|
||||
#endif // _UART_REGS_H_
|
|
@ -1,12 +1,23 @@
|
|||
|
||||
|
||||
#include "tb_cxxrtl_io.h"
|
||||
__attribute__((optimize("O0"))) int main() {
|
||||
#include "uart.h"
|
||||
|
||||
#define CLK_FREQ_MHZ 12
|
||||
|
||||
// __attribute__((optimize("O0")))
|
||||
int main() {
|
||||
// Float stuff should all be compile-time. 115200 baud.
|
||||
uart_init();
|
||||
uart_clkdiv_baud(CLK_FREQ_MHZ, 9600);
|
||||
uart_puts("Hello, UART!\n");
|
||||
// Need to wait for completion, else we will terminate the simulation
|
||||
// while characters still in FIFO.
|
||||
uart_wait_done();
|
||||
|
||||
// tb_puts("Hello world from Hazard3 + CXXRTL!\n");
|
||||
uint32_t addr = 0x40008000;
|
||||
uint32_t *point = (uint32_t *)addr;
|
||||
*point = 'C';
|
||||
*point = 'O';
|
||||
*point = 'L';
|
||||
*point = 'I';
|
||||
*point = 'N';
|
||||
return 123;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ TBEXEC := $(patsubst %.f,%,$(DOTF))
|
|||
FILE_LIST := $(shell HDL=$(HDL) $(SCRIPTS)/listfiles $(DOTF))
|
||||
BUILD_DIR := build-$(patsubst %.f,%,$(DOTF))
|
||||
|
||||
SRC = tb.cpp softuart.c
|
||||
INC = -I ${BUILD_DIR} -I ./
|
||||
|
||||
# Note: clang++-18 has a >20x compile time regression, even at low
|
||||
# optimisation levels. I have tried clang++-16 and clang++-17, both fine.
|
||||
CLANGXX := clang++-16
|
||||
|
@ -40,7 +43,7 @@ gdb:
|
|||
/opt/riscv/bin/riscv32-unknown-elf-gdb -x gdb_init
|
||||
|
||||
$(TBEXEC): $(BUILD_DIR)/dut.cpp tb.cpp
|
||||
$(CLANGXX) -O3 -std=c++14 $(addprefix -D,$(CDEFINES) $(CDEFINES_$(DOTF))) -I $(shell yosys-config --datdir)/include/backends/cxxrtl/runtime -I $(BUILD_DIR) tb.cpp -o $(TBEXEC)
|
||||
$(CLANGXX) -O3 -std=c++14 $(addprefix -D,$(CDEFINES) $(CDEFINES_$(DOTF))) -I $(shell yosys-config --datdir)/include/backends/cxxrtl/runtime $(INC) ${SRC} -o $(TBEXEC)
|
||||
|
||||
lint:
|
||||
verilator --lint-only --top-module $(TOP) -I$(HDL) $(FILE_LIST)
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
Software Uart For Stm32
|
||||
By Liyanboy74
|
||||
https://github.com/liyanboy74
|
||||
*/
|
||||
|
||||
#include "softuart.h"
|
||||
|
||||
// Some internal define
|
||||
#if (SoftUart_PARITY)
|
||||
#define SoftUart_IDEF_LEN_C1 (SoftUart_DATA_LEN + 2)
|
||||
#else
|
||||
#define SoftUart_IDEF_LEN_C1 (SoftUart_DATA_LEN + 1)
|
||||
#endif
|
||||
#define SoftUart_IDEF_LEN_C2 (SoftUart_IDEF_LEN_C1 + SoftUart_STOP_Bit)
|
||||
|
||||
// All Soft Uart Config and State
|
||||
SoftUart_S SUart;
|
||||
|
||||
// TX RX Data Buffer
|
||||
SoftUartBuffer_S SUBuffer;
|
||||
|
||||
// For timing division
|
||||
uint8_t SU_Timer = 0;
|
||||
|
||||
// Parity var
|
||||
static uint8_t DV, PCount;
|
||||
|
||||
// Initial Soft Uart
|
||||
SoftUart_S *SoftUartInit() {
|
||||
SUart.TxNComplated = 0;
|
||||
|
||||
SUart.RxBitCounter = 0;
|
||||
SUart.RxBitShift = 0;
|
||||
SUart.RxIndex = 0;
|
||||
|
||||
SUart.TxEnable = 0;
|
||||
SUart.RxEnable = 0;
|
||||
|
||||
SUart.TxBitCounter = 0;
|
||||
SUart.TxBitShift = 0;
|
||||
SUart.TxIndex = 0;
|
||||
|
||||
SUart.TxSize = 0;
|
||||
|
||||
SUart.Buffer = &SUBuffer;
|
||||
|
||||
SUart.RxTimingFlag = 0;
|
||||
SUart.RxBitOffset = 0;
|
||||
|
||||
return &SUart;
|
||||
}
|
||||
|
||||
// Send one bit to TX pin
|
||||
void SoftUartTransmitBit(SoftUart_S *SU, uint8_t Bit0_1) {
|
||||
SU->TxPinValue = Bit0_1;
|
||||
}
|
||||
|
||||
// Enable Soft Uart Receiving
|
||||
SoftUartState_E SoftUartEnableRx() {
|
||||
SUart.RxEnable = 1;
|
||||
return SoftUart_OK;
|
||||
}
|
||||
|
||||
// Disable Soft Uart Receiving
|
||||
SoftUartState_E SoftUartDisableRx() {
|
||||
SUart.RxEnable = 0;
|
||||
return SoftUart_OK;
|
||||
}
|
||||
|
||||
// Read Size of Received Data in buffer
|
||||
uint8_t SoftUartRxAlavailable() { return SUart.RxIndex; }
|
||||
|
||||
// Move Received Data to Another Buffer
|
||||
SoftUartState_E SoftUartReadRxBuffer(uint8_t *Buffer, uint8_t Len) {
|
||||
int i;
|
||||
for (i = 0; i < Len; i++) {
|
||||
Buffer[i] = SUart.Buffer->Rx[i];
|
||||
}
|
||||
for (i = 0; i < SUart.RxIndex; i++) {
|
||||
SUart.Buffer->Rx[i] = SUart.Buffer->Rx[i + Len];
|
||||
}
|
||||
SUart.RxIndex -= Len;
|
||||
return SoftUart_OK;
|
||||
}
|
||||
|
||||
// Soft Uart Transmit Data Process
|
||||
void SoftUartTxProcess(SoftUart_S *SU) {
|
||||
if (SU->TxEnable) {
|
||||
// Start
|
||||
if (SU->TxBitCounter == 0) {
|
||||
SU->TxNComplated = 1;
|
||||
SU->TxBitShift = 0;
|
||||
SoftUartTransmitBit(SU, 0);
|
||||
SU->TxBitCounter++;
|
||||
PCount = 0;
|
||||
}
|
||||
// Data
|
||||
else if (SU->TxBitCounter < (SoftUart_DATA_LEN + 1)) {
|
||||
DV = ((SU->Buffer->Tx[SU->TxIndex]) >> (SU->TxBitShift)) & 0x01;
|
||||
SoftUartTransmitBit(SU, DV);
|
||||
SU->TxBitCounter++;
|
||||
SU->TxBitShift++;
|
||||
|
||||
if (DV) PCount++;
|
||||
}
|
||||
// Parity
|
||||
else if (SU->TxBitCounter < SoftUart_IDEF_LEN_C1) {
|
||||
// Check Even or Odd
|
||||
DV = PCount % 2;
|
||||
|
||||
// if Odd Parity
|
||||
if (SoftUart_PARITY == 1) DV = !DV;
|
||||
|
||||
SoftUartTransmitBit(SU, DV);
|
||||
SU->TxBitCounter++;
|
||||
}
|
||||
// Stop
|
||||
else if (SU->TxBitCounter < SoftUart_IDEF_LEN_C2) {
|
||||
SoftUartTransmitBit(SU, 1);
|
||||
SU->TxBitCounter++;
|
||||
}
|
||||
// Complete
|
||||
else if (SU->TxBitCounter == SoftUart_IDEF_LEN_C2) {
|
||||
// Reset Bit Counter
|
||||
SU->TxBitCounter = 0;
|
||||
|
||||
// Ready To Send Another Data
|
||||
SU->TxIndex++;
|
||||
|
||||
// Check Size of Data
|
||||
if (SU->TxSize > SU->TxIndex) {
|
||||
// Continue Sending
|
||||
SU->TxNComplated = 1;
|
||||
SU->TxEnable = 1;
|
||||
} else {
|
||||
// Finish
|
||||
SU->TxNComplated = 0;
|
||||
SU->TxEnable = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Soft Uart Receive Data Process
|
||||
void SoftUartRxDataBitProcess(SoftUart_S *SU, uint8_t B0_1) {
|
||||
if (SU->RxEnable) {
|
||||
// Start
|
||||
if (SU->RxBitCounter == 0) {
|
||||
// Start Bit is 0
|
||||
if (B0_1) return;
|
||||
|
||||
SU->RxBitShift = 0;
|
||||
SU->RxBitCounter++;
|
||||
SU->Buffer->Rx[SU->RxIndex] = 0;
|
||||
}
|
||||
// Data
|
||||
else if (SU->RxBitCounter < (SoftUart_DATA_LEN + 1)) {
|
||||
SU->Buffer->Rx[SU->RxIndex] |= ((B0_1 & 0x01) << SU->RxBitShift);
|
||||
SU->RxBitCounter++;
|
||||
SU->RxBitShift++;
|
||||
}
|
||||
// Parity
|
||||
else if (SU->RxBitCounter < SoftUart_IDEF_LEN_C1) {
|
||||
// Need to be check
|
||||
// B0_1;
|
||||
SU->RxBitCounter++;
|
||||
}
|
||||
// Stop & Complete
|
||||
else if (SU->RxBitCounter < SoftUart_IDEF_LEN_C2) {
|
||||
SU->RxBitCounter = 0;
|
||||
SU->RxTimingFlag = 0;
|
||||
|
||||
// Stop Bit must be 1
|
||||
if (B0_1) {
|
||||
// Received successfully
|
||||
// Change RX Buffer Index
|
||||
if ((SU->RxIndex) < (SoftUartRxBufferSize - 1)) (SU->RxIndex)++;
|
||||
}
|
||||
// if not : ERROR -> Overwrite data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait Until Transmit Completed
|
||||
// You do not usually need to use this function!
|
||||
void SoftUartWaitUntilTxComplate() { while (SUart.TxNComplated); }
|
||||
|
||||
// Copy Data to Transmit Buffer and Start Sending
|
||||
SoftUartState_E SoftUartPuts(uint8_t *Data, uint8_t Len) {
|
||||
int i;
|
||||
if (SUart.TxNComplated) return SoftUart_Error;
|
||||
SUart.TxIndex = 0;
|
||||
SUart.TxSize = Len;
|
||||
for (i = 0; i < Len; i++) {
|
||||
SUart.Buffer->Tx[i] = Data[i];
|
||||
}
|
||||
SUart.TxNComplated = 1;
|
||||
SUart.TxEnable = 1;
|
||||
return SoftUart_OK;
|
||||
}
|
||||
|
||||
// Capture RX and Get BitOffset
|
||||
uint8_t SoftUartScanRxPorts(SoftUart_S *SU) {
|
||||
uint8_t Buffer = 0x00, Bit;
|
||||
// Read RX GPIO Value
|
||||
Bit = SU->RxPinValue;
|
||||
// Starting conditions
|
||||
if (!SUart.RxBitCounter && !SUart.RxTimingFlag && !Bit) {
|
||||
// Save RX Bit Offset
|
||||
// Calculate middle position of data puls
|
||||
SUart.RxBitOffset = ((SU_Timer + 2) % 5);
|
||||
// Timing Offset is Set
|
||||
SUart.RxTimingFlag = 1;
|
||||
}
|
||||
// Add all RX GPIO State to Buffer
|
||||
Buffer |= (Bit & 0x01);
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
// SoftUartHandler must call in interrupt every 0.2*(1/BR)
|
||||
// if BR=9600 then 0.2*(1/9600)=20.8333333 uS
|
||||
void SoftUartHandler(void) {
|
||||
uint8_t SU_DBuffer;
|
||||
|
||||
// Capture RX and Get BitOffset
|
||||
SU_DBuffer = SoftUartScanRxPorts(&SUart);
|
||||
// Receive Data if we in middle data pulse position
|
||||
if (SUart.RxBitOffset == SU_Timer) {
|
||||
SoftUartRxDataBitProcess(&SUart, (SU_DBuffer & 0x01));
|
||||
}
|
||||
|
||||
// Sending always happens in the first time slot
|
||||
if (SU_Timer == 0) {
|
||||
// Transmit Data
|
||||
SoftUartTxProcess(&SUart);
|
||||
}
|
||||
|
||||
// Timing process
|
||||
SU_Timer++;
|
||||
if (SU_Timer >= 5) SU_Timer = 0;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Software Uart For Stm32
|
||||
By Liyanboy74
|
||||
https://github.com/liyanboy74
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#define Number_Of_SoftUarts 1 // Max 8
|
||||
|
||||
#define SoftUartTxBufferSize 32
|
||||
#define SoftUartRxBufferSize 64
|
||||
|
||||
#define SoftUart_DATA_LEN 8 // Max 8 Bit
|
||||
#define SoftUart_PARITY 0 // 0=None 1=odd 2=even
|
||||
#define SoftUart_STOP_Bit 1 // Number of stop bits
|
||||
|
||||
typedef enum { SoftUart_OK, SoftUart_Error } SoftUartState_E;
|
||||
|
||||
typedef struct {
|
||||
uint8_t Tx[SoftUartTxBufferSize];
|
||||
uint8_t Rx[SoftUartRxBufferSize];
|
||||
} SoftUartBuffer_S;
|
||||
|
||||
typedef struct {
|
||||
uint8_t TxNComplated;
|
||||
uint8_t TxEnable;
|
||||
uint8_t RxEnable;
|
||||
uint8_t TxBitShift, TxBitCounter;
|
||||
uint8_t RxBitShift, RxBitCounter;
|
||||
uint8_t TxIndex, TxSize;
|
||||
uint8_t RxIndex;
|
||||
SoftUartBuffer_S *Buffer;
|
||||
uint8_t RxTimingFlag;
|
||||
uint8_t RxBitOffset;
|
||||
uint8_t RxPinValue; // set before SoftUartHandler
|
||||
uint8_t TxPinValue; // get after SoftUartHandler
|
||||
} SoftUart_S;
|
||||
|
||||
// Call Every (0.2)*(1/9600) = 20.83 uS
|
||||
void SoftUartHandler(void);
|
||||
|
||||
void SoftUartWaitUntilTxComplate();
|
||||
uint8_t SoftUartRxAlavailable();
|
||||
SoftUartState_E SoftUartPuts(uint8_t *Data, uint8_t Len);
|
||||
SoftUartState_E SoftUartEnableRx();
|
||||
SoftUartState_E SoftUartDisableRx();
|
||||
SoftUart_S *SoftUartInit();
|
||||
SoftUartState_E SoftUartReadRxBuffer(uint8_t *Buffer, uint8_t Len);
|
|
@ -12,6 +12,7 @@
|
|||
#include <cxxrtl/cxxrtl_vcd.h>
|
||||
|
||||
#include "dut.cpp"
|
||||
#include "softuart.h"
|
||||
|
||||
// There must be a better way
|
||||
#ifdef __x86_64__
|
||||
|
@ -110,6 +111,9 @@ int main(int argc, char **argv) {
|
|||
bool replay_jtag = false;
|
||||
std::string jtag_replay_path;
|
||||
|
||||
SoftUart_S *su = SoftUartInit();
|
||||
SoftUartEnableRx();
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string s(argv[i]);
|
||||
if (s.rfind("--", 0) != 0) {
|
||||
|
@ -246,6 +250,8 @@ int main(int argc, char **argv) {
|
|||
top.step();
|
||||
top.step(); // workaround for github.com/YosysHQ/yosys/issues/2780
|
||||
|
||||
int uart_sample_count = 0;
|
||||
|
||||
bool timed_out = false;
|
||||
for (int64_t cycle = 0; cycle < max_cycles || max_cycles == 0; ++cycle) {
|
||||
top.p_clk.set<bool>(false);
|
||||
|
@ -335,6 +341,31 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
// 12Mhz -> 9600 = 1250
|
||||
// SoftUartHandler must call in interrupt every 0.2*(1/BR)
|
||||
if (uart_sample_count >= (1250 / 5)) {
|
||||
// if (top.p_uart__tx.get<bool>())
|
||||
// printf("1");
|
||||
// else
|
||||
// printf("0");
|
||||
su->RxPinValue = (top.p_uart__tx.get<bool>() ? 1 : 0);
|
||||
SoftUartHandler();
|
||||
// uint8_t tx = su->TxPinValue;
|
||||
|
||||
// uint8_t ch = getchar(0);
|
||||
// SoftUartPuts(0, &ch, 1);
|
||||
|
||||
if (SoftUartRxAlavailable()) {
|
||||
uint8_t ch = 0;
|
||||
auto re = SoftUartReadRxBuffer(&ch, 1);
|
||||
if (re == SoftUart_OK && ch) printf("%c", ch);
|
||||
}
|
||||
|
||||
uart_sample_count = 0;
|
||||
} else {
|
||||
uart_sample_count++;
|
||||
}
|
||||
|
||||
if (dump_waves) {
|
||||
// The extra step() is just here to get the bus responses to line up
|
||||
// nicely in the VCD (hopefully is a quick update)
|
||||
|
|
Loading…
Reference in New Issue