@@ -0,0 +1,199 @@ | |||
/* Teensyduino Core Library | |||
* http://www.pjrc.com/teensy/ | |||
* Copyright (c) 2017 PJRC.COM, LLC. | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining | |||
* a copy of this software and associated documentation files (the | |||
* "Software"), to deal in the Software without restriction, including | |||
* without limitation the rights to use, copy, modify, merge, publish, | |||
* distribute, sublicense, and/or sell copies of the Software, and to | |||
* permit persons to whom the Software is furnished to do so, subject to | |||
* the following conditions: | |||
* | |||
* 1. The above copyright notice and this permission notice shall be | |||
* included in all copies or substantial portions of the Software. | |||
* | |||
* 2. If the Software is incorporated into a build system that allows | |||
* selection among a list of target devices, then similar target | |||
* devices manufactured by PJRC.COM must be included in the list of | |||
* target devices and selectable in the same manner. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
* SOFTWARE. | |||
*/ | |||
// Long ago this file contained code from Arduino.cc, which was | |||
// Copyright (c) 2008 David A. Mellis. No substantial portion of | |||
// Arduino's original code remains. In fact, several improvements | |||
// developed for Teensyduino have made their way back into | |||
// Arduino's code base. :-) | |||
#include <Arduino.h> | |||
#include "debug/printf.h" | |||
#undef printf | |||
size_t Print::write(const uint8_t *buffer, size_t size) | |||
{ | |||
size_t count = 0; | |||
while (size--) count += write(*buffer++); | |||
return count; | |||
} | |||
size_t Print::print(const String &s) | |||
{ | |||
uint8_t buffer[33]; | |||
size_t count = 0; | |||
unsigned int index = 0; | |||
unsigned int len = s.length(); | |||
while (len > 0) { | |||
s.getBytes(buffer, sizeof(buffer), index); | |||
unsigned int nbytes = len; | |||
if (nbytes > sizeof(buffer)-1) nbytes = sizeof(buffer)-1; | |||
index += nbytes; | |||
len -= nbytes; | |||
count += write(buffer, nbytes); | |||
} | |||
return count; | |||
} | |||
size_t Print::print(long n) | |||
{ | |||
uint8_t sign=0; | |||
if (n < 0) { | |||
sign = '-'; | |||
n = -n; | |||
} | |||
return printNumber(n, 10, sign); | |||
} | |||
size_t Print::println(void) | |||
{ | |||
uint8_t buf[2]={'\r', '\n'}; | |||
return write(buf, 2); | |||
} | |||
extern "C" { | |||
__attribute__((weak)) | |||
int _write(int file, char *ptr, int len) | |||
{ | |||
((class Print *)file)->write((uint8_t *)ptr, len); | |||
return len; | |||
} | |||
} | |||
int Print::printf(const char *format, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, format); | |||
#ifdef __STRICT_ANSI__ | |||
return 0; // TODO: make this work with -std=c++0x | |||
#else | |||
return vdprintf((int)this, format, ap); | |||
#endif | |||
} | |||
int Print::printf(const __FlashStringHelper *format, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, format); | |||
#ifdef __STRICT_ANSI__ | |||
return 0; | |||
#else | |||
return vdprintf((int)this, (const char *)format, ap); | |||
#endif | |||
} | |||
size_t Print::printNumber(unsigned long n, uint8_t base, uint8_t sign) | |||
{ | |||
uint8_t buf[34]; | |||
uint8_t digit, i; | |||
// TODO: make these checks as inline, since base is | |||
// almost always a constant. base = 0 (BYTE) should | |||
// inline as a call directly to write() | |||
if (base == 0) { | |||
return write((uint8_t)n); | |||
} else if (base == 1) { | |||
base = 10; | |||
} | |||
if (n == 0) { | |||
buf[sizeof(buf) - 1] = '0'; | |||
i = sizeof(buf) - 1; | |||
} else { | |||
i = sizeof(buf) - 1; | |||
while (1) { | |||
digit = n % base; | |||
buf[i] = ((digit < 10) ? '0' + digit : 'A' + digit - 10); | |||
n /= base; | |||
if (n == 0) break; | |||
i--; | |||
} | |||
} | |||
if (sign) { | |||
i--; | |||
buf[i] = '-'; | |||
} | |||
return write(buf + i, sizeof(buf) - i); | |||
} | |||
size_t Print::printFloat(double number, uint8_t digits) | |||
{ | |||
uint8_t sign=0; | |||
size_t count=0; | |||
if (isnan(number)) return print("nan"); | |||
if (isinf(number)) return print("inf"); | |||
if (number > 4294967040.0f) return print("ovf"); // constant determined empirically | |||
if (number <-4294967040.0f) return print("ovf"); // constant determined empirically | |||
// Handle negative numbers | |||
if (number < 0.0) { | |||
sign = 1; | |||
number = -number; | |||
} | |||
// Round correctly so that print(1.999, 2) prints as "2.00" | |||
double rounding = 0.5; | |||
for (uint8_t i=0; i<digits; ++i) { | |||
rounding *= 0.1; | |||
} | |||
number += rounding; | |||
// Extract the integer part of the number and print it | |||
unsigned long int_part = (unsigned long)number; | |||
double remainder = number - (double)int_part; | |||
count += printNumber(int_part, 10, sign); | |||
// Print the decimal point, but only if there are digits beyond | |||
if (digits > 0) { | |||
uint8_t n, buf[16], count=1; | |||
buf[0] = '.'; | |||
// Extract digits from the remainder one at a time | |||
if (digits > sizeof(buf) - 1) digits = sizeof(buf) - 1; | |||
while (digits-- > 0) { | |||
remainder *= 10.0; | |||
n = (uint8_t)(remainder); | |||
buf[count++] = '0' + n; | |||
remainder -= n; | |||
} | |||
count += write(buf, count); | |||
} | |||
return count; | |||
} | |||
@@ -109,23 +109,7 @@ class Print | |||
private: | |||
char write_error; | |||
size_t printFloat(double n, uint8_t digits); | |||
#ifdef __MKL26Z64__ | |||
size_t printNumberDec(unsigned long n, uint8_t sign); | |||
size_t printNumberHex(unsigned long n); | |||
size_t printNumberBin(unsigned long n); | |||
size_t printNumberAny(unsigned long n, uint8_t base); | |||
inline size_t printNumber(unsigned long n, uint8_t base, uint8_t sign) __attribute__((always_inline)) { | |||
// when "base" is a constant (pretty much always), the | |||
// compiler optimizes this to a single function call. | |||
if (base == 0) return write((uint8_t)n); | |||
if (base == 10 || base < 2) return printNumberDec(n, sign); | |||
if (base == 16) return printNumberHex(n); | |||
if (base == 2) return printNumberBin(n); | |||
return printNumberAny(n, base); | |||
} | |||
#else | |||
size_t printNumber(unsigned long n, uint8_t base, uint8_t sign); | |||
#endif | |||
}; | |||
@@ -0,0 +1,5 @@ | |||
#include <stdint.h> | |||
volatile uint32_t F_CPU_ACTUAL = 396000000; | |||
volatile uint32_t F_BUS_ACTUAL = 132000000; | |||
@@ -617,11 +617,6 @@ void analogWrite(uint8_t pin, int val); | |||
uint32_t analogWriteRes(uint32_t bits); | |||
static inline uint32_t analogWriteResolution(uint32_t bits) { return analogWriteRes(bits); } | |||
void analogWriteFrequency(uint8_t pin, float frequency); | |||
#ifdef __cplusplus | |||
void attachInterruptVector(IRQ_NUMBER_t irq, void (*function)(void)); | |||
#else | |||
void attachInterruptVector(enum IRQ_NUMBER_t irq, void (*function)(void)); | |||
#endif | |||
void attachInterrupt(uint8_t pin, void (*function)(void), int mode); | |||
void detachInterrupt(uint8_t pin); | |||
void _init_Teensyduino_internal_(void); |
@@ -2,9 +2,16 @@ | |||
#ifdef PRINT_DEBUG_STUFF | |||
#define printf_init() printf_debug_init() | |||
// defining printf this way breaks things like Serial.printf() in C++ :( | |||
#define printf(...) printf_debug(__VA_ARGS__) | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
void print_debug_init(void); | |||
void printf_debug(const char *format, ...); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#else | |||
#define printf_init() |
@@ -5,6 +5,7 @@ | |||
#include <stdarg.h> | |||
#include "imxrt.h" | |||
void putchar_debug(char c); | |||
static void puint_debug(unsigned int num); | |||
@@ -32,7 +33,6 @@ void printf_debug(const char *format, ...) | |||
n = -n; | |||
putchar_debug('-'); | |||
} | |||
val = n; | |||
puint_debug(n); | |||
} else if (*format == 'u') { | |||
puint_debug(va_arg(args, unsigned int)); | |||
@@ -80,11 +80,11 @@ void putchar_debug(char c) | |||
__attribute__((section(".progmem"))) | |||
void printf_debug_init(void) | |||
{ | |||
// turn on Serial4, run at 115200 baud using 24 MHz clock (works if PLL3 off) | |||
// turn on Serial4, run using 24 MHz clock (works if PLL3 off or bypassed) | |||
CCM_CCGR0 |= CCM_CCGR0_LPUART3(CCM_CCGR_ON); | |||
IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_06 = 2; // Arduino pin 17 | |||
CCM_CSCDR1 = (CCM_CSCDR1 & ~CCM_CSCDR1_UART_CLK_PODF(0x3F)) | CCM_CSCDR1_UART_CLK_SEL; | |||
LPUART3_BAUD = LPUART_BAUD_OSR(25) | LPUART_BAUD_SBR(8); | |||
LPUART3_BAUD = LPUART_BAUD_OSR(25) | LPUART_BAUD_SBR(8); // ~115200 baud | |||
LPUART3_CTRL = LPUART_CTRL_TE; | |||
} | |||
@@ -170,6 +170,17 @@ enum IRQ_NUMBER_t { | |||
#define NVIC_NUM_INTERRUPTS 160 | |||
#define DMA_NUM_CHANNELS 32 | |||
#ifdef __cplusplus | |||
extern "C" void (* _VectorsRam[NVIC_NUM_INTERRUPTS+16])(void); | |||
static inline void attachInterruptVector(IRQ_NUMBER_t irq, void (*function)(void)) __attribute__((always_inline, unused)); | |||
static inline void attachInterruptVector(IRQ_NUMBER_t irq, void (*function)(void)) { _VectorsRam[irq + 16] = function; } | |||
#else | |||
extern void (* _VectorsRam[NVIC_NUM_INTERRUPTS+16])(void); | |||
static inline void attachInterruptVector(enum IRQ_NUMBER_t irq, void (*function)(void)) __attribute__((always_inline, unused)); | |||
static inline void attachInterruptVector(enum IRQ_NUMBER_t irq, void (*function)(void)) { _VectorsRam[irq + 16] = function; } | |||
#endif | |||
#define DMAMUX_SOURCE_FLEXIO1_REQUEST0 0 | |||
#define DMAMUX_SOURCE_FLEXIO1_REQUEST1 0 | |||
#define DMAMUX_SOURCE_FLEXIO2_REQUEST0 1 |
@@ -55,12 +55,13 @@ SECTIONS | |||
_edata = ADDR(.data) + SIZEOF(.data); | |||
_sdataload = LOADADDR(.data); | |||
_estack = ORIGIN(DTCM) + LENGTH(DTCM) - 16; | |||
_estack = ORIGIN(DTCM) + LENGTH(DTCM); | |||
_sbss = ADDR(.bss); | |||
_ebss = ADDR(.bss) + SIZEOF(.bss); | |||
_flashimagelen = SIZEOF(.text.progmem) + SIZEOF(.text) + SIZEOF(.data); | |||
_teensy_model_identifier = 0x23; | |||
.debug_info 0 : { *(.debug_info) } | |||
.debug_abbrev 0 : { *(.debug_abbrev) } |
@@ -0,0 +1,24 @@ | |||
#include <errno.h> | |||
extern unsigned long _ebss; | |||
char *__brkval = (char *)&_ebss; // TODO: put heap into OCRAM, not DTCM | |||
#define STACK_MARGIN 8192 | |||
void * _sbrk(int incr) | |||
{ | |||
char *prev, *stack; | |||
prev = __brkval; | |||
if (incr != 0) { | |||
__asm__ volatile("mov %0, sp" : "=r" (stack) ::); | |||
if (prev + incr >= stack - STACK_MARGIN) { | |||
errno = ENOMEM; | |||
return (void *)-1; | |||
} | |||
__brkval = prev + incr; | |||
} | |||
return prev; | |||
} | |||
@@ -1,5 +1,7 @@ | |||
#include "imxrt.h" | |||
#include "wiring.h" | |||
#include "usb_dev.h" | |||
#include "debug/printf.h" | |||
// from the linker | |||
@@ -22,6 +24,7 @@ static void configure_systick(void); | |||
extern void systick_isr(void); | |||
void configure_cache(void); | |||
void unused_interrupt_vector(void); | |||
void usb_pll_start(); | |||
__attribute__((section(".startup"))) | |||
@@ -52,6 +55,7 @@ void ResetHandler(void) | |||
configure_cache(); | |||
configure_systick(); | |||
usb_pll_start(); | |||
#if 1 | |||
//uint32_t pll1; | |||
@@ -85,7 +89,10 @@ void ResetHandler(void) | |||
//set_arm_clock(300000000); | |||
#endif | |||
// TODO: wait at least 20ms before starting USB | |||
usb_init(); | |||
// TODO: wait tat least 300ms before calling setup | |||
printf("before setup\n"); | |||
setup(); | |||
printf("after setup\n"); | |||
@@ -220,9 +227,9 @@ void usb_pll_start() | |||
{ | |||
while (1) { | |||
uint32_t n = CCM_ANALOG_PLL_USB1; // pg 759 | |||
//printf("CCM_ANALOG_PLL_USB1=%08lX\r\n", n); | |||
printf("CCM_ANALOG_PLL_USB1=%08lX\n", n); | |||
if (n & CCM_ANALOG_PLL_USB1_DIV_SELECT) { | |||
//print(" ERROR, 528 MHz mode!\r\n"); // never supposed to use this mode! | |||
printf(" ERROR, 528 MHz mode!\n"); // never supposed to use this mode! | |||
CCM_ANALOG_PLL_USB1_CLR = 0xC000; // bypass 24 MHz | |||
CCM_ANALOG_PLL_USB1_SET = CCM_ANALOG_PLL_USB1_BYPASS; // bypass | |||
CCM_ANALOG_PLL_USB1_CLR = CCM_ANALOG_PLL_USB1_POWER | // power down | |||
@@ -232,27 +239,27 @@ void usb_pll_start() | |||
continue; | |||
} | |||
if (!(n & CCM_ANALOG_PLL_USB1_ENABLE)) { | |||
//print(" enable PLL\r\n"); | |||
printf(" enable PLL\n"); | |||
// TODO: should this be done so early, or later?? | |||
CCM_ANALOG_PLL_USB1_SET = CCM_ANALOG_PLL_USB1_ENABLE; | |||
continue; | |||
} | |||
if (!(n & CCM_ANALOG_PLL_USB1_POWER)) { | |||
//print(" power up PLL\r\n"); | |||
printf(" power up PLL\n"); | |||
CCM_ANALOG_PLL_USB1_SET = CCM_ANALOG_PLL_USB1_POWER; | |||
continue; | |||
} | |||
if (!(n & CCM_ANALOG_PLL_USB1_LOCK)) { | |||
//print(" wait for lock\r\n"); | |||
printf(" wait for lock\n"); | |||
continue; | |||
} | |||
if (n & CCM_ANALOG_PLL_USB1_BYPASS) { | |||
//print(" turn off bypass\r\n"); | |||
printf(" turn off bypass\n"); | |||
CCM_ANALOG_PLL_USB1_CLR = CCM_ANALOG_PLL_USB1_BYPASS; | |||
continue; | |||
} | |||
if (!(n & CCM_ANALOG_PLL_USB1_EN_USB_CLKS)) { | |||
//print(" enable USB clocks\r\n"); | |||
printf(" enable USB clocks\n"); | |||
CCM_ANALOG_PLL_USB1_SET = CCM_ANALOG_PLL_USB1_EN_USB_CLKS; | |||
continue; | |||
} |
@@ -1,15 +1,13 @@ | |||
#include "usb_dev.h" | |||
#define USB_DESC_LIST_DEFINE | |||
#include "usb_desc.h" | |||
#include "usb_serial.h" | |||
#include <string.h> | |||
// Use this for access to endpoint 1 for debug | |||
// https://github.com/BrandonLWhite/Stellaris-LaunchPad-UsbDevBulk-AutoWinusbInstall | |||
#include "debug/printf.h" | |||
// device mode, page 3155 | |||
typedef struct endpoint_struct endpoint_t; | |||
//typedef struct transfer_struct transfer_t; | |||
struct endpoint_struct { | |||
uint32_t config; | |||
@@ -73,6 +71,7 @@ static uint32_t endpointN_notify_mask=0; | |||
//static int reset_count=0; | |||
volatile uint8_t usb_configuration = 0; | |||
static uint8_t endpoint0_buffer[8]; | |||
static uint8_t usb_reboot_timer = 0; | |||
static void isr(void); | |||
@@ -86,7 +85,12 @@ static void endpoint0_complete(void); | |||
void usb_init(void) | |||
{ | |||
// TODO: make sure USB voltage regulator is running at full strength | |||
// TODO: only enable when VBUS detected | |||
// TODO: return to low power mode when VBUS removed | |||
// TODO: protect PMU access with MPU | |||
PMU_REG_3P0 = PMU_REG_3P0_OUTPUT_TRG(0x0F) | PMU_REG_3P0_BO_OFFSET(6) | |||
| PMU_REG_3P0_ENABLE_LINREG; | |||
// assume PLL3 is already running - already done by usb_pll_start() in main.c | |||
@@ -95,15 +99,15 @@ void usb_init(void) | |||
// Before programming this register, the PHY clocks must be enabled in registers | |||
// USBPHYx_CTRLn and CCM_ANALOG_USBPHYx_PLL_480_CTRLn. | |||
//printf("USBPHY1_PWD=%08lX\r\n", USBPHY1_PWD); | |||
//printf("USBPHY1_TX=%08lX\r\n", USBPHY1_TX); | |||
//printf("USBPHY1_RX=%08lX\r\n", USBPHY1_RX); | |||
//printf("USBPHY1_CTRL=%08lX\r\n", USBPHY1_CTRL); | |||
//printf("USB1_USBMODE=%08lX\r\n", USB1_USBMODE); | |||
//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); | |||
// turn on PLL3, wait for 480 MHz lock? | |||
// turn on CCM clock gates? CCGR6[CG0] | |||
#if 1 | |||
if ((USBPHY1_PWD & (USBPHY_PWD_RXPWDRX | USBPHY_PWD_RXPWDDIFF | USBPHY_PWD_RXPWD1PT1 | |||
| USBPHY_PWD_RXPWDENV | USBPHY_PWD_TXPWDV2I | USBPHY_PWD_TXPWDIBIAS | |||
| USBPHY_PWD_TXPWDFS)) || (USB1_USBMODE & USB_USBMODE_CM_MASK)) { | |||
@@ -116,17 +120,17 @@ void usb_init(void) | |||
NVIC_CLEAR_PENDING(IRQ_USB1); | |||
USBPHY1_CTRL_CLR = USBPHY_CTRL_SFTRST; // reset PHY | |||
//USB1_USBSTS = USB1_USBSTS; // TODO: is this needed? | |||
//printf("USB reset took %d loops\r\n", count); | |||
printf("USB reset took %d loops\n", count); | |||
//delay(10); | |||
//print("\r\n"); | |||
//printf("USBPHY1_PWD=%08lX\r\n", USBPHY1_PWD); | |||
//printf("USBPHY1_TX=%08lX\r\n", USBPHY1_TX); | |||
//printf("USBPHY1_RX=%08lX\r\n", USBPHY1_RX); | |||
//printf("USBPHY1_CTRL=%08lX\r\n", USBPHY1_CTRL); | |||
//printf("USB1_USBMODE=%08lX\r\n", USB1_USBMODE); | |||
//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(500); | |||
} | |||
#endif | |||
// Device Controller Initialization, page 3161 | |||
// USBCMD pg 3216 | |||
// USBSTS pg 3220 | |||
@@ -143,8 +147,8 @@ void usb_init(void) | |||
USBPHY1_CTRL_CLR = USBPHY_CTRL_CLKGATE; | |||
USBPHY1_PWD = 0; | |||
//printf("USBPHY1_PWD=%08lX\r\n", USBPHY1_PWD); | |||
//printf("USBPHY1_CTRL=%08lX\r\n", USBPHY1_CTRL); | |||
//printf("USBPHY1_PWD=%08lX\n", USBPHY1_PWD); | |||
//printf("USBPHY1_CTRL=%08lX\n", USBPHY1_CTRL); | |||
USB1_USBMODE = USB_USBMODE_CM(2) | USB_USBMODE_SLOM; | |||
memset(endpoint_queue_head, 0, sizeof(endpoint_queue_head)); | |||
@@ -158,17 +162,17 @@ void usb_init(void) | |||
//_VectorsRam[IRQ_USB1+16] = &isr; | |||
attachInterruptVector(IRQ_USB1, &isr); | |||
NVIC_ENABLE_IRQ(IRQ_USB1); | |||
//printf("USB1_ENDPTCTRL0=%08lX\r\n", USB1_ENDPTCTRL0); | |||
//printf("USB1_ENDPTCTRL1=%08lX\r\n", USB1_ENDPTCTRL1); | |||
//printf("USB1_ENDPTCTRL2=%08lX\r\n", USB1_ENDPTCTRL2); | |||
//printf("USB1_ENDPTCTRL3=%08lX\r\n", USB1_ENDPTCTRL3); | |||
//printf("USB1_ENDPTCTRL0=%08lX\n", USB1_ENDPTCTRL0); | |||
//printf("USB1_ENDPTCTRL1=%08lX\n", USB1_ENDPTCTRL1); | |||
//printf("USB1_ENDPTCTRL2=%08lX\n", USB1_ENDPTCTRL2); | |||
//printf("USB1_ENDPTCTRL3=%08lX\n", USB1_ENDPTCTRL3); | |||
USB1_USBCMD |= USB_USBCMD_RS; | |||
} | |||
static void isr(void) | |||
{ | |||
//print("*"); | |||
//printf("*"); | |||
// Port control in device mode is only used for | |||
// status port reset, suspend, and current connect status. | |||
@@ -180,9 +184,9 @@ static void isr(void) | |||
// USB_USBSTS_SRI - set when USB reset detected | |||
if (status & USB_USBSTS_UI) { | |||
//print("data\r\n"); | |||
//printf("data\n"); | |||
uint32_t setupstatus = USB1_ENDPTSETUPSTAT; | |||
//printf("USB1_ENDPTSETUPSTAT=%X\r\n", setupstatus); | |||
//printf("USB1_ENDPTSETUPSTAT=%X\n", setupstatus); | |||
while (setupstatus) { | |||
USB1_ENDPTSETUPSTAT = setupstatus; | |||
setup_t s; | |||
@@ -192,7 +196,7 @@ static void isr(void) | |||
s.word2 = endpoint_queue_head[0].setup1; | |||
} while (!(USB1_USBCMD & USB_USBCMD_SUTW)); | |||
USB1_USBCMD &= ~USB_USBCMD_SUTW; | |||
//printf("setup %08lX %08lX\r\n", s.word1, s.word2); | |||
//printf("setup %08lX %08lX\n", s.word1, s.word2); | |||
USB1_ENDPTFLUSH = (1<<16) | (1<<0); // page 3174 | |||
while (USB1_ENDPTFLUSH & ((1<<16) | (1<<0))) ; | |||
endpoint0_notify_mask = 0; | |||
@@ -202,7 +206,7 @@ static void isr(void) | |||
uint32_t completestatus = USB1_ENDPTCOMPLETE; | |||
if (completestatus) { | |||
USB1_ENDPTCOMPLETE = completestatus; | |||
//printf("USB1_ENDPTCOMPLETE=%lX\r\n", completestatus); | |||
//printf("USB1_ENDPTCOMPLETE=%lX\n", completestatus); | |||
if (completestatus & endpoint0_notify_mask) { | |||
endpoint0_notify_mask = 0; | |||
endpoint0_complete(); | |||
@@ -218,34 +222,43 @@ static void isr(void) | |||
while (USB1_ENDPTPRIME != 0) ; // Wait for any endpoint priming | |||
USB1_ENDPTFLUSH = 0xFFFFFFFF; // Cancel all endpoint primed status | |||
if ((USB1_PORTSC1 & USB_PORTSC1_PR)) { | |||
//print("reset\r\n"); | |||
//printf("reset\n"); | |||
} else { | |||
// we took too long to respond :( | |||
// TODO; is this ever really a problem? | |||
//print("reset too slow\r\n"); | |||
//printf("reset too slow\n"); | |||
} | |||
// TODO: Free all allocated dTDs | |||
//if (++reset_count >= 3) { | |||
// shut off USB - easier to see results in protocol analyzer | |||
//USB1_USBCMD &= ~USB_USBCMD_RS; | |||
//print("shut off USB\r\n"); | |||
//printf("shut off USB\n"); | |||
//} | |||
} | |||
if (status & USB_USBSTS_PCI) { | |||
if (USB1_PORTSC1 & USB_PORTSC1_HSP) { | |||
//print("port at 480 Mbit\r\n"); | |||
//printf("port at 480 Mbit\n"); | |||
} else { | |||
//print("port at 12 Mbit\r\n"); | |||
//printf("port at 12 Mbit\n"); | |||
} | |||
} | |||
if (status & USB_USBSTS_SLI) { // page 3165 | |||
//print("suspend\r\n"); | |||
//printf("suspend\n"); | |||
} | |||
if (status & USB_USBSTS_UEI) { | |||
//print("error\r\n"); | |||
//printf("error\n"); | |||
} | |||
if ((USB1_USBINTR & USB_USBINTR_SRE) && (status & USB_USBSTS_SRI)) { | |||
printf("sof %d\n", usb_reboot_timer); | |||
if (usb_reboot_timer) { | |||
if (--usb_reboot_timer == 0) { | |||
asm("bkpt #251"); // run bootloader | |||
} | |||
} else { | |||
// turn off the SOF interrupt if nothing using it | |||
USB1_USBINTR &= ~USB_USBINTR_SRE; | |||
} | |||
} | |||
} | |||
@@ -289,7 +302,7 @@ static void endpoint0_setup(uint64_t setupdata) | |||
uint32_t m = n & ~(USB_ENDPTCTRL_TXR | USB_ENDPTCTRL_RXR); | |||
*reg = m; | |||
//uint32_t p = *reg; | |||
//printf(" ep=%d: cfg=%08lX - %08lX - %08lX\r\n", i + 1, n, m, p); | |||
//printf(" ep=%d: cfg=%08lX - %08lX - %08lX\n", i + 1, n, m, p); | |||
reg++; | |||
} | |||
// TODO: configure all queue heads with max packet length, zlt & mult | |||
@@ -303,7 +316,7 @@ static void endpoint0_setup(uint64_t setupdata) | |||
case 0x0680: // GET_DESCRIPTOR | |||
case 0x0681: | |||
//printf("desc:\r\n"); // yay - sending device descriptor now works!!!! | |||
//printf("desc:\n"); // yay - sending device descriptor now works!!!! | |||
for (list = usb_descriptor_list; list->addr != NULL; list++) { | |||
if (setup.wValue == list->wValue && setup.wIndex == list->wIndex) { | |||
if ((setup.wValue >> 8) == 3) { | |||
@@ -336,7 +349,7 @@ static void endpoint0_setup(uint64_t setupdata) | |||
static void endpoint0_transmit(const void *data, uint32_t len, int notify) | |||
{ | |||
//printf("tx %lu\r\n", len); | |||
//printf("tx %lu\n", len); | |||
if (len > 0) { | |||
// Executing A Transfer Descriptor, page 3182 | |||
endpoint0_transfer_data.next = 1; | |||
@@ -365,7 +378,7 @@ static void endpoint0_transmit(const void *data, uint32_t len, int notify) | |||
static void endpoint0_receive(void *data, uint32_t len, int notify) | |||
{ | |||
//printf("rx %lu\r\n", len); | |||
//printf("rx %lu\n", len); | |||
if (len > 0) { | |||
// Executing A Transfer Descriptor, page 3182 | |||
endpoint0_transfer_data.next = 1; | |||
@@ -418,11 +431,15 @@ static void endpoint0_complete(void) | |||
setup_t setup; | |||
setup.bothwords = endpoint0_setupdata.bothwords; | |||
//print("complete\r\n"); | |||
//printf("complete\n"); | |||
#ifdef CDC_STATUS_INTERFACE | |||
if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) { | |||
//memcpy(usb_cdc_line_coding, endpoint0_buffer, 7); | |||
//if (usb_cdc_line_coding[0] == 134) usb_reboot_timer = 15; | |||
memcpy(usb_cdc_line_coding, endpoint0_buffer, 7); | |||
printf("usb_cdc_line_coding, baud=%u\n", usb_cdc_line_coding[0]); | |||
if (usb_cdc_line_coding[0] == 134) { | |||
USB1_USBINTR |= USB_USBINTR_SRE; | |||
usb_reboot_timer = 80; // TODO: 10 if only 12 Mbit/sec | |||
} | |||
} | |||
#endif | |||
} | |||
@@ -444,13 +461,13 @@ void usb_transmit(int endpoint_number, transfer_t *transfer) | |||
{ | |||
// endpoint 0 reserved for control | |||
// endpoint 1 reserved for debug | |||
//printf("usb_transmit %d\r\n", endpoint_number); | |||
//printf("usb_transmit %d\n", endpoint_number); | |||
if (endpoint_number < 2 || endpoint_number > NUM_ENDPOINTS) return; | |||
endpoint_t *endpoint = &endpoint_queue_head[endpoint_number * 2 + 1]; | |||
if (endpoint->callback_function) { | |||
transfer->status |= (1<<15); | |||
} else { | |||
transfer->status |= (1<<15); | |||
//transfer->status |= (1<<15); | |||
// remove all inactive transfers | |||
} | |||
uint32_t mask = 1 << (endpoint_number + 16); | |||
@@ -465,7 +482,7 @@ void usb_transmit(int endpoint_number, transfer_t *transfer) | |||
if (USB1_ENDPTPRIME & mask) { | |||
endpoint->last_transfer = transfer; | |||
__enable_irq(); | |||
printf(" case 2a\r\n"); | |||
printf(" case 2a\n"); | |||
return; | |||
} | |||
uint32_t stat; | |||
@@ -478,7 +495,7 @@ void usb_transmit(int endpoint_number, transfer_t *transfer) | |||
if (stat & mask) { | |||
endpoint->last_transfer = transfer; | |||
__enable_irq(); | |||
printf(" case 2b\r\n"); | |||
printf(" case 2b\n"); | |||
return; | |||
} | |||
} | |||
@@ -493,7 +510,7 @@ void usb_transmit(int endpoint_number, transfer_t *transfer) | |||
USB1_ENDPTPRIME |= mask; | |||
while (USB1_ENDPTPRIME & mask) ; | |||
__enable_irq(); | |||
//printf(" case 1\r\n"); | |||
//printf(" case 1\n"); | |||
// ENDPTPRIME - momentarily set by hardware during hardware re-priming |
@@ -4,7 +4,7 @@ | |||
typedef struct transfer_struct transfer_t; | |||
struct transfer_struct { | |||
uint32_t next; | |||
uint32_t status; | |||
volatile uint32_t status; | |||
uint32_t pointer0; | |||
uint32_t pointer1; | |||
uint32_t pointer2; |
@@ -0,0 +1,89 @@ | |||
/* Teensyduino Core Library | |||
* http://www.pjrc.com/teensy/ | |||
* Copyright (c) 2017 PJRC.COM, LLC. | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining | |||
* a copy of this software and associated documentation files (the | |||
* "Software"), to deal in the Software without restriction, including | |||
* without limitation the rights to use, copy, modify, merge, publish, | |||
* distribute, sublicense, and/or sell copies of the Software, and to | |||
* permit persons to whom the Software is furnished to do so, subject to | |||
* the following conditions: | |||
* | |||
* 1. The above copyright notice and this permission notice shall be | |||
* included in all copies or substantial portions of the Software. | |||
* | |||
* 2. If the Software is incorporated into a build system that allows | |||
* selection among a list of target devices, then similar target | |||
* devices manufactured by PJRC.COM must be included in the list of | |||
* target devices and selectable in the same manner. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
* SOFTWARE. | |||
*/ | |||
#include <Arduino.h> | |||
#include "usb_desc.h" | |||
#if F_CPU >= 20000000 | |||
#ifdef CDC_DATA_INTERFACE | |||
#ifdef CDC_STATUS_INTERFACE | |||
usb_serial_class Serial; | |||
#endif | |||
#endif | |||
#ifdef MIDI_INTERFACE | |||
usb_midi_class usbMIDI; | |||
#endif | |||
#ifdef KEYBOARD_INTERFACE | |||
usb_keyboard_class Keyboard; | |||
#endif | |||
#ifdef MOUSE_INTERFACE | |||
usb_mouse_class Mouse; | |||
#endif | |||
#ifdef RAWHID_INTERFACE | |||
usb_rawhid_class RawHID; | |||
#endif | |||
#ifdef FLIGHTSIM_INTERFACE | |||
FlightSimClass FlightSim; | |||
#endif | |||
#ifdef SEREMU_INTERFACE | |||
usb_seremu_class Serial; | |||
#endif | |||
#ifdef JOYSTICK_INTERFACE | |||
usb_joystick_class Joystick; | |||
uint8_t usb_joystick_class::manual_mode = 0; | |||
#endif | |||
#ifdef USB_DISABLED | |||
usb_serial_class Serial; | |||
#endif | |||
#else // F_CPU < 20 MHz | |||
#if defined(USB_SERIAL) || defined(USB_SERIAL_HID) | |||
usb_serial_class Serial; | |||
#elif (USB_DISABLED) | |||
usb_serial_class Serial; | |||
#else | |||
usb_seremu_class Serial; | |||
#endif | |||
#endif // F_CPU | |||
void serialEvent() __attribute__((weak)); | |||
void serialEvent() {} |
@@ -34,6 +34,9 @@ | |||
//#include "HardwareSerial.h" | |||
#include <string.h> // for memcpy() | |||
#include "debug/printf.h" | |||
#include "core_pins.h" | |||
// defined by usb_dev.h -> usb_desc.h | |||
#if defined(CDC_STATUS_INTERFACE) && defined(CDC_DATA_INTERFACE) | |||
//#if F_CPU >= 20000000 | |||
@@ -201,13 +204,29 @@ int usb_serial_putchar(uint8_t c) | |||
} | |||
static transfer_t transfer __attribute__ ((used, aligned(32))); | |||
static uint8_t txbuffer[256]; | |||
static transfer_t volatile transfer __attribute__ ((used, aligned(32))); | |||
static uint8_t txbuffer[1024]; | |||
//static uint8_t txbuffer1[1024]; | |||
//static uint8_t txbuffer2[1024]; | |||
//static uint8_t txstate=0; | |||
int usb_serial_write(const void *buffer, uint32_t size) | |||
{ | |||
// TODO: do something so much better that this quick hack.... | |||
if (size > sizeof(txbuffer)) size = sizeof(txbuffer); | |||
int count=0; | |||
digitalWriteFast(13, HIGH); | |||
while (1) { | |||
uint32_t status = (volatile)(transfer.status); | |||
if (count > 10) printf("status = %x\n", status); | |||
if (!(status & 0x80)) break; | |||
count++; | |||
//if (count > 50) break; // TODO: proper timout? | |||
// TODO: check for USB offline | |||
delayMicroseconds(5); // polling too quickly seem to block DMA - maybe DTCM issue? | |||
} | |||
digitalWriteFast(13, LOW); | |||
delayMicroseconds(1); // TODO: this must not be the answer! | |||
memcpy(txbuffer, buffer, size); | |||
usb_prepare_transfer(&transfer, txbuffer, size, 0); | |||
usb_transmit(CDC_TX_ENDPOINT, &transfer); |