ソースを参照

basic usb serial on imxrt

teensy4-core
PaulStoffregen 6年前
コミット
addd88d076
14個のファイルの変更445行の追加87行の削除
  1. +199
    -0
      teensy4/Print.cpp
  2. +0
    -16
      teensy4/Print.h
  3. +5
    -0
      teensy4/clockspeed.c
  4. +0
    -5
      teensy4/core_pins.h
  5. +7
    -0
      teensy4/debug/printf.h
  6. +3
    -3
      teensy4/debugprintf.c
  7. +11
    -0
      teensy4/imxrt.h
  8. +2
    -1
      teensy4/imxrt.ld
  9. +24
    -0
      teensy4/libc.c
  10. +14
    -7
      teensy4/startup.c
  11. +68
    -51
      teensy4/usb.c
  12. +1
    -1
      teensy4/usb_dev.h
  13. +89
    -0
      teensy4/usb_inst.cpp
  14. +22
    -3
      teensy4/usb_serial.c

+ 199
- 0
teensy4/Print.cpp ファイルの表示

/* 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;
}



+ 0
- 16
teensy4/Print.h ファイルの表示

private: private:
char write_error; char write_error;
size_t printFloat(double n, uint8_t digits); 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); size_t printNumber(unsigned long n, uint8_t base, uint8_t sign);
#endif
}; };





+ 5
- 0
teensy4/clockspeed.c ファイルの表示

#include <stdint.h>

volatile uint32_t F_CPU_ACTUAL = 396000000;
volatile uint32_t F_BUS_ACTUAL = 132000000;


+ 0
- 5
teensy4/core_pins.h ファイルの表示

uint32_t analogWriteRes(uint32_t bits); uint32_t analogWriteRes(uint32_t bits);
static inline uint32_t analogWriteResolution(uint32_t bits) { return analogWriteRes(bits); } static inline uint32_t analogWriteResolution(uint32_t bits) { return analogWriteRes(bits); }
void analogWriteFrequency(uint8_t pin, float frequency); 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 attachInterrupt(uint8_t pin, void (*function)(void), int mode);
void detachInterrupt(uint8_t pin); void detachInterrupt(uint8_t pin);
void _init_Teensyduino_internal_(void); void _init_Teensyduino_internal_(void);

+ 7
- 0
teensy4/debug/printf.h ファイルの表示



#ifdef PRINT_DEBUG_STUFF #ifdef PRINT_DEBUG_STUFF
#define printf_init() printf_debug_init() #define printf_init() printf_debug_init()
// defining printf this way breaks things like Serial.printf() in C++ :(
#define printf(...) printf_debug(__VA_ARGS__) #define printf(...) printf_debug(__VA_ARGS__)
#ifdef __cplusplus
extern "C" {
#endif
void print_debug_init(void); void print_debug_init(void);
void printf_debug(const char *format, ...); void printf_debug(const char *format, ...);
#ifdef __cplusplus
}
#endif


#else #else
#define printf_init() #define printf_init()

+ 3
- 3
teensy4/debugprintf.c ファイルの表示

#include <stdarg.h> #include <stdarg.h>
#include "imxrt.h" #include "imxrt.h"


void putchar_debug(char c);
static void puint_debug(unsigned int num); static void puint_debug(unsigned int num);




n = -n; n = -n;
putchar_debug('-'); putchar_debug('-');
} }
val = n;
puint_debug(n); puint_debug(n);
} else if (*format == 'u') { } else if (*format == 'u') {
puint_debug(va_arg(args, unsigned int)); puint_debug(va_arg(args, unsigned int));
__attribute__((section(".progmem"))) __attribute__((section(".progmem")))
void printf_debug_init(void) 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); CCM_CCGR0 |= CCM_CCGR0_LPUART3(CCM_CCGR_ON);
IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_06 = 2; // Arduino pin 17 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; 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; LPUART3_CTRL = LPUART_CTRL_TE;
} }



+ 11
- 0
teensy4/imxrt.h ファイルの表示

#define NVIC_NUM_INTERRUPTS 160 #define NVIC_NUM_INTERRUPTS 160
#define DMA_NUM_CHANNELS 32 #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_REQUEST0 0
#define DMAMUX_SOURCE_FLEXIO1_REQUEST1 0 #define DMAMUX_SOURCE_FLEXIO1_REQUEST1 0
#define DMAMUX_SOURCE_FLEXIO2_REQUEST0 1 #define DMAMUX_SOURCE_FLEXIO2_REQUEST0 1

+ 2
- 1
teensy4/imxrt.ld ファイルの表示

_edata = ADDR(.data) + SIZEOF(.data); _edata = ADDR(.data) + SIZEOF(.data);
_sdataload = LOADADDR(.data); _sdataload = LOADADDR(.data);


_estack = ORIGIN(DTCM) + LENGTH(DTCM) - 16;
_estack = ORIGIN(DTCM) + LENGTH(DTCM);


_sbss = ADDR(.bss); _sbss = ADDR(.bss);
_ebss = ADDR(.bss) + SIZEOF(.bss); _ebss = ADDR(.bss) + SIZEOF(.bss);


_flashimagelen = SIZEOF(.text.progmem) + SIZEOF(.text) + SIZEOF(.data); _flashimagelen = SIZEOF(.text.progmem) + SIZEOF(.text) + SIZEOF(.data);
_teensy_model_identifier = 0x23;


.debug_info 0 : { *(.debug_info) } .debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) } .debug_abbrev 0 : { *(.debug_abbrev) }

+ 24
- 0
teensy4/libc.c ファイルの表示

#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;
}


+ 14
- 7
teensy4/startup.c ファイルの表示

#include "imxrt.h" #include "imxrt.h"
#include "wiring.h" #include "wiring.h"
#include "usb_dev.h"

#include "debug/printf.h" #include "debug/printf.h"


// from the linker // from the linker
extern void systick_isr(void); extern void systick_isr(void);
void configure_cache(void); void configure_cache(void);
void unused_interrupt_vector(void); void unused_interrupt_vector(void);
void usb_pll_start();




__attribute__((section(".startup"))) __attribute__((section(".startup")))


configure_cache(); configure_cache();
configure_systick(); configure_systick();
usb_pll_start();
#if 1 #if 1


//uint32_t pll1; //uint32_t pll1;
//set_arm_clock(300000000); //set_arm_clock(300000000);
#endif #endif


// TODO: wait at least 20ms before starting USB
usb_init();


// TODO: wait tat least 300ms before calling setup
printf("before setup\n"); printf("before setup\n");
setup(); setup();
printf("after setup\n"); printf("after setup\n");
{ {
while (1) { while (1) {
uint32_t n = CCM_ANALOG_PLL_USB1; // pg 759 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) { 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_CLR = 0xC000; // bypass 24 MHz
CCM_ANALOG_PLL_USB1_SET = CCM_ANALOG_PLL_USB1_BYPASS; // bypass CCM_ANALOG_PLL_USB1_SET = CCM_ANALOG_PLL_USB1_BYPASS; // bypass
CCM_ANALOG_PLL_USB1_CLR = CCM_ANALOG_PLL_USB1_POWER | // power down CCM_ANALOG_PLL_USB1_CLR = CCM_ANALOG_PLL_USB1_POWER | // power down
continue; continue;
} }
if (!(n & CCM_ANALOG_PLL_USB1_ENABLE)) { 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?? // TODO: should this be done so early, or later??
CCM_ANALOG_PLL_USB1_SET = CCM_ANALOG_PLL_USB1_ENABLE; CCM_ANALOG_PLL_USB1_SET = CCM_ANALOG_PLL_USB1_ENABLE;
continue; continue;
} }
if (!(n & CCM_ANALOG_PLL_USB1_POWER)) { 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; CCM_ANALOG_PLL_USB1_SET = CCM_ANALOG_PLL_USB1_POWER;
continue; continue;
} }
if (!(n & CCM_ANALOG_PLL_USB1_LOCK)) { if (!(n & CCM_ANALOG_PLL_USB1_LOCK)) {
//print(" wait for lock\r\n");
printf(" wait for lock\n");
continue; continue;
} }
if (n & CCM_ANALOG_PLL_USB1_BYPASS) { 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; CCM_ANALOG_PLL_USB1_CLR = CCM_ANALOG_PLL_USB1_BYPASS;
continue; continue;
} }
if (!(n & CCM_ANALOG_PLL_USB1_EN_USB_CLKS)) { 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; CCM_ANALOG_PLL_USB1_SET = CCM_ANALOG_PLL_USB1_EN_USB_CLKS;
continue; continue;
} }

+ 68
- 51
teensy4/usb.c ファイルの表示

#include "usb_dev.h" #include "usb_dev.h"
#define USB_DESC_LIST_DEFINE #define USB_DESC_LIST_DEFINE
#include "usb_desc.h" #include "usb_desc.h"
#include "usb_serial.h"
#include <string.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 // device mode, page 3155


typedef struct endpoint_struct endpoint_t; typedef struct endpoint_struct endpoint_t;
//typedef struct transfer_struct transfer_t;


struct endpoint_struct { struct endpoint_struct {
uint32_t config; uint32_t config;
//static int reset_count=0; //static int reset_count=0;
volatile uint8_t usb_configuration = 0; volatile uint8_t usb_configuration = 0;
static uint8_t endpoint0_buffer[8]; static uint8_t endpoint0_buffer[8];
static uint8_t usb_reboot_timer = 0;




static void isr(void); static void isr(void);


void usb_init(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 // assume PLL3 is already running - already done by usb_pll_start() in main.c


// Before programming this register, the PHY clocks must be enabled in registers // Before programming this register, the PHY clocks must be enabled in registers
// USBPHYx_CTRLn and CCM_ANALOG_USBPHYx_PLL_480_CTRLn. // 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 PLL3, wait for 480 MHz lock?
// turn on CCM clock gates? CCGR6[CG0] // turn on CCM clock gates? CCGR6[CG0]
#if 1
if ((USBPHY1_PWD & (USBPHY_PWD_RXPWDRX | USBPHY_PWD_RXPWDDIFF | USBPHY_PWD_RXPWD1PT1 if ((USBPHY1_PWD & (USBPHY_PWD_RXPWDRX | USBPHY_PWD_RXPWDDIFF | USBPHY_PWD_RXPWD1PT1
| USBPHY_PWD_RXPWDENV | USBPHY_PWD_TXPWDV2I | USBPHY_PWD_TXPWDIBIAS | USBPHY_PWD_RXPWDENV | USBPHY_PWD_TXPWDV2I | USBPHY_PWD_TXPWDIBIAS
| USBPHY_PWD_TXPWDFS)) || (USB1_USBMODE & USB_USBMODE_CM_MASK)) { | USBPHY_PWD_TXPWDFS)) || (USB1_USBMODE & USB_USBMODE_CM_MASK)) {
NVIC_CLEAR_PENDING(IRQ_USB1); NVIC_CLEAR_PENDING(IRQ_USB1);
USBPHY1_CTRL_CLR = USBPHY_CTRL_SFTRST; // reset PHY USBPHY1_CTRL_CLR = USBPHY_CTRL_SFTRST; // reset PHY
//USB1_USBSTS = USB1_USBSTS; // TODO: is this needed? //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); //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); //delay(500);
} }
#endif
// Device Controller Initialization, page 3161 // Device Controller Initialization, page 3161
// USBCMD pg 3216 // USBCMD pg 3216
// USBSTS pg 3220 // USBSTS pg 3220


USBPHY1_CTRL_CLR = USBPHY_CTRL_CLKGATE; USBPHY1_CTRL_CLR = USBPHY_CTRL_CLKGATE;
USBPHY1_PWD = 0; 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; USB1_USBMODE = USB_USBMODE_CM(2) | USB_USBMODE_SLOM;
memset(endpoint_queue_head, 0, sizeof(endpoint_queue_head)); memset(endpoint_queue_head, 0, sizeof(endpoint_queue_head));
//_VectorsRam[IRQ_USB1+16] = &isr; //_VectorsRam[IRQ_USB1+16] = &isr;
attachInterruptVector(IRQ_USB1, &isr); attachInterruptVector(IRQ_USB1, &isr);
NVIC_ENABLE_IRQ(IRQ_USB1); 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; USB1_USBCMD |= USB_USBCMD_RS;
} }




static void isr(void) static void isr(void)
{ {
//print("*");
//printf("*");


// Port control in device mode is only used for // Port control in device mode is only used for
// status port reset, suspend, and current connect status. // status port reset, suspend, and current connect status.
// USB_USBSTS_SRI - set when USB reset detected // USB_USBSTS_SRI - set when USB reset detected


if (status & USB_USBSTS_UI) { if (status & USB_USBSTS_UI) {
//print("data\r\n");
//printf("data\n");
uint32_t setupstatus = USB1_ENDPTSETUPSTAT; uint32_t setupstatus = USB1_ENDPTSETUPSTAT;
//printf("USB1_ENDPTSETUPSTAT=%X\r\n", setupstatus);
//printf("USB1_ENDPTSETUPSTAT=%X\n", setupstatus);
while (setupstatus) { while (setupstatus) {
USB1_ENDPTSETUPSTAT = setupstatus; USB1_ENDPTSETUPSTAT = setupstatus;
setup_t s; setup_t s;
s.word2 = endpoint_queue_head[0].setup1; s.word2 = endpoint_queue_head[0].setup1;
} while (!(USB1_USBCMD & USB_USBCMD_SUTW)); } while (!(USB1_USBCMD & USB_USBCMD_SUTW));
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 USB1_ENDPTFLUSH = (1<<16) | (1<<0); // page 3174
while (USB1_ENDPTFLUSH & ((1<<16) | (1<<0))) ; while (USB1_ENDPTFLUSH & ((1<<16) | (1<<0))) ;
endpoint0_notify_mask = 0; endpoint0_notify_mask = 0;
uint32_t completestatus = USB1_ENDPTCOMPLETE; uint32_t completestatus = USB1_ENDPTCOMPLETE;
if (completestatus) { if (completestatus) {
USB1_ENDPTCOMPLETE = completestatus; USB1_ENDPTCOMPLETE = completestatus;
//printf("USB1_ENDPTCOMPLETE=%lX\r\n", completestatus);
//printf("USB1_ENDPTCOMPLETE=%lX\n", completestatus);
if (completestatus & endpoint0_notify_mask) { if (completestatus & endpoint0_notify_mask) {
endpoint0_notify_mask = 0; endpoint0_notify_mask = 0;
endpoint0_complete(); endpoint0_complete();
while (USB1_ENDPTPRIME != 0) ; // Wait for any endpoint priming while (USB1_ENDPTPRIME != 0) ; // Wait for any endpoint priming
USB1_ENDPTFLUSH = 0xFFFFFFFF; // Cancel all endpoint primed status USB1_ENDPTFLUSH = 0xFFFFFFFF; // Cancel all endpoint primed status
if ((USB1_PORTSC1 & USB_PORTSC1_PR)) { if ((USB1_PORTSC1 & USB_PORTSC1_PR)) {
//print("reset\r\n");
//printf("reset\n");
} else { } else {
// we took too long to respond :( // we took too long to respond :(
// TODO; is this ever really a problem? // TODO; is this ever really a problem?
//print("reset too slow\r\n");
//printf("reset too slow\n");
} }
// TODO: Free all allocated dTDs // TODO: Free all allocated dTDs
//if (++reset_count >= 3) { //if (++reset_count >= 3) {
// shut off USB - easier to see results in protocol analyzer // shut off USB - easier to see results in protocol analyzer
//USB1_USBCMD &= ~USB_USBCMD_RS; //USB1_USBCMD &= ~USB_USBCMD_RS;
//print("shut off USB\r\n");
//printf("shut off USB\n");
//} //}
} }
if (status & USB_USBSTS_PCI) { if (status & USB_USBSTS_PCI) {
if (USB1_PORTSC1 & USB_PORTSC1_HSP) { if (USB1_PORTSC1 & USB_PORTSC1_HSP) {
//print("port at 480 Mbit\r\n");
//printf("port at 480 Mbit\n");
} else { } else {
//print("port at 12 Mbit\r\n");
//printf("port at 12 Mbit\n");
} }
} }
if (status & USB_USBSTS_SLI) { // page 3165 if (status & USB_USBSTS_SLI) { // page 3165
//print("suspend\r\n");
//printf("suspend\n");
} }
if (status & USB_USBSTS_UEI) { 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;
}
} }


} }




uint32_t m = n & ~(USB_ENDPTCTRL_TXR | USB_ENDPTCTRL_RXR); uint32_t m = n & ~(USB_ENDPTCTRL_TXR | USB_ENDPTCTRL_RXR);
*reg = m; *reg = m;
//uint32_t p = *reg; //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++; reg++;
} }
// TODO: configure all queue heads with max packet length, zlt & mult // TODO: configure all queue heads with max packet length, zlt & mult


case 0x0680: // GET_DESCRIPTOR case 0x0680: // GET_DESCRIPTOR
case 0x0681: 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++) { for (list = usb_descriptor_list; list->addr != NULL; list++) {
if (setup.wValue == list->wValue && setup.wIndex == list->wIndex) { if (setup.wValue == list->wValue && setup.wIndex == list->wIndex) {
if ((setup.wValue >> 8) == 3) { if ((setup.wValue >> 8) == 3) {


static void endpoint0_transmit(const void *data, uint32_t len, int notify) 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) { if (len > 0) {
// Executing A Transfer Descriptor, page 3182 // Executing A Transfer Descriptor, page 3182
endpoint0_transfer_data.next = 1; endpoint0_transfer_data.next = 1;


static void endpoint0_receive(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) { if (len > 0) {
// Executing A Transfer Descriptor, page 3182 // Executing A Transfer Descriptor, page 3182
endpoint0_transfer_data.next = 1; endpoint0_transfer_data.next = 1;
setup_t setup; setup_t setup;


setup.bothwords = endpoint0_setupdata.bothwords; setup.bothwords = endpoint0_setupdata.bothwords;
//print("complete\r\n");
//printf("complete\n");
#ifdef CDC_STATUS_INTERFACE #ifdef CDC_STATUS_INTERFACE
if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) { 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 #endif
} }
{ {
// endpoint 0 reserved for control // endpoint 0 reserved for control
// endpoint 1 reserved for debug // 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; if (endpoint_number < 2 || endpoint_number > NUM_ENDPOINTS) return;
endpoint_t *endpoint = &endpoint_queue_head[endpoint_number * 2 + 1]; endpoint_t *endpoint = &endpoint_queue_head[endpoint_number * 2 + 1];
if (endpoint->callback_function) { if (endpoint->callback_function) {
transfer->status |= (1<<15); transfer->status |= (1<<15);
} else { } else {
transfer->status |= (1<<15);
//transfer->status |= (1<<15);
// remove all inactive transfers // remove all inactive transfers
} }
uint32_t mask = 1 << (endpoint_number + 16); uint32_t mask = 1 << (endpoint_number + 16);
if (USB1_ENDPTPRIME & mask) { if (USB1_ENDPTPRIME & mask) {
endpoint->last_transfer = transfer; endpoint->last_transfer = transfer;
__enable_irq(); __enable_irq();
printf(" case 2a\r\n");
printf(" case 2a\n");
return; return;
} }
uint32_t stat; uint32_t stat;
if (stat & mask) { if (stat & mask) {
endpoint->last_transfer = transfer; endpoint->last_transfer = transfer;
__enable_irq(); __enable_irq();
printf(" case 2b\r\n");
printf(" case 2b\n");
return; return;
} }
} }
USB1_ENDPTPRIME |= mask; USB1_ENDPTPRIME |= mask;
while (USB1_ENDPTPRIME & mask) ; while (USB1_ENDPTPRIME & mask) ;
__enable_irq(); __enable_irq();
//printf(" case 1\r\n");
//printf(" case 1\n");




// ENDPTPRIME - momentarily set by hardware during hardware re-priming // ENDPTPRIME - momentarily set by hardware during hardware re-priming

+ 1
- 1
teensy4/usb_dev.h ファイルの表示

typedef struct transfer_struct transfer_t; typedef struct transfer_struct transfer_t;
struct transfer_struct { struct transfer_struct {
uint32_t next; uint32_t next;
uint32_t status;
volatile uint32_t status;
uint32_t pointer0; uint32_t pointer0;
uint32_t pointer1; uint32_t pointer1;
uint32_t pointer2; uint32_t pointer2;

+ 89
- 0
teensy4/usb_inst.cpp ファイルの表示

/* 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() {}

+ 22
- 3
teensy4/usb_serial.c ファイルの表示

//#include "HardwareSerial.h" //#include "HardwareSerial.h"
#include <string.h> // for memcpy() #include <string.h> // for memcpy()


#include "debug/printf.h"
#include "core_pins.h"

// defined by usb_dev.h -> usb_desc.h // defined by usb_dev.h -> usb_desc.h
#if defined(CDC_STATUS_INTERFACE) && defined(CDC_DATA_INTERFACE) #if defined(CDC_STATUS_INTERFACE) && defined(CDC_DATA_INTERFACE)
//#if F_CPU >= 20000000 //#if F_CPU >= 20000000
} }




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) 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); 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); memcpy(txbuffer, buffer, size);
usb_prepare_transfer(&transfer, txbuffer, size, 0); usb_prepare_transfer(&transfer, txbuffer, size, 0);
usb_transmit(CDC_TX_ENDPOINT, &transfer); usb_transmit(CDC_TX_ENDPOINT, &transfer);

読み込み中…
キャンセル
保存