Skip to content

Commit

Permalink
arm-teensy3: fix paste via USB and fix restart
Browse files Browse the repository at this point in the history
- use half of the USB buffers for the TX path, and half for the RX path,
  and hand over only RX buffers when RX exhaustion is detected,

- add new words uart-on uart-off uart? for controlling UART console, and
  usb-on usb-off usb? for controlling USB console,

- add new word restart to use watchdog method for forcing system reset,
  and allow bye to fall out of interpreter into restart,

- add new word reflash for placing system into wait for loader,
  equivalent to pressing the button,

- remove watchdog test file; only ever used for restarting.
  • Loading branch information
quozl committed Jul 10, 2017
1 parent 702efdc commit 3bcb753
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 33 deletions.
1 change: 0 additions & 1 deletion src/app/arm-teensy3/app.fth
Expand Up @@ -3,7 +3,6 @@
fl ../../lib/misc.fth
fl ../../lib/dl.fth

fl ../../platform/arm-teensy3/watchdog.fth
fl ../../platform/arm-teensy3/timer.fth
fl ../../platform/arm-teensy3/pcr.fth
fl ../../platform/arm-teensy3/i2c.fth
Expand Down
104 changes: 95 additions & 9 deletions src/platform/arm-teensy3/consoleio.c
Expand Up @@ -26,15 +26,49 @@ char * ultoa(unsigned long val, char *buf, int radix)
return buf;
}

int seen_usb; /* data has been received from the USB host */
int use_uart; /* data has been received from the UART */
int use_usb; /* data has been received from the USB host */
int sent_usb; /* data has been sent to the USB layer that is not yet flushed */

void console_uart_on()
{
use_uart++;
}

void console_uart_off()
{
use_uart = 0;
}

int console_uart()
{
return use_uart;
}

void console_usb_on()
{
use_usb++;
}

void console_usb_off()
{
use_usb = 0;
}

int console_usb()
{
return use_usb;
}

void tx(char c)
{
while(!(UART0_S1 & UART_S1_TDRE)) // pause until transmit data register empty
;
UART0_D = c;
if (seen_usb) {
if (use_uart) {
/* pause until transmit data register empty */
while(!(UART0_S1 & UART_S1_TDRE))
;
UART0_D = c;
}
if (use_usb) {
usb_serial_putchar(c);
sent_usb++;
}
Expand All @@ -47,6 +81,50 @@ int putchar(int c)
tx(c);
}

#if 0
// usb debug
void serial_putchar(char c)
{
if (!use_usb) return;
while(!(UART0_S1 & UART_S1_TDRE))
;
UART0_D = c;
}

static void serial_phex1(uint32_t n)
{
n &= 15;
if (n < 10) {
serial_putchar('0' + n);
} else {
serial_putchar('A' - 10 + n);
}
}

void serial_phex(uint32_t n)
{
serial_phex1(n >> 4);
serial_phex1(n);
}

void serial_phex32(uint32_t n)
{
serial_phex(n >> 24);
serial_phex(n >> 16);
serial_phex(n >> 8);
serial_phex(n);
}

void serial_print(const char *p)
{
while (*p) {
char c = *p++;
if (c == '\n') serial_putchar('\r');
serial_putchar(c);
}
}
#endif

#if 0
// early debug
const char hexen[] = "0123456789ABCDEF";
Expand Down Expand Up @@ -74,8 +152,14 @@ void putline(char *str)

int kbhit()
{
if (UART0_RCFIFO > 0) return 1;
if (usb_serial_peekchar() != -1) return 1;
if (UART0_RCFIFO > 0) {
use_uart++;
return 1;
}
if (usb_serial_peekchar() != -1) {
use_usb++;
return 1;
}
return 0;
}

Expand All @@ -89,11 +173,12 @@ int getkey()
while (1) {
if (UART0_RCFIFO > 0) {
c = UART0_D;
use_uart++;
return c;
}
c = usb_serial_getchar();
if (c != -1) {
seen_usb++;
use_usb++;
return c;
}
}
Expand Down Expand Up @@ -127,7 +212,8 @@ void init_io(int argc, char **argv, cell *up)
// transmitter enable, receiver enable
UART0_C2 = UART_C2_TE | UART_C2_RE;

seen_usb = 0;
use_uart = 0;
use_usb = 0;
sent_usb = 0;
}

Expand Down
35 changes: 34 additions & 1 deletion src/platform/arm-teensy3/textend.c
Expand Up @@ -24,6 +24,12 @@ cell eeprom_write_byte();
unsigned long rtc_get(void);
void rtc_set(unsigned long t);
void rtc_compensate(int adjust);
void console_uart_on();
void console_uart_off();
int console_uart();
void console_usb_on();
void console_usb_off();
int console_usb();

cell version_adr(void)
{
Expand All @@ -37,6 +43,26 @@ cell build_date_adr(void)
return (cell)build_date;
}

/*
* "Watchdog Unlock register (WDOG_UNLOCK)"
* "Writing the unlock sequence values to this register to makes the
* watchdog write-once registers writable again. The required unlock
* sequence is 0xC520 followed by 0xD928 within 20 bus clock cycles.
* A valid unlock sequence opens a window equal in length to the WCT
* within which you can update the registers. Writing a value other
* than the above mentioned sequence or if the sequence is longer than
* 20 bus cycles, resets the system or if IRQRSTEN is set, it
* interrupts and then resets the system. The unlock sequence is
* effective only if ALLOWUPDATE is set."
* -- K20P64M72SF1RM.pdf 23.7.8 page 478
*/
#define WDOG_UNLOCK (*(volatile uint32_t *)0x4005200e)

void restart(void)
{
WDOG_UNLOCK = 0; /* force system reset */
}

cell ((* const ccalls[])()) = {
C(spins) //c spins { i.nspins -- }
C(wfi) //c wfi { -- }
Expand All @@ -48,7 +74,6 @@ cell ((* const ccalls[])()) = {
C(pinMode) //c m! { i.mode i.pin -- }
C(micros) //c get-usecs { -- n }
C(delay) //c ms { i.#ms -- }
C(_reboot_Teensyduino_) //c bye
C(eeprom_size) //c /nv { -- n }
C(eeprom_base) //c nv-base { -- n }
C(eeprom_length) //c nv-length { -- n }
Expand All @@ -59,4 +84,12 @@ cell ((* const ccalls[])()) = {
C(rtc_get) //c rtc@ { -- i.val }
C(rtc_set) //c rtc! { i.val -- }
C(rtc_compensate) //c rtc_compensate { i.adjust -- }
C(console_uart) //c uart? { -- i.bytes }
C(console_uart_on) //c uart-on { -- }
C(console_uart_off) //c uart-off { -- }
C(console_usb) //c usb? { -- i.bytes }
C(console_usb_on) //c usb-on { -- }
C(console_usb_off) //c usb-off { -- }
C(_reboot_Teensyduino_) //c reflash { -- }
C(restart) //c restart { -- }
};
2 changes: 1 addition & 1 deletion src/platform/arm-teensy3/tmain.c
Expand Up @@ -8,5 +8,5 @@ main()

up = (void *)init_forth();
execute_word("app", up); // Call the top-level application word
// execute_word("quit", up); // Call the Forth text interpreter
restart(); // On bye, restart rather than hang
}
6 changes: 3 additions & 3 deletions src/platform/arm-teensy3/usb_dev.c
Expand Up @@ -235,15 +235,15 @@ static void usb_setup(void)
#endif
if (epconf & USB_ENDPT_EPRXEN) {
usb_packet_t *p;
p = usb_malloc();
p = usb_malloc(1);
if (p) {
table[index(i, RX, EVEN)].addr = p->buf;
table[index(i, RX, EVEN)].desc = BDT_DESC(64, 0);
} else {
table[index(i, RX, EVEN)].desc = 0;
usb_rx_memory_needed++;
}
p = usb_malloc();
p = usb_malloc(1);
if (p) {
table[index(i, RX, ODD)].addr = p->buf;
table[index(i, RX, ODD)].desc = BDT_DESC(64, 1);
Expand Down Expand Up @@ -1008,7 +1008,7 @@ void usb_isr(void)
// packets, so a flood of incoming data on 1 endpoint
// doesn't starve the others if the user isn't reading
// it regularly
packet = usb_malloc();
packet = usb_malloc(1);
if (packet) {
b->addr = packet->buf;
b->desc = BDT_DESC(64,
Expand Down
23 changes: 14 additions & 9 deletions src/platform/arm-teensy3/usb_mem.c
Expand Up @@ -40,26 +40,31 @@ unsigned char usb_buffer_memory[NUM_USB_BUFFERS * sizeof(usb_packet_t)];

static uint32_t usb_buffer_available = 0xFFFFFFFF;

#define MASK_RX 0x55555555 // 50% share tx vs rx
#define MASK_TX 0xaaaaaaaa

// use bitmask and CLZ instruction to implement fast free list
// http://www.archivum.info/gnu.gcc.help/2006-08/00148/Re-GCC-Inline-Assembly.html
// http://gcc.gnu.org/ml/gcc/2012-06/msg00015.html
// __builtin_clz()

usb_packet_t * usb_malloc(void)
usb_packet_t * usb_malloc(int rx)
{
unsigned int n, avail;
unsigned int mask, n, avail;
uint8_t *p;

mask = rx ? MASK_TX : MASK_RX;
__disable_irq();
avail = usb_buffer_available;
n = __builtin_clz(avail); // clz = count leading zeros
n = __builtin_clz(avail & ~mask); // clz = count leading zeros
if (n >= NUM_USB_BUFFERS) {
__enable_irq();
//serial_print("MALLOC FAIL\n");
return NULL;
}
//serial_print("malloc:");
//serial_print("malloc ");
//serial_phex(n);
//serial_print("\n");
//if (rx) serial_print(" (rx)\n"); else serial_print(" (TX)\n");

usb_buffer_available = avail & ~(0x80000000 >> n);
__enable_irq();
Expand All @@ -80,23 +85,23 @@ void usb_free(usb_packet_t *p)
{
unsigned int n, mask;

//serial_print("free:");
n = ((uint8_t *)p - usb_buffer_memory) / sizeof(usb_packet_t);
if (n >= NUM_USB_BUFFERS) return;
//serial_print("free ");
//serial_phex(n);
//serial_print("\n");
mask = (0x80000000 >> n);

// if any endpoints are starving for memory to receive
// packets, give this memory to them immediately!
if (usb_rx_memory_needed && usb_configuration) {
if ((mask & MASK_RX) && usb_rx_memory_needed && usb_configuration) {
//serial_print("give to rx:");
//serial_phex32((int)p);
//serial_phex(n);
//serial_print("\n");
usb_rx_memory(p);
return;
}

mask = (0x80000000 >> n);
__disable_irq();
usb_buffer_available |= mask;
__enable_irq();
Expand Down
2 changes: 1 addition & 1 deletion src/platform/arm-teensy3/usb_mem.h
Expand Up @@ -44,7 +44,7 @@ typedef struct usb_packet_struct {
extern "C" {
#endif

usb_packet_t * usb_malloc(void);
usb_packet_t * usb_malloc(int);
void usb_free(usb_packet_t *p);

#ifdef __cplusplus
Expand Down
8 changes: 4 additions & 4 deletions src/platform/arm-teensy3/usb_serial.c
Expand Up @@ -206,7 +206,7 @@ int usb_serial_write(const void *buffer, uint32_t size)
}
if (usb_tx_packet_count(CDC_TX_ENDPOINT) < TX_PACKET_LIMIT) {
tx_noautoflush = 1;
tx_packet = usb_malloc();
tx_packet = usb_malloc(0);
if (tx_packet) break;
tx_noautoflush = 0;
}
Expand Down Expand Up @@ -243,7 +243,7 @@ int usb_serial_write_buffer_free(void)
if (!tx_packet) {
if (!usb_configuration ||
usb_tx_packet_count(CDC_TX_ENDPOINT) >= TX_PACKET_LIMIT ||
(tx_packet = usb_malloc()) == NULL) {
(tx_packet = usb_malloc(0)) == NULL) {
tx_noautoflush = 0;
return 0;
}
Expand All @@ -270,7 +270,7 @@ void usb_serial_flush_output(void)
usb_tx(CDC_TX_ENDPOINT, tx_packet);
tx_packet = NULL;
} else {
usb_packet_t *tx = usb_malloc();
usb_packet_t *tx = usb_malloc(0);
if (tx) {
usb_cdc_transmit_flush_timer = 0;
usb_tx(CDC_TX_ENDPOINT, tx);
Expand All @@ -289,7 +289,7 @@ void usb_serial_flush_callback(void)
usb_tx(CDC_TX_ENDPOINT, tx_packet);
tx_packet = NULL;
} else {
usb_packet_t *tx = usb_malloc();
usb_packet_t *tx = usb_malloc(0);
if (tx) {
usb_tx(CDC_TX_ENDPOINT, tx);
} else {
Expand Down
4 changes: 0 additions & 4 deletions src/platform/arm-teensy3/watchdog.fth

This file was deleted.

0 comments on commit 3bcb753

Please sign in to comment.