Skip to content

Commit

Permalink
Try #91:
Browse files Browse the repository at this point in the history
  • Loading branch information
bors[bot] authored Dec 26, 2020
2 parents bca94ff + b74dbb5 commit ba2fc98
Show file tree
Hide file tree
Showing 25 changed files with 690 additions and 243 deletions.
82 changes: 81 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,87 @@

## Unreleased

- Add `teensy4_bsp::usb::Filter` type alias to simplify USB filter definitions
This release lets users combine the USB logging system with RTIC. The new
feature required a few breaking changes. The rest of this section notes
the breaking changes, migration tips, and other minor features in this
release.

De-couple the USB logging and SysTick modules. You no longer need the SysTick
timer to use the USB logging system. The BSP features are now independent,
though they're both enabled by default. This change means that you can use
RTIC with USB logging. See the RTIC examples for a demonstration.

Users may now check USB poll status in their own USB interrupt handler. This
may support more responsive reading from a USB host.

**BREAKING** The `"usb-logging"` feature will not implicitly enable the
`"systick"` feature. To fix your build, explicitly add the `"systick"` feature:

```toml
[dependencies.teensy4-bsp]
# features = ["usb-logging"] # Before
features = ["usb-logging", "systick"] # After
default-features = false
```

This only affects users who specify `default-features = false`.

**BREAKING** Since USB logging does not need SysTick, the setup functions
do not accept a `&SysTick` reference. The change applies to these two
functions:

- `usb::init`
- `usb::split`

Instead, the functions require the `imxrt_ral`'s `USB1` instance. The example
below shows one way to migrate your code:

```rust
use teensy4_bsp as bsp;

// Before
let systick = bsp::SysTick::new(cortex_m::Peripherals::take().unwrap().SYST);
bsp::usb::init(&systick, Default::default()).unwrap();

// Now
use bsp::hal::ral::usb::USB1;
bsp::usb::init(USB1::take().unwrap(), Default::default()).unwrap();
```

**BREAKING** The USB `Reader` and `Writer` methods are fallible. Instead of
returning `usize`s, the methods now return `Result<usize, Error>`. See the
documentation to understand the `Error` type, and to learn about the new
method guarantees.

**BREAKING** Users must `poll()` the USB driver to coordinate USB I/O. The BSP
does not implement the `USB_OTG1` interrupt handler. If you do not
repeatedly call `poll()`, or you do not call it fast enough, the USB device may
now work.

Consider calling `poll()` in your own `USB_OTG1` interrupt handler to maintain
compatibility. If using an interrupt handler, make sure to unmask the `USB_OTG1`
interrupt.

The snippet below should be sufficient to maintain compatibility in your
system:

```rust
use teensy4_bsp as bsp;
use bsp::interrupt;

#[cortex_m_rt::interrupt]
unsafe fn USB_OTG1() {
bsp::usb::poll();
}

// Unmask the interrupt after calling the `usb::init`
// or `usb::setup` functions.
unsafe { cortex_m::peripheral::NVIC::unmask(interrupt::USB_OTG1) };
```

Add a `flush` method to the `usb::Writer` type.

Add `teensy4_bsp::usb::Filter` type alias to simplify USB filter definitions.

## [0.1.0] - 2020-10-16

Expand Down
6 changes: 1 addition & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,7 @@ members = [
# Default features established for prototype development
default = ["usb-logging", "systick"]
# Enables the USB logging stack
#
# This will introduce the teensy4-usb-sys bindings into the build
# graph. It also requires systick, since the USB stack depends on
# the systick counter for timekeeping.
usb-logging = ["systick", "log"]
usb-logging = ["log"]
# Include a definition of the SysTick exception handler. This enables
# a simple delay() spinloop that waits for the timer to elapse.
#
Expand Down
Binary file modified bin/libt4usb.a
Binary file not shown.
29 changes: 23 additions & 6 deletions bin/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
#include <string.h>
#include "debug/printf.h"

void delay(uint32_t);

//#define LOG_SIZE 20
//uint32_t transfer_log_head=0;
//uint32_t transfer_log_count=0;
Expand Down Expand Up @@ -97,6 +95,9 @@ static void endpoint0_complete(void);

static void run_callbacks(endpoint_t *ep);

int32_t usb_device_is_configured(void) {
return !!usb_configuration;
}

FLASHMEM void usb_init(void)
{
Expand Down Expand Up @@ -143,14 +144,12 @@ FLASHMEM void usb_init(void)
USBPHY1_CTRL_CLR = USBPHY_CTRL_SFTRST; // reset PHY
//USB1_USBSTS = USB1_USBSTS; // TODO: is this needed?
printf("USB reset took %d loops\n", count);
//delay(10);
//printf("\n");
//printf("USBPHY1_PWD=%08lX\n", USBPHY1_PWD);
//printf("USBPHY1_TX=%08lX\n", USBPHY1_TX);
//printf("USBPHY1_RX=%08lX\n", USBPHY1_RX);
//printf("USBPHY1_CTRL=%08lX\n", USBPHY1_CTRL);
//printf("USB1_USBMODE=%08lX\n", USB1_USBMODE);
delay(25);
}
#endif
// Device Controller Initialization, page 3161
Expand Down Expand Up @@ -197,15 +196,28 @@ FLASHMEM void usb_init(void)
//transfer_log_count = 0;
}

#define POLL_RX_ENDPOINT_MASK(ep) (1 << ep)
#define POLL_TX_ENDPOINT_MASK(ep) (1 << (ep + 16))

//
// Keep these in sync with the constants
// in bindings.rs.
//

typedef enum {
POLL_CDC_RX_COMPLETE = 1,
POLL_CDC_TX_COMPLETE = 2,
} poll_flag_t;

void isr(void)
uint32_t poll(void)
{
//printf("*");

// Port control in device mode is only used for
// status port reset, suspend, and current connect status.
uint32_t status = USB1_USBSTS;
USB1_USBSTS = status;
uint32_t poll_flags = 0;

// USB_USBSTS_SLI - set to 1 when enters a suspend state from an active state
// USB_USBSTS_SRI - set at start of frame
Expand All @@ -232,6 +244,10 @@ void isr(void)
setupstatus = USB1_ENDPTSETUPSTAT; // page 3175
}
uint32_t completestatus = USB1_ENDPTCOMPLETE;

poll_flags |= (POLL_RX_ENDPOINT_MASK(CDC_RX_ENDPOINT) & completestatus) ? POLL_CDC_RX_COMPLETE : 0;
poll_flags |= (POLL_TX_ENDPOINT_MASK(CDC_TX_ENDPOINT) & completestatus) ? POLL_CDC_TX_COMPLETE : 0;

if (completestatus) {
USB1_ENDPTCOMPLETE = completestatus;
//printf("USB1_ENDPTCOMPLETE=%lX\n", completestatus);
Expand Down Expand Up @@ -308,6 +324,8 @@ void isr(void)
USB1_USBINTR &= ~USB_USBINTR_SRE;
}
}

return poll_flags;
}


Expand Down Expand Up @@ -450,7 +468,6 @@ static void endpoint0_setup(uint64_t setupdata)
break;
#if defined(CDC_STATUS_INTERFACE)
case 0x2221: // CDC_SET_CONTROL_LINE_STATE
usb_cdc_line_rtsdtr_millis = systick_millis_count;
usb_cdc_line_rtsdtr = setup.wValue;
__attribute__((fallthrough));
case 0x2321: // CDC_SEND_BREAK
Expand Down
62 changes: 10 additions & 52 deletions bin/usb_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ void yield(void);
//#if F_CPU >= 20000000

uint32_t usb_cdc_line_coding[2];
volatile uint32_t usb_cdc_line_rtsdtr_millis;
volatile uint8_t usb_cdc_line_rtsdtr=0;
volatile uint8_t usb_cdc_transmit_flush_timer=0;

Expand Down Expand Up @@ -99,7 +98,7 @@ void usb_serial_configure(void)
}
memset(tx_transfer, 0, sizeof(tx_transfer));
tx_head = 0;
tx_available = 0;
tx_available = TX_SIZE;
memset(rx_transfer, 0, sizeof(rx_transfer));
memset(rx_count, 0, sizeof(rx_count));
memset(rx_index, 0, sizeof(rx_index));
Expand Down Expand Up @@ -267,21 +266,12 @@ int usb_serial_getchar(void)
#define TX_TIMEOUT_MSEC 120


// When we've suffered the transmit timeout, don't wait again until the computer
// begins accepting data. If no software is running to receive, we'll just discard
// data as rapidly as Serial.print() can generate it, until there's something to
// actually receive it.
static uint8_t transmit_previous_timeout=0;


// transmit a character. 0 returned on success, -1 on error
int usb_serial_putchar(uint8_t c)
{
return usb_serial_write(&c, 1);
}

extern volatile uint32_t systick_millis_count;

static void timer_config(void (*callback)(void), uint32_t microseconds);
static void timer_start_oneshot();
static void timer_stop();
Expand All @@ -305,50 +295,20 @@ static void timer_stop(void)
USB1_GPTIMER0CTRL = 0;
}

// Keep this in sync with the error constants
// in bindings.rs.
typedef enum {
SERIAL_NOT_CONFIGURED = -1,
} serial_err_t;

int usb_serial_write(const void *buffer, uint32_t size)
{
uint32_t sent=0;
const uint8_t *data = (const uint8_t *)buffer;

if (!usb_configuration) return 0;
if (!usb_configuration) return SERIAL_NOT_CONFIGURED;
while (size > 0) {
transfer_t *xfer = tx_transfer + tx_head;
int waiting=0;
uint32_t wait_begin_at=0;
while (!tx_available) {
//digitalWriteFast(3, HIGH);
uint32_t status = usb_transfer_status(xfer);
if (!(status & 0x80)) {
if (status & 0x68) {
// TODO: what if status has errors???
printf("ERROR status = %x, i=%d, ms=%u\n",
status, tx_head, systick_millis_count);
}
tx_available = TX_SIZE;
transmit_previous_timeout = 0;
break;
}
if (!waiting) {
wait_begin_at = systick_millis_count;
waiting = 1;
}
if (transmit_previous_timeout) return sent;
if (systick_millis_count - wait_begin_at > TX_TIMEOUT_MSEC) {
// waited too long, assume the USB host isn't listening
transmit_previous_timeout = 1;
return sent;
//printf("\nstop, waited too long\n");
//printf("status = %x\n", status);
//printf("tx head=%d\n", tx_head);
//printf("TXFILLTUNING=%08lX\n", USB1_TXFILLTUNING);
//usb_print_transfer_log();
//while (1) ;
}
if (!usb_configuration) return sent;
yield();
}
//digitalWriteFast(3, LOW);
uint8_t *txdata = txbuffer + (tx_head * TX_SIZE) + (TX_SIZE - tx_available);
if (size >= tx_available) {
memcpy(txdata, data, tx_available);
Expand All @@ -362,7 +322,7 @@ int usb_serial_write(const void *buffer, uint32_t size)
size -= tx_available;
sent += tx_available;
data += tx_available;
tx_available = 0;
tx_available = TX_SIZE;
timer_stop();
} else {
memcpy(txdata, data, size);
Expand Down Expand Up @@ -391,7 +351,6 @@ void usb_serial_flush_output(void)
{

if (!usb_configuration) return;
if (tx_available == 0) return;
tx_noautoflush = 1;
transfer_t *xfer = tx_transfer + tx_head;
uint8_t *txbuf = txbuffer + (tx_head * TX_SIZE);
Expand All @@ -400,15 +359,14 @@ void usb_serial_flush_output(void)
arm_dcache_flush_delete(txbuf, txnum);
usb_transmit(CDC_TX_ENDPOINT, xfer);
if (++tx_head >= TX_NUM) tx_head = 0;
tx_available = 0;
tx_available = TX_SIZE;
tx_noautoflush = 0;
}

static void usb_serial_flush_callback(void)
{
if (tx_noautoflush) return;
if (!usb_configuration) return;
if (tx_available == 0) return;
//printf("flush callback, %d bytes\n", TX_SIZE - tx_available);
transfer_t *xfer = tx_transfer + tx_head;
uint8_t *txbuf = txbuffer + (tx_head * TX_SIZE);
Expand All @@ -417,7 +375,7 @@ static void usb_serial_flush_callback(void)
arm_dcache_flush_delete(txbuf, txnum);
usb_transmit(CDC_TX_ENDPOINT, xfer);
if (++tx_head >= TX_NUM) tx_head = 0;
tx_available = 0;
tx_available = TX_SIZE;
}


Expand Down
Loading

0 comments on commit ba2fc98

Please sign in to comment.