reset improvement

This commit is contained in:
Mateusz Faderewski 2024-06-30 17:43:28 +02:00
parent f669f730da
commit 6d460e83bd
6 changed files with 160 additions and 85 deletions

View File

@ -394,13 +394,13 @@ module mcu_top (
REG_USB_SCR: begin
reg_rdata <= {
2'd0,
1'd0,
usb_scb.fifo_flush_busy,
usb_scb.pwrsav,
usb_scb.reset_state,
usb_scb.tx_count,
usb_scb.rx_count,
2'b00,
usb_scb.reset_pending,
3'b000,
~fifo_bus.tx_full,
~fifo_bus.rx_empty,
1'b0
@ -681,9 +681,10 @@ module mcu_top (
mem_start <= 1'b0;
mem_stop <= 1'b0;
usb_scb.write_buffer_flush <= 1'b0;
usb_scb.reset_ack <= 1'b0;
usb_scb.fifo_flush <= 1'b0;
usb_scb.write_buffer_flush <= 1'b0;
usb_scb.reset_on_ack <= 1'b0;
usb_scb.reset_off_ack <= 1'b0;
usb_dma_scb.start <= 1'b0;
usb_dma_scb.stop <= 1'b0;
@ -770,11 +771,10 @@ module mcu_top (
end
REG_USB_SCR: begin
{
usb_scb.write_buffer_flush,
usb_scb.reset_ack,
usb_scb.fifo_flush
} <= {reg_wdata[5:4], reg_wdata[0]};
usb_scb.write_buffer_flush <= reg_wdata[5];
usb_scb.reset_off_ack <= reg_wdata[4];
usb_scb.reset_on_ack <= reg_wdata[3];
usb_scb.fifo_flush <= reg_wdata[0];
end
REG_USB_DMA_ADDRESS: begin

View File

@ -1,34 +1,37 @@
interface usb_scb ();
logic fifo_flush;
logic reset_pending;
logic reset_ack;
logic fifo_flush_busy;
logic write_buffer_flush;
logic [10:0] rx_count;
logic [10:0] tx_count;
logic pwrsav;
logic reset_state;
logic reset_on_ack;
logic reset_off_ack;
modport controller (
output fifo_flush,
input reset_pending,
output reset_ack,
input fifo_flush_busy,
output write_buffer_flush,
input rx_count,
input tx_count,
input pwrsav,
input reset_state
input reset_state,
output reset_on_ack,
output reset_off_ack
);
modport usb (
input fifo_flush,
output reset_pending,
input reset_ack,
output fifo_flush_busy,
input write_buffer_flush,
output rx_count,
output tx_count,
output pwrsav,
output reset_state
output reset_state,
input reset_on_ack,
input reset_off_ack
);
endinterface
@ -59,9 +62,11 @@ module usb_ft1248 (
logic tx_read;
logic [7:0] tx_rdata;
logic fifo_flush;
fifo_8kb fifo_8kb_rx_inst (
.clk(clk),
.reset(reset || usb_scb.fifo_flush),
.reset(reset || fifo_flush),
.empty(fifo_bus.rx_empty),
.almost_empty(fifo_bus.rx_almost_empty),
@ -78,7 +83,7 @@ module usb_ft1248 (
fifo_8kb fifo_8kb_tx_inst (
.clk(clk),
.reset(reset || usb_scb.fifo_flush),
.reset(reset || fifo_flush),
.empty(tx_empty),
.almost_empty(tx_almost_empty),
@ -142,7 +147,6 @@ module usb_ft1248 (
logic [3:0] phase;
logic last_tx_failed;
logic reset_reply;
logic last_reset_status;
logic [4:0] modem_status_counter;
logic write_modem_status_pending;
logic write_buffer_flush_pending;
@ -152,7 +156,7 @@ module usb_ft1248 (
cmd <= next_cmd;
usb_scb.pwrsav <= !ft_pwrsav;
usb_scb.reset_state <= last_reset_status;
fifo_flush <= 1'b0;
phase <= {phase[2:0], phase[3]};
if (state == STATE_IDLE) begin
@ -160,25 +164,38 @@ module usb_ft1248 (
end
if (reset) begin
usb_scb.fifo_flush_busy <= 1'b0;
usb_scb.reset_state <= 1'b0;
last_tx_failed <= 1'b0;
usb_scb.reset_pending <= 1'b0;
last_reset_status <= 1'b0;
reset_reply <= 1'b0;
modem_status_counter <= 5'd0;
write_modem_status_pending <= 1'b0;
write_modem_status_pending <= 1'b1;
write_buffer_flush_pending <= 1'b0;
end else begin
if (usb_scb.reset_ack) begin
usb_scb.reset_pending <= 1'b0;
if (usb_scb.fifo_flush) begin
usb_scb.fifo_flush_busy <= 1'b1;
end
if (usb_scb.reset_on_ack) begin
reset_reply <= 1'b1;
write_modem_status_pending <= 1'b1;
end
if (usb_scb.reset_off_ack) begin
reset_reply <= 1'b0;
write_modem_status_pending <= 1'b1;
end
if (usb_scb.write_buffer_flush) begin
write_buffer_flush_pending <= 1'b1;
end
if (state == STATE_IDLE) begin
modem_status_counter <= modem_status_counter + 1'd1;
if (usb_scb.fifo_flush_busy) begin
usb_scb.fifo_flush_busy <= 1'b0;
fifo_flush <= 1'b1;
end
end
if ((state == STATE_DATA) && (cmd == CMD_WRITE) && phase[3]) begin
@ -187,14 +204,7 @@ module usb_ft1248 (
if (!ft_miso && (state == STATE_DATA) && phase[3]) begin
if (cmd == CMD_READ_MODEM_STATUS) begin
last_reset_status <= ft_miosi_in[0];
if (!last_reset_status && ft_miosi_in[0]) begin
usb_scb.reset_pending <= 1'b1;
end
if (last_reset_status && !ft_miosi_in[0]) begin
reset_reply <= 1'b0;
write_modem_status_pending <= 1'b1;
end
usb_scb.reset_state <= ft_miosi_in[0];
end
if (cmd == CMD_WRITE_MODEM_STATUS) begin
write_modem_status_pending <= 1'b0;
@ -283,7 +293,7 @@ module usb_ft1248 (
end else begin
case (state)
STATE_IDLE: begin
if (ft_pwrsav) begin
if (ft_pwrsav && !(usb_scb.fifo_flush || usb_scb.fifo_flush_busy || fifo_flush)) begin
if (write_modem_status_pending) begin
next_state = STATE_SELECT;
next_cmd = CMD_WRITE_MODEM_STATUS;

View File

@ -79,8 +79,8 @@ typedef enum {
#define USB_SCR_FIFO_FLUSH (1 << 0)
#define USB_SCR_RXNE (1 << 1)
#define USB_SCR_TXE (1 << 2)
#define USB_SCR_RESET_PENDING (1 << 3)
#define USB_SCR_RESET_ACK (1 << 4)
#define USB_SCR_RESET_ON_ACK (1 << 3)
#define USB_SCR_RESET_OFF_ACK (1 << 4)
#define USB_SCR_WRITE_FLUSH (1 << 5)
#define USB_SCR_RX_COUNT_BIT (6)
#define USB_SCR_RX_COUNT_MASK (0x7FF << USB_SCR_RX_COUNT_BIT)
@ -88,6 +88,7 @@ typedef enum {
#define USB_SCR_TX_COUNT_MASK (0x7FF << USB_SCR_TX_COUNT_BIT)
#define USB_SCR_RESET_STATE (1 << 28)
#define USB_SCR_PWRSAV (1 << 29)
#define USB_SCR_FIFO_FLUSH_BUSY (1 << 30)
#define DMA_SCR_START (1 << 0)
#define DMA_SCR_STOP (1 << 1)

View File

@ -43,6 +43,8 @@ enum tx_state {
struct process {
bool last_reset_state;
enum rx_state rx_state;
uint8_t rx_counter;
uint8_t rx_cmd;
@ -80,10 +82,6 @@ static const uint32_t ERR_TOKEN = (0x45525200UL);
static const uint32_t PKT_TOKEN = (0x504B5400UL);
static bool usb_dma_ready (void) {
return !((fpga_reg_get(REG_USB_DMA_SCR) & DMA_SCR_BUSY));
}
static bool usb_rx_byte (uint8_t *data) {
if (fpga_usb_status_get() & USB_STATUS_RXNE) {
*data = fpga_usb_pop();
@ -149,6 +147,59 @@ static bool usb_rx_cmd (uint8_t *cmd) {
return false;
}
static void usb_reset (void) {
fpga_reg_set(REG_USB_DMA_SCR, DMA_SCR_STOP);
while (fpga_reg_get(REG_USB_DMA_SCR) & DMA_SCR_BUSY);
fpga_reg_set(REG_USB_SCR, USB_SCR_FIFO_FLUSH);
while (fpga_reg_get(REG_USB_SCR) & USB_SCR_FIFO_FLUSH_BUSY);
p.rx_state = RX_STATE_IDLE;
p.tx_state = TX_STATE_IDLE;
p.response_pending = false;
p.packet_pending = false;
p.read_ready = true;
p.read_length = 0;
p.read_address = 0;
usb_rx_word_counter = 0;
usb_rx_word_buffer = 0;
usb_tx_word_counter = 0;
usb_rx_cmd_counter = 0;
}
static void usb_flush_packet (void) {
if (p.packet_pending && p.packet_info.done_callback) {
p.packet_pending = false;
p.packet_info.done_callback();
}
if (p.tx_state != TX_STATE_IDLE && p.tx_info.done_callback) {
p.tx_info.done_callback();
}
}
static bool usb_is_active (void) {
uint32_t scr = fpga_reg_get(REG_USB_SCR);
bool reset_state = (scr & USB_SCR_RESET_STATE);
if (p.last_reset_state != reset_state) {
p.last_reset_state = reset_state;
if (reset_state) {
usb_flush_packet();
usb_reset();
fpga_reg_set(REG_USB_SCR, USB_SCR_WRITE_FLUSH);
}
fpga_reg_set(REG_USB_SCR, reset_state ? USB_SCR_RESET_ON_ACK : USB_SCR_RESET_OFF_ACK);
return false;
}
return !(reset_state || (scr & USB_SCR_PWRSAV));
}
static bool usb_dma_ready (void) {
return !((fpga_reg_get(REG_USB_DMA_SCR) & DMA_SCR_BUSY));
}
static bool usb_validate_address_length (uint32_t address, uint32_t length, bool exclude_bootloader) {
if ((address >= MEMORY_LENGTH) || (length > MEMORY_LENGTH)) {
return true;
@ -556,42 +607,16 @@ void usb_get_read_info (uint32_t *args) {
void usb_init (void) {
fpga_reg_set(REG_USB_DMA_SCR, DMA_SCR_STOP);
fpga_reg_set(REG_USB_SCR, USB_SCR_FIFO_FLUSH);
p.rx_state = RX_STATE_IDLE;
p.tx_state = TX_STATE_IDLE;
p.response_pending = false;
p.packet_pending = false;
p.read_ready = true;
p.read_length = 0;
p.read_address = 0;
usb_rx_word_counter = 0;
usb_rx_word_buffer = 0;
usb_tx_word_counter = 0;
usb_rx_cmd_counter = 0;
p.last_reset_state = false;
usb_reset();
}
void usb_process (void) {
uint32_t scr = fpga_reg_get(REG_USB_SCR);
if (scr & (USB_SCR_PWRSAV | USB_SCR_RESET_STATE | USB_SCR_RESET_PENDING)) {
if (p.packet_pending && p.packet_info.done_callback) {
p.packet_pending = false;
p.packet_info.done_callback();
}
if (scr & USB_SCR_RESET_PENDING) {
if (p.tx_state != TX_STATE_IDLE && p.tx_info.done_callback) {
p.tx_info.done_callback();
}
usb_init();
fpga_reg_set(REG_USB_SCR, USB_SCR_RESET_ACK);
}
} else {
if (usb_is_active()) {
usb_rx_process();
usb_tx_process();
} else {
usb_flush_packet();
}
}

View File

@ -27,6 +27,7 @@ struct Wrapper {
context: *mut libftdi1_sys::ftdi_context,
unclog_buffer: std::collections::VecDeque<u8>,
write_buffer: Vec<u8>,
read_timeout: std::time::Duration,
write_timeout: std::time::Duration,
read_chunksize: usize,
write_chunksize: usize,
@ -49,6 +50,7 @@ impl Wrapper {
context,
unclog_buffer: std::collections::VecDeque::new(),
write_buffer: vec![],
read_timeout: Wrapper::DEFAULT_RW_TIMEOUT,
write_timeout: Wrapper::DEFAULT_RW_TIMEOUT,
read_chunksize: Wrapper::DEFAULT_CHUNKSIZE,
write_chunksize: Wrapper::DEFAULT_CHUNKSIZE,
@ -158,6 +160,7 @@ impl Wrapper {
(*self.context).usb_write_timeout = i32::try_from(write_timeout.as_millis())
.map_err(|_| std::io::ErrorKind::InvalidInput)?;
}
self.read_timeout = read_timeout;
self.write_timeout = write_timeout;
Ok(())
}
@ -221,6 +224,17 @@ impl Wrapper {
}
}
fn usb_reset(&mut self) -> std::io::Result<()> {
match unsafe { libftdi1_sys::ftdi_usb_reset(self.context) } {
0 => Ok(()),
-1 => Err(std::io::ErrorKind::BrokenPipe.into()),
-2 => Err(std::io::ErrorKind::NotConnected.into()),
result => Err(std::io::Error::other(format!(
"Unexpected response from ftdi_usb_reset: {result}"
))),
}
}
fn set_latency_timer(&mut self, latency: Option<std::time::Duration>) -> std::io::Result<()> {
let latency = u8::try_from(latency.unwrap_or(Wrapper::DEFAULT_POLL_TIMEOUT).as_millis())
.map_err(|_| std::io::ErrorKind::InvalidInput)?;
@ -300,14 +314,33 @@ impl Wrapper {
}
}
fn tcioflush(&mut self) -> std::io::Result<()> {
match unsafe { libftdi1_sys::ftdi_tcioflush(self.context) } {
fn tciflush(&mut self) -> std::io::Result<()> {
let timeout = std::time::Instant::now();
loop {
match self.read(&mut vec![0u8; self.read_chunksize]) {
Ok(_) => {}
Err(error) => match error.kind() {
std::io::ErrorKind::Interrupted | std::io::ErrorKind::WouldBlock => {
return Ok(());
}
_ => return Err(error),
},
};
if timeout.elapsed() > self.read_timeout {
return Err(std::io::ErrorKind::TimedOut.into());
}
}
}
fn tcoflush(&mut self) -> std::io::Result<()> {
self.write_buffer.clear();
match unsafe { libftdi1_sys::ftdi_tcoflush(self.context) } {
0 => Ok(()),
-1 => Err(std::io::ErrorKind::BrokenPipe.into()),
-2 => Err(std::io::ErrorKind::BrokenPipe.into()),
-3 => Err(std::io::ErrorKind::NotConnected.into()),
result => Err(std::io::Error::other(format!(
"Unexpected response from ftdi_tcioflush: {result}"
"Unexpected response from ftdi_tcoflush: {result}"
))),
}
}
@ -443,6 +476,8 @@ impl FtdiDevice {
wrapper.usb_open_string(description)?;
wrapper.usb_reset()?;
wrapper.set_latency_timer(poll_timeout)?;
Ok(FtdiDevice { wrapper })
@ -456,8 +491,12 @@ impl FtdiDevice {
Ok(self.wrapper.poll_modem_status()?.dsr)
}
pub fn discard_buffers(&mut self) -> std::io::Result<()> {
self.wrapper.tcioflush()
pub fn discard_input(&mut self) -> std::io::Result<()> {
self.wrapper.tciflush()
}
pub fn discard_output(&mut self) -> std::io::Result<()> {
self.wrapper.tcoflush()
}
}

View File

@ -1,5 +1,4 @@
use super::{error::Error, ftdi::FtdiDevice};
use serial2::SerialPort;
use std::{
collections::VecDeque,
fmt::Display,
@ -197,7 +196,7 @@ pub trait Backend {
}
pub struct SerialBackend {
device: SerialPort,
device: serial2::SerialPort,
}
impl Backend for SerialBackend {
@ -250,7 +249,7 @@ impl Backend for SerialBackend {
}
fn new_serial_backend(port: &str) -> std::io::Result<SerialBackend> {
let mut serial = SerialPort::open(port, 115_200)?;
let mut serial = serial2::SerialPort::open(port, 115_200)?;
serial.set_read_timeout(POLL_TIMEOUT)?;
serial.set_write_timeout(WRITE_TIMEOUT)?;
Ok(SerialBackend { device: serial })
@ -274,10 +273,11 @@ impl Backend for FtdiBackend {
}
fn reset(&mut self) -> std::io::Result<()> {
self.device.set_dtr(true)?;
self.device.discard_output()?;
let timeout = Instant::now();
self.device.set_dtr(true)?;
loop {
self.device.discard_buffers()?;
if self.device.read_dsr()? {
break;
}
@ -289,10 +289,10 @@ impl Backend for FtdiBackend {
}
}
self.purge_incoming_data()?;
self.device.discard_input()?;
self.device.set_dtr(false)?;
let timeout = Instant::now();
self.device.set_dtr(false)?;
loop {
if !self.device.read_dsr()? {
break;