@@ -1,4 +1,4 @@ | |||
Teensy 2.0, 3.x, LC core libraries for Arduino. | |||
Teensy 2.0, LC, 3.x, 4.x core libraries for Arduino. | |||
The latest stable version of Teensy's core library is always available in the Teensyduino installer, at this page: | |||
@@ -8,6 +8,7 @@ nullptr LITERAL1 | |||
noexcept LITERAL1 | |||
static_assert LITERAL1 | |||
thread_local LITERAL1 | |||
size_t LITERAL1 | |||
# teensy specific functions | |||
elapsedMillis LITERAL1 | |||
@@ -26,18 +27,28 @@ IntervalTimer KEYWORD2 | |||
printf KEYWORD2 | |||
digitalWriteFast KEYWORD2 | |||
digitalReadFast KEYWORD2 | |||
digitalToggleFast KEYWORD2 | |||
digitalToggle KEYWORD2 | |||
transmitterEnable KEYWORD2 | |||
attachRts KEYWORD2 | |||
attachCts KEYWORD2 | |||
PROGMEM LITERAL1 | |||
FLASHMEM LITERAL1 | |||
DMAMEM LITERAL1 | |||
EXTMEM LITERAL1 | |||
FASTRUN LITERAL1 | |||
Serial4 KEYWORD1 | |||
Serial5 KEYWORD1 | |||
Serial6 KEYWORD1 | |||
Serial7 KEYWORD1 | |||
Serial8 KEYWORD1 | |||
SerialUSB1 KEYWORD1 | |||
SerialUSB2 KEYWORD1 | |||
setRX KEYWORD2 | |||
setTX KEYWORD2 | |||
write9bit KEYWORD2 | |||
addMemoryForRead KEYWORD2 | |||
addMemoryForWrite KEYWORD2 | |||
clear KEYWORD2 | |||
EventResponder LITERAL1 | |||
EventResponderRef LITERAL1 | |||
@@ -51,9 +62,15 @@ getContext KEYWORD2 | |||
waitForEvent KEYWORD2 | |||
MillisTimer LITERAL1 | |||
beginRepeating KEYWORD2 | |||
delayNanoseconds KEYWORD2 | |||
extmem_malloc KEYWORD2 | |||
extmem_free KEYWORD2 | |||
extmem_calloc KEYWORD2 | |||
extmem_realloc KEYWORD2 | |||
strcasecmp KEYWORD2 | |||
# removed by Arduino 1.0, but still in Teensyduino | |||
BYTE LITERAL1 | |||
# removed by Arduino 1.0, now also removed from Teensyduino | |||
#BYTE LITERAL1 | |||
# Arduino constants | |||
A0 LITERAL1 | |||
@@ -95,6 +112,9 @@ analogInputToDigitalPin KEYWORD2 | |||
digitalPinHasPWM KEYWORD2 | |||
NOT_AN_INTERRUPT LITERAL1 | |||
digitalPinToInterrupt KEYWORD2 | |||
FILE_READ LITERAL1 | |||
FILE_WRITE LITERAL1 | |||
FILE_WRITE_BEGIN LITERAL1 | |||
# HardwareSerial modes | |||
SERIAL_7E1 LITERAL1 | |||
@@ -503,6 +523,8 @@ FlightSimCommand KEYWORD2 | |||
FlightSimInteger KEYWORD2 | |||
FlightSimFloat KEYWORD2 | |||
FlightSimElapsedFrames KEYWORD2 | |||
FlightSimData KEYWORD2 | |||
FlightSimEvent KEYWORD2 | |||
onChange KEYWORD2 | |||
update KEYWORD2 | |||
isEnabled KEYWORD2 |
@@ -0,0 +1,183 @@ | |||
/* Teensyduino Core Library - File base class | |||
* http://www.pjrc.com/teensy/ | |||
* Copyright (c) 2020 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. | |||
*/ | |||
#ifndef FS_H | |||
#define FS_H | |||
#ifdef __cplusplus | |||
#include <Arduino.h> | |||
#define FILE_READ 0 | |||
#define FILE_WRITE 1 | |||
#define FILE_WRITE_BEGIN 2 | |||
enum SeekMode { | |||
SeekSet = 0, | |||
SeekCur = 1, | |||
SeekEnd = 2 | |||
}; | |||
//#define FILE_WHOAMI | |||
class File : public Stream { | |||
public: | |||
File() : f(nullptr) { } | |||
File(File *file) { | |||
// "file" must only be a class derived from File | |||
// can we use is_same or is_polymorphic with static_assert? | |||
// or is_base_of | |||
//static_assert(std::is_same<decltype(*file),File>::value, | |||
//"File(File *file) constructor only accepts pointers " | |||
//"to derived classes, not File itself"); | |||
f = file; | |||
if (f) f->refcount++; | |||
} | |||
File(const File &file) { | |||
//Serial.println("File copy constructor"); | |||
//static int copycount=0; | |||
//if (++copycount > 20) while (1) ; | |||
f = file.f; | |||
if (f) f->refcount++; | |||
} | |||
File& operator = (const File &file) { | |||
//Serial.println("File assignment"); | |||
//static int assigncount=0; | |||
//if (++assigncount > 20) while (1) ; | |||
invalidate(); | |||
f = file.f; | |||
if (f) f->refcount++; | |||
return *this; | |||
} | |||
virtual ~File() { | |||
invalidate(); | |||
} | |||
#ifdef FILE_WHOAMI | |||
virtual void whoami() { // testing only | |||
Serial.printf(" File this=%x, f=%x\n", (int)this, (int)f); | |||
if (f) f->whoami(); | |||
} | |||
unsigned int getRefcount() { // testing only | |||
return refcount; | |||
} | |||
#endif | |||
virtual size_t read(void *buf, size_t nbyte) { | |||
return (f) ? f->read(buf, nbyte) : 0; | |||
} | |||
virtual size_t write(const void *buf, size_t size) { | |||
return (f) ? f->write(buf, size) : 0; | |||
} | |||
virtual int available() { | |||
return (f) ? f->available() : 0; | |||
} | |||
virtual int peek() { | |||
return (f) ? f->peek() : -1; | |||
} | |||
virtual void flush() { | |||
if (f) f->flush(); | |||
} | |||
virtual bool truncate(uint64_t size=0) { | |||
return (f) ? f->truncate(size) : false; | |||
} | |||
virtual bool seek(uint64_t pos, int mode) { | |||
return (f) ? f->seek(pos, mode) : false; | |||
} | |||
virtual uint64_t position() { | |||
return (f) ? f->position() : 0; | |||
} | |||
virtual uint64_t size() { | |||
return (f) ? f->size() : 0; | |||
} | |||
virtual void close() { | |||
if (f) f->close(); | |||
} | |||
virtual operator bool() { | |||
return (f) ? (bool)*f : false; | |||
} | |||
virtual const char* name() { | |||
return (f) ? f->name() : ""; | |||
} | |||
virtual bool isDirectory() { | |||
return (f) ? f->isDirectory() : false; | |||
} | |||
virtual File openNextFile(uint8_t mode=0) { | |||
return (f) ? f->openNextFile(mode) : *this; | |||
} | |||
virtual void rewindDirectory(void) { | |||
if (f) f->rewindDirectory(); | |||
} | |||
bool seek(uint64_t pos) { | |||
return seek(pos, SeekSet); | |||
} | |||
int read() { | |||
if (!f) return -1; | |||
unsigned char b; | |||
if (f->read(&b, 1) < 1) return -1; | |||
return b; | |||
} | |||
size_t write(uint8_t b) { | |||
return write(&b, 1); | |||
} | |||
size_t write(const char *str) { | |||
return write(str, strlen(str)); | |||
} | |||
size_t readBytes(char *buffer, size_t length) { | |||
return read(buffer, length); | |||
} | |||
private: | |||
void invalidate() { | |||
if (f && --(f->refcount) == 0) delete f; | |||
} | |||
union { | |||
// instances of base File class use this pointer | |||
File *f; | |||
// instances of derived classes (which actually access media) | |||
// use this reference count which is managed by the base class | |||
unsigned int refcount; | |||
}; | |||
}; | |||
class FS | |||
{ | |||
public: | |||
FS() {} | |||
virtual File open(const char *filename, uint8_t mode = FILE_READ); | |||
virtual bool exists(const char *filepath); | |||
virtual bool mkdir(const char *filepath); | |||
virtual bool rename(const char *oldfilepath, const char *newfilepath); | |||
virtual bool remove(const char *filepath); | |||
virtual bool rmdir(const char *filepath); | |||
virtual uint64_t usedSize(); | |||
virtual uint64_t totalSize(); | |||
}; | |||
#endif // __cplusplus | |||
#endif // FS_H |
@@ -353,6 +353,39 @@ size_t Print::printNumberAny(unsigned long n, uint8_t base) | |||
return write(p, sizeof(buf) - (p - buf)); | |||
} | |||
size_t Print::print(int64_t n) | |||
{ | |||
if (n < 0) return printNumber64(-n, 10, 1); | |||
return printNumber64(n, 10, 0); | |||
} | |||
size_t Print::printNumber64(uint64_t n, uint8_t base, uint8_t sign) | |||
{ | |||
uint8_t buf[66]; | |||
uint8_t digit, i; | |||
if (base < 2) return 0; | |||
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; |
@@ -34,9 +34,9 @@ | |||
// BYTE was defined in very old versions of Arduino | |||
// maybe this now causes more trouble than it's worth? | |||
#ifndef BYTE | |||
#define BYTE 0 | |||
#endif | |||
//#ifndef BYTE | |||
//#define BYTE 0 | |||
//#endif | |||
class __FlashStringHelper; | |||
@@ -60,12 +60,16 @@ class Print | |||
size_t print(unsigned int n) { return printNumber(n, 0, 10); } | |||
size_t print(long n); | |||
size_t print(unsigned long n) { return printNumber(n, 0, 10); } | |||
size_t print(int64_t n); | |||
size_t print(uint64_t n) { return printNumber64(n, 10, 0); } | |||
size_t print(unsigned char n, int base) { return printNumber(n, 0, base); } | |||
size_t print(int n, int base) { return (base == 10) ? print(n) : printNumber(n, 0, base); } | |||
size_t print(unsigned int n, int base) { return printNumber(n, 0, base); } | |||
size_t print(long n, int base) { return (base == 10) ? print(n) : printNumber(n, 0, base); } | |||
size_t print(unsigned long n, int base) { return printNumber(n, 0, base); } | |||
size_t print(int64_t n, int base) { return (base == 10) ? print(n) : printNumber64(n, base, 0); } | |||
size_t print(uint64_t n, int base) { return printNumber64(n, base, 0); } | |||
size_t print(double n, int digits = 2) { return printFloat(n, digits); } | |||
size_t print(const Printable &obj) { return obj.printTo(*this); } | |||
@@ -80,12 +84,16 @@ class Print | |||
size_t println(unsigned int n) { return print(n) + println(); } | |||
size_t println(long n) { return print(n) + println(); } | |||
size_t println(unsigned long n) { return print(n) + println(); } | |||
size_t println(int64_t n) { return print(n) + println(); } | |||
size_t println(uint64_t n) { return print(n) + println(); } | |||
size_t println(unsigned char n, int base) { return print(n, base) + println(); } | |||
size_t println(int n, int base) { return print(n, base) + println(); } | |||
size_t println(unsigned int n, int base) { return print(n, base) + println(); } | |||
size_t println(long n, int base) { return print(n, base) + println(); } | |||
size_t println(unsigned long n, int base) { return print(n, base) + println(); } | |||
size_t println(int64_t n, int base) { return print(n, base) + println(); } | |||
size_t println(uint64_t n, int base) { return print(n, base) + println(); } | |||
size_t println(double n, int digits = 2) { return print(n, digits) + println(); } | |||
size_t println(const Printable &obj) { return obj.printTo(*this) + println(); } | |||
@@ -111,6 +119,7 @@ class Print | |||
if (base == 2) return printNumberBin(n); | |||
return printNumberAny(n, base); | |||
} | |||
size_t printNumber64(uint64_t n, uint8_t base, uint8_t sign); | |||
size_t printFloat(double n, uint8_t digits); | |||
}; | |||
@@ -44,6 +44,7 @@ class UDP : public Stream { | |||
public: | |||
virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use | |||
virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } | |||
virtual void stop() =0; // Finish with the UDP socket | |||
// Sending UDP packets |
@@ -1935,6 +1935,253 @@ static inline void pinMode(uint8_t pin, uint8_t mode) | |||
} | |||
} | |||
static inline void digitalToggle(uint8_t) __attribute__((always_inline, unused)); | |||
static inline void digitalToggle(uint8_t pin) | |||
{ | |||
if (__builtin_constant_p(pin)) { | |||
if (pin == 0) { | |||
CORE_PIN0_PINREG = CORE_PIN0_BITMASK; | |||
} else if (pin == 1) { | |||
CORE_PIN1_PINREG = CORE_PIN1_BITMASK; | |||
} else if (pin == 2) { | |||
CORE_PIN2_PINREG = CORE_PIN2_BITMASK; | |||
} else if (pin == 3) { | |||
CORE_PIN3_PINREG = CORE_PIN3_BITMASK; | |||
} else if (pin == 4) { | |||
CORE_PIN4_PINREG = CORE_PIN4_BITMASK; | |||
} else if (pin == 5) { | |||
CORE_PIN5_PINREG = CORE_PIN5_BITMASK; | |||
} else if (pin == 6) { | |||
CORE_PIN6_PINREG = CORE_PIN6_BITMASK; | |||
} else if (pin == 7) { | |||
CORE_PIN7_PINREG = CORE_PIN7_BITMASK; | |||
} else if (pin == 8) { | |||
CORE_PIN8_PINREG = CORE_PIN8_BITMASK; | |||
} else if (pin == 9) { | |||
CORE_PIN9_PINREG = CORE_PIN9_BITMASK; | |||
} else if (pin == 10) { | |||
CORE_PIN10_PINREG = CORE_PIN10_BITMASK; | |||
} else if (pin == 11) { | |||
CORE_PIN11_PINREG = CORE_PIN11_BITMASK; | |||
} else if (pin == 12) { | |||
CORE_PIN12_PINREG = CORE_PIN12_BITMASK; | |||
} else if (pin == 13) { | |||
CORE_PIN13_PINREG = CORE_PIN13_BITMASK; | |||
} else if (pin == 14) { | |||
CORE_PIN14_PINREG = CORE_PIN14_BITMASK; | |||
} else if (pin == 15) { | |||
CORE_PIN15_PINREG = CORE_PIN15_BITMASK; | |||
} else if (pin == 16) { | |||
CORE_PIN16_PINREG = CORE_PIN16_BITMASK; | |||
} else if (pin == 17) { | |||
CORE_PIN17_PINREG = CORE_PIN17_BITMASK; | |||
} else if (pin == 18) { | |||
CORE_PIN18_PINREG = CORE_PIN18_BITMASK; | |||
} else if (pin == 19) { | |||
CORE_PIN19_PINREG = CORE_PIN19_BITMASK; | |||
} else if (pin == 20) { | |||
CORE_PIN20_PINREG = CORE_PIN20_BITMASK; | |||
} | |||
#if CORE_NUM_TOTAL_PINS > 21 | |||
else if (pin == 21) { | |||
CORE_PIN21_PINREG = CORE_PIN21_BITMASK; | |||
} else if (pin == 22) { | |||
CORE_PIN22_PINREG = CORE_PIN22_BITMASK; | |||
} else if (pin == 23) { | |||
CORE_PIN23_PINREG = CORE_PIN23_BITMASK; | |||
} else if (pin == 24) { | |||
CORE_PIN24_PINREG = CORE_PIN24_BITMASK; | |||
} | |||
#endif | |||
#if CORE_NUM_TOTAL_PINS > 25 | |||
else if (pin == 25) { | |||
CORE_PIN25_PINREG = CORE_PIN25_BITMASK; | |||
} else if (pin == 26) { | |||
CORE_PIN26_PINREG = CORE_PIN26_BITMASK; | |||
} else if (pin == 27) { | |||
CORE_PIN27_PINREG = CORE_PIN27_BITMASK; | |||
} else if (pin == 28) { | |||
CORE_PIN28_PINREG = CORE_PIN28_BITMASK; | |||
} else if (pin == 29) { | |||
CORE_PIN29_PINREG = CORE_PIN29_BITMASK; | |||
} else if (pin == 30) { | |||
CORE_PIN30_PINREG = CORE_PIN30_BITMASK; | |||
} else if (pin == 31) { | |||
CORE_PIN31_PINREG = CORE_PIN31_BITMASK; | |||
} else if (pin == 32) { | |||
CORE_PIN32_PINREG = CORE_PIN32_BITMASK; | |||
} else if (pin == 33) { | |||
CORE_PIN33_PINREG = CORE_PIN33_BITMASK; | |||
} else if (pin == 34) { | |||
CORE_PIN34_PINREG = CORE_PIN34_BITMASK; | |||
} else if (pin == 35) { | |||
CORE_PIN35_PINREG = CORE_PIN35_BITMASK; | |||
} else if (pin == 36) { | |||
CORE_PIN36_PINREG = CORE_PIN36_BITMASK; | |||
} else if (pin == 37) { | |||
CORE_PIN37_PINREG = CORE_PIN37_BITMASK; | |||
} else if (pin == 38) { | |||
CORE_PIN38_PINREG = CORE_PIN38_BITMASK; | |||
} else if (pin == 39) { | |||
CORE_PIN39_PINREG = CORE_PIN39_BITMASK; | |||
} else if (pin == 40) { | |||
CORE_PIN40_PINREG = CORE_PIN40_BITMASK; | |||
} else if (pin == 41) { | |||
CORE_PIN41_PINREG = CORE_PIN41_BITMASK; | |||
} else if (pin == 42) { | |||
CORE_PIN42_PINREG = CORE_PIN42_BITMASK; | |||
} else if (pin == 43) { | |||
CORE_PIN43_PINREG = CORE_PIN43_BITMASK; | |||
} else if (pin == 44) { | |||
CORE_PIN44_PINREG = CORE_PIN44_BITMASK; | |||
} else if (pin == 45) { | |||
CORE_PIN45_PINREG = CORE_PIN45_BITMASK; | |||
} | |||
#endif | |||
if (pin == CORE_OC0B_PIN) { | |||
_SFR_BYTE(TCCR0A) &= ~(1<<COM0B1); | |||
} else if (pin == CORE_OC1A_PIN) { | |||
TCCR1A &= ~(1<<COM1A1); | |||
} else if (pin == CORE_OC1B_PIN) { | |||
TCCR1A &= ~(1<<COM1B1); | |||
} else if (pin == CORE_OC1C_PIN) { | |||
TCCR1A &= ~(1<<COM1C1); | |||
} | |||
#if defined(__AVR_ATmega32U4__) | |||
else if (pin == CORE_OC3A_PIN) { | |||
TCCR3A &= ~(1<<COM3A1); | |||
} else if (pin == CORE_OC4A_PIN) { | |||
TCCR4A &= ~(1<<COM4A1); | |||
} else if (pin == CORE_OC4D_PIN) { | |||
TCCR4C &= ~(1<<COM4D1); | |||
} | |||
#endif | |||
#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) | |||
else if (pin == CORE_OC2A_PIN) { | |||
TCCR2A &= ~(1<<COM2A1); | |||
} else if (pin == CORE_OC2B_PIN) { | |||
TCCR2A &= ~(1<<COM2B1); | |||
} else if (pin == CORE_OC3A_PIN) { | |||
TCCR3A &= ~(1<<COM3A1); | |||
} else if (pin == CORE_OC3B_PIN) { | |||
TCCR3A &= ~(1<<COM3B1); | |||
} else if (pin == CORE_OC3C_PIN) { | |||
TCCR3A &= ~(1<<COM3C1); | |||
} | |||
#endif | |||
} else { | |||
digitalWrite(pin, !(digitalRead(pin))); | |||
} | |||
} | |||
static inline void digitalToggleFast(uint8_t) __attribute__((always_inline, unused)); | |||
static inline void digitalToggleFast(uint8_t pin) | |||
{ | |||
if (__builtin_constant_p(pin)) { | |||
if (pin == 0) { | |||
CORE_PIN0_PINREG = CORE_PIN0_BITMASK; | |||
} else if (pin == 1) { | |||
CORE_PIN1_PINREG = CORE_PIN1_BITMASK; | |||
} else if (pin == 2) { | |||
CORE_PIN2_PINREG = CORE_PIN2_BITMASK; | |||
} else if (pin == 3) { | |||
CORE_PIN3_PINREG = CORE_PIN3_BITMASK; | |||
} else if (pin == 4) { | |||
CORE_PIN4_PINREG = CORE_PIN4_BITMASK; | |||
} else if (pin == 5) { | |||
CORE_PIN5_PINREG = CORE_PIN5_BITMASK; | |||
} else if (pin == 6) { | |||
CORE_PIN6_PINREG = CORE_PIN6_BITMASK; | |||
} else if (pin == 7) { | |||
CORE_PIN7_PINREG = CORE_PIN7_BITMASK; | |||
} else if (pin == 8) { | |||
CORE_PIN8_PINREG = CORE_PIN8_BITMASK; | |||
} else if (pin == 9) { | |||
CORE_PIN9_PINREG = CORE_PIN9_BITMASK; | |||
} else if (pin == 10) { | |||
CORE_PIN10_PINREG = CORE_PIN10_BITMASK; | |||
} else if (pin == 11) { | |||
CORE_PIN11_PINREG = CORE_PIN11_BITMASK; | |||
} else if (pin == 12) { | |||
CORE_PIN12_PINREG = CORE_PIN12_BITMASK; | |||
} else if (pin == 13) { | |||
CORE_PIN13_PINREG = CORE_PIN13_BITMASK; | |||
} else if (pin == 14) { | |||
CORE_PIN14_PINREG = CORE_PIN14_BITMASK; | |||
} else if (pin == 15) { | |||
CORE_PIN15_PINREG = CORE_PIN15_BITMASK; | |||
} else if (pin == 16) { | |||
CORE_PIN16_PINREG = CORE_PIN16_BITMASK; | |||
} else if (pin == 17) { | |||
CORE_PIN17_PINREG = CORE_PIN17_BITMASK; | |||
} else if (pin == 18) { | |||
CORE_PIN18_PINREG = CORE_PIN18_BITMASK; | |||
} else if (pin == 19) { | |||
CORE_PIN19_PINREG = CORE_PIN19_BITMASK; | |||
} else if (pin == 20) { | |||
CORE_PIN20_PINREG = CORE_PIN20_BITMASK; | |||
} | |||
#if CORE_NUM_TOTAL_PINS > 21 | |||
else if (pin == 21) { | |||
CORE_PIN21_PINREG = CORE_PIN21_BITMASK; | |||
} else if (pin == 22) { | |||
CORE_PIN22_PINREG = CORE_PIN22_BITMASK; | |||
} else if (pin == 23) { | |||
CORE_PIN23_PINREG = CORE_PIN23_BITMASK; | |||
} else if (pin == 24) { | |||
CORE_PIN24_PINREG = CORE_PIN24_BITMASK; | |||
} | |||
#endif | |||
#if CORE_NUM_TOTAL_PINS > 25 | |||
else if (pin == 25) { | |||
CORE_PIN25_PINREG = CORE_PIN25_BITMASK; | |||
} else if (pin == 26) { | |||
CORE_PIN26_PINREG = CORE_PIN26_BITMASK; | |||
} else if (pin == 27) { | |||
CORE_PIN27_PINREG = CORE_PIN27_BITMASK; | |||
} else if (pin == 28) { | |||
CORE_PIN28_PINREG = CORE_PIN28_BITMASK; | |||
} else if (pin == 29) { | |||
CORE_PIN29_PINREG = CORE_PIN29_BITMASK; | |||
} else if (pin == 30) { | |||
CORE_PIN30_PINREG = CORE_PIN30_BITMASK; | |||
} else if (pin == 31) { | |||
CORE_PIN31_PINREG = CORE_PIN31_BITMASK; | |||
} else if (pin == 32) { | |||
CORE_PIN32_PINREG = CORE_PIN32_BITMASK; | |||
} else if (pin == 33) { | |||
CORE_PIN33_PINREG = CORE_PIN33_BITMASK; | |||
} else if (pin == 34) { | |||
CORE_PIN34_PINREG = CORE_PIN34_BITMASK; | |||
} else if (pin == 35) { | |||
CORE_PIN35_PINREG = CORE_PIN35_BITMASK; | |||
} else if (pin == 36) { | |||
CORE_PIN36_PINREG = CORE_PIN36_BITMASK; | |||
} else if (pin == 37) { | |||
CORE_PIN37_PINREG = CORE_PIN37_BITMASK; | |||
} else if (pin == 38) { | |||
CORE_PIN38_PINREG = CORE_PIN38_BITMASK; | |||
} else if (pin == 39) { | |||
CORE_PIN39_PINREG = CORE_PIN39_BITMASK; | |||
} else if (pin == 40) { | |||
CORE_PIN40_PINREG = CORE_PIN40_BITMASK; | |||
} else if (pin == 41) { | |||
CORE_PIN41_PINREG = CORE_PIN41_BITMASK; | |||
} else if (pin == 42) { | |||
CORE_PIN42_PINREG = CORE_PIN42_BITMASK; | |||
} else if (pin == 43) { | |||
CORE_PIN43_PINREG = CORE_PIN43_BITMASK; | |||
} else if (pin == 44) { | |||
CORE_PIN44_PINREG = CORE_PIN44_BITMASK; | |||
} else if (pin == 45) { | |||
CORE_PIN45_PINREG = CORE_PIN45_BITMASK; | |||
} | |||
#endif | |||
} else { | |||
digitalWrite(pin, !(digitalRead(pin))); | |||
} | |||
} | |||
extern void _init_Teensyduino_internal_(void); | |||
extern int analogRead(uint8_t); | |||
@@ -2198,6 +2445,94 @@ static inline void delayMicroseconds(uint16_t usec) | |||
} | |||
static inline void delayNanoseconds(uint16_t) __attribute__((always_inline, unused)); | |||
static inline void delayNanoseconds(uint16_t nsec) | |||
{ | |||
if (__builtin_constant_p(nsec)) { | |||
// use NOPs for the common usage of a constexpr input and short delay | |||
if (nsec == 0) return; | |||
if (nsec <= 1000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop"); | |||
return; | |||
} | |||
if (nsec <= 2000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 3000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 4000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 5000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 6000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop"); | |||
return; | |||
} | |||
if (nsec <= 7000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 8000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 9000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 10000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 11000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop"); | |||
return; | |||
} | |||
if (nsec <= 12000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 13000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 14000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 15000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
return; | |||
} | |||
} | |||
// if we can't use NOPs, just round up to the nearest microsecond... | |||
// not ideal, but AVR is too slow to do anything more complex | |||
delayMicroseconds((nsec >> 10) + 1); | |||
} | |||
#ifdef __cplusplus |
@@ -1451,7 +1451,7 @@ extern "C"{ | |||
#define ASCII_20 KEY_SPACE // 32 | |||
#define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | |||
#define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | |||
#define ASCII_23 KEY_BACKSPACE // 35 # | |||
#define ASCII_23 KEY_BACKSLASH // 35 # | |||
#define ASCII_24 KEY_4 + SHIFT_MASK // 36 $ | |||
#define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | |||
#define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | |||
@@ -4533,7 +4533,7 @@ extern "C"{ | |||
#define ASCII_20 KEY_SPACE // 32 | |||
#define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | |||
#define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | |||
#define ASCII_23 KEY_BACKSPACE // 35 # | |||
#define ASCII_23 KEY_BACKSLASH // 35 # | |||
#define ASCII_24 KEY_4 + SHIFT_MASK // 36 $ | |||
#define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | |||
#define ASCII_26 KEY_7 + SHIFT_MASK // 38 & |
@@ -73,7 +73,7 @@ struct __freelist *__flp; // freelist pointer (head of freelist) | |||
void * | |||
malloc(size_t len) | |||
{ | |||
struct __freelist *fp1, *fp2, *sfp1, *sfp2; | |||
struct __freelist *fp1, *fp2, *sfp1=NULL, *sfp2=NULL; | |||
char *cp; | |||
size_t s, avail; | |||
@@ -36,6 +36,12 @@ const static uint8_t SCL = CORE_SCL0_PIN; | |||
#define NUM_DIGITAL_PINS CORE_NUM_TOTAL_PINS | |||
#define NUM_ANALOG_INPUTS CORE_NUM_ANALOG | |||
// default CS pin to use for Ethernet library | |||
#if defined(__AVR_ATmega32U4__) | |||
#define PIN_SPI_SS_ETHERNET_LIB 0 | |||
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) | |||
#define PIN_SPI_SS_ETHERNET_LIB 20 | |||
#endif | |||
// This allows CapSense to work. Do any libraries | |||
// depend on these to be zero? |
@@ -27,6 +27,7 @@ | |||
#include <avr/io.h> | |||
#include <stdlib.h> | |||
#include <stdbool.h> | |||
#include <math.h> | |||
#include "binary.h" | |||
#include "core_id.h" | |||
@@ -39,9 +40,6 @@ | |||
extern "C"{ | |||
#endif | |||
#define true 1 | |||
#define false 0 | |||
#define PI 3.1415926535897932384626433832795 | |||
#define HALF_PI 1.5707963267948966192313216916398 | |||
#define TWO_PI 6.283185307179586476925286766559 | |||
@@ -93,7 +91,7 @@ typedef unsigned int word; | |||
#define bit(b) (1UL << (b)) | |||
typedef uint8_t boolean; | |||
typedef bool boolean; | |||
typedef uint8_t byte; | |||
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); |
@@ -1,4 +1,9 @@ | |||
// This header file is in the public domain. | |||
#ifndef Arduino_h | |||
#define Arduino_h | |||
#include "WProgram.h" | |||
#include "pins_arduino.h" | |||
#endif |
@@ -29,9 +29,8 @@ | |||
*/ | |||
#include <string.h> // for memcpy | |||
#include "AudioStream.h" | |||
#include <Arduino.h> | |||
#include "AudioStream.h" | |||
#if defined(__MKL26Z64__) | |||
#define MAX_AUDIO_MEMORY 6144 | |||
@@ -244,6 +243,8 @@ void AudioConnection::disconnect(void) | |||
// Remove destination from source list | |||
p = src.destination_list; | |||
if (p == NULL) { | |||
//>>> PAH re-enable the IRQ | |||
__enable_irq(); | |||
return; | |||
} else if (p == this) { | |||
if (p->next_dest) { | |||
@@ -265,8 +266,14 @@ void AudioConnection::disconnect(void) | |||
p = p->next_dest; | |||
} | |||
} | |||
//>>> PAH release the audio buffer properly | |||
//Remove possible pending src block from destination | |||
dst.inputQueue[dest_index] = NULL; | |||
if(dst.inputQueue[dest_index] != NULL) { | |||
AudioStream::release(dst.inputQueue[dest_index]); | |||
// release() re-enables the IRQ. Need it to be disabled a little longer | |||
__disable_irq(); | |||
dst.inputQueue[dest_index] = NULL; | |||
} | |||
//Check if the disconnected AudioStream objects should still be active | |||
src.numConnections--; | |||
@@ -313,9 +320,13 @@ void software_isr(void) // AudioStream::update_all() | |||
{ | |||
AudioStream *p; | |||
#if defined(KINETISK) | |||
ARM_DEMCR |= ARM_DEMCR_TRCENA; | |||
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; | |||
uint32_t totalcycles = ARM_DWT_CYCCNT; | |||
#elif defined(KINETISL) | |||
uint32_t totalcycles = micros(); | |||
#endif | |||
//digitalWriteFast(2, HIGH); | |||
for (p = AudioStream::first_update; p; p = p->next_update) { | |||
if (p->active) { | |||
@@ -329,7 +340,11 @@ void software_isr(void) // AudioStream::update_all() | |||
} | |||
} | |||
//digitalWriteFast(2, LOW); | |||
totalcycles = (ARM_DWT_CYCCNT - totalcycles) >> 4;; | |||
#if defined(KINETISK) | |||
totalcycles = (ARM_DWT_CYCCNT - totalcycles) >> 4; | |||
#elif defined(KINETISL) | |||
totalcycles = micros() - totalcycles; | |||
#endif | |||
AudioStream::cpu_cycles_total = totalcycles; | |||
if (totalcycles > AudioStream::cpu_cycles_total_max) | |||
AudioStream::cpu_cycles_total_max = totalcycles; |
@@ -59,7 +59,8 @@ | |||
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
#define AUDIO_SAMPLE_RATE_EXACT 44117.64706 // 48 MHz / 1088, or 96 MHz * 2 / 17 / 256 | |||
#elif defined(__MKL26Z64__) | |||
#define AUDIO_SAMPLE_RATE_EXACT 22058.82353 // 48 MHz / 2176, or 96 MHz * 1 / 17 / 256 | |||
//#define AUDIO_SAMPLE_RATE_EXACT 22058.82353 // 48 MHz / 2176, or 96 MHz * 1 / 17 / 256 | |||
#define AUDIO_SAMPLE_RATE_EXACT 44117.64706 | |||
#endif | |||
#endif | |||
@@ -113,7 +114,11 @@ protected: | |||
AudioStream::initialize_memory(data, num); \ | |||
}) | |||
#if defined(KINETISK) | |||
#define CYCLE_COUNTER_APPROX_PERCENT(n) (((n) + (F_CPU / 32 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100)) / (F_CPU / 16 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100)) | |||
#elif defined(KINETISL) | |||
#define CYCLE_COUNTER_APPROX_PERCENT(n) ((n) * (int)(AUDIO_SAMPLE_RATE) + (int)(AUDIO_SAMPLE_RATE/2)) / (AUDIO_BLOCK_SAMPLES * 10000) | |||
#endif | |||
#define AudioProcessorUsage() (CYCLE_COUNTER_APPROX_PERCENT(AudioStream::cpu_cycles_total)) | |||
#define AudioProcessorUsageMax() (CYCLE_COUNTER_APPROX_PERCENT(AudioStream::cpu_cycles_total_max)) |
@@ -380,6 +380,7 @@ protected: | |||
DMABaseClass() {} | |||
static inline void copy_tcd(TCD_t *dst, const TCD_t *src) { | |||
dst->CSR = 0; | |||
const uint32_t *p = (const uint32_t *)src; | |||
uint32_t *q = (uint32_t *)dst; | |||
uint32_t t1, t2, t3, t4; | |||
@@ -534,6 +535,12 @@ public: | |||
NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); | |||
} | |||
void attachInterrupt(void (*isr)(void), uint8_t prio) { | |||
_VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr; | |||
NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); | |||
NVIC_SET_PRIORITY(IRQ_DMA_CH0 + channel, prio); | |||
} | |||
void detachInterrupt(void) { | |||
NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel); | |||
} | |||
@@ -811,11 +818,11 @@ public: | |||
void transferSize(unsigned int len) { | |||
uint32_t dcr = CFG->DCR & 0xF0C8FFFF; | |||
if (len == 4) { | |||
CFG->DCR = dcr | DMA_DCR_DSIZE(0) | DMA_DCR_DSIZE(0); | |||
CFG->DCR = dcr | DMA_DCR_SSIZE(0) | DMA_DCR_DSIZE(0); | |||
} else if (len == 2) { | |||
CFG->DCR = dcr | DMA_DCR_DSIZE(2) | DMA_DCR_DSIZE(2); | |||
CFG->DCR = dcr | DMA_DCR_SSIZE(2) | DMA_DCR_DSIZE(2); | |||
} else { | |||
CFG->DCR = dcr | DMA_DCR_DSIZE(1) | DMA_DCR_DSIZE(1); | |||
CFG->DCR = dcr | DMA_DCR_SSIZE(1) | DMA_DCR_DSIZE(1); | |||
} | |||
} | |||
@@ -1034,7 +1041,13 @@ public: | |||
_VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr; | |||
NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); | |||
} | |||
void attachInterrupt(void (*isr)(void), uint8_t prio) { | |||
_VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr; | |||
NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); | |||
NVIC_SET_PRIORITY(IRQ_DMA_CH0 + channel, prio); | |||
} | |||
void detachInterrupt(void) { | |||
NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel); | |||
} |
@@ -31,6 +31,7 @@ | |||
* https://forum.pjrc.com/threads/44723-Arduino-Events | |||
*/ | |||
#include <Arduino.h> | |||
#include "EventResponder.h" | |||
EventResponder * EventResponder::firstYield = nullptr; | |||
@@ -40,6 +41,10 @@ EventResponder * EventResponder::lastInterrupt = nullptr; | |||
bool EventResponder::runningFromYield = false; | |||
// TODO: interrupt disable/enable needed in many places!!! | |||
// BUGBUG: See if file name order makes difference? | |||
uint8_t _serialEvent_default __attribute__((weak)) PROGMEM = 0 ; | |||
uint8_t _serialEventUSB1_default __attribute__((weak)) PROGMEM = 0 ; | |||
uint8_t _serialEventUSB2_default __attribute__((weak)) PROGMEM = 0 ; | |||
void EventResponder::triggerEventNotImmediate() | |||
{ | |||
@@ -334,10 +339,17 @@ void MillisTimer::runFromTimer() | |||
// with libraries using mid-to-high priority interrupts. | |||
extern "C" volatile uint32_t systick_millis_count; | |||
void systick_isr(void) | |||
{ | |||
systick_millis_count++; | |||
} | |||
extern "C" void systick_isr_with_timer_events(void) | |||
{ | |||
systick_millis_count++; | |||
MillisTimer::runFromTimer(); | |||
} | |||
@@ -59,6 +59,7 @@ | |||
* your function is called only one time, based on the last trigger | |||
* event. | |||
*/ | |||
extern "C" void systick_isr_with_timer_events(void); | |||
class EventResponder; | |||
typedef EventResponder& EventResponderRef; | |||
@@ -87,6 +88,7 @@ public: | |||
detachNoInterrupts(); | |||
_function = function; | |||
_type = EventTypeYield; | |||
yield_active_check_flags |= YIELD_CHECK_EVENT_RESPONDER; // user setup a yield type... | |||
enableInterrupts(irq); | |||
} | |||
@@ -112,6 +114,8 @@ public: | |||
_function = function; | |||
_type = EventTypeInterrupt; | |||
SCB_SHPR3 |= 0x00FF0000; // configure PendSV, lowest priority | |||
// Make sure we are using the systic ISR that process this | |||
_VectorsRam[15] = systick_isr_with_timer_events; | |||
enableInterrupts(irq); | |||
} | |||
@@ -170,6 +174,7 @@ public: | |||
EventResponder * waitForEvent(EventResponder *list, int listsize, int timeout); | |||
static void runFromYield() { | |||
if (!firstYield) return; | |||
// First, check if yield was called from an interrupt | |||
// never call normal handler functions from any interrupt context | |||
uint32_t ipsr; |
@@ -1,43 +1,146 @@ | |||
/* Experimental File & Dir base classes. VERY experimental! | |||
These are intended to someday allow libraries using files, | |||
such as a JPEG decoder, to accept a File object from SD, | |||
Bridge, USB Host, ESP SPIFFS, and others. Perhaps only a | |||
distant dream at this point, but maybe someday.... | |||
*/ | |||
/* Teensyduino Core Library - File base class | |||
* http://www.pjrc.com/teensy/ | |||
* Copyright (c) 2020 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. | |||
*/ | |||
#ifndef FS_H | |||
#define FS_H | |||
#ifdef __cplusplus | |||
#include "Stream.h" | |||
#include "WString.h" | |||
#include <Arduino.h> | |||
#define FILE_READ 0 | |||
#define FILE_WRITE 1 | |||
#define FILE_WRITE_BEGIN 2 | |||
enum SeekMode { | |||
SeekSet = 0, | |||
SeekCur = 1, | |||
SeekEnd = 2 | |||
}; | |||
#define FILE_WHOAMI | |||
class File : public Stream { | |||
public: | |||
constexpr File() {} | |||
enum SeekMode { | |||
SeekSet = 0, | |||
SeekCur = 1, | |||
SeekEnd = 2 | |||
}; | |||
virtual size_t read(void *buf, size_t nbyte); | |||
virtual size_t write(const void *buf, size_t size); | |||
virtual int available(); | |||
virtual int read(); | |||
virtual int peek(); | |||
virtual void flush(); | |||
virtual bool seek(uint32_t pos, int mode); | |||
virtual uint32_t position() const; | |||
virtual uint32_t size() const; | |||
virtual void close(); | |||
virtual operator bool() const; | |||
//virtual const char* name() const; // why does ESP have this in File? | |||
bool seek(uint32_t pos) { | |||
constexpr File() : f(nullptr) { } | |||
File(File *file) { | |||
// "file" must only be a class derived from File | |||
// can we use is_same or is_polymorphic with static_assert? | |||
// or is_base_of | |||
//static_assert(std::is_same<decltype(*file),File>::value, | |||
//"File(File *file) constructor only accepts pointers " | |||
//"to derived classes, not File itself"); | |||
f = file; | |||
if (f) f->refcount++; | |||
} | |||
File(const File &file) { | |||
//Serial.println("File copy constructor"); | |||
//static int copycount=0; | |||
//if (++copycount > 20) while (1) ; | |||
f = file.f; | |||
if (f) f->refcount++; | |||
} | |||
File& operator = (const File &file) { | |||
//Serial.println("File assignment"); | |||
//static int assigncount=0; | |||
//if (++assigncount > 20) while (1) ; | |||
invalidate(); | |||
f = file.f; | |||
if (f) f->refcount++; | |||
return *this; | |||
} | |||
virtual ~File() { | |||
invalidate(); | |||
} | |||
#ifdef FILE_WHOAMI | |||
virtual void whoami() { // testing only | |||
Serial.printf(" File this=%x, f=%x\n", (int)this, (int)f); | |||
if (f) f->whoami(); | |||
} | |||
unsigned int getRefcount() { // testing only | |||
return refcount; | |||
} | |||
#endif | |||
virtual size_t read(void *buf, size_t nbyte) { | |||
return (f) ? f->read(buf, nbyte) : 0; | |||
} | |||
virtual size_t write(const void *buf, size_t size) { | |||
return (f) ? f->write(buf, size) : 0; | |||
} | |||
virtual int available() { | |||
return (f) ? f->available() : 0; | |||
} | |||
virtual int peek() { | |||
return (f) ? f->peek() : -1; | |||
} | |||
virtual void flush() { | |||
if (f) f->flush(); | |||
} | |||
virtual bool truncate(uint64_t size=0) { | |||
return (f) ? f->truncate(size) : false; | |||
} | |||
virtual bool seek(uint64_t pos, int mode) { | |||
return (f) ? f->seek(pos, mode) : false; | |||
} | |||
virtual uint64_t position() { | |||
return (f) ? f->position() : 0; | |||
} | |||
virtual uint64_t size() { | |||
return (f) ? f->size() : 0; | |||
} | |||
virtual void close() { | |||
if (f) f->close(); | |||
} | |||
virtual operator bool() { | |||
return (f) ? (bool)*f : false; | |||
} | |||
virtual const char* name() { | |||
return (f) ? f->name() : ""; | |||
} | |||
virtual bool isDirectory() { | |||
return (f) ? f->isDirectory() : false; | |||
} | |||
virtual File openNextFile(uint8_t mode=0) { | |||
return (f) ? f->openNextFile(mode) : *this; | |||
} | |||
virtual void rewindDirectory(void) { | |||
if (f) f->rewindDirectory(); | |||
} | |||
bool seek(uint64_t pos) { | |||
return seek(pos, SeekSet); | |||
} | |||
int read() { | |||
if (!f) return -1; | |||
unsigned char b; | |||
if (f->read(&b, 1) < 1) return -1; | |||
return b; | |||
} | |||
size_t write(uint8_t b) { | |||
return write(&b, 1); | |||
} | |||
@@ -47,26 +150,34 @@ public: | |||
size_t readBytes(char *buffer, size_t length) { | |||
return read(buffer, length); | |||
} | |||
// needed for compatiblity with Arduino's SD & Bridge libs | |||
virtual const char* name(); | |||
virtual bool isDirectory(); | |||
virtual File openNextFile(uint8_t mode=0); | |||
virtual void rewindDirectory(void); | |||
private: | |||
void invalidate() { | |||
if (f && --(f->refcount) == 0) delete f; | |||
} | |||
union { | |||
// instances of base File class use this pointer | |||
File *f; | |||
// instances of derived classes (which actually access media) | |||
// use this reference count which is managed by the base class | |||
unsigned int refcount; | |||
}; | |||
}; | |||
class Dir { | |||
class FS | |||
{ | |||
public: | |||
constexpr Dir() {} | |||
virtual const char *name(); // from SD's File (and ESP's File) | |||
virtual uint32_t fileSize(); | |||
virtual bool isDirectory(); // from SD, not in ESP | |||
virtual File openFile(const char *mode); | |||
virtual bool next(); | |||
String fileName() { | |||
return String(name()); | |||
} | |||
FS() {} | |||
virtual File open(const char *filename, uint8_t mode = FILE_READ); | |||
virtual bool exists(const char *filepath); | |||
virtual bool mkdir(const char *filepath); | |||
virtual bool rename(const char *oldfilepath, const char *newfilepath); | |||
virtual bool remove(const char *filepath); | |||
virtual bool rmdir(const char *filepath); | |||
virtual uint64_t usedSize(); | |||
virtual uint64_t totalSize(); | |||
}; | |||
#endif // __cplusplus | |||
#endif // FS_H |
@@ -0,0 +1,45 @@ | |||
/* Teensyduino Core Library | |||
* http://www.pjrc.com/teensy/ | |||
* Copyright (c) 2019 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 "HardwareSerial.h" | |||
#include "core_pins.h" | |||
#include "Arduino.h" | |||
// define our static objects | |||
HardwareSerial *HardwareSerial::s_serials_with_serial_events[CNT_HARDWARE_SERIAL]; | |||
uint8_t HardwareSerial::s_count_serials_with_serial_events = 0; | |||
// simple helper function that add us to the list of Serial ports that have | |||
// their own serialEvent code defined that needs to be called at yield. | |||
void HardwareSerial::addToSerialEventsList() { | |||
s_serials_with_serial_events[s_count_serials_with_serial_events++] = this; | |||
yield_active_check_flags |= YIELD_CHECK_HARDWARE_SERIAL; | |||
} | |||
@@ -253,8 +253,13 @@ void serial6_clear(void); | |||
class HardwareSerial : public Stream | |||
{ | |||
public: | |||
constexpr HardwareSerial() {} | |||
virtual void begin(uint32_t baud) { serial_begin(BAUD2DIV(baud)); } | |||
constexpr HardwareSerial(void (* const se)()) : _serialEvent(se) {} | |||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
enum {CNT_HARDWARE_SERIAL = 6}; | |||
#else //(__MK64FX512__) || defined(__MK66FX1M0__) | |||
enum {CNT_HARDWARE_SERIAL = 3}; | |||
#endif | |||
virtual void begin(uint32_t baud); | |||
virtual void begin(uint32_t baud, uint32_t format) { | |||
serial_begin(BAUD2DIV(baud)); | |||
serial_format(format); } | |||
@@ -283,6 +288,21 @@ public: | |||
return len; } | |||
virtual size_t write9bit(uint32_t c) { serial_putchar(c); return 1; } | |||
operator bool() { return true; } | |||
static inline void processSerialEventsList() { | |||
for (uint8_t i = 0; i < s_count_serials_with_serial_events; i++) { | |||
s_serials_with_serial_events[i]->doYieldCode(); | |||
} | |||
} | |||
protected: | |||
static HardwareSerial *s_serials_with_serial_events[CNT_HARDWARE_SERIAL]; | |||
static uint8_t s_count_serials_with_serial_events; | |||
void (* const _serialEvent)(); | |||
void addToSerialEventsList(); | |||
inline void doYieldCode() { | |||
if (available()) (*_serialEvent)(); | |||
} | |||
}; | |||
extern HardwareSerial Serial1; | |||
extern void serialEvent1(void); | |||
@@ -290,8 +310,8 @@ extern void serialEvent1(void); | |||
class HardwareSerial2 : public HardwareSerial | |||
{ | |||
public: | |||
constexpr HardwareSerial2() {} | |||
virtual void begin(uint32_t baud) { serial2_begin(BAUD2DIV2(baud)); } | |||
constexpr HardwareSerial2(void (* const se)()) : HardwareSerial(se) {} | |||
virtual void begin(uint32_t baud); | |||
virtual void begin(uint32_t baud, uint32_t format) { | |||
serial2_begin(BAUD2DIV2(baud)); | |||
serial2_format(format); } | |||
@@ -327,8 +347,8 @@ extern void serialEvent2(void); | |||
class HardwareSerial3 : public HardwareSerial | |||
{ | |||
public: | |||
constexpr HardwareSerial3() {} | |||
virtual void begin(uint32_t baud) { serial3_begin(BAUD2DIV3(baud)); } | |||
constexpr HardwareSerial3(void (* const se)()) : HardwareSerial(se) {} | |||
virtual void begin(uint32_t baud); | |||
virtual void begin(uint32_t baud, uint32_t format) { | |||
serial3_begin(BAUD2DIV3(baud)); | |||
serial3_format(format); } | |||
@@ -364,8 +384,8 @@ extern void serialEvent3(void); | |||
class HardwareSerial4 : public HardwareSerial | |||
{ | |||
public: | |||
constexpr HardwareSerial4() {} | |||
virtual void begin(uint32_t baud) { serial4_begin(BAUD2DIV3(baud)); } | |||
constexpr HardwareSerial4(void (* const se)()) : HardwareSerial(se) {} | |||
virtual void begin(uint32_t baud); | |||
virtual void begin(uint32_t baud, uint32_t format) { | |||
serial4_begin(BAUD2DIV3(baud)); | |||
serial4_format(format); } | |||
@@ -401,8 +421,8 @@ extern void serialEvent4(void); | |||
class HardwareSerial5 : public HardwareSerial | |||
{ | |||
public: | |||
constexpr HardwareSerial5() {} | |||
virtual void begin(uint32_t baud) { serial5_begin(BAUD2DIV3(baud)); } | |||
constexpr HardwareSerial5(void (* const se)()) : HardwareSerial(se) {} | |||
virtual void begin(uint32_t baud); | |||
virtual void begin(uint32_t baud, uint32_t format) { | |||
serial5_begin(BAUD2DIV3(baud)); | |||
serial5_format(format); } | |||
@@ -438,14 +458,14 @@ extern void serialEvent5(void); | |||
class HardwareSerial6 : public HardwareSerial | |||
{ | |||
public: | |||
constexpr HardwareSerial6() {} | |||
constexpr HardwareSerial6(void (* const se)()) : HardwareSerial(se) {} | |||
#if defined(__MK66FX1M0__) // For LPUART just pass baud straight in. | |||
virtual void begin(uint32_t baud) { serial6_begin(baud); } | |||
virtual void begin(uint32_t baud); | |||
virtual void begin(uint32_t baud, uint32_t format) { | |||
serial6_begin(baud); | |||
serial6_format(format); } | |||
#else | |||
virtual void begin(uint32_t baud) { serial6_begin(BAUD2DIV3(baud)); } | |||
virtual void begin(uint32_t baud); | |||
virtual void begin(uint32_t baud, uint32_t format) { | |||
serial6_begin(BAUD2DIV3(baud)); | |||
serial6_format(format); } |
@@ -28,9 +28,16 @@ | |||
* SOFTWARE. | |||
*/ | |||
#include <Arduino.h> | |||
#include "HardwareSerial.h" | |||
HardwareSerial Serial1; | |||
void serialEvent1() __attribute__((weak)); | |||
void serialEvent1() {} | |||
uint8_t _serialEvent1_default __attribute__((weak)) PROGMEM = 0 ; | |||
HardwareSerial Serial1(&serialEvent1); | |||
void HardwareSerial::begin(uint32_t baud) { | |||
serial_begin(BAUD2DIV(baud)); | |||
if (!_serialEvent1_default) addToSerialEventsList(); | |||
} | |||
@@ -27,10 +27,14 @@ | |||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
* SOFTWARE. | |||
*/ | |||
#include <Arduino.h> | |||
#include "HardwareSerial.h" | |||
HardwareSerial2 Serial2; | |||
HardwareSerial2 Serial2(&serialEvent2); | |||
uint8_t _serialEvent2_default __attribute__((weak)) PROGMEM = 0 ; | |||
void serialEvent2() __attribute__((weak)); | |||
void serialEvent2() {} | |||
void HardwareSerial2::begin(uint32_t baud) { | |||
serial2_begin(BAUD2DIV2(baud)); | |||
if (!_serialEvent2_default) addToSerialEventsList(); | |||
} |
@@ -28,9 +28,14 @@ | |||
* SOFTWARE. | |||
*/ | |||
#include <Arduino.h> | |||
#include "HardwareSerial.h" | |||
HardwareSerial3 Serial3; | |||
HardwareSerial3 Serial3(&serialEvent3); | |||
void serialEvent3() __attribute__((weak)); | |||
void serialEvent3() {} | |||
uint8_t _serialEvent3_default __attribute__((weak)) PROGMEM = 0 ; | |||
void HardwareSerial3::begin(uint32_t baud) { | |||
serial3_begin(BAUD2DIV3(baud)); | |||
if (!_serialEvent3_default) addToSerialEventsList(); | |||
} |
@@ -28,13 +28,18 @@ | |||
* SOFTWARE. | |||
*/ | |||
#include <Arduino.h> | |||
#include "HardwareSerial.h" | |||
#ifdef HAS_KINETISK_UART3 | |||
HardwareSerial4 Serial4; | |||
HardwareSerial4 Serial4(&serialEvent4); | |||
void serialEvent4() __attribute__((weak)); | |||
void serialEvent4() {} | |||
uint8_t _serialEvent4_default __attribute__((weak)) PROGMEM = 0 ; | |||
void HardwareSerial4::begin(uint32_t baud) { | |||
serial4_begin(BAUD2DIV3(baud)); | |||
if (!_serialEvent4_default) addToSerialEventsList(); | |||
} | |||
#endif |
@@ -28,13 +28,18 @@ | |||
* SOFTWARE. | |||
*/ | |||
#include <Arduino.h> | |||
#include "HardwareSerial.h" | |||
#ifdef HAS_KINETISK_UART4 | |||
HardwareSerial5 Serial5; | |||
HardwareSerial5 Serial5(&serialEvent5); | |||
void serialEvent5() __attribute__((weak)); | |||
void serialEvent5() {} | |||
uint8_t _serialEvent5_default __attribute__((weak)) PROGMEM = 0 ; | |||
void HardwareSerial5::begin(uint32_t baud) { | |||
serial5_begin(BAUD2DIV3(baud)); | |||
if (!_serialEvent5_default) addToSerialEventsList(); | |||
} | |||
#endif |
@@ -28,13 +28,22 @@ | |||
* SOFTWARE. | |||
*/ | |||
#include <Arduino.h> | |||
#include "HardwareSerial.h" | |||
#if defined(HAS_KINETISK_UART5) || defined (HAS_KINETISK_LPUART0) | |||
HardwareSerial6 Serial6; | |||
HardwareSerial6 Serial6(&serialEvent6); | |||
void serialEvent6() __attribute__((weak)); | |||
void serialEvent6() {} | |||
uint8_t _serialEvent6_default __attribute__((weak)) PROGMEM = 0 ; | |||
void HardwareSerial6::begin(uint32_t baud) { | |||
#if defined(__MK66FX1M0__) // For LPUART just pass baud straight in. | |||
serial6_begin(baud); | |||
#else | |||
serial6_begin(BAUD2DIV3(baud)); | |||
#endif | |||
if (!_serialEvent6_default) addToSerialEventsList(); | |||
} | |||
#endif |
@@ -17,7 +17,7 @@ | |||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |||
*/ | |||
#include "Arduino.h" | |||
#include <Arduino.h> | |||
#include "IPAddress.h" | |||
size_t IPAddress::printTo(Print& p) const |
@@ -53,7 +53,7 @@ endif | |||
OPTIONS = -DF_CPU=48000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH -DUSING_MAKEFILE | |||
# options needed by many Arduino libraries to configure for Teensy 3.x | |||
OPTIONS += -D__$(MCU)__ -DARDUINO=10805 -DTEENSYDUINO=141 | |||
OPTIONS += -D__$(MCU)__ -DARDUINO=10805 -DTEENSYDUINO=144 | |||
# use "cortex-m4" for Teensy 3.x | |||
# use "cortex-m0plus" for Teensy LC |
@@ -34,15 +34,12 @@ | |||
// developed for Teensyduino have made their way back into | |||
// Arduino's code base. :-) | |||
#include <inttypes.h> | |||
#include <math.h> | |||
#include "Print.h" | |||
#include <Arduino.h> | |||
size_t Print::write(const uint8_t *buffer, size_t size) | |||
{ | |||
if (buffer == nullptr) return 0; | |||
size_t count = 0; | |||
while (size--) count += write(*buffer++); | |||
return count; | |||
@@ -290,6 +287,38 @@ size_t Print::printNumber(unsigned long n, uint8_t base, uint8_t sign) | |||
#endif | |||
size_t Print::print(int64_t n) | |||
{ | |||
if (n < 0) return printNumber64(-n, 10, 1); | |||
return printNumber64(n, 10, 0); | |||
} | |||
size_t Print::printNumber64(uint64_t n, uint8_t base, uint8_t sign) | |||
{ | |||
uint8_t buf[66]; | |||
uint8_t digit, i; | |||
if (base < 2) return 0; | |||
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; |
@@ -45,9 +45,9 @@ | |||
// BYTE was defined in very old versions of Arduino | |||
// maybe this now causes more trouble than it's worth? | |||
#ifndef BYTE | |||
#define BYTE 0 | |||
#endif | |||
//#ifndef BYTE | |||
//#define BYTE 0 | |||
//#endif | |||
class __FlashStringHelper; | |||
@@ -71,12 +71,16 @@ class Print | |||
size_t print(unsigned int n) { return printNumber(n, 10, 0); } | |||
size_t print(long n); | |||
size_t print(unsigned long n) { return printNumber(n, 10, 0); } | |||
size_t print(int64_t n); | |||
size_t print(uint64_t n) { return printNumber64(n, 10, 0); } | |||
size_t print(unsigned char n, int base) { return printNumber(n, base, 0); } | |||
size_t print(int n, int base) { return (base == 10) ? print(n) : printNumber(n, base, 0); } | |||
size_t print(unsigned int n, int base) { return printNumber(n, base, 0); } | |||
size_t print(long n, int base) { return (base == 10) ? print(n) : printNumber(n, base, 0); } | |||
size_t print(unsigned long n, int base) { return printNumber(n, base, 0); } | |||
size_t print(int64_t n, int base) { return (base == 10) ? print(n) : printNumber64(n, base, 0); } | |||
size_t print(uint64_t n, int base) { return printNumber64(n, base, 0); } | |||
size_t print(double n, int digits = 2) { return printFloat(n, digits); } | |||
size_t print(const Printable &obj) { return obj.printTo(*this); } | |||
@@ -91,18 +95,24 @@ class Print | |||
size_t println(unsigned int n) { return print(n) + println(); } | |||
size_t println(long n) { return print(n) + println(); } | |||
size_t println(unsigned long n) { return print(n) + println(); } | |||
size_t println(int64_t n) { return print(n) + println(); } | |||
size_t println(uint64_t n) { return print(n) + println(); } | |||
size_t println(unsigned char n, int base) { return print(n, base) + println(); } | |||
size_t println(int n, int base) { return print(n, base) + println(); } | |||
size_t println(unsigned int n, int base) { return print(n, base) + println(); } | |||
size_t println(long n, int base) { return print(n, base) + println(); } | |||
size_t println(unsigned long n, int base) { return print(n, base) + println(); } | |||
size_t println(int64_t n, int base) { return print(n, base) + println(); } | |||
size_t println(uint64_t n, int base) { return print(n, base) + println(); } | |||
size_t println(double n, int digits = 2) { return print(n, digits) + println(); } | |||
size_t println(const Printable &obj) { return obj.printTo(*this) + println(); } | |||
int getWriteError() { return write_error; } | |||
void clearWriteError() { setWriteError(0); } | |||
int printf(const char *format, ...); | |||
// format warnings are too pedantic - disable until newer toolchain offers better... | |||
// https://forum.pjrc.com/threads/62473?p=256873&viewfull=1#post256873 | |||
int printf(const char *format, ...) /*__attribute__ ((format (printf, 2, 3)))*/; | |||
int printf(const __FlashStringHelper *format, ...); | |||
protected: | |||
void setWriteError(int err = 1) { write_error = err; } | |||
@@ -126,6 +136,7 @@ class Print | |||
#else | |||
size_t printNumber(unsigned long n, uint8_t base, uint8_t sign); | |||
#endif | |||
size_t printNumber64(uint64_t n, uint8_t base, uint8_t sign); | |||
}; | |||
@@ -37,7 +37,16 @@ | |||
// The preferred way to set SPI speed is with SPI.beginTransaction() | |||
#if F_BUS == 120000000 | |||
#if F_BUS == 128000000 | |||
#define HAS_SPIFIFO | |||
#define SPI_CLOCK_24MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0)) //(128 / 3) * ((1+0)/2) = 21.3MHz | |||
#define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2)) //(128 / 2) * ((1+0)/4) | |||
#define SPI_CLOCK_12MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(2)) //(128 / 3) * ((1+0)/4) = 10.6 MHz | |||
#define SPI_CLOCK_8MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(6)) //(128 / 2) * ((1+0)/8) | |||
#define SPI_CLOCK_6MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(6)) //(128 / 3) * ((1+0)/8) = 5.3 MHz | |||
#define SPI_CLOCK_4MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(6)) //(128 / 5) * ((1+0)/8) = 3.2MHz | |||
#elif F_BUS == 120000000 | |||
#define HAS_SPIFIFO | |||
#define SPI_CLOCK_24MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(120 / 5) * ((1+1)/2) | |||
#define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2)) //(120 / 2) * ((1+0)/4) = 15 MHz |
@@ -20,8 +20,7 @@ | |||
parsing functions based on TextFinder library by Michael Margolis | |||
*/ | |||
#include "Arduino.h" | |||
#include "Stream.h" | |||
#include <Arduino.h> | |||
#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait | |||
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field | |||
@@ -90,7 +89,9 @@ bool Stream::find(const char *target, size_t length) | |||
// as find but search ends if the terminator string is found | |||
bool Stream::findUntil(const char *target, const char *terminator) | |||
{ | |||
return findUntil(target, strlen(target), terminator, strlen(terminator)); | |||
if(target == nullptr) return true; | |||
size_t tlen = (terminator==nullptr)?0:strlen(terminator); | |||
return findUntil(target, strlen(target), terminator, tlen); | |||
} | |||
// reads data from the stream until the target string of the given length is found | |||
@@ -101,9 +102,10 @@ bool Stream::findUntil(const char *target, size_t targetLen, const char *termina | |||
size_t index = 0; // maximum target string length is 64k bytes! | |||
size_t termIndex = 0; | |||
int c; | |||
if( target == nullptr) return true; | |||
if( *target == 0) return true; // return true if target is a null string | |||
if (terminator == nullptr) termLen = 0; | |||
if( *target == 0) | |||
return true; // return true if target is a null string | |||
while( (c = timedRead()) > 0){ | |||
if( c == target[index]){ | |||
//////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); | |||
@@ -216,6 +218,7 @@ float Stream::parseFloat(char skipChar){ | |||
// | |||
size_t Stream::readBytes(char *buffer, size_t length) | |||
{ | |||
if (buffer == nullptr) return 0; | |||
size_t count = 0; | |||
while (count < length) { | |||
int c = timedRead(); | |||
@@ -236,6 +239,7 @@ size_t Stream::readBytes(char *buffer, size_t length) | |||
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) | |||
{ | |||
if (buffer == nullptr) return 0; | |||
if (length < 1) return 0; | |||
length--; | |||
size_t index = 0; |
@@ -28,10 +28,7 @@ | |||
* SOFTWARE. | |||
*/ | |||
#include "core_pins.h" | |||
#include "pins_arduino.h" | |||
#include "HardwareSerial.h" | |||
#include "IntervalTimer.h" | |||
#include <Arduino.h> | |||
// IntervalTimer based tone. This allows tone() to share the timers with other | |||
// libraries, rather than permanently hogging one PIT timer even for projects |
@@ -44,6 +44,7 @@ class UDP : public Stream { | |||
public: | |||
virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use | |||
virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } | |||
virtual void stop() =0; // Finish with the UDP socket | |||
// Sending UDP packets |
@@ -61,7 +61,7 @@ inline boolean isAlpha(int c) | |||
// that fits into the ASCII character set. | |||
inline boolean isAscii(int c) | |||
{ | |||
return ( isascii (c) == 0 ? false : true); | |||
return ((c & ~0x7F) != 0 ? false : true); | |||
} | |||
@@ -143,7 +143,7 @@ inline boolean isHexadecimalDigit(int c) | |||
// ASCII character set, by clearing the high-order bits. | |||
inline int toAscii(int c) | |||
{ | |||
return toascii (c); | |||
return (c & 0x7F); | |||
} | |||
@@ -52,6 +52,8 @@ | |||
#include "avr_emulation.h" | |||
#include "usb_serial.h" | |||
#include "usb_serial2.h" | |||
#include "usb_serial3.h" | |||
#include "usb_seremu.h" | |||
#include "usb_keyboard.h" | |||
#include "usb_mouse.h" |
@@ -19,7 +19,7 @@ | |||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |||
*/ | |||
#include "WString.h" | |||
#include <Arduino.h> | |||
/*********************************************/ | |||
@@ -484,6 +484,8 @@ unsigned char String::endsWith( const String &s2 ) const | |||
/* Character Access */ | |||
/*********************************************/ | |||
const char String::zerotermination = 0; | |||
char String::charAt(unsigned int loc) const | |||
{ | |||
return operator[](loc); |
@@ -164,7 +164,10 @@ public: | |||
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const; | |||
void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const | |||
{getBytes((unsigned char *)buf, bufsize, index);} | |||
const char * c_str() const { return buffer; } | |||
const char * c_str() const { | |||
if (!buffer) return &zerotermination; // https://forum.pjrc.com/threads/63842 | |||
return buffer; | |||
} | |||
// search | |||
int indexOf( char ch ) const; | |||
@@ -205,6 +208,7 @@ private: | |||
// for more information http://www.artima.com/cppsource/safebool.html | |||
typedef void (String::*StringIfHelperType)() const; | |||
void StringIfHelper() const {} | |||
static const char zerotermination; | |||
public: | |||
operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } | |||
}; |
@@ -40,8 +40,12 @@ static uint8_t analog_reference_internal = 0; | |||
// the alternate clock is connected to OSCERCLK (16 MHz). | |||
// datasheet says ADC clock should be 2 to 12 MHz for 16 bit mode | |||
// datasheet says ADC clock should be 1 to 18 MHz for 8-12 bit mode | |||
#if F_BUS == 120000000 | |||
#if F_BUS == 128000000 | |||
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(3) + ADC_CFG1_ADICLK(1) // 8 MHz | |||
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 16 MHz | |||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 16 MHz | |||
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 16 MHz | |||
#elif F_BUS == 120000000 | |||
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(3) + ADC_CFG1_ADICLK(1) // 7.5 MHz | |||
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 15 MHz | |||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 15 MHz | |||
@@ -127,7 +131,7 @@ static uint8_t analog_reference_internal = 0; | |||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz | |||
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz | |||
#else | |||
#error "F_BUS must be 120, 108, 96, 90, 80, 72, 64, 60, 56, 54, 48, 40, 36, 24, 4 or 2 MHz" | |||
#error "F_BUS must be 128, 120, 108, 96, 90, 80, 72, 64, 60, 56, 54, 48, 40, 36, 24, 4 or 2 MHz" | |||
#endif | |||
void analog_init(void) | |||
@@ -524,8 +528,7 @@ void analogWriteDAC0(int val) | |||
} else { | |||
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2 | |||
} | |||
if (val < 0) val = 0; // TODO: saturate instruction? | |||
else if (val > 4095) val = 4095; | |||
__asm__ ("usat %[value], #12, %[value]\n\t" : [value] "+r" (val)); // 0 <= val <= 4095 | |||
*(volatile aliased_int16_t *)&(DAC0_DAT0L) = val; | |||
#elif defined(__MKL26Z64__) | |||
@@ -554,8 +557,7 @@ void analogWriteDAC1(int val) | |||
} else { | |||
DAC1_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2 | |||
} | |||
if (val < 0) val = 0; // TODO: saturate instruction? | |||
else if (val > 4095) val = 4095; | |||
__asm__ ("usat %[value], #12, %[value]\n\t" : [value] "+r" (val)); // 0 <= val <= 4095 | |||
*(volatile aliased_int16_t *)&(DAC1_DAT0L) = val; | |||
} |
@@ -20,6 +20,9 @@ | |||
* THE SOFTWARE. | |||
*/ | |||
// Guidelines for editing this file: | |||
// https://forum.pjrc.com/threads/34537-Teensy-LC-Increase-EEPROM-Size/page2 | |||
#ifndef _AVR_EEPROM_H_ | |||
#define _AVR_EEPROM_H_ 1 | |||
@@ -26,6 +26,7 @@ | |||
#include <inttypes.h> | |||
#define PROGMEM | |||
#define FLASHMEM | |||
#define PGM_P const char * | |||
#define PSTR(str) (str) | |||
@@ -29,7 +29,7 @@ | |||
*/ | |||
#include "avr_emulation.h" | |||
#include <Arduino.h> | |||
#include "SPIFIFO.h" | |||
uint8_t SPCRemulation::pinout = 0; |
@@ -602,7 +602,7 @@ public: | |||
int ret = 0; | |||
if (digitalReadFast(14)) ret |= (1<<0); | |||
if (digitalReadFast(15)) ret |= (1<<1); | |||
if (digitalReadFast(15)) ret |= (1<<2); | |||
if (digitalReadFast(16)) ret |= (1<<2); | |||
if (digitalReadFast(17)) ret |= (1<<3); | |||
if (digitalReadFast(18)) ret |= (1<<4); | |||
if (digitalReadFast(19)) ret |= (1<<5); |
@@ -95,7 +95,7 @@ static inline void eeprom_update_block(const void *buf, void *addr, uint32_t len | |||
char * ultoa(unsigned long val, char *buf, int radix); | |||
char * ltoa(long val, char *buf, int radix); | |||
#if defined(_NEWLIB_VERSION) && (__NEWLIB__ < 2 || __NEWLIB__ == 2 && __NEWLIB_MINOR__ < 2) | |||
#if defined(__STRICT_ANSI__) || (defined(_NEWLIB_VERSION) && (__NEWLIB__ < 2 || __NEWLIB__ == 2 && __NEWLIB_MINOR__ < 2)) | |||
static inline char * utoa(unsigned int val, char *buf, int radix) __attribute__((always_inline, unused)); | |||
static inline char * utoa(unsigned int val, char *buf, int radix) { return ultoa(val, buf, radix); } | |||
static inline char * itoa(int val, char *buf, int radix) __attribute__((always_inline, unused)); |
@@ -292,6 +292,41 @@ | |||
#define CORE_PIN32_PORTSET GPIOB_PSOR | |||
#define CORE_PIN33_PORTSET GPIOA_PSOR | |||
#define CORE_PIN0_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN1_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN2_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN3_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN4_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN5_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN6_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN7_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN8_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN9_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN10_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN11_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN12_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN13_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN14_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN15_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN16_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN17_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN18_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN19_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN20_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN21_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN22_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN23_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN24_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN25_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN26_PORTTOGGLE GPIOE_PTOR | |||
#define CORE_PIN27_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN28_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN29_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN30_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN31_PORTTOGGLE GPIOE_PTOR | |||
#define CORE_PIN32_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN33_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN0_PORTCLEAR GPIOB_PCOR | |||
#define CORE_PIN1_PORTCLEAR GPIOB_PCOR | |||
#define CORE_PIN2_PORTCLEAR GPIOD_PCOR | |||
@@ -605,6 +640,34 @@ | |||
#define CORE_PIN25_PORTSET FGPIOE_PSOR | |||
#define CORE_PIN26_PORTSET FGPIOE_PSOR | |||
#define CORE_PIN0_PORTTOGGLE FGPIOB_PTOR | |||
#define CORE_PIN1_PORTTOGGLE FGPIOB_PTOR | |||
#define CORE_PIN2_PORTTOGGLE FGPIOD_PTOR | |||
#define CORE_PIN3_PORTTOGGLE FGPIOA_PTOR | |||
#define CORE_PIN4_PORTTOGGLE FGPIOA_PTOR | |||
#define CORE_PIN5_PORTTOGGLE FGPIOD_PTOR | |||
#define CORE_PIN6_PORTTOGGLE FGPIOD_PTOR | |||
#define CORE_PIN7_PORTTOGGLE FGPIOD_PTOR | |||
#define CORE_PIN8_PORTTOGGLE FGPIOD_PTOR | |||
#define CORE_PIN9_PORTTOGGLE FGPIOC_PTOR | |||
#define CORE_PIN10_PORTTOGGLE FGPIOC_PTOR | |||
#define CORE_PIN11_PORTTOGGLE FGPIOC_PTOR | |||
#define CORE_PIN12_PORTTOGGLE FGPIOC_PTOR | |||
#define CORE_PIN13_PORTTOGGLE FGPIOC_PTOR | |||
#define CORE_PIN14_PORTTOGGLE FGPIOD_PTOR | |||
#define CORE_PIN15_PORTTOGGLE FGPIOC_PTOR | |||
#define CORE_PIN16_PORTTOGGLE FGPIOB_PTOR | |||
#define CORE_PIN17_PORTTOGGLE FGPIOB_PTOR | |||
#define CORE_PIN18_PORTTOGGLE FGPIOB_PTOR | |||
#define CORE_PIN19_PORTTOGGLE FGPIOB_PTOR | |||
#define CORE_PIN20_PORTTOGGLE FGPIOD_PTOR | |||
#define CORE_PIN21_PORTTOGGLE FGPIOD_PTOR | |||
#define CORE_PIN22_PORTTOGGLE FGPIOC_PTOR | |||
#define CORE_PIN23_PORTTOGGLE FGPIOC_PTOR | |||
#define CORE_PIN24_PORTTOGGLE FGPIOE_PTOR | |||
#define CORE_PIN25_PORTTOGGLE FGPIOE_PTOR | |||
#define CORE_PIN26_PORTTOGGLE FGPIOE_PTOR | |||
#define CORE_PIN0_PORTCLEAR FGPIOB_PCOR | |||
#define CORE_PIN1_PORTCLEAR FGPIOB_PCOR | |||
#define CORE_PIN2_PORTCLEAR FGPIOD_PCOR | |||
@@ -1021,6 +1084,71 @@ | |||
#define CORE_PIN62_PORTSET GPIOE_PSOR | |||
#define CORE_PIN63_PORTSET GPIOE_PSOR | |||
#define CORE_PIN0_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN1_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN2_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN3_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN4_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN5_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN6_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN7_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN8_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN9_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN10_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN11_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN12_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN13_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN14_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN15_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN16_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN17_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN18_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN19_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN20_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN21_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN22_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN23_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN24_PORTTOGGLE GPIOE_PTOR | |||
#define CORE_PIN25_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN26_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN27_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN28_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN29_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN30_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN31_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN32_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN33_PORTTOGGLE GPIOE_PTOR | |||
#define CORE_PIN34_PORTTOGGLE GPIOE_PTOR | |||
#define CORE_PIN35_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN36_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN37_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN38_PORTTOGGLE GPIOC_PTOR | |||
#define CORE_PIN39_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN40_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN41_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN42_PORTTOGGLE GPIOA_PTOR | |||
#define CORE_PIN43_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN44_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN45_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN46_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN47_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN48_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN49_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN50_PORTTOGGLE GPIOB_PTOR | |||
#define CORE_PIN51_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN52_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN53_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN54_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN55_PORTTOGGLE GPIOD_PTOR | |||
#define CORE_PIN56_PORTTOGGLE GPIOE_PTOR | |||
#define CORE_PIN57_PORTTOGGLE GPIOE_PTOR | |||
#define CORE_PIN58_PORTTOGGLE GPIOE_PTOR | |||
#define CORE_PIN59_PORTTOGGLE GPIOE_PTOR | |||
#define CORE_PIN60_PORTTOGGLE GPIOE_PTOR | |||
#define CORE_PIN61_PORTTOGGLE GPIOE_PTOR | |||
#define CORE_PIN62_PORTTOGGLE GPIOE_PTOR | |||
#define CORE_PIN63_PORTTOGGLE GPIOE_PTOR | |||
#define CORE_PIN0_PORTCLEAR GPIOB_PCOR | |||
#define CORE_PIN1_PORTCLEAR GPIOB_PCOR | |||
#define CORE_PIN2_PORTCLEAR GPIOD_PCOR | |||
@@ -1762,6 +1890,213 @@ static inline void digitalWriteFast(uint8_t pin, uint8_t val) | |||
} | |||
} | |||
void digitalToggle(uint8_t pin); | |||
static inline void digitalToggleFast(uint8_t pin) __attribute__((always_inline, unused)); | |||
static inline void digitalToggleFast(uint8_t pin) | |||
{ | |||
if (__builtin_constant_p(pin)) { | |||
if (pin == 0) { | |||
CORE_PIN0_PORTTOGGLE = CORE_PIN0_BITMASK; | |||
} | |||
else if (pin == 1) { | |||
CORE_PIN1_PORTTOGGLE = CORE_PIN1_BITMASK; | |||
} | |||
else if (pin == 2) { | |||
CORE_PIN2_PORTTOGGLE = CORE_PIN2_BITMASK; | |||
} | |||
else if (pin == 3) { | |||
CORE_PIN3_PORTTOGGLE = CORE_PIN3_BITMASK; | |||
} | |||
else if (pin == 4) { | |||
CORE_PIN4_PORTTOGGLE = CORE_PIN4_BITMASK; | |||
} | |||
else if (pin == 5) { | |||
CORE_PIN5_PORTTOGGLE = CORE_PIN5_BITMASK; | |||
} | |||
else if (pin == 6) { | |||
CORE_PIN6_PORTTOGGLE = CORE_PIN6_BITMASK; | |||
} | |||
else if (pin == 7) { | |||
CORE_PIN7_PORTTOGGLE = CORE_PIN7_BITMASK; | |||
} | |||
else if (pin == 8) { | |||
CORE_PIN8_PORTTOGGLE = CORE_PIN8_BITMASK; | |||
} | |||
else if (pin == 9) { | |||
CORE_PIN9_PORTTOGGLE = CORE_PIN9_BITMASK; | |||
} | |||
else if (pin == 10) { | |||
CORE_PIN10_PORTTOGGLE = CORE_PIN10_BITMASK; | |||
} | |||
else if (pin == 11) { | |||
CORE_PIN11_PORTTOGGLE = CORE_PIN11_BITMASK; | |||
} | |||
else if (pin == 12) { | |||
CORE_PIN12_PORTTOGGLE = CORE_PIN12_BITMASK; | |||
} | |||
else if (pin == 13) { | |||
CORE_PIN13_PORTTOGGLE = CORE_PIN13_BITMASK; | |||
} | |||
else if (pin == 14) { | |||
CORE_PIN14_PORTTOGGLE = CORE_PIN14_BITMASK; | |||
} | |||
else if (pin == 15) { | |||
CORE_PIN15_PORTTOGGLE = CORE_PIN15_BITMASK; | |||
} | |||
else if (pin == 16) { | |||
CORE_PIN16_PORTTOGGLE = CORE_PIN16_BITMASK; | |||
} | |||
else if (pin == 17) { | |||
CORE_PIN17_PORTTOGGLE = CORE_PIN17_BITMASK; | |||
} | |||
else if (pin == 18) { | |||
CORE_PIN18_PORTTOGGLE = CORE_PIN18_BITMASK; | |||
} | |||
else if (pin == 19) { | |||
CORE_PIN19_PORTTOGGLE = CORE_PIN19_BITMASK; | |||
} | |||
else if (pin == 20) { | |||
CORE_PIN20_PORTTOGGLE = CORE_PIN20_BITMASK; | |||
} | |||
else if (pin == 21) { | |||
CORE_PIN21_PORTTOGGLE = CORE_PIN21_BITMASK; | |||
} | |||
else if (pin == 22) { | |||
CORE_PIN22_PORTTOGGLE = CORE_PIN22_BITMASK; | |||
} | |||
else if (pin == 23) { | |||
CORE_PIN23_PORTTOGGLE = CORE_PIN23_BITMASK; | |||
} | |||
else if (pin == 24) { | |||
CORE_PIN24_PORTTOGGLE = CORE_PIN24_BITMASK; | |||
} | |||
else if (pin == 25) { | |||
CORE_PIN25_PORTTOGGLE = CORE_PIN25_BITMASK; | |||
} | |||
else if (pin == 26) { | |||
CORE_PIN26_PORTTOGGLE = CORE_PIN26_BITMASK; | |||
} | |||
#if defined(CORE_PIN27_PORTTOGGLE) | |||
else if (pin == 27) { | |||
CORE_PIN27_PORTTOGGLE = CORE_PIN27_BITMASK; | |||
} | |||
else if (pin == 28) { | |||
CORE_PIN28_PORTTOGGLE = CORE_PIN28_BITMASK; | |||
} | |||
else if (pin == 29) { | |||
CORE_PIN29_PORTTOGGLE = CORE_PIN29_BITMASK; | |||
} | |||
else if (pin == 30) { | |||
CORE_PIN30_PORTTOGGLE = CORE_PIN30_BITMASK; | |||
} | |||
else if (pin == 31) { | |||
CORE_PIN31_PORTTOGGLE = CORE_PIN31_BITMASK; | |||
} | |||
else if (pin == 32) { | |||
CORE_PIN32_PORTTOGGLE = CORE_PIN32_BITMASK; | |||
} | |||
else if (pin == 33) { | |||
CORE_PIN33_PORTTOGGLE = CORE_PIN33_BITMASK; | |||
} | |||
#endif | |||
#if defined(CORE_PIN34_PORTSET) | |||
else if (pin == 34) { | |||
CORE_PIN34_PORTTOGGLE = CORE_PIN34_BITMASK; | |||
} | |||
else if (pin == 35) { | |||
CORE_PIN35_PORTTOGGLE = CORE_PIN35_BITMASK; | |||
} | |||
else if (pin == 36) { | |||
CORE_PIN36_PORTTOGGLE = CORE_PIN36_BITMASK; | |||
} | |||
else if (pin == 37) { | |||
CORE_PIN37_PORTTOGGLE = CORE_PIN37_BITMASK; | |||
} | |||
else if (pin == 38) { | |||
CORE_PIN38_PORTTOGGLE = CORE_PIN38_BITMASK; | |||
} | |||
else if (pin == 39) { | |||
CORE_PIN39_PORTTOGGLE = CORE_PIN39_BITMASK; | |||
} | |||
else if (pin == 40) { | |||
CORE_PIN40_PORTTOGGLE = CORE_PIN40_BITMASK; | |||
} | |||
else if (pin == 41) { | |||
CORE_PIN41_PORTTOGGLE = CORE_PIN41_BITMASK; | |||
} | |||
else if (pin == 42) { | |||
CORE_PIN42_PORTTOGGLE = CORE_PIN42_BITMASK; | |||
} | |||
else if (pin == 43) { | |||
CORE_PIN43_PORTTOGGLE = CORE_PIN43_BITMASK; | |||
} | |||
else if (pin == 44) { | |||
CORE_PIN44_PORTTOGGLE = CORE_PIN44_BITMASK; | |||
} | |||
else if (pin == 45) { | |||
CORE_PIN45_PORTTOGGLE = CORE_PIN45_BITMASK; | |||
} | |||
else if (pin == 46) { | |||
CORE_PIN46_PORTTOGGLE = CORE_PIN46_BITMASK; | |||
} | |||
else if (pin == 47) { | |||
CORE_PIN47_PORTTOGGLE = CORE_PIN47_BITMASK; | |||
} | |||
else if (pin == 48) { | |||
CORE_PIN48_PORTTOGGLE = CORE_PIN48_BITMASK; | |||
} | |||
else if (pin == 49) { | |||
CORE_PIN49_PORTTOGGLE = CORE_PIN49_BITMASK; | |||
} | |||
else if (pin == 50) { | |||
CORE_PIN50_PORTTOGGLE = CORE_PIN50_BITMASK; | |||
} | |||
else if (pin == 51) { | |||
CORE_PIN51_PORTTOGGLE = CORE_PIN51_BITMASK; | |||
} | |||
else if (pin == 52) { | |||
CORE_PIN52_PORTTOGGLE = CORE_PIN52_BITMASK; | |||
} | |||
else if (pin == 53) { | |||
CORE_PIN53_PORTTOGGLE = CORE_PIN53_BITMASK; | |||
} | |||
else if (pin == 54) { | |||
CORE_PIN54_PORTTOGGLE = CORE_PIN54_BITMASK; | |||
} | |||
else if (pin == 55) { | |||
CORE_PIN55_PORTTOGGLE = CORE_PIN55_BITMASK; | |||
} | |||
else if (pin == 56) { | |||
CORE_PIN56_PORTTOGGLE = CORE_PIN56_BITMASK; | |||
} | |||
else if (pin == 57) { | |||
CORE_PIN57_PORTTOGGLE = CORE_PIN57_BITMASK; | |||
} | |||
else if (pin == 58) { | |||
CORE_PIN58_PORTTOGGLE = CORE_PIN58_BITMASK; | |||
} | |||
else if (pin == 59) { | |||
CORE_PIN59_PORTTOGGLE = CORE_PIN59_BITMASK; | |||
} | |||
else if (pin == 60) { | |||
CORE_PIN60_PORTTOGGLE = CORE_PIN60_BITMASK; | |||
} | |||
else if (pin == 61) { | |||
CORE_PIN61_PORTTOGGLE = CORE_PIN61_BITMASK; | |||
} | |||
else if (pin == 62) { | |||
CORE_PIN62_PORTTOGGLE = CORE_PIN62_BITMASK; | |||
} | |||
else if (pin == 63) { | |||
CORE_PIN63_PORTTOGGLE = CORE_PIN63_BITMASK; | |||
} | |||
#endif | |||
} | |||
else { | |||
*portToggleRegister(pin) = digitalPinToBitMask(pin); | |||
} | |||
} | |||
uint8_t digitalRead(uint8_t pin); | |||
static inline uint8_t digitalReadFast(uint8_t pin) __attribute__((always_inline, unused)); | |||
static inline uint8_t digitalReadFast(uint8_t pin) | |||
@@ -1996,6 +2331,16 @@ static inline uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrde | |||
void _reboot_Teensyduino_(void) __attribute__((noreturn)); | |||
void _restart_Teensyduino_(void) __attribute__((noreturn)); | |||
// Define a set of flags to know which things yield should check when called. | |||
// Probably should be in a better spot. | |||
extern uint8_t yield_active_check_flags; | |||
#define YIELD_CHECK_USB_SERIAL 0x1 // check the USB for Serial.available() | |||
#define YIELD_CHECK_HARDWARE_SERIAL 0x2 // check Hardware Serial ports available | |||
#define YIELD_CHECK_EVENT_RESPONDER 0x4 // User has created eventResponders that use yield | |||
#define YIELD_CHECK_USB_SERIALUSB1 0x8 // Check for SerialUSB1 | |||
#define YIELD_CHECK_USB_SERIALUSB2 0x10 // Check for SerialUSB2 | |||
void yield(void); | |||
void delay(uint32_t msec); | |||
@@ -2023,7 +2368,9 @@ uint32_t micros(void); | |||
static inline void delayMicroseconds(uint32_t) __attribute__((always_inline, unused)); | |||
static inline void delayMicroseconds(uint32_t usec) | |||
{ | |||
#if F_CPU == 240000000 | |||
#if F_CPU == 256000000 | |||
uint32_t n = usec * 85; | |||
#elif F_CPU == 240000000 | |||
uint32_t n = usec * 80; | |||
#elif F_CPU == 216000000 | |||
uint32_t n = usec * 72; | |||
@@ -2063,11 +2410,13 @@ static inline void delayMicroseconds(uint32_t usec) | |||
#endif | |||
#ifdef KINETISL | |||
"sub %0, #1" "\n\t" | |||
"bne L_%=_delayMicroseconds" "\n" | |||
: "+l" (n) : | |||
#else | |||
"subs %0, #1" "\n\t" | |||
#endif | |||
"bne L_%=_delayMicroseconds" "\n" | |||
: "+r" (n) : | |||
#endif | |||
); | |||
} | |||
@@ -2075,9 +2424,103 @@ static inline void delayMicroseconds(uint32_t usec) | |||
} | |||
#endif | |||
static inline void delayNanoseconds(uint32_t) __attribute__((always_inline, unused)); | |||
static inline void delayNanoseconds(uint32_t nsec) | |||
{ | |||
if (__builtin_constant_p(nsec)) { | |||
// use NOPs for the common usage of a constexpr input and short delay | |||
if (nsec == 0) return; | |||
if (nsec <= 1000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop"); | |||
return; | |||
} | |||
if (nsec <= 2000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 3000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 4000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 5000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 6000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop"); | |||
return; | |||
} | |||
if (nsec <= 7000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 8000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 9000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 10000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 11000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop"); | |||
return; | |||
} | |||
if (nsec <= 12000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 13000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 14000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop"); | |||
return; | |||
} | |||
if (nsec <= 15000 / (F_CPU / 1000000)) { | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
__asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
return; | |||
} | |||
} | |||
uint32_t n = nsec * (F_CPU / 45776) >> 16; | |||
if (n == 0) return; | |||
__asm__ volatile( | |||
"L_%=_delayNanoseconds:" "\n\t" | |||
#ifdef KINETISL | |||
"sub %0, #1" "\n\t" | |||
"bne L_%=_delayNanoseconds" "\n" | |||
: "+l" (n) : | |||
#else | |||
"subs %0, #1" "\n\t" | |||
"bne L_%=_delayNanoseconds" "\n" | |||
: "+r" (n) : | |||
#endif | |||
); | |||
} | |||
@@ -28,6 +28,14 @@ | |||
* SOFTWARE. | |||
*/ | |||
// To configure the EEPROM size, edit E2END in avr/eeprom.h. | |||
// | |||
// Do *NOT* edit EEPROM_SIZE in this file. It will automatically | |||
// change based on your changes to E2END in avr/eeprom.h. | |||
// | |||
// Generally you should avoid editing this code, unless you really | |||
// know what you're doing. | |||
#include "kinetis.h" | |||
#include <avr/eeprom.h> | |||
//#include "HardwareSerial.h" |
@@ -1451,7 +1451,7 @@ extern "C"{ | |||
#define ASCII_20 KEY_SPACE // 32 | |||
#define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | |||
#define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | |||
#define ASCII_23 KEY_BACKSPACE // 35 # | |||
#define ASCII_23 KEY_BACKSLASH // 35 # | |||
#define ASCII_24 KEY_4 + SHIFT_MASK // 36 $ | |||
#define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | |||
#define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | |||
@@ -4533,7 +4533,7 @@ extern "C"{ | |||
#define ASCII_20 KEY_SPACE // 32 | |||
#define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | |||
#define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | |||
#define ASCII_23 KEY_BACKSPACE // 35 # | |||
#define ASCII_23 KEY_BACKSLASH // 35 # | |||
#define ASCII_24 KEY_4 + SHIFT_MASK // 36 $ | |||
#define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | |||
#define ASCII_26 KEY_7 + SHIFT_MASK // 38 & |
@@ -761,8 +761,14 @@ enum IRQ_NUMBER_t { | |||
#endif // end of board-specific definitions | |||
#if (F_CPU == 240000000) | |||
#if (F_CPU == 256000000) | |||
#define F_PLL 256000000 | |||
#ifndef F_BUS | |||
#define F_BUS 64000000 | |||
//#define F_BUS 128000000 // all the usual overclocking caveats apply... | |||
#endif | |||
#define F_MEM 32000000 | |||
#elif (F_CPU == 240000000) | |||
#define F_PLL 240000000 | |||
#ifndef F_BUS | |||
#define F_BUS 60000000 | |||
@@ -864,6 +870,7 @@ enum IRQ_NUMBER_t { | |||
#define PORTA_PCR0 (*(volatile uint32_t *)0x40049000) // Pin Control Register n | |||
#define PORT_PCR_ISF ((uint32_t)0x01000000) // Interrupt Status Flag | |||
// how to use PORT_PCR_ISF with polling: https://forum.pjrc.com/threads/58193 | |||
#define PORT_PCR_IRQC(n) ((uint32_t)(((n) & 15) << 16)) // Interrupt Configuration | |||
#define PORT_PCR_IRQC_MASK ((uint32_t)0x000F0000) | |||
#define PORT_PCR_LK ((uint32_t)0x00008000) // Lock Register | |||
@@ -3329,8 +3336,8 @@ typedef struct { | |||
#define FTM0_CONF (*(volatile uint32_t *)0x40038084) // Configuration | |||
#define FTM_CONF_GTBEOUT 0x400 // Global Time Base Output | |||
#define FTM_CONF_GTBEEN 0x200 // Global Time Base Enable | |||
#define FTM_CONF_BDMMODE (((n) & 3) << 6) // Behavior when in debug mode | |||
#define FTM_CONF_NUMTOF (((n) & 31) << 0) // ratio of counter overflows to TOF bit set | |||
#define FTM_CONF_BDMMODE(n) (((n) & 3) << 6) // Behavior when in debug mode | |||
#define FTM_CONF_NUMTOF(n) (((n) & 31) << 0) // ratio of counter overflows to TOF bit set | |||
#define FTM0_FLTPOL (*(volatile uint32_t *)0x40038088) // FTM Fault Input Polarity | |||
#define FTM_FLTPOL_FLT3POL 0x08 // Fault Input 3 Polarity | |||
#define FTM_FLTPOL_FLT2POL 0x04 // Fault Input 2 Polarity | |||
@@ -3621,22 +3628,22 @@ typedef struct { | |||
#define ENET_EIR_TS_AVAIL ((uint32_t)0x00010000) // Transmit Timestamp Available | |||
#define ENET_EIR_TS_TIMER ((uint32_t)0x00008000) // Timestamp Timer | |||
#define ENET_EIMR (*(volatile uint32_t *)0x400C0008) // Interrupt Mask Register | |||
#define ENET_EIRM_BABR ((uint32_t)0x40000000) // Babbling Receive Error Mask | |||
#define ENET_EIRM_BABT ((uint32_t)0x20000000) // Babbling Transmit Error Mask | |||
#define ENET_EIRM_GRA ((uint32_t)0x10000000) // Graceful Stop Complete Mask | |||
#define ENET_EIRM_TXF ((uint32_t)0x08000000) // Transmit Frame Interrupt Mask | |||
#define ENET_EIRM_TXB ((uint32_t)0x04000000) // Transmit Buffer Interrupt Mask | |||
#define ENET_EIRM_RXF ((uint32_t)0x02000000) // Receive Frame Interrupt Mask | |||
#define ENET_EIRM_RXB ((uint32_t)0x01000000) // Receive Buffer Interrupt Mask | |||
#define ENET_EIRM_MII ((uint32_t)0x00800000) // MII Interrupt Mask | |||
#define ENET_EIRM_EBERR ((uint32_t)0x00400000) // Ethernet Bus Error Mask | |||
#define ENET_EIRM_LC ((uint32_t)0x00200000) // Late Collision Mask | |||
#define ENET_EIRM_RL ((uint32_t)0x00100000) // Collision Retry Limit Mask | |||
#define ENET_EIRM_UN ((uint32_t)0x00080000) // Transmit FIFO Underrun Mask | |||
#define ENET_EIRM_PLR ((uint32_t)0x00040000) // Payload Receive Error Mask | |||
#define ENET_EIRM_WAKEUP ((uint32_t)0x00020000) // Node Wakeup Request Indication Mask | |||
#define ENET_EIRM_TS_AVAIL ((uint32_t)0x00010000) // Transmit Timestamp Available Mask | |||
#define ENET_EIRM_TS_TIMER ((uint32_t)0x00008000) // Timestamp Timer Mask | |||
#define ENET_EIMR_BABR ((uint32_t)0x40000000) // Babbling Receive Error Mask | |||
#define ENET_EIMR_BABT ((uint32_t)0x20000000) // Babbling Transmit Error Mask | |||
#define ENET_EIMR_GRA ((uint32_t)0x10000000) // Graceful Stop Complete Mask | |||
#define ENET_EIMR_TXF ((uint32_t)0x08000000) // Transmit Frame Interrupt Mask | |||
#define ENET_EIMR_TXB ((uint32_t)0x04000000) // Transmit Buffer Interrupt Mask | |||
#define ENET_EIMR_RXF ((uint32_t)0x02000000) // Receive Frame Interrupt Mask | |||
#define ENET_EIMR_RXB ((uint32_t)0x01000000) // Receive Buffer Interrupt Mask | |||
#define ENET_EIMR_MII ((uint32_t)0x00800000) // MII Interrupt Mask | |||
#define ENET_EIMR_EBERR ((uint32_t)0x00400000) // Ethernet Bus Error Mask | |||
#define ENET_EIMR_LC ((uint32_t)0x00200000) // Late Collision Mask | |||
#define ENET_EIMR_RL ((uint32_t)0x00100000) // Collision Retry Limit Mask | |||
#define ENET_EIMR_UN ((uint32_t)0x00080000) // Transmit FIFO Underrun Mask | |||
#define ENET_EIMR_PLR ((uint32_t)0x00040000) // Payload Receive Error Mask | |||
#define ENET_EIMR_WAKEUP ((uint32_t)0x00020000) // Node Wakeup Request Indication Mask | |||
#define ENET_EIMR_TS_AVAIL ((uint32_t)0x00010000) // Transmit Timestamp Available Mask | |||
#define ENET_EIMR_TS_TIMER ((uint32_t)0x00008000) // Timestamp Timer Mask | |||
#define ENET_RDAR (*(volatile uint32_t *)0x400C0010) // Receive Descriptor Active Register | |||
#define ENET_RDAR_RDAR ((uint32_t)0x01000000) | |||
#define ENET_TDAR (*(volatile uint32_t *)0x400C0014) // Transmit Descriptor Active Register | |||
@@ -4545,7 +4552,7 @@ typedef struct { | |||
#define SPI1_MH (KINETISL_SPI1.MH) // Match High | |||
#define SPI1_DL (KINETISL_SPI1.DL) // Data Low | |||
#define SPI1_DH (KINETISL_SPI1.DH) // Data High | |||
#define SPI1_CI (KINETISL_SPI1.CI) // Dlear Interrupt | |||
#define SPI1_CI (KINETISL_SPI1.CI) // Clear Interrupt | |||
#define SPI1_C3 (KINETISL_SPI1.C3) // Control Register 3 | |||
#endif | |||
@@ -5851,6 +5858,14 @@ extern void software_isr(void); | |||
extern void (* _VectorsRam[NVIC_NUM_INTERRUPTS+16])(void); | |||
extern void (* const _VectorsFlash[NVIC_NUM_INTERRUPTS+16])(void); | |||
// Cache management functions for compatibility with Teensy 4.0 | |||
__attribute__((always_inline, unused)) | |||
static inline void arm_dcache_flush(void *addr, uint32_t size) { } | |||
__attribute__((always_inline, unused)) | |||
static inline void arm_dcache_delete(void *addr, uint32_t size) { } | |||
__attribute__((always_inline, unused)) | |||
static inline void arm_dcache_flush_delete(void *addr, uint32_t size) { } | |||
#ifdef __cplusplus | |||
} | |||
#endif |
@@ -28,7 +28,7 @@ | |||
* SOFTWARE. | |||
*/ | |||
#include "WProgram.h" | |||
#include <Arduino.h> | |||
extern "C" int main(void) | |||
{ |
@@ -745,8 +745,10 @@ void ResetHandler(void) | |||
UART0_C2 = UART_C2_TE; | |||
PORTB_PCR17 = PORT_PCR_MUX(3); | |||
#endif | |||
#ifdef KINETISK | |||
// if the RTC oscillator isn't enabled, get it started early | |||
#if defined(KINETISK) && !defined(__MK66FX1M0__) | |||
// If the RTC oscillator isn't enabled, get it started early. | |||
// But don't do this early on Teensy 3.6 - RTC_CR depends on 3.3V+VBAT | |||
// which may be ~0.4V "behind" 3.3V if the power ramps up slowly. | |||
if (!(RTC_CR & RTC_CR_OSCE)) { | |||
RTC_SR = 0; | |||
RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE; | |||
@@ -841,7 +843,12 @@ void ResetHandler(void) | |||
SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode | |||
while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN | |||
#endif | |||
#if F_CPU == 240000000 | |||
#if F_CPU == 256000000 | |||
//See table in 27.4.6 MCG Control 6 Register (MCG_C6) | |||
//16 -> Multiply factor 32. 32*8MHz =256MHz | |||
MCG_C5 = MCG_C5_PRDIV0(0); | |||
MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(16); | |||
#elif F_CPU == 240000000 | |||
MCG_C5 = MCG_C5_PRDIV0(0); | |||
MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(14); | |||
#elif F_CPU == 216000000 | |||
@@ -900,7 +907,18 @@ void ResetHandler(void) | |||
#endif | |||
#endif | |||
// now program the clock dividers | |||
#if F_CPU == 240000000 | |||
#if F_CPU == 256000000 | |||
// config divisors: 256 MHz core, 64 MHz bus, 32 MHz flash, USB = IRC48M | |||
// TODO: gradual ramp-up for HSRUN mode | |||
#if F_BUS == 64000000 | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(7); | |||
#elif F_BUS == 128000000 | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(7); | |||
#else | |||
#error "This F_CPU & F_BUS combination is not supported" | |||
#endif | |||
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(0); | |||
#elif F_CPU == 240000000 | |||
// config divisors: 240 MHz core, 60 MHz bus, 30 MHz flash, USB = 240 / 5 | |||
// TODO: gradual ramp-up for HSRUN mode | |||
#if F_BUS == 60000000 | |||
@@ -921,7 +939,8 @@ void ResetHandler(void) | |||
#elif F_BUS == 72000000 | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(7); | |||
#elif F_BUS == 108000000 | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(7); | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(7); | |||
#else | |||
#error "This F_CPU & F_BUS combination is not supported" | |||
#endif | |||
@@ -1046,7 +1065,7 @@ void ResetHandler(void) | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV4(1); | |||
#endif | |||
#else | |||
#error "Error, F_CPU must be 192, 180, 168, 144, 120, 96, 72, 48, 24, 16, 8, 4, or 2 MHz" | |||
#error "Error, F_CPU must be 256, 240, 216, 192, 180, 168, 144, 120, 96, 72, 48, 24, 16, 8, 4, or 2 MHz" | |||
#endif | |||
#if F_CPU > 16000000 | |||
@@ -1055,11 +1074,13 @@ void ResetHandler(void) | |||
// wait for PLL clock to be used | |||
while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) ; | |||
// now we're in PEE mode | |||
// USB uses PLL clock, trace is CPU clock, CLKOUT=OSCERCLK0 | |||
// trace is CPU clock, CLKOUT=OSCERCLK0 | |||
#if defined(KINETISK) | |||
#if F_CPU == 216000000 || F_CPU == 180000000 | |||
#if F_CPU == 256000000 || F_CPU == 216000000 || F_CPU == 180000000 | |||
// USB uses IRC48 | |||
SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_IRC48SEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); | |||
#else | |||
// USB uses PLL clock | |||
SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); | |||
#endif | |||
#elif defined(KINETISL) | |||
@@ -1081,6 +1102,15 @@ void ResetHandler(void) | |||
SMC_PMCTRL = SMC_PMCTRL_RUNM(2); // VLPR mode :-) | |||
#endif | |||
#if defined(__MK66FX1M0__) | |||
// If the RTC oscillator isn't enabled, get it started. For Teensy 3.6 | |||
// we don't do this early. See comment above about slow rising power. | |||
if (!(RTC_CR & RTC_CR_OSCE)) { | |||
RTC_SR = 0; | |||
RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE; | |||
} | |||
#endif | |||
// initialize the SysTick counter | |||
SYST_RVR = (F_CPU / 1000) - 1; | |||
SYST_CVR = 0; | |||
@@ -1128,6 +1158,7 @@ void ResetHandler(void) | |||
startup_late_hook(); | |||
main(); | |||
while (1) ; | |||
} | |||
@@ -1259,7 +1290,11 @@ int kinetis_hsrun_disable(void) | |||
// the peripheral speed (F_BUS). Serial1 & Serial2 baud | |||
// rates will be impacted, but most other peripherals | |||
// will continue functioning at the same speed. | |||
#if F_CPU == 240000000 && F_BUS == 60000000 | |||
#if F_CPU == 256000000 && F_BUS == 64000000 | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // TODO: TEST | |||
#elif F_CPU == 256000000 && F_BUS == 128000000 | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // TODO: TEST | |||
#elif F_CPU == 240000000 && F_BUS == 60000000 | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // ok | |||
#elif F_CPU == 240000000 && F_BUS == 80000000 | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok | |||
@@ -1305,7 +1340,11 @@ int kinetis_hsrun_enable(void) | |||
SMC_PMCTRL = SMC_PMCTRL_RUNM(3); | |||
while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) {;} // wait | |||
// Then configure clock for full speed | |||
#if F_CPU == 240000000 && F_BUS == 60000000 | |||
#if F_CPU == 256000000 && F_BUS == 64000000 | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7); | |||
#elif F_CPU == 256000000 && F_BUS == 128000000 | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 7); | |||
#elif F_CPU == 240000000 && F_BUS == 60000000 | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7); | |||
#elif F_CPU == 240000000 && F_BUS == 80000000 | |||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 7); |
@@ -34,6 +34,7 @@ MEMORY | |||
RAM (rwx) : ORIGIN = 0x1FFFE000, LENGTH = 16K | |||
} | |||
ENTRY(_VectorsFlash) | |||
SECTIONS | |||
{ | |||
@@ -107,6 +108,7 @@ SECTIONS | |||
} > RAM | |||
_estack = ORIGIN(RAM) + LENGTH(RAM); | |||
_teensy_model_identifier = 0x1D; | |||
} | |||
@@ -34,6 +34,7 @@ MEMORY | |||
RAM (rwx) : ORIGIN = 0x1FFF8000, LENGTH = 64K | |||
} | |||
ENTRY(_VectorsFlash) | |||
SECTIONS | |||
{ | |||
@@ -107,6 +108,7 @@ SECTIONS | |||
} > RAM | |||
_estack = ORIGIN(RAM) + LENGTH(RAM); | |||
_teensy_model_identifier = 0x21; | |||
} | |||
@@ -31,9 +31,10 @@ | |||
MEMORY | |||
{ | |||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K | |||
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 192K | |||
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 262136 | |||
} | |||
ENTRY(_VectorsFlash) | |||
SECTIONS | |||
{ | |||
@@ -107,6 +108,7 @@ SECTIONS | |||
} > RAM | |||
_estack = ORIGIN(RAM) + LENGTH(RAM); | |||
_teensy_model_identifier = 0x1F; | |||
} | |||
@@ -34,6 +34,7 @@ MEMORY | |||
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K | |||
} | |||
ENTRY(_VectorsFlash) | |||
SECTIONS | |||
{ | |||
@@ -107,6 +108,7 @@ SECTIONS | |||
} > RAM | |||
_estack = ORIGIN(RAM) + LENGTH(RAM); | |||
_teensy_model_identifier = 0x22; | |||
} | |||
@@ -34,6 +34,7 @@ MEMORY | |||
RAM (rwx) : ORIGIN = 0x1FFFF800, LENGTH = 8K | |||
} | |||
ENTRY(_VectorsFlash) | |||
SECTIONS | |||
{ | |||
@@ -107,6 +108,7 @@ SECTIONS | |||
} > RAM | |||
_estack = ORIGIN(RAM) + LENGTH(RAM); | |||
_teensy_model_identifier = 0x20; | |||
} | |||
@@ -173,11 +173,14 @@ const static uint8_t SCL = 19; | |||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) <= 12) ? (p) + 14 : -1)) | |||
#define digitalPinHasPWM(p) ((p) == 3 || (p) == 4 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 16 || (p) == 17 || (p) == 20 || (p) == 22 || (p) == 23) | |||
#define digitalPinToInterrupt(p) ((((p) >= 2 && (p) <= 15) || ((p) >= 20 && (p) <= 23)) ? (p) : -1) | |||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
// TODO analogInputToDigitalPin needs update... | |||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) >= 12 && (p) <= 20) ? (p) + 19 : -1)) | |||
#elif defined(__MK64FX512__) | |||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) >= 12 && (p) <= 20) ? (p) + 19 : (((p) == 23 || (p) == 24) ? (p) + 26 : -1))) | |||
#define digitalPinHasPWM(p) (((p) >= 2 && (p) <= 10) || (p) == 14 || ((p) >= 20 && (p) <= 23) || (p) == 29 || (p) == 30 || ((p) >= 35 && (p) <= 38)) | |||
#define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1) | |||
#elif defined(__MK66FX1M0__) | |||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) >= 12 && (p) <= 20) ? (p) + 19 : (((p) == 23 || (p) == 24) ? (p) + 26 : -1))) | |||
#define digitalPinHasPWM(p) (((p) >= 2 && (p) <= 10) || (p) == 14 || (p) == 16 || (p) == 17 || ((p) >= 20 && (p) <= 23) || (p) == 29 || (p) == 30 || ((p) >= 35 && (p) <= 38)) | |||
#define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1) | |||
#endif | |||
#define digitalPinToPCICR(p) ((volatile uint8_t *)0) |
@@ -166,7 +166,7 @@ voidFuncPtr isr_table_portE[CORE_MAX_PIN_PORTE+1] = { [0 ... CORE_MAX_PIN_PORTE] | |||
// The Pin Config Register is used to look up the correct interrupt table | |||
// for the corresponding port. | |||
inline voidFuncPtr* getIsrTable(volatile uint32_t *config) { | |||
static inline voidFuncPtr* getIsrTable(volatile uint32_t *config) { | |||
voidFuncPtr* isr_table = NULL; | |||
if(&PORTA_PCR0 <= config && config <= &PORTA_PCR31) isr_table = isr_table_portA; | |||
else if(&PORTB_PCR0 <= config && config <= &PORTB_PCR31) isr_table = isr_table_portB; | |||
@@ -456,7 +456,10 @@ extern void usb_init(void); | |||
#endif | |||
#if F_TIMER == 120000000 | |||
#if F_TIMER == 128000000 | |||
#define DEFAULT_FTM_MOD (65536 - 1) | |||
#define DEFAULT_FTM_PRESCALE 2 | |||
#elif F_TIMER == 120000000 | |||
#define DEFAULT_FTM_MOD (61440 - 1) | |||
#define DEFAULT_FTM_PRESCALE 2 | |||
#elif F_TIMER == 108000000 | |||
@@ -580,12 +583,30 @@ void _init_Teensyduino_internal_(void) | |||
TPM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); | |||
#endif | |||
analog_init(); | |||
#if !defined(TEENSY_INIT_USB_DELAY_BEFORE) | |||
#if TEENSYDUINO >= 142 | |||
#define TEENSY_INIT_USB_DELAY_BEFORE 25 | |||
#else | |||
#define TEENSY_INIT_USB_DELAY_BEFORE 50 | |||
#endif | |||
#endif | |||
#if !defined(TEENSY_INIT_USB_DELAY_AFTER) | |||
#if TEENSYDUINO >= 142 | |||
#define TEENSY_INIT_USB_DELAY_AFTER 275 | |||
#else | |||
#define TEENSY_INIT_USB_DELAY_AFTER 350 | |||
#endif | |||
#endif | |||
// for background about this startup delay, please see these conversations | |||
// https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980 | |||
// https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273 | |||
delay(50); | |||
delay(TEENSY_INIT_USB_DELAY_BEFORE); | |||
usb_init(); | |||
delay(350); | |||
delay(TEENSY_INIT_USB_DELAY_AFTER); | |||
} | |||
@@ -1044,6 +1065,16 @@ void digitalWrite(uint8_t pin, uint8_t val) | |||
} | |||
void digitalToggle(uint8_t pin) | |||
{ | |||
if (pin >= CORE_NUM_DIGITAL) return; | |||
#ifdef KINETISK | |||
*portToggleRegister(pin) = 1; | |||
#else | |||
*portToggleRegister(pin) = digitalPinToBitMask(pin); | |||
#endif | |||
} | |||
uint8_t digitalRead(uint8_t pin) | |||
{ | |||
if (pin >= CORE_NUM_DIGITAL) return 0; | |||
@@ -1200,7 +1231,9 @@ void delay(uint32_t ms) | |||
} | |||
// TODO: verify these result in correct timeouts... | |||
#if F_CPU == 240000000 | |||
#if F_CPU == 256000000 | |||
#define PULSEIN_LOOPS_PER_USEC 34 | |||
#elif F_CPU == 240000000 | |||
#define PULSEIN_LOOPS_PER_USEC 33 | |||
#elif F_CPU == 216000000 | |||
#define PULSEIN_LOOPS_PER_USEC 31 |
@@ -79,14 +79,20 @@ static volatile uint8_t transmitting = 0; | |||
#define rts_assert() *(rts_pin+8) = rts_mask; | |||
#define rts_deassert() *(rts_pin+4) = rts_mask; | |||
#endif | |||
#if SERIAL1_TX_BUFFER_SIZE > 255 | |||
#if SERIAL1_TX_BUFFER_SIZE > 65535 | |||
static volatile uint32_t tx_buffer_head = 0; | |||
static volatile uint32_t tx_buffer_tail = 0; | |||
#elif SERIAL1_TX_BUFFER_SIZE > 255 | |||
static volatile uint16_t tx_buffer_head = 0; | |||
static volatile uint16_t tx_buffer_tail = 0; | |||
#else | |||
static volatile uint8_t tx_buffer_head = 0; | |||
static volatile uint8_t tx_buffer_tail = 0; | |||
#endif | |||
#if SERIAL1_RX_BUFFER_SIZE > 255 | |||
#if SERIAL1_RX_BUFFER_SIZE > 65535 | |||
static volatile uint32_t rx_buffer_head = 0; | |||
static volatile uint32_t rx_buffer_tail = 0; | |||
#elif SERIAL1_RX_BUFFER_SIZE > 255 | |||
static volatile uint16_t rx_buffer_head = 0; | |||
static volatile uint16_t rx_buffer_tail = 0; | |||
#else | |||
@@ -222,6 +228,8 @@ void serial_end(void) | |||
case 26: CORE_PIN26_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
#endif | |||
} | |||
UART0_S1; | |||
UART0_D; // clear leftover error status | |||
rx_buffer_head = 0; | |||
rx_buffer_tail = 0; | |||
if (rts_pin) rts_deassert(); |
@@ -78,14 +78,20 @@ static volatile uint8_t transmitting = 0; | |||
#define rts_assert() *(rts_pin+8) = rts_mask; | |||
#define rts_deassert() *(rts_pin+4) = rts_mask; | |||
#endif | |||
#if SERIAL2_TX_BUFFER_SIZE > 255 | |||
#if SERIAL2_TX_BUFFER_SIZE > 65535 | |||
static volatile uint32_t tx_buffer_head = 0; | |||
static volatile uint32_t tx_buffer_tail = 0; | |||
#elif SERIAL2_TX_BUFFER_SIZE > 255 | |||
static volatile uint16_t tx_buffer_head = 0; | |||
static volatile uint16_t tx_buffer_tail = 0; | |||
#else | |||
static volatile uint8_t tx_buffer_head = 0; | |||
static volatile uint8_t tx_buffer_tail = 0; | |||
#endif | |||
#if SERIAL2_RX_BUFFER_SIZE > 255 | |||
#if SERIAL2_RX_BUFFER_SIZE > 65535 | |||
static volatile uint32_t rx_buffer_head = 0; | |||
static volatile uint32_t rx_buffer_tail = 0; | |||
#elif SERIAL2_RX_BUFFER_SIZE > 255 | |||
static volatile uint16_t rx_buffer_head = 0; | |||
static volatile uint16_t rx_buffer_tail = 0; | |||
#else | |||
@@ -221,6 +227,8 @@ void serial2_end(void) | |||
CORE_PIN9_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); // PTC3 | |||
CORE_PIN10_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); // PTC4 | |||
#endif | |||
UART1_S1; | |||
UART1_D; // clear leftover error status | |||
rx_buffer_head = 0; | |||
rx_buffer_tail = 0; | |||
if (rts_pin) rts_deassert(); |
@@ -79,14 +79,20 @@ static volatile uint8_t transmitting = 0; | |||
#define rts_assert() *(rts_pin+8) = rts_mask; | |||
#define rts_deassert() *(rts_pin+4) = rts_mask; | |||
#endif | |||
#if SERIAL3_TX_BUFFER_SIZE > 255 | |||
#if SERIAL3_TX_BUFFER_SIZE > 65535 | |||
static volatile uint32_t tx_buffer_head = 0; | |||
static volatile uint32_t tx_buffer_tail = 0; | |||
#elif SERIAL3_TX_BUFFER_SIZE > 255 | |||
static volatile uint16_t tx_buffer_head = 0; | |||
static volatile uint16_t tx_buffer_tail = 0; | |||
#else | |||
static volatile uint8_t tx_buffer_head = 0; | |||
static volatile uint8_t tx_buffer_tail = 0; | |||
#endif | |||
#if SERIAL3_RX_BUFFER_SIZE > 255 | |||
#if SERIAL3_RX_BUFFER_SIZE > 65535 | |||
static volatile uint32_t rx_buffer_head = 0; | |||
static volatile uint32_t rx_buffer_tail = 0; | |||
#elif SERIAL3_RX_BUFFER_SIZE > 255 | |||
static volatile uint16_t rx_buffer_head = 0; | |||
static volatile uint16_t rx_buffer_tail = 0; | |||
#else | |||
@@ -196,6 +202,8 @@ void serial3_end(void) | |||
case 20: CORE_PIN20_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
} | |||
#endif | |||
UART2_S1; | |||
UART2_D; // clear leftover error status | |||
rx_buffer_head = 0; | |||
rx_buffer_tail = 0; | |||
if (rts_pin) rts_deassert(); |
@@ -70,14 +70,20 @@ static volatile uint8_t *transmit_pin=NULL; | |||
static volatile uint8_t *rts_pin=NULL; | |||
#define rts_assert() *rts_pin = 0 | |||
#define rts_deassert() *rts_pin = 1 | |||
#if SERIAL4_TX_BUFFER_SIZE > 255 | |||
#if SERIAL4_TX_BUFFER_SIZE > 65535 | |||
static volatile uint32_t tx_buffer_head = 0; | |||
static volatile uint32_t tx_buffer_tail = 0; | |||
#elif SERIAL4_TX_BUFFER_SIZE > 255 | |||
static volatile uint16_t tx_buffer_head = 0; | |||
static volatile uint16_t tx_buffer_tail = 0; | |||
#else | |||
static volatile uint8_t tx_buffer_head = 0; | |||
static volatile uint8_t tx_buffer_tail = 0; | |||
#endif | |||
#if SERIAL4_RX_BUFFER_SIZE > 255 | |||
#if SERIAL4_RX_BUFFER_SIZE > 65535 | |||
static volatile uint32_t rx_buffer_head = 0; | |||
static volatile uint32_t rx_buffer_tail = 0; | |||
#elif SERIAL4_RX_BUFFER_SIZE > 255 | |||
static volatile uint16_t rx_buffer_head = 0; | |||
static volatile uint16_t rx_buffer_tail = 0; | |||
#else | |||
@@ -168,6 +174,8 @@ void serial4_end(void) | |||
case 32: CORE_PIN32_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; // PTC4 | |||
case 62: CORE_PIN62_CONFIG = 0; break; | |||
} | |||
UART3_S1; | |||
UART3_D; // clear leftover error status | |||
rx_buffer_head = 0; | |||
rx_buffer_tail = 0; | |||
if (rts_pin) rts_deassert(); |
@@ -70,14 +70,20 @@ static volatile uint8_t *transmit_pin=NULL; | |||
static volatile uint8_t *rts_pin=NULL; | |||
#define rts_assert() *rts_pin = 0 | |||
#define rts_deassert() *rts_pin = 1 | |||
#if SERIAL5_TX_BUFFER_SIZE > 255 | |||
#if SERIAL5_TX_BUFFER_SIZE > 65535 | |||
static volatile uint32_t tx_buffer_head = 0; | |||
static volatile uint32_t tx_buffer_tail = 0; | |||
#elif SERIAL5_TX_BUFFER_SIZE > 255 | |||
static volatile uint16_t tx_buffer_head = 0; | |||
static volatile uint16_t tx_buffer_tail = 0; | |||
#else | |||
static volatile uint8_t tx_buffer_head = 0; | |||
static volatile uint8_t tx_buffer_tail = 0; | |||
#endif | |||
#if SERIAL5_RX_BUFFER_SIZE > 255 | |||
#if SERIAL5_RX_BUFFER_SIZE > 65535 | |||
static volatile uint32_t rx_buffer_head = 0; | |||
static volatile uint32_t rx_buffer_tail = 0; | |||
#elif SERIAL5_RX_BUFFER_SIZE > 255 | |||
static volatile uint16_t rx_buffer_head = 0; | |||
static volatile uint16_t rx_buffer_tail = 0; | |||
#else | |||
@@ -153,6 +159,8 @@ void serial5_end(void) | |||
UART4_C2 = 0; | |||
CORE_PIN34_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
CORE_PIN33_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
UART4_S1; | |||
UART4_D; // clear leftover error status | |||
rx_buffer_head = 0; | |||
rx_buffer_tail = 0; | |||
if (rts_pin) rts_deassert(); |
@@ -70,14 +70,20 @@ static volatile uint8_t *transmit_pin=NULL; | |||
static volatile uint8_t *rts_pin=NULL; | |||
#define rts_assert() *rts_pin = 0 | |||
#define rts_deassert() *rts_pin = 1 | |||
#if SERIAL6_TX_BUFFER_SIZE > 255 | |||
#if SERIAL6_TX_BUFFER_SIZE > 65535 | |||
static volatile uint32_t tx_buffer_head = 0; | |||
static volatile uint32_t tx_buffer_tail = 0; | |||
#elif SERIAL6_TX_BUFFER_SIZE > 255 | |||
static volatile uint16_t tx_buffer_head = 0; | |||
static volatile uint16_t tx_buffer_tail = 0; | |||
#else | |||
static volatile uint8_t tx_buffer_head = 0; | |||
static volatile uint8_t tx_buffer_tail = 0; | |||
#endif | |||
#if SERIAL6_RX_BUFFER_SIZE > 255 | |||
#if SERIAL6_RX_BUFFER_SIZE > 65535 | |||
static volatile uint32_t rx_buffer_head = 0; | |||
static volatile uint32_t rx_buffer_tail = 0; | |||
#elif SERIAL6_RX_BUFFER_SIZE > 255 | |||
static volatile uint16_t rx_buffer_head = 0; | |||
static volatile uint16_t rx_buffer_tail = 0; | |||
#else | |||
@@ -153,6 +159,8 @@ void serial6_end(void) | |||
UART5_C2 = 0; | |||
CORE_PIN47_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
CORE_PIN48_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
UART5_S1; | |||
UART5_D; // clear leftover error status | |||
rx_buffer_head = 0; | |||
rx_buffer_tail = 0; | |||
if (rts_pin) rts_deassert(); |
@@ -460,4 +460,4 @@ void lpuart0_status_isr(void) | |||
} | |||
} | |||
#endif // HAS_KINETISK_UART4 | |||
#endif // HAS_KINETISK_LPUART0 |
@@ -0,0 +1,6 @@ | |||
#include <Arduino.h> | |||
void serialEvent() __attribute__((weak)); | |||
void serialEvent() { | |||
} | |||
uint8_t _serialEvent_default PROGMEM = 1; |
@@ -0,0 +1,6 @@ | |||
#include <Arduino.h> | |||
#include "HardwareSerial.h" | |||
void serialEvent1() __attribute__((weak)); | |||
void serialEvent1() {} // No use calling this so disable if called... | |||
uint8_t _serialEvent1_default PROGMEM = 1; |
@@ -0,0 +1,6 @@ | |||
#include <Arduino.h> | |||
#include "HardwareSerial.h" | |||
void serialEvent2() __attribute__((weak)); | |||
void serialEvent2() {} // No use calling this so disable if called... | |||
uint8_t _serialEvent2_default PROGMEM = 1; |
@@ -0,0 +1,6 @@ | |||
#include <Arduino.h> | |||
#include "HardwareSerial.h" | |||
void serialEvent3() __attribute__((weak)); | |||
void serialEvent3() {} // No use calling this so disable if called... | |||
uint8_t _serialEvent3_default PROGMEM = 1; |
@@ -0,0 +1,8 @@ | |||
#include <Arduino.h> | |||
#include "HardwareSerial.h" | |||
#ifdef HAS_KINETISK_UART3 | |||
void serialEvent4() __attribute__((weak)); | |||
void serialEvent4() {} // No use calling this so disable if called... | |||
uint8_t _serialEvent4_default PROGMEM = 1; | |||
#endif |
@@ -0,0 +1,8 @@ | |||
#include <Arduino.h> | |||
#include "HardwareSerial.h" | |||
#ifdef HAS_KINETISK_UART4 | |||
void serialEvent5() __attribute__((weak)); | |||
void serialEvent5() {} // No use calling this so disable if called... | |||
uint8_t _serialEvent5_default PROGMEM = 1; | |||
#endif |
@@ -0,0 +1,8 @@ | |||
#include <Arduino.h> | |||
#include "HardwareSerial.h" | |||
#if defined(HAS_KINETISK_UART5) || defined (HAS_KINETISK_LPUART0) | |||
void serialEvent6() __attribute__((weak)); | |||
void serialEvent6() {} // No use calling this so disable if called... | |||
uint8_t _serialEvent6_default PROGMEM = 1; | |||
#endif |
@@ -0,0 +1,5 @@ | |||
#include <Arduino.h> | |||
void serialEventUSB1() __attribute__((weak)); | |||
void serialEventUSB1() {} | |||
uint8_t _serialEventUSB1_default PROGMEM = 1; |
@@ -0,0 +1,5 @@ | |||
#include <Arduino.h> | |||
void serialEventUSB2() __attribute__((weak)); | |||
void serialEventUSB2() {} | |||
uint8_t _serialEventUSB2_default PROGMEM = 1; |
@@ -28,10 +28,8 @@ | |||
* SOFTWARE. | |||
*/ | |||
#include <Arduino.h> | |||
#include "usb_dev.h" | |||
#include "usb_audio.h" | |||
#include "HardwareSerial.h" | |||
#include <string.h> // for memcpy() | |||
#ifdef AUDIO_INTERFACE // defined by usb_dev.h -> usb_desc.h | |||
#if F_CPU >= 20000000 |
@@ -90,7 +90,22 @@ static uint8_t device_descriptor[] = { | |||
#ifdef BCD_DEVICE | |||
LSB(BCD_DEVICE), MSB(BCD_DEVICE), // bcdDevice | |||
#else | |||
// For USB types that don't explicitly define BCD_DEVICE, | |||
// use the minor version number to help teensy_ports | |||
// identify which Teensy model is used. | |||
#if defined(__MKL26Z64__) | |||
0x73, 0x02, | |||
#elif defined(__MK20DX128__) | |||
0x74, 0x02, | |||
#elif defined(__MK20DX256__) | |||
0x75, 0x02, | |||
#elif defined(__MK64FX512__) | |||
0x76, 0x02, | |||
#elif defined(__MK66FX1M0__) | |||
0x77, 0x02, | |||
#else | |||
0x00, 0x02, | |||
#endif | |||
#endif | |||
1, // iManufacturer | |||
2, // iProduct | |||
@@ -379,6 +394,11 @@ static uint8_t multitouch_report_desc[] = { | |||
0x95, 0x01, // Report Count (1) | |||
0x09, 0x56, // Usage (Scan Time) | |||
0x81, 0x02, // Input (variable,absolute) | |||
0x09, 0x54, // USAGE (Contact count) | |||
0x25, 0x7f, // LOGICAL_MAXIMUM (127) | |||
0x95, 0x01, // REPORT_COUNT (1) | |||
0x75, 0x08, // REPORT_SIZE (8) | |||
0x81, 0x02, // INPUT (Data,Var,Abs) | |||
0x05, 0x0D, // Usage Page (Digitizers) | |||
0x09, 0x55, // Usage (Contact Count Maximum) | |||
0x25, MULTITOUCH_FINGERS, // Logical Maximum (10) | |||
@@ -469,7 +489,21 @@ static uint8_t flightsim_report_desc[] = { | |||
#define CDC_DATA_INTERFACE_DESC_SIZE 0 | |||
#endif | |||
#define MIDI_INTERFACE_DESC_POS CDC_DATA_INTERFACE_DESC_POS+CDC_DATA_INTERFACE_DESC_SIZE | |||
#define CDC2_DATA_INTERFACE_DESC_POS CDC_DATA_INTERFACE_DESC_POS+CDC_DATA_INTERFACE_DESC_SIZE | |||
#ifdef CDC2_DATA_INTERFACE | |||
#define CDC2_DATA_INTERFACE_DESC_SIZE 8 + 9+5+5+4+5+7+9+7+7 | |||
#else | |||
#define CDC2_DATA_INTERFACE_DESC_SIZE 0 | |||
#endif | |||
#define CDC3_DATA_INTERFACE_DESC_POS CDC2_DATA_INTERFACE_DESC_POS+CDC2_DATA_INTERFACE_DESC_SIZE | |||
#ifdef CDC3_DATA_INTERFACE | |||
#define CDC3_DATA_INTERFACE_DESC_SIZE 8 + 9+5+5+4+5+7+9+7+7 | |||
#else | |||
#define CDC3_DATA_INTERFACE_DESC_SIZE 0 | |||
#endif | |||
#define MIDI_INTERFACE_DESC_POS CDC3_DATA_INTERFACE_DESC_POS+CDC3_DATA_INTERFACE_DESC_SIZE | |||
#ifdef MIDI_INTERFACE | |||
#if !defined(MIDI_NUM_CABLES) || MIDI_NUM_CABLES < 1 || MIDI_NUM_CABLES > 16 | |||
#error "MIDI_NUM_CABLES must be defined between 1 to 16" | |||
@@ -588,7 +622,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
0x02, // bFunctionClass | |||
0x02, // bFunctionSubClass | |||
0x01, // bFunctionProtocol | |||
4, // iFunction | |||
0, // iFunction | |||
#endif | |||
#ifdef CDC_DATA_INTERFACE | |||
@@ -657,6 +691,156 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
0, // bInterval | |||
#endif // CDC_DATA_INTERFACE | |||
#ifdef CDC2_DATA_INTERFACE | |||
// interface association descriptor, USB ECN, Table 9-Z | |||
8, // bLength | |||
11, // bDescriptorType | |||
CDC2_STATUS_INTERFACE, // bFirstInterface | |||
2, // bInterfaceCount | |||
0x02, // bFunctionClass | |||
0x02, // bFunctionSubClass | |||
0x01, // bFunctionProtocol | |||
0, // iFunction | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
CDC2_STATUS_INTERFACE, // bInterfaceNumber | |||
0, // bAlternateSetting | |||
1, // bNumEndpoints | |||
0x02, // bInterfaceClass | |||
0x02, // bInterfaceSubClass | |||
0x01, // bInterfaceProtocol | |||
0, // iInterface | |||
// CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 | |||
5, // bFunctionLength | |||
0x24, // bDescriptorType | |||
0x00, // bDescriptorSubtype | |||
0x10, 0x01, // bcdCDC | |||
// Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 | |||
5, // bFunctionLength | |||
0x24, // bDescriptorType | |||
0x01, // bDescriptorSubtype | |||
0x01, // bmCapabilities | |||
1, // bDataInterface | |||
// Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 | |||
4, // bFunctionLength | |||
0x24, // bDescriptorType | |||
0x02, // bDescriptorSubtype | |||
0x06, // bmCapabilities | |||
// Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 | |||
5, // bFunctionLength | |||
0x24, // bDescriptorType | |||
0x06, // bDescriptorSubtype | |||
CDC2_STATUS_INTERFACE, // bMasterInterface | |||
CDC2_DATA_INTERFACE, // bSlaveInterface0 | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
5, // bDescriptorType | |||
CDC2_ACM_ENDPOINT | 0x80, // bEndpointAddress | |||
0x03, // bmAttributes (0x03=intr) | |||
CDC2_ACM_SIZE, 0, // wMaxPacketSize | |||
64, // bInterval | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
CDC2_DATA_INTERFACE, // bInterfaceNumber | |||
0, // bAlternateSetting | |||
2, // bNumEndpoints | |||
0x0A, // bInterfaceClass | |||
0x00, // bInterfaceSubClass | |||
0x00, // bInterfaceProtocol | |||
0, // iInterface | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
5, // bDescriptorType | |||
CDC2_RX_ENDPOINT, // bEndpointAddress | |||
0x02, // bmAttributes (0x02=bulk) | |||
CDC2_RX_SIZE, 0, // wMaxPacketSize | |||
0, // bInterval | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
5, // bDescriptorType | |||
CDC2_TX_ENDPOINT | 0x80, // bEndpointAddress | |||
0x02, // bmAttributes (0x02=bulk) | |||
CDC2_TX_SIZE, 0, // wMaxPacketSize | |||
0, // bInterval | |||
#endif // CDC2_DATA_INTERFACE | |||
#ifdef CDC3_DATA_INTERFACE | |||
// interface association descriptor, USB ECN, Table 9-Z | |||
8, // bLength | |||
11, // bDescriptorType | |||
CDC3_STATUS_INTERFACE, // bFirstInterface | |||
2, // bInterfaceCount | |||
0x02, // bFunctionClass | |||
0x02, // bFunctionSubClass | |||
0x01, // bFunctionProtocol | |||
0, // iFunction | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
CDC3_STATUS_INTERFACE, // bInterfaceNumber | |||
0, // bAlternateSetting | |||
1, // bNumEndpoints | |||
0x02, // bInterfaceClass | |||
0x02, // bInterfaceSubClass | |||
0x01, // bInterfaceProtocol | |||
0, // iInterface | |||
// CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 | |||
5, // bFunctionLength | |||
0x24, // bDescriptorType | |||
0x00, // bDescriptorSubtype | |||
0x10, 0x01, // bcdCDC | |||
// Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 | |||
5, // bFunctionLength | |||
0x24, // bDescriptorType | |||
0x01, // bDescriptorSubtype | |||
0x01, // bmCapabilities | |||
1, // bDataInterface | |||
// Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 | |||
4, // bFunctionLength | |||
0x24, // bDescriptorType | |||
0x02, // bDescriptorSubtype | |||
0x06, // bmCapabilities | |||
// Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 | |||
5, // bFunctionLength | |||
0x24, // bDescriptorType | |||
0x06, // bDescriptorSubtype | |||
CDC3_STATUS_INTERFACE, // bMasterInterface | |||
CDC3_DATA_INTERFACE, // bSlaveInterface0 | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
5, // bDescriptorType | |||
CDC3_ACM_ENDPOINT | 0x80, // bEndpointAddress | |||
0x03, // bmAttributes (0x03=intr) | |||
CDC3_ACM_SIZE, 0, // wMaxPacketSize | |||
64, // bInterval | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
CDC3_DATA_INTERFACE, // bInterfaceNumber | |||
0, // bAlternateSetting | |||
2, // bNumEndpoints | |||
0x0A, // bInterfaceClass | |||
0x00, // bInterfaceSubClass | |||
0x00, // bInterfaceProtocol | |||
0, // iInterface | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
5, // bDescriptorType | |||
CDC3_RX_ENDPOINT, // bEndpointAddress | |||
0x02, // bmAttributes (0x02=bulk) | |||
CDC3_RX_SIZE, 0, // wMaxPacketSize | |||
0, // bInterval | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
5, // bDescriptorType | |||
CDC3_TX_ENDPOINT | 0x80, // bEndpointAddress | |||
0x02, // bmAttributes (0x02=bulk) | |||
CDC3_TX_SIZE, 0, // wMaxPacketSize | |||
0, // bInterval | |||
#endif // CDC3_DATA_INTERFACE | |||
#ifdef MIDI_INTERFACE | |||
// Standard MS Interface Descriptor, | |||
9, // bLength | |||
@@ -1086,7 +1270,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
0x06, // bInterfaceClass (0x06 = still image) | |||
0x01, // bInterfaceSubClass | |||
0x01, // bInterfaceProtocol | |||
4, // iInterface | |||
0, // iInterface | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
5, // bDescriptorType |
@@ -40,7 +40,7 @@ | |||
#include <stddef.h> | |||
#define ENDPOINT_UNUSED 0x00 | |||
#define ENDPOINT_TRANSIMIT_ONLY 0x15 | |||
#define ENDPOINT_TRANSMIT_ONLY 0x15 | |||
#define ENDPOINT_RECEIVE_ONLY 0x19 | |||
#define ENDPOINT_TRANSMIT_AND_RECEIVE 0x1D | |||
#define ENDPOINT_RECEIVE_ISOCHRONOUS 0x18 | |||
@@ -136,9 +136,90 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define CDC_ACM_SIZE 16 | |||
#define CDC_RX_SIZE 64 | |||
#define CDC_TX_SIZE 64 | |||
#define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#elif defined(USB_DUAL_SERIAL) | |||
#define VENDOR_ID 0x16C0 | |||
#define PRODUCT_ID 0x048B | |||
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'} | |||
#define MANUFACTURER_NAME_LEN 11 | |||
#define PRODUCT_NAME {'D','u','a','l',' ','S','e','r','i','a','l'} | |||
#define PRODUCT_NAME_LEN 11 | |||
#define EP0_SIZE 64 | |||
#define NUM_ENDPOINTS 7 | |||
#define NUM_USB_BUFFERS 22 | |||
#define NUM_INTERFACE 4 | |||
#define CDC_IAD_DESCRIPTOR 1 // Serial | |||
#define CDC_STATUS_INTERFACE 0 | |||
#define CDC_DATA_INTERFACE 1 | |||
#define CDC_ACM_ENDPOINT 2 | |||
#define CDC_RX_ENDPOINT 3 | |||
#define CDC_TX_ENDPOINT 4 | |||
#define CDC_ACM_SIZE 16 | |||
#define CDC_RX_SIZE 64 | |||
#define CDC_TX_SIZE 64 | |||
#define CDC2_STATUS_INTERFACE 2 // SerialUSB1 | |||
#define CDC2_DATA_INTERFACE 3 | |||
#define CDC2_ACM_ENDPOINT 5 | |||
#define CDC2_RX_ENDPOINT 6 | |||
#define CDC2_TX_ENDPOINT 7 | |||
#define CDC2_ACM_SIZE 16 | |||
#define CDC2_RX_SIZE 64 | |||
#define CDC2_TX_SIZE 64 | |||
#define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT7_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#elif defined(USB_TRIPLE_SERIAL) | |||
#define VENDOR_ID 0x16C0 | |||
#define PRODUCT_ID 0x048C | |||
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'} | |||
#define MANUFACTURER_NAME_LEN 11 | |||
#define PRODUCT_NAME {'T','r','i','p','l','e',' ','S','e','r','i','a','l'} | |||
#define PRODUCT_NAME_LEN 13 | |||
#define EP0_SIZE 64 | |||
#define NUM_ENDPOINTS 10 | |||
#define NUM_USB_BUFFERS 32 | |||
#define NUM_INTERFACE 6 | |||
#define CDC_IAD_DESCRIPTOR 1 // Serial | |||
#define CDC_STATUS_INTERFACE 0 | |||
#define CDC_DATA_INTERFACE 1 | |||
#define CDC_ACM_ENDPOINT 2 | |||
#define CDC_RX_ENDPOINT 3 | |||
#define CDC_TX_ENDPOINT 4 | |||
#define CDC_ACM_SIZE 16 | |||
#define CDC_RX_SIZE 64 | |||
#define CDC_TX_SIZE 64 | |||
#define CDC2_STATUS_INTERFACE 2 // SerialUSB1 | |||
#define CDC2_DATA_INTERFACE 3 | |||
#define CDC2_ACM_ENDPOINT 5 | |||
#define CDC2_RX_ENDPOINT 6 | |||
#define CDC2_TX_ENDPOINT 7 | |||
#define CDC2_ACM_SIZE 16 | |||
#define CDC2_RX_SIZE 64 | |||
#define CDC2_TX_SIZE 64 | |||
#define CDC3_STATUS_INTERFACE 4 // SerialUSB2 | |||
#define CDC3_DATA_INTERFACE 5 | |||
#define CDC3_ACM_ENDPOINT 8 | |||
#define CDC3_RX_ENDPOINT 9 | |||
#define CDC3_TX_ENDPOINT 10 | |||
#define CDC3_ACM_SIZE 16 | |||
#define CDC3_RX_SIZE 64 | |||
#define CDC3_TX_SIZE 64 | |||
#define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT7_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT8_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT9_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT10_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#elif defined(USB_KEYBOARDONLY) | |||
#define VENDOR_ID 0x16C0 | |||
@@ -166,12 +247,12 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define KEYMEDIA_ENDPOINT 4 | |||
#define KEYMEDIA_SIZE 8 | |||
#define KEYMEDIA_INTERVAL 4 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#elif defined(USB_HID) | |||
#define VENDOR_ID 0x16C0 | |||
@@ -207,12 +288,12 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define JOYSTICK_ENDPOINT 4 | |||
#define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | |||
#define JOYSTICK_INTERVAL 2 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#elif defined(USB_SERIAL_HID) | |||
#define VENDOR_ID 0x16C0 | |||
@@ -253,13 +334,13 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define JOYSTICK_ENDPOINT 6 | |||
#define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | |||
#define JOYSTICK_INTERVAL 1 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT7_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT7_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#elif defined(USB_TOUCHSCREEN) | |||
#define VENDOR_ID 0x16C0 | |||
@@ -289,13 +370,13 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define KEYMEDIA_INTERVAL 4 | |||
#define MULTITOUCH_INTERFACE 3 // Touchscreen | |||
#define MULTITOUCH_ENDPOINT 5 | |||
#define MULTITOUCH_SIZE 8 | |||
#define MULTITOUCH_SIZE 16 | |||
#define MULTITOUCH_FINGERS 10 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#elif defined(USB_HID_TOUCHSCREEN) | |||
#define VENDOR_ID 0x16C0 | |||
@@ -329,14 +410,14 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define MOUSE_INTERVAL 2 | |||
#define MULTITOUCH_INTERFACE 4 // Touchscreen | |||
#define MULTITOUCH_ENDPOINT 5 | |||
#define MULTITOUCH_SIZE 8 | |||
#define MULTITOUCH_SIZE 16 | |||
#define MULTITOUCH_FINGERS 10 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#elif defined(USB_MIDI) | |||
#define VENDOR_ID 0x16C0 | |||
@@ -362,9 +443,9 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define MIDI_TX_SIZE 64 | |||
#define MIDI_RX_ENDPOINT 4 | |||
#define MIDI_RX_SIZE 64 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#elif defined(USB_MIDI4) | |||
@@ -392,9 +473,9 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define MIDI_TX_SIZE 64 | |||
#define MIDI_RX_ENDPOINT 4 | |||
#define MIDI_RX_SIZE 64 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#elif defined(USB_MIDI16) | |||
@@ -422,9 +503,9 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define MIDI_TX_SIZE 64 | |||
#define MIDI_RX_ENDPOINT 4 | |||
#define MIDI_RX_SIZE 64 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#elif defined(USB_MIDI_SERIAL) | |||
@@ -453,10 +534,10 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define MIDI_TX_SIZE 64 | |||
#define MIDI_RX_ENDPOINT 5 | |||
#define MIDI_RX_SIZE 64 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#elif defined(USB_MIDI4_SERIAL) | |||
@@ -486,10 +567,10 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define MIDI_TX_SIZE 64 | |||
#define MIDI_RX_ENDPOINT 5 | |||
#define MIDI_RX_SIZE 64 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#elif defined(USB_MIDI16_SERIAL) | |||
@@ -519,10 +600,10 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define MIDI_TX_SIZE 64 | |||
#define MIDI_RX_ENDPOINT 5 | |||
#define MIDI_RX_SIZE 64 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#elif defined(USB_RAWHID) | |||
@@ -552,9 +633,9 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define SEREMU_RX_ENDPOINT 2 | |||
#define SEREMU_RX_SIZE 32 | |||
#define SEREMU_RX_INTERVAL 2 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#elif defined(USB_FLIGHTSIM) | |||
@@ -582,14 +663,15 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define SEREMU_RX_ENDPOINT 2 | |||
#define SEREMU_RX_SIZE 32 | |||
#define SEREMU_RX_INTERVAL 2 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#elif defined(USB_FLIGHTSIM_JOYSTICK) | |||
#define VENDOR_ID 0x16C0 | |||
#define PRODUCT_ID 0x04D9 | |||
#define PRODUCT_ID 0x0488 | |||
#define BCD_DEVICE 0x0211 | |||
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'} | |||
#define MANUFACTURER_NAME_LEN 11 | |||
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','F','l','i','g','h','t',' ','S','i','m',' ','C','o','n','t','r','o','l','s'} | |||
@@ -616,11 +698,11 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define JOYSTICK_ENDPOINT 5 | |||
#define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | |||
#define JOYSTICK_INTERVAL 1 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#elif defined(USB_MTPDISK) | |||
@@ -649,9 +731,10 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define SEREMU_RX_ENDPOINT 2 | |||
#define SEREMU_RX_SIZE 32 | |||
#define SEREMU_RX_INTERVAL 2 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
// TODO: Should ENDPOINT4_CONFIG be ENDPOINT_TRANSMIT_ONLY ??? | |||
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#elif defined(USB_AUDIO) | |||
@@ -678,7 +761,7 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define AUDIO_RX_ENDPOINT 4 | |||
#define AUDIO_RX_SIZE 180 | |||
#define AUDIO_SYNC_ENDPOINT 5 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | |||
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | |||
@@ -716,10 +799,10 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define AUDIO_RX_ENDPOINT 7 | |||
#define AUDIO_RX_SIZE 180 | |||
#define AUDIO_SYNC_ENDPOINT 8 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | |||
#define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | |||
@@ -758,10 +841,10 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define AUDIO_RX_ENDPOINT 7 | |||
#define AUDIO_RX_SIZE 180 | |||
#define AUDIO_SYNC_ENDPOINT 8 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | |||
#define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | |||
@@ -848,21 +931,21 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
#define MULTITOUCH_ENDPOINT 15 | |||
#define MULTITOUCH_SIZE 8 | |||
#define MULTITOUCH_FINGERS 10 | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
#define ENDPOINT7_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
#define ENDPOINT8_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT8_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT9_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
#define ENDPOINT10_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT10_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT11_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
#define ENDPOINT12_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT12_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#define ENDPOINT13_CONFIG (ENDPOINT_RECEIVE_ISOCHRONOUS|ENDPOINT_TRANSMIT_ISOCHRONOUS) | |||
#define ENDPOINT14_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | |||
#define ENDPOINT15_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT15_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
#endif | |||
@@ -45,6 +45,14 @@ | |||
#include "usb_mem.h" | |||
#include <string.h> // for memset | |||
// This code has a known bug with compiled with -O2 optimization on gcc 5.4.1 | |||
// https://forum.pjrc.com/threads/53574-Teensyduino-1-43-Beta-2?p=186177&viewfull=1#post186177 | |||
#if defined(__MKL26Z64__) | |||
#pragma GCC optimize ("Os") | |||
#else | |||
#pragma GCC optimize ("O3") | |||
#endif | |||
// buffer descriptor table | |||
typedef struct { | |||
@@ -345,12 +353,30 @@ static void usb_setup(void) | |||
//serial_print("desc: not found\n"); | |||
endpoint0_stall(); | |||
return; | |||
#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; | |||
switch (setup.wIndex) { | |||
#ifdef CDC_STATUS_INTERFACE | |||
case CDC_STATUS_INTERFACE: | |||
usb_cdc_line_rtsdtr_millis = systick_millis_count; | |||
usb_cdc_line_rtsdtr = setup.wValue; | |||
break; | |||
#endif | |||
#ifdef CDC2_STATUS_INTERFACE | |||
case CDC2_STATUS_INTERFACE: | |||
usb_cdc2_line_rtsdtr_millis = systick_millis_count; | |||
usb_cdc2_line_rtsdtr = setup.wValue; | |||
break; | |||
#endif | |||
#ifdef CDC3_STATUS_INTERFACE | |||
case CDC3_STATUS_INTERFACE: | |||
usb_cdc3_line_rtsdtr_millis = systick_millis_count; | |||
usb_cdc3_line_rtsdtr = setup.wValue; | |||
break; | |||
#endif | |||
} | |||
//serial_print("set control line state\n"); | |||
break; | |||
#ifdef CDC_STATUS_INTERFACE | |||
case 0x2321: // CDC_SEND_BREAK | |||
break; | |||
case 0x2021: // CDC_SET_LINE_CODING | |||
@@ -586,21 +612,39 @@ static void usb_control(uint32_t stat) | |||
case 0x01: // OUT transaction received from host | |||
case 0x02: | |||
//serial_print("PID=OUT\n"); | |||
#ifdef CDC_STATUS_INTERFACE | |||
if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) { | |||
int i; | |||
uint8_t *dst = (uint8_t *)usb_cdc_line_coding; | |||
//serial_print("set line coding "); | |||
for (i=0; i<7; i++) { | |||
//serial_phex(*buf); | |||
*dst++ = *buf++; | |||
uint32_t *line_coding = NULL; | |||
switch (setup.wIndex) { | |||
#ifdef CDC_STATUS_INTERFACE | |||
case CDC_STATUS_INTERFACE: | |||
line_coding = usb_cdc_line_coding; | |||
break; | |||
#endif | |||
#ifdef CDC2_STATUS_INTERFACE | |||
case CDC2_STATUS_INTERFACE: | |||
line_coding = usb_cdc2_line_coding; | |||
break; | |||
#endif | |||
#ifdef CDC3_STATUS_INTERFACE | |||
case CDC3_STATUS_INTERFACE: | |||
line_coding = usb_cdc3_line_coding; | |||
break; | |||
#endif | |||
} | |||
if (line_coding) { | |||
uint8_t *dst = (uint8_t *)line_coding; | |||
//serial_print("set line coding "); | |||
for (i=0; i<7; i++) { | |||
//serial_phex(*buf); | |||
*dst++ = *buf++; | |||
} | |||
//serial_phex32(line_coding[0]); | |||
//serial_print("\n"); | |||
if (line_coding[0] == 134) usb_reboot_timer = 15; | |||
} | |||
//serial_phex32(usb_cdc_line_coding[0]); | |||
//serial_print("\n"); | |||
if (usb_cdc_line_coding[0] == 134) usb_reboot_timer = 15; | |||
endpoint0_transmit(NULL, 0); | |||
} | |||
#endif | |||
#ifdef KEYBOARD_INTERFACE | |||
if (setup.word1 == 0x02000921 && setup.word2 == ((1<<16)|KEYBOARD_INTERFACE)) { | |||
keyboard_leds = buf[0]; | |||
@@ -711,6 +755,9 @@ uint32_t usb_tx_byte_count(uint32_t endpoint) | |||
return usb_queue_byte_count(tx_first[endpoint]); | |||
} | |||
// Discussion about using this function and USB transmit latency | |||
// https://forum.pjrc.com/threads/58663?p=223513&viewfull=1#post223513 | |||
// | |||
uint32_t usb_tx_packet_count(uint32_t endpoint) | |||
{ | |||
const usb_packet_t *p; | |||
@@ -848,6 +895,7 @@ void _reboot_Teensyduino_(void) | |||
{ | |||
// TODO: initialize R0 with a code.... | |||
__asm__ volatile("bkpt"); | |||
__builtin_unreachable(); | |||
} | |||
@@ -877,6 +925,20 @@ void usb_isr(void) | |||
if (t == 0) usb_serial_flush_callback(); | |||
} | |||
#endif | |||
#ifdef CDC2_DATA_INTERFACE | |||
t = usb_cdc2_transmit_flush_timer; | |||
if (t) { | |||
usb_cdc2_transmit_flush_timer = --t; | |||
if (t == 0) usb_serial2_flush_callback(); | |||
} | |||
#endif | |||
#ifdef CDC3_DATA_INTERFACE | |||
t = usb_cdc3_transmit_flush_timer; | |||
if (t) { | |||
usb_cdc3_transmit_flush_timer = --t; | |||
if (t == 0) usb_serial3_flush_callback(); | |||
} | |||
#endif | |||
#ifdef SEREMU_INTERFACE | |||
t = usb_seremu_transmit_flush_timer; | |||
if (t) { | |||
@@ -1107,7 +1169,7 @@ void usb_init(void) | |||
usb_init_serialnumber(); | |||
for (i=0; i <= NUM_ENDPOINTS*4; i++) { | |||
for (i=0; i < (NUM_ENDPOINTS+1)*4; i++) { | |||
table[i].desc = 0; | |||
table[i].addr = 0; | |||
} | |||
@@ -1121,7 +1183,7 @@ void usb_init(void) | |||
#ifdef HAS_KINETIS_MPU | |||
MPU_RGDAAC0 |= 0x03000000; | |||
#endif | |||
#if F_CPU == 180000000 || F_CPU == 216000000 | |||
#if F_CPU == 180000000 || F_CPU == 216000000 || F_CPU == 256000000 | |||
// if using IRC48M, turn on the USB clock recovery hardware | |||
USB0_CLK_RECOVER_IRC_EN = USB_CLK_RECOVER_IRC_EN_IRC_EN | USB_CLK_RECOVER_IRC_EN_REG_EN; | |||
USB0_CLK_RECOVER_CTRL = USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN | |
@@ -67,15 +67,6 @@ static inline uint32_t usb_rx_byte_count(uint32_t endpoint) | |||
return usb_rx_byte_count_data[endpoint]; | |||
} | |||
#ifdef CDC_DATA_INTERFACE | |||
extern uint32_t usb_cdc_line_coding[2]; | |||
extern volatile uint32_t usb_cdc_line_rtsdtr_millis; | |||
extern volatile uint32_t systick_millis_count; | |||
extern volatile uint8_t usb_cdc_line_rtsdtr; | |||
extern volatile uint8_t usb_cdc_transmit_flush_timer; | |||
extern void usb_serial_flush_callback(void); | |||
#endif | |||
#ifdef SEREMU_INTERFACE | |||
extern volatile uint8_t usb_seremu_transmit_flush_timer; | |||
extern void usb_seremu_flush_callback(void); | |||
@@ -119,6 +110,18 @@ extern void usb_touchscreen_update_callback(void); | |||
} | |||
#endif | |||
#ifdef CDC_DATA_INTERFACE | |||
#include "usb_serial.h" | |||
#endif | |||
#ifdef CDC2_DATA_INTERFACE | |||
#include "usb_serial2.h" | |||
#endif | |||
#ifdef CDC3_DATA_INTERFACE | |||
#include "usb_serial3.h" | |||
#endif | |||
#else // F_CPU < 20000000 | |||
#ifdef __cplusplus |
@@ -42,6 +42,12 @@ FlightSimInteger * FlightSimInteger::first = NULL; | |||
FlightSimInteger * FlightSimInteger::last = NULL; | |||
FlightSimFloat * FlightSimFloat::first = NULL; | |||
FlightSimFloat * FlightSimFloat::last = NULL; | |||
/// JB | |||
FlightSimEvent * FlightSimEvent::first = NULL; | |||
FlightSimEvent * FlightSimEvent::last = NULL; | |||
FlightSimData * FlightSimData::first = NULL; | |||
FlightSimData * FlightSimData::last = NULL; | |||
/// JB End | |||
uint8_t FlightSimClass::enabled = 0; | |||
uint8_t FlightSimClass::request_id_messages = 0; | |||
@@ -92,6 +98,146 @@ void FlightSimCommand::sendcmd(uint8_t n) | |||
FlightSimClass::xmit(buf, 4, NULL, 0); | |||
} | |||
/// JB | |||
FlightSimEvent::FlightSimEvent() | |||
{ | |||
id = unassigned_id++; | |||
if (!first) { | |||
first = this; | |||
} else { | |||
last->next = this; | |||
} | |||
last = this; | |||
name = NULL; | |||
next = NULL; | |||
occur_callback = NULL; | |||
occurredFlag = 0; | |||
callbackInfo = NULL; | |||
hasCallbackInfo = 0; | |||
value = 0; | |||
FlightSimClass::request_id_messages = 1; | |||
} | |||
void FlightSimEvent::identify(void) | |||
{ | |||
uint8_t len, buf[6]; | |||
if (!FlightSim.enabled || !name) return; | |||
len = strlen((const char *)name); | |||
buf[0] = len + 6; | |||
buf[1] = 1; | |||
buf[2] = id; | |||
buf[3] = id >> 8; | |||
buf[4] = 3; | |||
buf[5] = 0; | |||
FlightSimClass::xmit(buf, 6, name, len); | |||
} | |||
void FlightSimEvent::send(unsigned int data, unsigned int flags) | |||
{ | |||
uint8_t buf[4]; | |||
uint32_t txData[2]; | |||
if (!FlightSim.enabled || !name) return; | |||
buf[0] = 12; | |||
buf[1] = 7; | |||
buf[2] = id; | |||
buf[3] = id >> 8; | |||
value = data; | |||
txData[0] = data; | |||
txData[1] = flags; | |||
FlightSimClass::xmit(buf, 4, (uint8_t *)&txData, 8); | |||
} | |||
void FlightSimEvent::update(long val) | |||
{ | |||
value = (unsigned int) val; | |||
occurredFlag = true; | |||
if (occur_callback) { | |||
if (!hasCallbackInfo) { | |||
(*occur_callback)(val); | |||
} else { | |||
(*(void(*)(long,void*))occur_callback)(val,callbackInfo); | |||
} | |||
} | |||
} | |||
FlightSimEvent * FlightSimEvent::find(unsigned int n) | |||
{ | |||
for (FlightSimEvent *p = first; p; p = p->next) { | |||
if (p->id == n) return p; | |||
} | |||
return NULL; | |||
} | |||
FlightSimData::FlightSimData() | |||
{ | |||
id = unassigned_id++; | |||
if (!first) { | |||
first = this; | |||
} else { | |||
last->next = this; | |||
} | |||
last = this; | |||
name = NULL; | |||
next = NULL; | |||
valueLen = 0; | |||
hasCallbackInfo = 0; | |||
callbackWithObject = 0; | |||
callbackInfo = NULL; | |||
change_callback = NULL; | |||
FlightSimClass::request_id_messages = 1; | |||
} | |||
void FlightSimData::identify(void) | |||
{ | |||
uint8_t len, buf[6]; | |||
if (!FlightSim.enabled || !name) return; | |||
len = strlen((const char *)name); | |||
buf[0] = len + 6; | |||
buf[1] = 1; | |||
buf[2] = id; | |||
buf[3] = id >> 8; | |||
buf[4] = 4; | |||
buf[5] = 0; | |||
FlightSimClass::xmit(buf, 6, name, len); | |||
} | |||
void FlightSimData::update(char *val, size_t len) | |||
{ | |||
valueLen = len; | |||
memcpy(value, val, len); | |||
if (len<FLIGHTSIM_DATA_MAXLEN) { | |||
memset(value+len,0,FLIGHTSIM_DATA_MAXLEN-len); | |||
} | |||
if (change_callback) { | |||
if (!callbackWithObject) { | |||
if (!hasCallbackInfo) { | |||
(*change_callback)(value); | |||
} else { | |||
(*(void(*)(char*,void*))change_callback)(value,callbackInfo); | |||
} | |||
} else { | |||
if (!hasCallbackInfo) { | |||
(*(void(*)(FlightSimData*))change_callback)(this); | |||
} else { | |||
(*(void(*)(FlightSimData*,void*))change_callback)(this,callbackInfo); | |||
} | |||
} | |||
} | |||
} | |||
FlightSimData * FlightSimData::find(unsigned int n) | |||
{ | |||
for (FlightSimData *p = first; p; p = p->next) { | |||
if (p->id == n) return p; | |||
} | |||
return NULL; | |||
} | |||
/// JB End | |||
FlightSimInteger::FlightSimInteger() | |||
{ | |||
@@ -287,6 +433,24 @@ void FlightSimClass::update(void) | |||
data.b[2] = p[8]; | |||
data.b[3] = p[9]; | |||
item->update(data.f); | |||
/// JB | |||
} else if (type == 3) { | |||
FlightSimEvent *item = FlightSimEvent::find(id); | |||
if (!item) break; | |||
#ifdef KINETISK | |||
data.l = *(long *)(p + 6); | |||
#else | |||
data.b[0] = p[6]; | |||
data.b[1] = p[7]; | |||
data.b[2] = p[8]; | |||
data.b[3] = p[9]; | |||
#endif | |||
item->update(data.f); | |||
} else if (type == 4) { | |||
FlightSimData *item = FlightSimData::find(id); | |||
if (!item) break; | |||
item->update(((char*)p)+6,len-6); | |||
/// JB End | |||
} | |||
break; | |||
case 0x03: // enable/disable | |||
@@ -313,6 +477,14 @@ void FlightSimClass::update(void) | |||
for (FlightSimCommand *p = FlightSimCommand::first; p; p = p->next) { | |||
p->identify(); | |||
} | |||
/// JB | |||
for (FlightSimEvent *p = FlightSimEvent::first; p; p = p->next) { | |||
p->identify(); | |||
} | |||
for (FlightSimData *p = FlightSimData::first; p; p=p->next) { | |||
p->identify(); | |||
} | |||
/// JB End | |||
for (FlightSimInteger *p = FlightSimInteger::first; p; p = p->next) { | |||
p->identify(); | |||
// TODO: send any dirty data |
@@ -70,6 +70,10 @@ private: | |||
friend class FlightSimCommand; | |||
friend class FlightSimInteger; | |||
friend class FlightSimFloat; | |||
/// JB | |||
friend class FlightSimEvent; | |||
friend class FlightSimData; | |||
/// JB End | |||
}; | |||
@@ -94,6 +98,101 @@ private: | |||
friend class FlightSimClass; | |||
}; | |||
/// JB | |||
class FlightSimEvent | |||
{ | |||
public: | |||
FlightSimEvent(); | |||
void assign(const _XpRefStr_ *s) { name = s; if (FlightSimClass::enabled) identify(); } | |||
FlightSimEvent & operator = (const _XpRefStr_ *s) { assign(s); return *this; } | |||
void send() { send(0,0); } | |||
void send(int data) { send(data,0); } | |||
void sendOnce() { send(0,0); } | |||
void sendOnce(int data) { send(data,0); } | |||
void sendRepeat(int data, uint16_t initialDelay, uint16_t repeatDelay) { send(data, initialDelay<<16 | repeatDelay); } | |||
void sendRepeat(uint16_t initialDelay, uint16_t repeatDelay) { send(0, initialDelay<<16 | repeatDelay); } | |||
void stopRepeat() { send(0,-1); } | |||
FlightSimEvent & operator = (int n) { send(n,0); return *this; } | |||
bool occurred() { bool hasOccurred = occurredFlag; occurredFlag = 0; return hasOccurred; } | |||
void identify(); | |||
static FlightSimEvent * find(unsigned int n); | |||
void update(long val); | |||
void onOccur(void (*fptr)(long)) { | |||
hasCallbackInfo=false; | |||
occur_callback = fptr; | |||
} | |||
void onOccur(void (*fptr)(long,void*), void* info) { | |||
hasCallbackInfo=true; | |||
occur_callback = (void (*)(long))fptr; | |||
callbackInfo = info; | |||
} | |||
private: | |||
void send(unsigned int data, unsigned int flags); | |||
unsigned int id; | |||
const _XpRefStr_ *name; | |||
bool occurredFlag; | |||
unsigned int value; | |||
FlightSimEvent *next; | |||
void (*occur_callback)(long); | |||
void* callbackInfo; | |||
bool hasCallbackInfo; | |||
static FlightSimEvent *first; | |||
static FlightSimEvent *last; | |||
friend class FlightSimClass; | |||
}; | |||
#define FLIGHTSIM_DATA_MAXLEN 58 | |||
class FlightSimData | |||
{ | |||
public: | |||
FlightSimData(); | |||
void assign(const _XpRefStr_ *s) { name = s; if (FlightSimClass::enabled) identify(); } | |||
FlightSimData & operator = (const _XpRefStr_ *s) { assign(s); return *this; } | |||
char *read() { return value; } | |||
operator char* () { return value; } | |||
void identify(); | |||
void update(char *val, size_t len); | |||
size_t len() { return valueLen; } | |||
static FlightSimData * find(unsigned int n); | |||
void onChange(void (*fptr)(char *)) { | |||
hasCallbackInfo = false; | |||
change_callback = fptr; | |||
} | |||
void onChange(void (*fptr)(char *,void *), void *info) { | |||
hasCallbackInfo = true; | |||
change_callback = (void (*)(char*)) fptr; | |||
callbackInfo = info; | |||
} | |||
void onChange(void (*fptr)(FlightSimData *)) { | |||
callbackWithObject = true; | |||
hasCallbackInfo = false; | |||
change_callback = (void (*)(char*)) fptr; | |||
} | |||
void onChange(void (*fptr)(FlightSimData *, void*), void* info) { | |||
callbackWithObject = true; | |||
hasCallbackInfo = true; | |||
change_callback = (void (*)(char*)) fptr; | |||
callbackInfo = info; | |||
} | |||
private: | |||
unsigned int id; | |||
const _XpRefStr_ *name; | |||
char value[FLIGHTSIM_DATA_MAXLEN]; | |||
size_t valueLen; | |||
void (*change_callback)(char *); | |||
void* callbackInfo; | |||
bool hasCallbackInfo; | |||
bool callbackWithObject; | |||
FlightSimData *next; | |||
static FlightSimData *first; | |||
static FlightSimData *last; | |||
friend class FlightSimClass; | |||
}; | |||
/// JB End | |||
class FlightSimInteger | |||
{ |
@@ -28,7 +28,7 @@ | |||
* SOFTWARE. | |||
*/ | |||
#include "WProgram.h" | |||
#include <Arduino.h> | |||
#include "usb_desc.h" | |||
#if F_CPU >= 20000000 | |||
@@ -39,6 +39,18 @@ usb_serial_class Serial; | |||
#endif | |||
#endif | |||
#ifdef CDC2_DATA_INTERFACE | |||
#ifdef CDC2_STATUS_INTERFACE | |||
usb_serial2_class SerialUSB1; | |||
#endif | |||
#endif | |||
#ifdef CDC3_DATA_INTERFACE | |||
#ifdef CDC3_STATUS_INTERFACE | |||
usb_serial3_class SerialUSB2; | |||
#endif | |||
#endif | |||
#ifdef MIDI_INTERFACE | |||
usb_midi_class usbMIDI; | |||
#endif | |||
@@ -75,7 +87,8 @@ usb_serial_class Serial; | |||
#else // F_CPU < 20 MHz | |||
#if defined(USB_SERIAL) || defined(USB_SERIAL_HID) | |||
#if defined(USB_SERIAL) || defined(USB_DUAL_SERIAL) || \ | |||
defined(USB_TRIPLE_SERIAL) || defined(USB_SERIAL_HID) | |||
usb_serial_class Serial; | |||
#elif (USB_DISABLED) | |||
usb_serial_class Serial; | |||
@@ -84,6 +97,3 @@ usb_seremu_class Serial; | |||
#endif | |||
#endif // F_CPU | |||
void serialEvent() __attribute__((weak)); | |||
void serialEvent() {} |
@@ -48,8 +48,9 @@ static uint8_t transmit_previous_timeout=0; | |||
// When the PC isn't listening, how long do we wait before discarding data? | |||
#define TX_TIMEOUT_MSEC 30 | |||
#if F_CPU == 240000000 | |||
#if F_CPU == 256000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
#elif F_CPU == 240000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
#elif F_CPU == 216000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
@@ -496,8 +496,9 @@ static uint8_t transmit_previous_timeout=0; | |||
// When the PC isn't listening, how long do we wait before discarding data? | |||
#define TX_TIMEOUT_MSEC 50 | |||
#if F_CPU == 240000000 | |||
#if F_CPU == 256000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
#elif F_CPU == 240000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
#elif F_CPU == 216000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
@@ -87,6 +87,7 @@ public: | |||
void set_key4(uint8_t c) { keyboard_keys[3] = c; } | |||
void set_key5(uint8_t c) { keyboard_keys[4] = c; } | |||
void set_key6(uint8_t c) { keyboard_keys[5] = c; } | |||
#ifdef KEYMEDIA_INTERFACE | |||
void set_media(uint16_t c) { | |||
if (c == 0) { | |||
usb_keymedia_release_all(); | |||
@@ -94,6 +95,7 @@ public: | |||
press(c); | |||
} | |||
} | |||
#endif | |||
void send_now(void) { usb_keyboard_send(); } | |||
void press(uint16_t n) { usb_keyboard_press_keycode(n); } | |||
void release(uint16_t n) { usb_keyboard_release_keycode(n); } |
@@ -76,8 +76,9 @@ static uint8_t tx_noautoflush=0; | |||
// When the PC isn't listening, how long do we wait before discarding data? | |||
#define TX_TIMEOUT_MSEC 40 | |||
#if F_CPU == 240000000 | |||
#if F_CPU == 256000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
#elif F_CPU == 240000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
#elif F_CPU == 216000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | |||
@@ -102,6 +103,13 @@ static uint8_t tx_noautoflush=0; | |||
#endif | |||
// This 32 bit input format is documented in the "Universal Serial Bus Device Class | |||
// Definition for MIDI Devices" specification, version 1.0, Nov 1, 1999. It can be | |||
// downloaded from www.usb.org. https://www.usb.org/sites/default/files/midi10.pdf | |||
// If the USB-IF reorganizes their website and this link no longer works, Google | |||
// search the name to find it. This data format is shown on page 16 in Figure #8. | |||
// Byte 0 (shown on the left hand side of Figure #8) is the least significant byte | |||
// of this 32 bit input. | |||
void usb_midi_write_packed(uint32_t n) | |||
{ | |||
uint32_t index, wait_count=0; | |||
@@ -133,7 +141,7 @@ void usb_midi_write_packed(uint32_t n) | |||
} else { | |||
tx_packet->len = MIDI_TX_SIZE; | |||
usb_tx(MIDI_TX_ENDPOINT, tx_packet); | |||
tx_packet = usb_malloc(); | |||
tx_packet = NULL; | |||
} | |||
tx_noautoflush = 0; | |||
} | |||
@@ -189,7 +197,7 @@ void usb_midi_flush_output(void) | |||
if (tx_noautoflush == 0 && tx_packet && tx_packet->index > 0) { | |||
tx_packet->len = tx_packet->index * 4; | |||
usb_tx(MIDI_TX_ENDPOINT, tx_packet); | |||
tx_packet = usb_malloc(); | |||
tx_packet = NULL; | |||
} | |||
} | |||
@@ -116,8 +116,9 @@ static uint8_t transmit_previous_timeout=0; | |||
// When the PC isn't listening, how long do we wait before discarding data? | |||
#define TX_TIMEOUT_MSEC 30 | |||
#if F_CPU == 240000000 | |||
#if F_CPU == 256000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
#elif F_CPU == 240000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
#elif F_CPU == 216000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
@@ -138,8 +138,9 @@ void usb_seremu_flush_input(void) | |||
// too short, we risk losing data during the stalls that are common with ordinary desktop | |||
// software. If it's too long, we stall the user's program when no software is running. | |||
#define TX_TIMEOUT_MSEC 30 | |||
#if F_CPU == 240000000 | |||
#if F_CPU == 256000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
#elif F_CPU == 240000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
#elif F_CPU == 216000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
@@ -148,8 +148,9 @@ void usb_serial_flush_input(void) | |||
// too short, we risk losing data during the stalls that are common with ordinary desktop | |||
// software. If it's too long, we stall the user's program when no software is running. | |||
#define TX_TIMEOUT_MSEC 70 | |||
#if F_CPU == 240000000 | |||
#if F_CPU == 256000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
#elif F_CPU == 240000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
#elif F_CPU == 216000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
@@ -39,6 +39,8 @@ | |||
#if F_CPU >= 20000000 && !defined(USB_DISABLED) | |||
#include "core_pins.h" // for millis() | |||
// C language implementation | |||
#ifdef __cplusplus | |||
extern "C" { | |||
@@ -52,6 +54,7 @@ int usb_serial_putchar(uint8_t c); | |||
int usb_serial_write(const void *buffer, uint32_t size); | |||
int usb_serial_write_buffer_free(void); | |||
void usb_serial_flush_output(void); | |||
void usb_serial_flush_callback(void); | |||
extern uint32_t usb_cdc_line_coding[2]; | |||
extern volatile uint32_t usb_cdc_line_rtsdtr_millis; | |||
extern volatile uint32_t systick_millis_count; | |||
@@ -106,9 +109,8 @@ public: | |||
uint8_t numbits(void) { return usb_cdc_line_coding[1] >> 16; } | |||
uint8_t dtr(void) { return (usb_cdc_line_rtsdtr & USB_SERIAL_DTR) ? 1 : 0; } | |||
uint8_t rts(void) { return (usb_cdc_line_rtsdtr & USB_SERIAL_RTS) ? 1 : 0; } | |||
operator bool() { return usb_configuration && | |||
(usb_cdc_line_rtsdtr & (USB_SERIAL_DTR | USB_SERIAL_RTS)) && | |||
((uint32_t)(systick_millis_count - usb_cdc_line_rtsdtr_millis) >= 25); | |||
operator bool() { return usb_configuration && (usb_cdc_line_rtsdtr & USB_SERIAL_DTR) && | |||
((uint32_t)(systick_millis_count - usb_cdc_line_rtsdtr_millis) >= 15); | |||
} | |||
size_t readBytes(char *buffer, size_t length) { | |||
size_t count=0; |
@@ -0,0 +1,306 @@ | |||
/* 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 "usb_dev.h" | |||
#include "usb_serial2.h" | |||
#include "core_pins.h" // for yield() | |||
//#include "HardwareSerial.h" | |||
#include <string.h> // for memcpy() | |||
// defined by usb_dev.h -> usb_desc.h | |||
#if defined(CDC2_STATUS_INTERFACE) && defined(CDC2_DATA_INTERFACE) | |||
#if F_CPU >= 20000000 | |||
uint32_t usb_cdc2_line_coding[2]; | |||
volatile uint32_t usb_cdc2_line_rtsdtr_millis; | |||
volatile uint8_t usb_cdc2_line_rtsdtr=0; | |||
volatile uint8_t usb_cdc2_transmit_flush_timer=0; | |||
static usb_packet_t *rx_packet=NULL; | |||
static usb_packet_t *tx_packet=NULL; | |||
static volatile uint8_t tx_noautoflush=0; | |||
#define TRANSMIT_FLUSH_TIMEOUT 5 /* in milliseconds */ | |||
// get the next character, or -1 if nothing received | |||
int usb_serial2_getchar(void) | |||
{ | |||
unsigned int i; | |||
int c; | |||
if (!rx_packet) { | |||
if (!usb_configuration) return -1; | |||
rx_packet = usb_rx(CDC2_RX_ENDPOINT); | |||
if (!rx_packet) return -1; | |||
} | |||
i = rx_packet->index; | |||
c = rx_packet->buf[i++]; | |||
if (i >= rx_packet->len) { | |||
usb_free(rx_packet); | |||
rx_packet = NULL; | |||
} else { | |||
rx_packet->index = i; | |||
} | |||
return c; | |||
} | |||
// peek at the next character, or -1 if nothing received | |||
int usb_serial2_peekchar(void) | |||
{ | |||
if (!rx_packet) { | |||
if (!usb_configuration) return -1; | |||
rx_packet = usb_rx(CDC2_RX_ENDPOINT); | |||
if (!rx_packet) return -1; | |||
} | |||
if (!rx_packet) return -1; | |||
return rx_packet->buf[rx_packet->index]; | |||
} | |||
// number of bytes available in the receive buffer | |||
int usb_serial2_available(void) | |||
{ | |||
int count; | |||
count = usb_rx_byte_count(CDC2_RX_ENDPOINT); | |||
if (rx_packet) count += rx_packet->len - rx_packet->index; | |||
return count; | |||
} | |||
// read a block of bytes to a buffer | |||
int usb_serial2_read(void *buffer, uint32_t size) | |||
{ | |||
uint8_t *p = (uint8_t *)buffer; | |||
uint32_t qty, count=0; | |||
while (size) { | |||
if (!usb_configuration) break; | |||
if (!rx_packet) { | |||
rx: | |||
rx_packet = usb_rx(CDC2_RX_ENDPOINT); | |||
if (!rx_packet) break; | |||
if (rx_packet->len == 0) { | |||
usb_free(rx_packet); | |||
goto rx; | |||
} | |||
} | |||
qty = rx_packet->len - rx_packet->index; | |||
if (qty > size) qty = size; | |||
memcpy(p, rx_packet->buf + rx_packet->index, qty); | |||
p += qty; | |||
count += qty; | |||
size -= qty; | |||
rx_packet->index += qty; | |||
if (rx_packet->index >= rx_packet->len) { | |||
usb_free(rx_packet); | |||
rx_packet = NULL; | |||
} | |||
} | |||
return count; | |||
} | |||
// discard any buffered input | |||
void usb_serial2_flush_input(void) | |||
{ | |||
usb_packet_t *rx; | |||
if (!usb_configuration) return; | |||
if (rx_packet) { | |||
usb_free(rx_packet); | |||
rx_packet = NULL; | |||
} | |||
while (1) { | |||
rx = usb_rx(CDC2_RX_ENDPOINT); | |||
if (!rx) break; | |||
usb_free(rx); | |||
} | |||
} | |||
// Maximum number of transmit packets to queue so we don't starve other endpoints for memory | |||
#define TX_PACKET_LIMIT 8 | |||
// When the PC isn't listening, how long do we wait before discarding data? If this is | |||
// too short, we risk losing data during the stalls that are common with ordinary desktop | |||
// software. If it's too long, we stall the user's program when no software is running. | |||
#define TX_TIMEOUT_MSEC 70 | |||
#if F_CPU == 256000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
#elif F_CPU == 240000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
#elif F_CPU == 216000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | |||
#elif F_CPU == 192000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1280) | |||
#elif F_CPU == 180000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1200) | |||
#elif F_CPU == 168000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1100) | |||
#elif F_CPU == 144000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 932) | |||
#elif F_CPU == 120000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 764) | |||
#elif F_CPU == 96000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596) | |||
#elif F_CPU == 72000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 512) | |||
#elif F_CPU == 48000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428) | |||
#elif F_CPU == 24000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262) | |||
#endif | |||
// 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_serial2_putchar(uint8_t c) | |||
{ | |||
return usb_serial2_write(&c, 1); | |||
} | |||
int usb_serial2_write(const void *buffer, uint32_t size) | |||
{ | |||
uint32_t ret = size; | |||
uint32_t len; | |||
uint32_t wait_count; | |||
const uint8_t *src = (const uint8_t *)buffer; | |||
uint8_t *dest; | |||
tx_noautoflush = 1; | |||
while (size > 0) { | |||
if (!tx_packet) { | |||
wait_count = 0; | |||
while (1) { | |||
if (!usb_configuration) { | |||
tx_noautoflush = 0; | |||
return -1; | |||
} | |||
if (usb_tx_packet_count(CDC2_TX_ENDPOINT) < TX_PACKET_LIMIT) { | |||
tx_noautoflush = 1; | |||
tx_packet = usb_malloc(); | |||
if (tx_packet) break; | |||
tx_noautoflush = 0; | |||
} | |||
if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) { | |||
transmit_previous_timeout = 1; | |||
return -1; | |||
} | |||
yield(); | |||
} | |||
} | |||
transmit_previous_timeout = 0; | |||
len = CDC2_TX_SIZE - tx_packet->index; | |||
if (len > size) len = size; | |||
dest = tx_packet->buf + tx_packet->index; | |||
tx_packet->index += len; | |||
size -= len; | |||
while (len-- > 0) *dest++ = *src++; | |||
if (tx_packet->index >= CDC2_TX_SIZE) { | |||
tx_packet->len = CDC2_TX_SIZE; | |||
usb_tx(CDC2_TX_ENDPOINT, tx_packet); | |||
tx_packet = NULL; | |||
} | |||
usb_cdc2_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT; | |||
} | |||
tx_noautoflush = 0; | |||
return ret; | |||
} | |||
int usb_serial2_write_buffer_free(void) | |||
{ | |||
uint32_t len; | |||
tx_noautoflush = 1; | |||
if (!tx_packet) { | |||
if (!usb_configuration || | |||
usb_tx_packet_count(CDC2_TX_ENDPOINT) >= TX_PACKET_LIMIT || | |||
(tx_packet = usb_malloc()) == NULL) { | |||
tx_noautoflush = 0; | |||
return 0; | |||
} | |||
} | |||
len = CDC2_TX_SIZE - tx_packet->index; | |||
// TODO: Perhaps we need "usb_cdc_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT" | |||
// added here, so the SOF interrupt can't take away the available buffer | |||
// space we just promised the user could write without blocking? | |||
// But does this come with other performance downsides? Could it lead to | |||
// buffer data never actually transmitting in some usage cases? More | |||
// investigation is needed. | |||
// https://github.com/PaulStoffregen/cores/issues/10#issuecomment-61514955 | |||
tx_noautoflush = 0; | |||
return len; | |||
} | |||
void usb_serial2_flush_output(void) | |||
{ | |||
if (!usb_configuration) return; | |||
tx_noautoflush = 1; | |||
if (tx_packet) { | |||
usb_cdc2_transmit_flush_timer = 0; | |||
tx_packet->len = tx_packet->index; | |||
usb_tx(CDC2_TX_ENDPOINT, tx_packet); | |||
tx_packet = NULL; | |||
} else { | |||
usb_packet_t *tx = usb_malloc(); | |||
if (tx) { | |||
usb_cdc2_transmit_flush_timer = 0; | |||
usb_tx(CDC2_TX_ENDPOINT, tx); | |||
} else { | |||
usb_cdc2_transmit_flush_timer = 1; | |||
} | |||
} | |||
tx_noautoflush = 0; | |||
} | |||
void usb_serial2_flush_callback(void) | |||
{ | |||
if (tx_noautoflush) return; | |||
if (tx_packet) { | |||
tx_packet->len = tx_packet->index; | |||
usb_tx(CDC2_TX_ENDPOINT, tx_packet); | |||
tx_packet = NULL; | |||
} else { | |||
usb_packet_t *tx = usb_malloc(); | |||
if (tx) { | |||
usb_tx(CDC2_TX_ENDPOINT, tx); | |||
} else { | |||
usb_cdc2_transmit_flush_timer = 1; | |||
} | |||
} | |||
} | |||
#endif // F_CPU | |||
#endif // CDC2_STATUS_INTERFACE && CDC2_DATA_INTERFACE |
@@ -0,0 +1,139 @@ | |||
/* 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. | |||
*/ | |||
#ifndef USBserial2_h_ | |||
#define USBserial2_h_ | |||
#include "usb_desc.h" | |||
#if defined(CDC2_STATUS_INTERFACE) && defined(CDC2_DATA_INTERFACE) | |||
#include <inttypes.h> | |||
#if F_CPU >= 20000000 | |||
#include "core_pins.h" // for millis() | |||
// C language implementation | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
int usb_serial2_getchar(void); | |||
int usb_serial2_peekchar(void); | |||
int usb_serial2_available(void); | |||
int usb_serial2_read(void *buffer, uint32_t size); | |||
void usb_serial2_flush_input(void); | |||
int usb_serial2_putchar(uint8_t c); | |||
int usb_serial2_write(const void *buffer, uint32_t size); | |||
int usb_serial2_write_buffer_free(void); | |||
void usb_serial2_flush_output(void); | |||
void usb_serial2_flush_callback(void); | |||
extern uint32_t usb_cdc2_line_coding[2]; | |||
extern volatile uint32_t usb_cdc2_line_rtsdtr_millis; | |||
extern volatile uint32_t systick_millis_count; | |||
extern volatile uint8_t usb_cdc2_line_rtsdtr; | |||
extern volatile uint8_t usb_cdc2_transmit_flush_timer; | |||
extern volatile uint8_t usb_configuration; | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#ifndef USB_SERIAL_DTR | |||
#define USB_SERIAL_DTR 0x01 | |||
#endif | |||
#ifndef USB_SERIAL_RTS | |||
#define USB_SERIAL_RTS 0x02 | |||
#endif | |||
// C++ interface | |||
#ifdef __cplusplus | |||
#include "Stream.h" | |||
class usb_serial2_class : public Stream | |||
{ | |||
public: | |||
constexpr usb_serial2_class() {} | |||
void begin(long) { | |||
//uint32_t millis_begin = systick_millis_count; | |||
//disabled for now - causes more trouble than it solves? | |||
//while (!(*this)) { | |||
// wait up to 2.5 seconds for Arduino Serial Monitor | |||
// Yes, this is a long time, but some Windows systems open | |||
// the port very slowly. This wait allows programs for | |||
// Arduino Uno to "just work" (without forcing a reboot when | |||
// the port is opened), and when no PC is connected the user's | |||
// sketch still gets to run normally after this wait time. | |||
//if ((uint32_t)(systick_millis_count - millis_begin) > 2500) break; | |||
//} | |||
} | |||
void end() { /* TODO: flush output and shut down USB port */ }; | |||
virtual int available() { return usb_serial2_available(); } | |||
virtual int read() { return usb_serial2_getchar(); } | |||
virtual int peek() { return usb_serial2_peekchar(); } | |||
virtual void flush() { usb_serial2_flush_output(); } // TODO: actually wait for data to leave USB... | |||
virtual void clear(void) { usb_serial2_flush_input(); } | |||
virtual size_t write(uint8_t c) { return usb_serial2_putchar(c); } | |||
virtual size_t write(const uint8_t *buffer, size_t size) { return usb_serial2_write(buffer, size); } | |||
size_t write(unsigned long n) { return write((uint8_t)n); } | |||
size_t write(long n) { return write((uint8_t)n); } | |||
size_t write(unsigned int n) { return write((uint8_t)n); } | |||
size_t write(int n) { return write((uint8_t)n); } | |||
virtual int availableForWrite() { return usb_serial2_write_buffer_free(); } | |||
using Print::write; | |||
void send_now(void) { usb_serial2_flush_output(); } | |||
uint32_t baud(void) { return usb_cdc2_line_coding[0]; } | |||
uint8_t stopbits(void) { uint8_t b = usb_cdc2_line_coding[1]; if (!b) b = 1; return b; } | |||
uint8_t paritytype(void) { return usb_cdc2_line_coding[1] >> 8; } // 0=none, 1=odd, 2=even | |||
uint8_t numbits(void) { return usb_cdc2_line_coding[1] >> 16; } | |||
uint8_t dtr(void) { return (usb_cdc2_line_rtsdtr & USB_SERIAL_DTR) ? 1 : 0; } | |||
uint8_t rts(void) { return (usb_cdc2_line_rtsdtr & USB_SERIAL_RTS) ? 1 : 0; } | |||
operator bool() { return usb_configuration && (usb_cdc2_line_rtsdtr & USB_SERIAL_DTR) && | |||
((uint32_t)(systick_millis_count - usb_cdc2_line_rtsdtr_millis) >= 15); | |||
} | |||
size_t readBytes(char *buffer, size_t length) { | |||
size_t count=0; | |||
unsigned long startMillis = millis(); | |||
do { | |||
count += usb_serial2_read(buffer + count, length - count); | |||
if (count >= length) return count; | |||
} while(millis() - startMillis < _timeout); | |||
setReadError(); | |||
return count; | |||
} | |||
}; | |||
extern usb_serial2_class SerialUSB1; | |||
extern void serialEventUSB1(void); | |||
#endif // __cplusplus | |||
#endif // F_CPU | |||
#endif // CDC2_STATUS_INTERFACE && CDC2_DATA_INTERFACE | |||
#endif // USBserial2_h_ |
@@ -0,0 +1,306 @@ | |||
/* 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 "usb_dev.h" | |||
#include "usb_serial3.h" | |||
#include "core_pins.h" // for yield() | |||
//#include "HardwareSerial.h" | |||
#include <string.h> // for memcpy() | |||
// defined by usb_dev.h -> usb_desc.h | |||
#if defined(CDC3_STATUS_INTERFACE) && defined(CDC3_DATA_INTERFACE) | |||
#if F_CPU >= 20000000 | |||
uint32_t usb_cdc3_line_coding[2]; | |||
volatile uint32_t usb_cdc3_line_rtsdtr_millis; | |||
volatile uint8_t usb_cdc3_line_rtsdtr=0; | |||
volatile uint8_t usb_cdc3_transmit_flush_timer=0; | |||
static usb_packet_t *rx_packet=NULL; | |||
static usb_packet_t *tx_packet=NULL; | |||
static volatile uint8_t tx_noautoflush=0; | |||
#define TRANSMIT_FLUSH_TIMEOUT 5 /* in milliseconds */ | |||
// get the next character, or -1 if nothing received | |||
int usb_serial3_getchar(void) | |||
{ | |||
unsigned int i; | |||
int c; | |||
if (!rx_packet) { | |||
if (!usb_configuration) return -1; | |||
rx_packet = usb_rx(CDC3_RX_ENDPOINT); | |||
if (!rx_packet) return -1; | |||
} | |||
i = rx_packet->index; | |||
c = rx_packet->buf[i++]; | |||
if (i >= rx_packet->len) { | |||
usb_free(rx_packet); | |||
rx_packet = NULL; | |||
} else { | |||
rx_packet->index = i; | |||
} | |||
return c; | |||
} | |||
// peek at the next character, or -1 if nothing received | |||
int usb_serial3_peekchar(void) | |||
{ | |||
if (!rx_packet) { | |||
if (!usb_configuration) return -1; | |||
rx_packet = usb_rx(CDC3_RX_ENDPOINT); | |||
if (!rx_packet) return -1; | |||
} | |||
if (!rx_packet) return -1; | |||
return rx_packet->buf[rx_packet->index]; | |||
} | |||
// number of bytes available in the receive buffer | |||
int usb_serial3_available(void) | |||
{ | |||
int count; | |||
count = usb_rx_byte_count(CDC3_RX_ENDPOINT); | |||
if (rx_packet) count += rx_packet->len - rx_packet->index; | |||
return count; | |||
} | |||
// read a block of bytes to a buffer | |||
int usb_serial3_read(void *buffer, uint32_t size) | |||
{ | |||
uint8_t *p = (uint8_t *)buffer; | |||
uint32_t qty, count=0; | |||
while (size) { | |||
if (!usb_configuration) break; | |||
if (!rx_packet) { | |||
rx: | |||
rx_packet = usb_rx(CDC3_RX_ENDPOINT); | |||
if (!rx_packet) break; | |||
if (rx_packet->len == 0) { | |||
usb_free(rx_packet); | |||
goto rx; | |||
} | |||
} | |||
qty = rx_packet->len - rx_packet->index; | |||
if (qty > size) qty = size; | |||
memcpy(p, rx_packet->buf + rx_packet->index, qty); | |||
p += qty; | |||
count += qty; | |||
size -= qty; | |||
rx_packet->index += qty; | |||
if (rx_packet->index >= rx_packet->len) { | |||
usb_free(rx_packet); | |||
rx_packet = NULL; | |||
} | |||
} | |||
return count; | |||
} | |||
// discard any buffered input | |||
void usb_serial3_flush_input(void) | |||
{ | |||
usb_packet_t *rx; | |||
if (!usb_configuration) return; | |||
if (rx_packet) { | |||
usb_free(rx_packet); | |||
rx_packet = NULL; | |||
} | |||
while (1) { | |||
rx = usb_rx(CDC3_RX_ENDPOINT); | |||
if (!rx) break; | |||
usb_free(rx); | |||
} | |||
} | |||
// Maximum number of transmit packets to queue so we don't starve other endpoints for memory | |||
#define TX_PACKET_LIMIT 8 | |||
// When the PC isn't listening, how long do we wait before discarding data? If this is | |||
// too short, we risk losing data during the stalls that are common with ordinary desktop | |||
// software. If it's too long, we stall the user's program when no software is running. | |||
#define TX_TIMEOUT_MSEC 70 | |||
#if F_CPU == 256000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
#elif F_CPU == 240000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
#elif F_CPU == 216000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | |||
#elif F_CPU == 192000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1280) | |||
#elif F_CPU == 180000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1200) | |||
#elif F_CPU == 168000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1100) | |||
#elif F_CPU == 144000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 932) | |||
#elif F_CPU == 120000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 764) | |||
#elif F_CPU == 96000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596) | |||
#elif F_CPU == 72000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 512) | |||
#elif F_CPU == 48000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428) | |||
#elif F_CPU == 24000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262) | |||
#endif | |||
// 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_serial3_putchar(uint8_t c) | |||
{ | |||
return usb_serial3_write(&c, 1); | |||
} | |||
int usb_serial3_write(const void *buffer, uint32_t size) | |||
{ | |||
uint32_t ret = size; | |||
uint32_t len; | |||
uint32_t wait_count; | |||
const uint8_t *src = (const uint8_t *)buffer; | |||
uint8_t *dest; | |||
tx_noautoflush = 1; | |||
while (size > 0) { | |||
if (!tx_packet) { | |||
wait_count = 0; | |||
while (1) { | |||
if (!usb_configuration) { | |||
tx_noautoflush = 0; | |||
return -1; | |||
} | |||
if (usb_tx_packet_count(CDC3_TX_ENDPOINT) < TX_PACKET_LIMIT) { | |||
tx_noautoflush = 1; | |||
tx_packet = usb_malloc(); | |||
if (tx_packet) break; | |||
tx_noautoflush = 0; | |||
} | |||
if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) { | |||
transmit_previous_timeout = 1; | |||
return -1; | |||
} | |||
yield(); | |||
} | |||
} | |||
transmit_previous_timeout = 0; | |||
len = CDC3_TX_SIZE - tx_packet->index; | |||
if (len > size) len = size; | |||
dest = tx_packet->buf + tx_packet->index; | |||
tx_packet->index += len; | |||
size -= len; | |||
while (len-- > 0) *dest++ = *src++; | |||
if (tx_packet->index >= CDC3_TX_SIZE) { | |||
tx_packet->len = CDC3_TX_SIZE; | |||
usb_tx(CDC3_TX_ENDPOINT, tx_packet); | |||
tx_packet = NULL; | |||
} | |||
usb_cdc3_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT; | |||
} | |||
tx_noautoflush = 0; | |||
return ret; | |||
} | |||
int usb_serial3_write_buffer_free(void) | |||
{ | |||
uint32_t len; | |||
tx_noautoflush = 1; | |||
if (!tx_packet) { | |||
if (!usb_configuration || | |||
usb_tx_packet_count(CDC3_TX_ENDPOINT) >= TX_PACKET_LIMIT || | |||
(tx_packet = usb_malloc()) == NULL) { | |||
tx_noautoflush = 0; | |||
return 0; | |||
} | |||
} | |||
len = CDC3_TX_SIZE - tx_packet->index; | |||
// TODO: Perhaps we need "usb_cdc_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT" | |||
// added here, so the SOF interrupt can't take away the available buffer | |||
// space we just promised the user could write without blocking? | |||
// But does this come with other performance downsides? Could it lead to | |||
// buffer data never actually transmitting in some usage cases? More | |||
// investigation is needed. | |||
// https://github.com/PaulStoffregen/cores/issues/10#issuecomment-61514955 | |||
tx_noautoflush = 0; | |||
return len; | |||
} | |||
void usb_serial3_flush_output(void) | |||
{ | |||
if (!usb_configuration) return; | |||
tx_noautoflush = 1; | |||
if (tx_packet) { | |||
usb_cdc3_transmit_flush_timer = 0; | |||
tx_packet->len = tx_packet->index; | |||
usb_tx(CDC3_TX_ENDPOINT, tx_packet); | |||
tx_packet = NULL; | |||
} else { | |||
usb_packet_t *tx = usb_malloc(); | |||
if (tx) { | |||
usb_cdc3_transmit_flush_timer = 0; | |||
usb_tx(CDC3_TX_ENDPOINT, tx); | |||
} else { | |||
usb_cdc3_transmit_flush_timer = 1; | |||
} | |||
} | |||
tx_noautoflush = 0; | |||
} | |||
void usb_serial3_flush_callback(void) | |||
{ | |||
if (tx_noautoflush) return; | |||
if (tx_packet) { | |||
tx_packet->len = tx_packet->index; | |||
usb_tx(CDC3_TX_ENDPOINT, tx_packet); | |||
tx_packet = NULL; | |||
} else { | |||
usb_packet_t *tx = usb_malloc(); | |||
if (tx) { | |||
usb_tx(CDC3_TX_ENDPOINT, tx); | |||
} else { | |||
usb_cdc3_transmit_flush_timer = 1; | |||
} | |||
} | |||
} | |||
#endif // F_CPU | |||
#endif // CDC3_STATUS_INTERFACE && CDC3_DATA_INTERFACE |
@@ -0,0 +1,139 @@ | |||
/* 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. | |||
*/ | |||
#ifndef USBserial3_h_ | |||
#define USBserial3_h_ | |||
#include "usb_desc.h" | |||
#if defined(CDC3_STATUS_INTERFACE) && defined(CDC3_DATA_INTERFACE) | |||
#include <inttypes.h> | |||
#if F_CPU >= 20000000 | |||
#include "core_pins.h" // for millis() | |||
// C language implementation | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
int usb_serial3_getchar(void); | |||
int usb_serial3_peekchar(void); | |||
int usb_serial3_available(void); | |||
int usb_serial3_read(void *buffer, uint32_t size); | |||
void usb_serial3_flush_input(void); | |||
int usb_serial3_putchar(uint8_t c); | |||
int usb_serial3_write(const void *buffer, uint32_t size); | |||
int usb_serial3_write_buffer_free(void); | |||
void usb_serial3_flush_output(void); | |||
void usb_serial3_flush_callback(void); | |||
extern uint32_t usb_cdc3_line_coding[2]; | |||
extern volatile uint32_t usb_cdc3_line_rtsdtr_millis; | |||
extern volatile uint32_t systick_millis_count; | |||
extern volatile uint8_t usb_cdc3_line_rtsdtr; | |||
extern volatile uint8_t usb_cdc3_transmit_flush_timer; | |||
extern volatile uint8_t usb_configuration; | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#ifndef USB_SERIAL_DTR | |||
#define USB_SERIAL_DTR 0x01 | |||
#endif | |||
#ifndef USB_SERIAL_RTS | |||
#define USB_SERIAL_RTS 0x02 | |||
#endif | |||
// C++ interface | |||
#ifdef __cplusplus | |||
#include "Stream.h" | |||
class usb_serial3_class : public Stream | |||
{ | |||
public: | |||
constexpr usb_serial3_class() {} | |||
void begin(long) { | |||
//uint32_t millis_begin = systick_millis_count; | |||
//disabled for now - causes more trouble than it solves? | |||
//while (!(*this)) { | |||
// wait up to 2.5 seconds for Arduino Serial Monitor | |||
// Yes, this is a long time, but some Windows systems open | |||
// the port very slowly. This wait allows programs for | |||
// Arduino Uno to "just work" (without forcing a reboot when | |||
// the port is opened), and when no PC is connected the user's | |||
// sketch still gets to run normally after this wait time. | |||
//if ((uint32_t)(systick_millis_count - millis_begin) > 2500) break; | |||
//} | |||
} | |||
void end() { /* TODO: flush output and shut down USB port */ }; | |||
virtual int available() { return usb_serial3_available(); } | |||
virtual int read() { return usb_serial3_getchar(); } | |||
virtual int peek() { return usb_serial3_peekchar(); } | |||
virtual void flush() { usb_serial3_flush_output(); } // TODO: actually wait for data to leave USB... | |||
virtual void clear(void) { usb_serial3_flush_input(); } | |||
virtual size_t write(uint8_t c) { return usb_serial3_putchar(c); } | |||
virtual size_t write(const uint8_t *buffer, size_t size) { return usb_serial3_write(buffer, size); } | |||
size_t write(unsigned long n) { return write((uint8_t)n); } | |||
size_t write(long n) { return write((uint8_t)n); } | |||
size_t write(unsigned int n) { return write((uint8_t)n); } | |||
size_t write(int n) { return write((uint8_t)n); } | |||
virtual int availableForWrite() { return usb_serial3_write_buffer_free(); } | |||
using Print::write; | |||
void send_now(void) { usb_serial3_flush_output(); } | |||
uint32_t baud(void) { return usb_cdc3_line_coding[0]; } | |||
uint8_t stopbits(void) { uint8_t b = usb_cdc3_line_coding[1]; if (!b) b = 1; return b; } | |||
uint8_t paritytype(void) { return usb_cdc3_line_coding[1] >> 8; } // 0=none, 1=odd, 2=even | |||
uint8_t numbits(void) { return usb_cdc3_line_coding[1] >> 16; } | |||
uint8_t dtr(void) { return (usb_cdc3_line_rtsdtr & USB_SERIAL_DTR) ? 1 : 0; } | |||
uint8_t rts(void) { return (usb_cdc3_line_rtsdtr & USB_SERIAL_RTS) ? 1 : 0; } | |||
operator bool() { return usb_configuration && (usb_cdc3_line_rtsdtr & USB_SERIAL_DTR) && | |||
((uint32_t)(systick_millis_count - usb_cdc3_line_rtsdtr_millis) >= 15); | |||
} | |||
size_t readBytes(char *buffer, size_t length) { | |||
size_t count=0; | |||
unsigned long startMillis = millis(); | |||
do { | |||
count += usb_serial3_read(buffer + count, length - count); | |||
if (count >= length) return count; | |||
} while(millis() - startMillis < _timeout); | |||
setReadError(); | |||
return count; | |||
} | |||
}; | |||
extern usb_serial3_class SerialUSB2; | |||
extern void serialEventUSB2(void); | |||
#endif // __cplusplus | |||
#endif // F_CPU | |||
#endif // CDC3_STATUS_INTERFACE && CDC3_DATA_INTERFACE | |||
#endif // USBserial3_h_ |
@@ -86,12 +86,14 @@ void usb_touchscreen_release(uint8_t finger) | |||
// 5: Y msb | |||
// 6: scan time lsb | |||
// 7: scan time msb | |||
// 8: contact count | |||
// Called by the start-of-frame interrupt. | |||
// | |||
void usb_touchscreen_update_callback(void) | |||
{ | |||
uint8_t contact_count = 0; | |||
if (scan_index == 0) { | |||
if (usb_tx_packet_count(MULTITOUCH_ENDPOINT) > 1) { | |||
// wait to begin another scan if if more than | |||
@@ -100,7 +102,16 @@ void usb_touchscreen_update_callback(void) | |||
} | |||
scan_timestamp = millis() * 10; | |||
scan_count = 0; | |||
// Get the contact count (usage 0x54) | |||
// Only set this value on first contact | |||
// Subsequent concurrent contacts should report 0 | |||
for (uint8_t i = 0; i < MULTITOUCH_FINGERS; i++) | |||
{ | |||
if (contactid[i]) contact_count++; | |||
} | |||
} | |||
while (scan_index < MULTITOUCH_FINGERS) { | |||
uint32_t press = pressure[scan_index]; | |||
uint32_t id = contactid[scan_index]; | |||
@@ -123,7 +134,8 @@ void usb_touchscreen_update_callback(void) | |||
*(tx_packet->buf + 5) = ypos[scan_index] >> 8; | |||
*(tx_packet->buf + 6) = scan_timestamp; | |||
*(tx_packet->buf + 7) = scan_timestamp >> 8; | |||
tx_packet->len = 8; | |||
*(tx_packet->buf + 8) = contact_count; | |||
tx_packet->len = 9; | |||
usb_tx(MULTITOUCH_ENDPOINT, tx_packet); | |||
scan_index++; | |||
return; |
@@ -41,8 +41,8 @@ | |||
#ifdef ENDPOINT_UNUSED | |||
#undef ENDPOINT_UNUSED | |||
#endif | |||
#ifdef ENDPOINT_TRANSIMIT_ONLY | |||
#undef ENDPOINT_TRANSIMIT_ONLY | |||
#ifdef ENDPOINT_TRANSMIT_ONLY | |||
#undef ENDPOINT_TRANSMIT_ONLY | |||
#endif | |||
#ifdef ENDPOINT_RECEIVE_ONLY | |||
#undef ENDPOINT_RECEIVE_ONLY | |||
@@ -110,6 +110,54 @@ | |||
#ifdef CDC_TX_SIZE | |||
#undef CDC_TX_SIZE | |||
#endif | |||
#ifdef CDC2_STATUS_INTERFACE | |||
#undef CDC2_STATUS_INTERFACE | |||
#endif | |||
#ifdef CDC2_DATA_INTERFACE | |||
#undef CDC2_DATA_INTERFACE | |||
#endif | |||
#ifdef CDC2_ACM_ENDPOINT | |||
#undef CDC2_ACM_ENDPOINT | |||
#endif | |||
#ifdef CDC2_RX_ENDPOINT | |||
#undef CDC2_RX_ENDPOINT | |||
#endif | |||
#ifdef CDC2_TX_ENDPOINT | |||
#undef CDC2_TX_ENDPOINT | |||
#endif | |||
#ifdef CDC2_ACM_SIZE | |||
#undef CDC2_ACM_SIZE | |||
#endif | |||
#ifdef CDC2_RX_SIZE | |||
#undef CDC2_RX_SIZE | |||
#endif | |||
#ifdef CDC2_TX_SIZE | |||
#undef CDC2_TX_SIZE | |||
#endif | |||
#ifdef CDC3_STATUS_INTERFACE | |||
#undef CDC3_STATUS_INTERFACE | |||
#endif | |||
#ifdef CDC3_DATA_INTERFACE | |||
#undef CDC3_DATA_INTERFACE | |||
#endif | |||
#ifdef CDC3_ACM_ENDPOINT | |||
#undef CDC3_ACM_ENDPOINT | |||
#endif | |||
#ifdef CDC3_RX_ENDPOINT | |||
#undef CDC3_RX_ENDPOINT | |||
#endif | |||
#ifdef CDC3_TX_ENDPOINT | |||
#undef CDC3_TX_ENDPOINT | |||
#endif | |||
#ifdef CDC3_ACM_SIZE | |||
#undef CDC3_ACM_SIZE | |||
#endif | |||
#ifdef CDC3_RX_SIZE | |||
#undef CDC3_RX_SIZE | |||
#endif | |||
#ifdef CDC3_TX_SIZE | |||
#undef CDC3_TX_SIZE | |||
#endif | |||
#ifdef SEREMU_INTERFACE | |||
#undef SEREMU_INTERFACE | |||
#endif |
@@ -33,6 +33,7 @@ | |||
#include <stdint.h> | |||
#include <stdlib.h> | |||
#include <stdbool.h> | |||
#include "binary.h" | |||
#include "core_id.h" | |||
#include "core_pins.h" | |||
@@ -48,15 +49,35 @@ long map(T _x, A _in_min, B _in_max, C _out_min, D _out_max, typename std::enabl | |||
{ | |||
long x = _x, in_min = _in_min, in_max = _in_max, out_min = _out_min, out_max = _out_max; | |||
// Arduino's traditional algorithm | |||
//return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; | |||
#if 0 | |||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; | |||
#endif | |||
#if 0 | |||
// st42's suggestion: https://github.com/arduino/Arduino/issues/2466#issuecomment-69873889 | |||
// more conversation: | |||
// https://forum.pjrc.com/threads/44503-map()-function-improvements | |||
if ((in_max - in_min) > (out_max - out_min)) { | |||
return (x - in_min) * (out_max - out_min+1) / (in_max - in_min+1) + out_min; | |||
} else { | |||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; | |||
} | |||
#endif | |||
long in_range = in_max - in_min; | |||
long out_range = out_max - out_min; | |||
if (in_range == 0) return out_min + out_range / 2; | |||
long num = (x - in_min) * out_range; | |||
if (out_range >= 0) { | |||
num += in_range / 2; | |||
} else { | |||
num -= in_range / 2; | |||
} | |||
long result = num / in_range + out_min; | |||
if (out_range >= 0) { | |||
if (in_range * num < 0) return result - 1; | |||
} else { | |||
if (in_range * num >= 0) return result + 1; | |||
} | |||
return result; | |||
// more conversation: | |||
// https://forum.pjrc.com/threads/44503-map()-function-improvements | |||
} | |||
// when the input is a float or double, do all math using the input's type | |||
template <class T, class A, class B, class C, class D> | |||
@@ -64,7 +85,7 @@ T map(T x, A in_min, B in_max, C out_min, D out_max, typename std::enable_if<std | |||
{ | |||
return (x - (T)in_min) * ((T)out_max - (T)out_min) / ((T)in_max - (T)in_min) + (T)out_min; | |||
} | |||
#include <algorithm> // c++ min, max | |||
//#include <algorithm> // this isn't really needed, is it? (slows down compiling) | |||
#include <utility> | |||
// https://forum.pjrc.com/threads/44596-Teensyduino-1-37-Beta-2-(Arduino-1-8-3-support)?p=145150&viewfull=1#post145150 | |||
template<class A, class B> | |||
@@ -190,8 +211,6 @@ void loop(void); | |||
typedef bool boolean; | |||
#else | |||
typedef uint8_t boolean; | |||
#define false 0 | |||
#define true (!false) | |||
#endif | |||
#endif |
@@ -28,32 +28,56 @@ | |||
* SOFTWARE. | |||
*/ | |||
#include "core_pins.h" | |||
#include "HardwareSerial.h" | |||
#include "usb_serial.h" | |||
#include "usb_seremu.h" | |||
#include <Arduino.h> | |||
#include "EventResponder.h" | |||
#ifdef USB_TRIPLE_SERIAL | |||
uint8_t yield_active_check_flags = YIELD_CHECK_USB_SERIAL | YIELD_CHECK_USB_SERIALUSB1 | YIELD_CHECK_USB_SERIALUSB2; // default to check USB. | |||
extern const uint8_t _serialEventUSB2_default; | |||
extern const uint8_t _serialEventUSB1_default; | |||
#elif defined(USB_DUAL_SERIAL) | |||
uint8_t yield_active_check_flags = YIELD_CHECK_USB_SERIAL | YIELD_CHECK_USB_SERIALUSB1; // default to check USB. | |||
extern const uint8_t _serialEventUSB1_default; | |||
#else | |||
uint8_t yield_active_check_flags = YIELD_CHECK_USB_SERIAL; // default to check USB. | |||
#endif | |||
extern const uint8_t _serialEvent_default; | |||
void yield(void) __attribute__ ((weak)); | |||
void yield(void) | |||
{ | |||
static uint8_t running=0; | |||
if (!yield_active_check_flags) return; // nothing to do | |||
if (running) return; // TODO: does this need to be atomic? | |||
running = 1; | |||
if (Serial.available()) serialEvent(); | |||
if (Serial1.available()) serialEvent1(); | |||
if (Serial2.available()) serialEvent2(); | |||
if (Serial3.available()) serialEvent3(); | |||
#ifdef HAS_KINETISK_UART3 | |||
if (Serial4.available()) serialEvent4(); | |||
#endif | |||
#ifdef HAS_KINETISK_UART4 | |||
if (Serial5.available()) serialEvent5(); | |||
// USB Serail - Add hack to minimize impact... | |||
if (yield_active_check_flags & YIELD_CHECK_USB_SERIAL) { | |||
if (Serial.available()) serialEvent(); | |||
if (_serialEvent_default) yield_active_check_flags &= ~YIELD_CHECK_USB_SERIAL; | |||
} | |||
// Current workaround until integrate with EventResponder. | |||
#if defined(USB_DUAL_SERIAL) || defined(USB_TRIPLE_SERIAL) | |||
if (yield_active_check_flags & YIELD_CHECK_USB_SERIALUSB1) { | |||
if (SerialUSB1.available()) serialEventUSB1(); | |||
if (_serialEventUSB1_default) yield_active_check_flags &= ~YIELD_CHECK_USB_SERIALUSB1; | |||
} | |||
#endif | |||
#if defined(HAS_KINETISK_UART5) || defined (HAS_KINETISK_LPUART0) | |||
if (Serial6.available()) serialEvent6(); | |||
#ifdef USB_TRIPLE_SERIAL | |||
if (yield_active_check_flags & YIELD_CHECK_USB_SERIALUSB2) { | |||
if (SerialUSB2.available()) serialEventUSB2(); | |||
if (_serialEventUSB2_default) yield_active_check_flags &= ~YIELD_CHECK_USB_SERIALUSB2; | |||
} | |||
#endif | |||
if (yield_active_check_flags & YIELD_CHECK_HARDWARE_SERIAL) { | |||
HardwareSerial::processSerialEventsList(); | |||
} | |||
running = 0; | |||
EventResponder::runFromYield(); | |||
if (yield_active_check_flags & YIELD_CHECK_EVENT_RESPONDER) EventResponder::runFromYield(); | |||
}; |
@@ -0,0 +1,9 @@ | |||
// This header file is in the public domain. | |||
#ifndef Arduino_h | |||
#define Arduino_h | |||
#include "WProgram.h" | |||
#include "pins_arduino.h" | |||
#endif |
@@ -0,0 +1,337 @@ | |||
/* 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 "AudioStream.h" | |||
#if defined(__IMXRT1062__) | |||
#define MAX_AUDIO_MEMORY 229376 | |||
#endif | |||
#define NUM_MASKS (((MAX_AUDIO_MEMORY / AUDIO_BLOCK_SAMPLES / 2) + 31) / 32) | |||
audio_block_t * AudioStream::memory_pool; | |||
uint32_t AudioStream::memory_pool_available_mask[NUM_MASKS]; | |||
uint16_t AudioStream::memory_pool_first_mask; | |||
uint16_t AudioStream::cpu_cycles_total = 0; | |||
uint16_t AudioStream::cpu_cycles_total_max = 0; | |||
uint16_t AudioStream::memory_used = 0; | |||
uint16_t AudioStream::memory_used_max = 0; | |||
void software_isr(void); | |||
// Set up the pool of audio data blocks | |||
// placing them all onto the free list | |||
FLASHMEM void AudioStream::initialize_memory(audio_block_t *data, unsigned int num) | |||
{ | |||
unsigned int i; | |||
unsigned int maxnum = MAX_AUDIO_MEMORY / AUDIO_BLOCK_SAMPLES / 2; | |||
//Serial.println("AudioStream initialize_memory"); | |||
//delay(10); | |||
if (num > maxnum) num = maxnum; | |||
__disable_irq(); | |||
memory_pool = data; | |||
memory_pool_first_mask = 0; | |||
for (i=0; i < NUM_MASKS; i++) { | |||
memory_pool_available_mask[i] = 0; | |||
} | |||
for (i=0; i < num; i++) { | |||
memory_pool_available_mask[i >> 5] |= (1 << (i & 0x1F)); | |||
} | |||
for (i=0; i < num; i++) { | |||
data[i].memory_pool_index = i; | |||
} | |||
__enable_irq(); | |||
} | |||
// Allocate 1 audio data block. If successful | |||
// the caller is the only owner of this new block | |||
audio_block_t * AudioStream::allocate(void) | |||
{ | |||
uint32_t n, index, avail; | |||
uint32_t *p, *end; | |||
audio_block_t *block; | |||
uint32_t used; | |||
p = memory_pool_available_mask; | |||
end = p + NUM_MASKS; | |||
__disable_irq(); | |||
index = memory_pool_first_mask; | |||
p += index; | |||
while (1) { | |||
if (p >= end) { | |||
__enable_irq(); | |||
//Serial.println("alloc:null"); | |||
return NULL; | |||
} | |||
avail = *p; | |||
if (avail) break; | |||
index++; | |||
p++; | |||
} | |||
n = __builtin_clz(avail); | |||
avail &= ~(0x80000000 >> n); | |||
*p = avail; | |||
if (!avail) index++; | |||
memory_pool_first_mask = index; | |||
used = memory_used + 1; | |||
memory_used = used; | |||
__enable_irq(); | |||
index = p - memory_pool_available_mask; | |||
block = memory_pool + ((index << 5) + (31 - n)); | |||
block->ref_count = 1; | |||
if (used > memory_used_max) memory_used_max = used; | |||
//Serial.print("alloc:"); | |||
//Serial.println((uint32_t)block, HEX); | |||
return block; | |||
} | |||
// Release ownership of a data block. If no | |||
// other streams have ownership, the block is | |||
// returned to the free pool | |||
void AudioStream::release(audio_block_t *block) | |||
{ | |||
//if (block == NULL) return; | |||
uint32_t mask = (0x80000000 >> (31 - (block->memory_pool_index & 0x1F))); | |||
uint32_t index = block->memory_pool_index >> 5; | |||
__disable_irq(); | |||
if (block->ref_count > 1) { | |||
block->ref_count--; | |||
} else { | |||
//Serial.print("reles:"); | |||
//Serial.println((uint32_t)block, HEX); | |||
memory_pool_available_mask[index] |= mask; | |||
if (index < memory_pool_first_mask) memory_pool_first_mask = index; | |||
memory_used--; | |||
} | |||
__enable_irq(); | |||
} | |||
// Transmit an audio data block | |||
// to all streams that connect to an output. The block | |||
// becomes owned by all the recepients, but also is still | |||
// owned by this object. Normally, a block must be released | |||
// by the caller after it's transmitted. This allows the | |||
// caller to transmit to same block to more than 1 output, | |||
// and then release it once after all transmit calls. | |||
void AudioStream::transmit(audio_block_t *block, unsigned char index) | |||
{ | |||
for (AudioConnection *c = destination_list; c != NULL; c = c->next_dest) { | |||
if (c->src_index == index) { | |||
if (c->dst.inputQueue[c->dest_index] == NULL) { | |||
c->dst.inputQueue[c->dest_index] = block; | |||
block->ref_count++; | |||
} | |||
} | |||
} | |||
} | |||
// Receive block from an input. The block's data | |||
// may be shared with other streams, so it must not be written | |||
audio_block_t * AudioStream::receiveReadOnly(unsigned int index) | |||
{ | |||
audio_block_t *in; | |||
if (index >= num_inputs) return NULL; | |||
in = inputQueue[index]; | |||
inputQueue[index] = NULL; | |||
return in; | |||
} | |||
// Receive block from an input. The block will not | |||
// be shared, so its contents may be changed. | |||
audio_block_t * AudioStream::receiveWritable(unsigned int index) | |||
{ | |||
audio_block_t *in, *p; | |||
if (index >= num_inputs) return NULL; | |||
in = inputQueue[index]; | |||
inputQueue[index] = NULL; | |||
if (in && in->ref_count > 1) { | |||
p = allocate(); | |||
if (p) memcpy(p->data, in->data, sizeof(p->data)); | |||
in->ref_count--; | |||
in = p; | |||
} | |||
return in; | |||
} | |||
void AudioConnection::connect(void) | |||
{ | |||
AudioConnection *p; | |||
if (isConnected) return; | |||
if (dest_index > dst.num_inputs) return; | |||
__disable_irq(); | |||
p = src.destination_list; | |||
if (p == NULL) { | |||
src.destination_list = this; | |||
} else { | |||
while (p->next_dest) { | |||
if (&p->src == &this->src && &p->dst == &this->dst | |||
&& p->src_index == this->src_index && p->dest_index == this->dest_index) { | |||
//Source and destination already connected through another connection, abort | |||
__enable_irq(); | |||
return; | |||
} | |||
p = p->next_dest; | |||
} | |||
p->next_dest = this; | |||
} | |||
this->next_dest = NULL; | |||
src.numConnections++; | |||
src.active = true; | |||
dst.numConnections++; | |||
dst.active = true; | |||
isConnected = true; | |||
__enable_irq(); | |||
} | |||
void AudioConnection::disconnect(void) | |||
{ | |||
AudioConnection *p; | |||
if (!isConnected) return; | |||
if (dest_index > dst.num_inputs) return; | |||
__disable_irq(); | |||
// Remove destination from source list | |||
p = src.destination_list; | |||
if (p == NULL) { | |||
//>>> PAH re-enable the IRQ | |||
__enable_irq(); | |||
return; | |||
} else if (p == this) { | |||
if (p->next_dest) { | |||
src.destination_list = next_dest; | |||
} else { | |||
src.destination_list = NULL; | |||
} | |||
} else { | |||
while (p) { | |||
if (p == this) { | |||
if (p->next_dest) { | |||
p = next_dest; | |||
break; | |||
} else { | |||
p = NULL; | |||
break; | |||
} | |||
} | |||
p = p->next_dest; | |||
} | |||
} | |||
//>>> PAH release the audio buffer properly | |||
//Remove possible pending src block from destination | |||
if(dst.inputQueue[dest_index] != NULL) { | |||
AudioStream::release(dst.inputQueue[dest_index]); | |||
// release() re-enables the IRQ. Need it to be disabled a little longer | |||
__disable_irq(); | |||
dst.inputQueue[dest_index] = NULL; | |||
} | |||
//Check if the disconnected AudioStream objects should still be active | |||
src.numConnections--; | |||
if (src.numConnections == 0) { | |||
src.active = false; | |||
} | |||
dst.numConnections--; | |||
if (dst.numConnections == 0) { | |||
dst.active = false; | |||
} | |||
isConnected = false; | |||
__enable_irq(); | |||
} | |||
// When an object has taken responsibility for calling update_all() | |||
// at each block interval (approx 2.9ms), this variable is set to | |||
// true. Objects that are capable of calling update_all(), typically | |||
// input and output based on interrupts, must check this variable in | |||
// their constructors. | |||
bool AudioStream::update_scheduled = false; | |||
bool AudioStream::update_setup(void) | |||
{ | |||
if (update_scheduled) return false; | |||
attachInterruptVector(IRQ_SOFTWARE, software_isr); | |||
NVIC_SET_PRIORITY(IRQ_SOFTWARE, 208); // 255 = lowest priority | |||
NVIC_ENABLE_IRQ(IRQ_SOFTWARE); | |||
update_scheduled = true; | |||
return true; | |||
} | |||
void AudioStream::update_stop(void) | |||
{ | |||
NVIC_DISABLE_IRQ(IRQ_SOFTWARE); | |||
update_scheduled = false; | |||
} | |||
AudioStream * AudioStream::first_update = NULL; | |||
void software_isr(void) // AudioStream::update_all() | |||
{ | |||
AudioStream *p; | |||
uint32_t totalcycles = ARM_DWT_CYCCNT; | |||
//digitalWriteFast(2, HIGH); | |||
for (p = AudioStream::first_update; p; p = p->next_update) { | |||
if (p->active) { | |||
uint32_t cycles = ARM_DWT_CYCCNT; | |||
p->update(); | |||
// TODO: traverse inputQueueArray and release | |||
// any input blocks that weren't consumed? | |||
cycles = (ARM_DWT_CYCCNT - cycles) >> 6; | |||
p->cpu_cycles = cycles; | |||
if (cycles > p->cpu_cycles_max) p->cpu_cycles_max = cycles; | |||
} | |||
} | |||
//digitalWriteFast(2, LOW); | |||
totalcycles = (ARM_DWT_CYCCNT - totalcycles) >> 6; | |||
AudioStream::cpu_cycles_total = totalcycles; | |||
if (totalcycles > AudioStream::cpu_cycles_total_max) | |||
AudioStream::cpu_cycles_total_max = totalcycles; | |||
asm("DSB"); | |||
} | |||