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: | The latest stable version of Teensy's core library is always available in the Teensyduino installer, at this page: | ||||
noexcept LITERAL1 | noexcept LITERAL1 | ||||
static_assert LITERAL1 | static_assert LITERAL1 | ||||
thread_local LITERAL1 | thread_local LITERAL1 | ||||
size_t LITERAL1 | |||||
# teensy specific functions | # teensy specific functions | ||||
elapsedMillis LITERAL1 | elapsedMillis LITERAL1 | ||||
printf KEYWORD2 | printf KEYWORD2 | ||||
digitalWriteFast KEYWORD2 | digitalWriteFast KEYWORD2 | ||||
digitalReadFast KEYWORD2 | digitalReadFast KEYWORD2 | ||||
digitalToggleFast KEYWORD2 | |||||
digitalToggle KEYWORD2 | |||||
transmitterEnable KEYWORD2 | transmitterEnable KEYWORD2 | ||||
attachRts KEYWORD2 | attachRts KEYWORD2 | ||||
attachCts KEYWORD2 | attachCts KEYWORD2 | ||||
PROGMEM LITERAL1 | PROGMEM LITERAL1 | ||||
FLASHMEM LITERAL1 | |||||
DMAMEM LITERAL1 | DMAMEM LITERAL1 | ||||
EXTMEM LITERAL1 | |||||
FASTRUN LITERAL1 | FASTRUN LITERAL1 | ||||
Serial4 KEYWORD1 | Serial4 KEYWORD1 | ||||
Serial5 KEYWORD1 | Serial5 KEYWORD1 | ||||
Serial6 KEYWORD1 | Serial6 KEYWORD1 | ||||
Serial7 KEYWORD1 | |||||
Serial8 KEYWORD1 | |||||
SerialUSB1 KEYWORD1 | |||||
SerialUSB2 KEYWORD1 | |||||
setRX KEYWORD2 | setRX KEYWORD2 | ||||
setTX KEYWORD2 | setTX KEYWORD2 | ||||
write9bit KEYWORD2 | write9bit KEYWORD2 | ||||
addMemoryForRead KEYWORD2 | |||||
addMemoryForWrite KEYWORD2 | |||||
clear KEYWORD2 | clear KEYWORD2 | ||||
EventResponder LITERAL1 | EventResponder LITERAL1 | ||||
EventResponderRef LITERAL1 | EventResponderRef LITERAL1 | ||||
waitForEvent KEYWORD2 | waitForEvent KEYWORD2 | ||||
MillisTimer LITERAL1 | MillisTimer LITERAL1 | ||||
beginRepeating KEYWORD2 | 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 | # Arduino constants | ||||
A0 LITERAL1 | A0 LITERAL1 | ||||
digitalPinHasPWM KEYWORD2 | digitalPinHasPWM KEYWORD2 | ||||
NOT_AN_INTERRUPT LITERAL1 | NOT_AN_INTERRUPT LITERAL1 | ||||
digitalPinToInterrupt KEYWORD2 | digitalPinToInterrupt KEYWORD2 | ||||
FILE_READ LITERAL1 | |||||
FILE_WRITE LITERAL1 | |||||
FILE_WRITE_BEGIN LITERAL1 | |||||
# HardwareSerial modes | # HardwareSerial modes | ||||
SERIAL_7E1 LITERAL1 | SERIAL_7E1 LITERAL1 | ||||
FlightSimInteger KEYWORD2 | FlightSimInteger KEYWORD2 | ||||
FlightSimFloat KEYWORD2 | FlightSimFloat KEYWORD2 | ||||
FlightSimElapsedFrames KEYWORD2 | FlightSimElapsedFrames KEYWORD2 | ||||
FlightSimData KEYWORD2 | |||||
FlightSimEvent KEYWORD2 | |||||
onChange KEYWORD2 | onChange KEYWORD2 | ||||
update KEYWORD2 | update KEYWORD2 | ||||
isEnabled KEYWORD2 | isEnabled KEYWORD2 |
/* 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 |
return write(p, sizeof(buf) - (p - buf)); | 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) | size_t Print::printFloat(double number, uint8_t digits) | ||||
{ | { | ||||
uint8_t sign=0; | uint8_t sign=0; |
// BYTE was defined in very old versions of Arduino | // BYTE was defined in very old versions of Arduino | ||||
// maybe this now causes more trouble than it's worth? | // maybe this now causes more trouble than it's worth? | ||||
#ifndef BYTE | |||||
#define BYTE 0 | |||||
#endif | |||||
//#ifndef BYTE | |||||
//#define BYTE 0 | |||||
//#endif | |||||
class __FlashStringHelper; | class __FlashStringHelper; | ||||
size_t print(unsigned int n) { return printNumber(n, 0, 10); } | size_t print(unsigned int n) { return printNumber(n, 0, 10); } | ||||
size_t print(long n); | size_t print(long n); | ||||
size_t print(unsigned long n) { return printNumber(n, 0, 10); } | 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(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(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(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(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(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(double n, int digits = 2) { return printFloat(n, digits); } | ||||
size_t print(const Printable &obj) { return obj.printTo(*this); } | size_t print(const Printable &obj) { return obj.printTo(*this); } | ||||
size_t println(unsigned int n) { return print(n) + println(); } | size_t println(unsigned int n) { return print(n) + println(); } | ||||
size_t println(long 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(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(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(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(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(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(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(double n, int digits = 2) { return print(n, digits) + println(); } | ||||
size_t println(const Printable &obj) { return obj.printTo(*this) + println(); } | size_t println(const Printable &obj) { return obj.printTo(*this) + println(); } | ||||
if (base == 2) return printNumberBin(n); | if (base == 2) return printNumberBin(n); | ||||
return printNumberAny(n, base); | return printNumberAny(n, base); | ||||
} | } | ||||
size_t printNumber64(uint64_t n, uint8_t base, uint8_t sign); | |||||
size_t printFloat(double n, uint8_t digits); | size_t printFloat(double n, uint8_t digits); | ||||
}; | }; | ||||
public: | 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 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 | virtual void stop() =0; // Finish with the UDP socket | ||||
// Sending UDP packets | // Sending UDP packets |
} | } | ||||
} | } | ||||
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 void _init_Teensyduino_internal_(void); | ||||
extern int analogRead(uint8_t); | extern int analogRead(uint8_t); | ||||
} | } | ||||
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 | #ifdef __cplusplus |
#define ASCII_20 KEY_SPACE // 32 | #define ASCII_20 KEY_SPACE // 32 | ||||
#define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | ||||
#define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | #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_24 KEY_4 + SHIFT_MASK // 36 $ | ||||
#define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | ||||
#define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | ||||
#define ASCII_20 KEY_SPACE // 32 | #define ASCII_20 KEY_SPACE // 32 | ||||
#define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | ||||
#define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | #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_24 KEY_4 + SHIFT_MASK // 36 $ | ||||
#define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | ||||
#define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & |
void * | void * | ||||
malloc(size_t len) | malloc(size_t len) | ||||
{ | { | ||||
struct __freelist *fp1, *fp2, *sfp1, *sfp2; | |||||
struct __freelist *fp1, *fp2, *sfp1=NULL, *sfp2=NULL; | |||||
char *cp; | char *cp; | ||||
size_t s, avail; | size_t s, avail; | ||||
#define NUM_DIGITAL_PINS CORE_NUM_TOTAL_PINS | #define NUM_DIGITAL_PINS CORE_NUM_TOTAL_PINS | ||||
#define NUM_ANALOG_INPUTS CORE_NUM_ANALOG | #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 | // This allows CapSense to work. Do any libraries | ||||
// depend on these to be zero? | // depend on these to be zero? |
#include <avr/io.h> | #include <avr/io.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <stdbool.h> | |||||
#include <math.h> | #include <math.h> | ||||
#include "binary.h" | #include "binary.h" | ||||
#include "core_id.h" | #include "core_id.h" | ||||
extern "C"{ | extern "C"{ | ||||
#endif | #endif | ||||
#define true 1 | |||||
#define false 0 | |||||
#define PI 3.1415926535897932384626433832795 | #define PI 3.1415926535897932384626433832795 | ||||
#define HALF_PI 1.5707963267948966192313216916398 | #define HALF_PI 1.5707963267948966192313216916398 | ||||
#define TWO_PI 6.283185307179586476925286766559 | #define TWO_PI 6.283185307179586476925286766559 | ||||
#define bit(b) (1UL << (b)) | #define bit(b) (1UL << (b)) | ||||
typedef uint8_t boolean; | |||||
typedef bool boolean; | |||||
typedef uint8_t byte; | typedef uint8_t byte; | ||||
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); | unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); |
// This header file is in the public domain. | // This header file is in the public domain. | ||||
#ifndef Arduino_h | |||||
#define Arduino_h | |||||
#include "WProgram.h" | #include "WProgram.h" | ||||
#include "pins_arduino.h" | #include "pins_arduino.h" | ||||
#endif |
*/ | */ | ||||
#include <string.h> // for memcpy | |||||
#include "AudioStream.h" | |||||
#include <Arduino.h> | #include <Arduino.h> | ||||
#include "AudioStream.h" | |||||
#if defined(__MKL26Z64__) | #if defined(__MKL26Z64__) | ||||
#define MAX_AUDIO_MEMORY 6144 | #define MAX_AUDIO_MEMORY 6144 | ||||
// Remove destination from source list | // Remove destination from source list | ||||
p = src.destination_list; | p = src.destination_list; | ||||
if (p == NULL) { | if (p == NULL) { | ||||
//>>> PAH re-enable the IRQ | |||||
__enable_irq(); | |||||
return; | return; | ||||
} else if (p == this) { | } else if (p == this) { | ||||
if (p->next_dest) { | if (p->next_dest) { | ||||
p = p->next_dest; | p = p->next_dest; | ||||
} | } | ||||
} | } | ||||
//>>> PAH release the audio buffer properly | |||||
//Remove possible pending src block from destination | //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 | //Check if the disconnected AudioStream objects should still be active | ||||
src.numConnections--; | src.numConnections--; | ||||
{ | { | ||||
AudioStream *p; | AudioStream *p; | ||||
#if defined(KINETISK) | |||||
ARM_DEMCR |= ARM_DEMCR_TRCENA; | ARM_DEMCR |= ARM_DEMCR_TRCENA; | ||||
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; | ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; | ||||
uint32_t totalcycles = ARM_DWT_CYCCNT; | uint32_t totalcycles = ARM_DWT_CYCCNT; | ||||
#elif defined(KINETISL) | |||||
uint32_t totalcycles = micros(); | |||||
#endif | |||||
//digitalWriteFast(2, HIGH); | //digitalWriteFast(2, HIGH); | ||||
for (p = AudioStream::first_update; p; p = p->next_update) { | for (p = AudioStream::first_update; p; p = p->next_update) { | ||||
if (p->active) { | if (p->active) { | ||||
} | } | ||||
} | } | ||||
//digitalWriteFast(2, LOW); | //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; | AudioStream::cpu_cycles_total = totalcycles; | ||||
if (totalcycles > AudioStream::cpu_cycles_total_max) | if (totalcycles > AudioStream::cpu_cycles_total_max) | ||||
AudioStream::cpu_cycles_total_max = totalcycles; | AudioStream::cpu_cycles_total_max = totalcycles; |
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | #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 | #define AUDIO_SAMPLE_RATE_EXACT 44117.64706 // 48 MHz / 1088, or 96 MHz * 2 / 17 / 256 | ||||
#elif defined(__MKL26Z64__) | #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 | ||||
#endif | #endif | ||||
AudioStream::initialize_memory(data, num); \ | 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)) | #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 AudioProcessorUsage() (CYCLE_COUNTER_APPROX_PERCENT(AudioStream::cpu_cycles_total)) | ||||
#define AudioProcessorUsageMax() (CYCLE_COUNTER_APPROX_PERCENT(AudioStream::cpu_cycles_total_max)) | #define AudioProcessorUsageMax() (CYCLE_COUNTER_APPROX_PERCENT(AudioStream::cpu_cycles_total_max)) |
DMABaseClass() {} | DMABaseClass() {} | ||||
static inline void copy_tcd(TCD_t *dst, const TCD_t *src) { | static inline void copy_tcd(TCD_t *dst, const TCD_t *src) { | ||||
dst->CSR = 0; | |||||
const uint32_t *p = (const uint32_t *)src; | const uint32_t *p = (const uint32_t *)src; | ||||
uint32_t *q = (uint32_t *)dst; | uint32_t *q = (uint32_t *)dst; | ||||
uint32_t t1, t2, t3, t4; | uint32_t t1, t2, t3, t4; | ||||
NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); | 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) { | void detachInterrupt(void) { | ||||
NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel); | NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel); | ||||
} | } | ||||
void transferSize(unsigned int len) { | void transferSize(unsigned int len) { | ||||
uint32_t dcr = CFG->DCR & 0xF0C8FFFF; | uint32_t dcr = CFG->DCR & 0xF0C8FFFF; | ||||
if (len == 4) { | 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) { | } 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 { | } else { | ||||
CFG->DCR = dcr | DMA_DCR_DSIZE(1) | DMA_DCR_DSIZE(1); | |||||
CFG->DCR = dcr | DMA_DCR_SSIZE(1) | DMA_DCR_DSIZE(1); | |||||
} | } | ||||
} | } | ||||
_VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr; | _VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr; | ||||
NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); | 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) { | void detachInterrupt(void) { | ||||
NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel); | NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel); | ||||
} | } |
* https://forum.pjrc.com/threads/44723-Arduino-Events | * https://forum.pjrc.com/threads/44723-Arduino-Events | ||||
*/ | */ | ||||
#include <Arduino.h> | |||||
#include "EventResponder.h" | #include "EventResponder.h" | ||||
EventResponder * EventResponder::firstYield = nullptr; | EventResponder * EventResponder::firstYield = nullptr; | ||||
bool EventResponder::runningFromYield = false; | bool EventResponder::runningFromYield = false; | ||||
// TODO: interrupt disable/enable needed in many places!!! | // 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() | void EventResponder::triggerEventNotImmediate() | ||||
{ | { | ||||
// with libraries using mid-to-high priority interrupts. | // with libraries using mid-to-high priority interrupts. | ||||
extern "C" volatile uint32_t systick_millis_count; | extern "C" volatile uint32_t systick_millis_count; | ||||
void systick_isr(void) | void systick_isr(void) | ||||
{ | |||||
systick_millis_count++; | |||||
} | |||||
extern "C" void systick_isr_with_timer_events(void) | |||||
{ | { | ||||
systick_millis_count++; | systick_millis_count++; | ||||
MillisTimer::runFromTimer(); | MillisTimer::runFromTimer(); | ||||
} | } | ||||
* your function is called only one time, based on the last trigger | * your function is called only one time, based on the last trigger | ||||
* event. | * event. | ||||
*/ | */ | ||||
extern "C" void systick_isr_with_timer_events(void); | |||||
class EventResponder; | class EventResponder; | ||||
typedef EventResponder& EventResponderRef; | typedef EventResponder& EventResponderRef; | ||||
detachNoInterrupts(); | detachNoInterrupts(); | ||||
_function = function; | _function = function; | ||||
_type = EventTypeYield; | _type = EventTypeYield; | ||||
yield_active_check_flags |= YIELD_CHECK_EVENT_RESPONDER; // user setup a yield type... | |||||
enableInterrupts(irq); | enableInterrupts(irq); | ||||
} | } | ||||
_function = function; | _function = function; | ||||
_type = EventTypeInterrupt; | _type = EventTypeInterrupt; | ||||
SCB_SHPR3 |= 0x00FF0000; // configure PendSV, lowest priority | 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); | enableInterrupts(irq); | ||||
} | } | ||||
EventResponder * waitForEvent(EventResponder *list, int listsize, int timeout); | EventResponder * waitForEvent(EventResponder *list, int listsize, int timeout); | ||||
static void runFromYield() { | static void runFromYield() { | ||||
if (!firstYield) return; | |||||
// First, check if yield was called from an interrupt | // First, check if yield was called from an interrupt | ||||
// never call normal handler functions from any interrupt context | // never call normal handler functions from any interrupt context | ||||
uint32_t ipsr; | uint32_t ipsr; |
/* 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 | #ifndef FS_H | ||||
#define FS_H | #define FS_H | ||||
#ifdef __cplusplus | #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 { | class File : public Stream { | ||||
public: | 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); | 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) { | size_t write(uint8_t b) { | ||||
return write(&b, 1); | return write(&b, 1); | ||||
} | } | ||||
size_t readBytes(char *buffer, size_t length) { | size_t readBytes(char *buffer, size_t length) { | ||||
return read(buffer, 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: | 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 // __cplusplus | ||||
#endif // FS_H | #endif // FS_H |
/* 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; | |||||
} | |||||
class HardwareSerial : public Stream | class HardwareSerial : public Stream | ||||
{ | { | ||||
public: | 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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
serial_begin(BAUD2DIV(baud)); | serial_begin(BAUD2DIV(baud)); | ||||
serial_format(format); } | serial_format(format); } | ||||
return len; } | return len; } | ||||
virtual size_t write9bit(uint32_t c) { serial_putchar(c); return 1; } | virtual size_t write9bit(uint32_t c) { serial_putchar(c); return 1; } | ||||
operator bool() { return true; } | 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 HardwareSerial Serial1; | ||||
extern void serialEvent1(void); | extern void serialEvent1(void); | ||||
class HardwareSerial2 : public HardwareSerial | class HardwareSerial2 : public HardwareSerial | ||||
{ | { | ||||
public: | 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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
serial2_begin(BAUD2DIV2(baud)); | serial2_begin(BAUD2DIV2(baud)); | ||||
serial2_format(format); } | serial2_format(format); } | ||||
class HardwareSerial3 : public HardwareSerial | class HardwareSerial3 : public HardwareSerial | ||||
{ | { | ||||
public: | 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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
serial3_begin(BAUD2DIV3(baud)); | serial3_begin(BAUD2DIV3(baud)); | ||||
serial3_format(format); } | serial3_format(format); } | ||||
class HardwareSerial4 : public HardwareSerial | class HardwareSerial4 : public HardwareSerial | ||||
{ | { | ||||
public: | 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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
serial4_begin(BAUD2DIV3(baud)); | serial4_begin(BAUD2DIV3(baud)); | ||||
serial4_format(format); } | serial4_format(format); } | ||||
class HardwareSerial5 : public HardwareSerial | class HardwareSerial5 : public HardwareSerial | ||||
{ | { | ||||
public: | 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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
serial5_begin(BAUD2DIV3(baud)); | serial5_begin(BAUD2DIV3(baud)); | ||||
serial5_format(format); } | serial5_format(format); } | ||||
class HardwareSerial6 : public HardwareSerial | class HardwareSerial6 : public HardwareSerial | ||||
{ | { | ||||
public: | public: | ||||
constexpr HardwareSerial6() {} | |||||
constexpr HardwareSerial6(void (* const se)()) : HardwareSerial(se) {} | |||||
#if defined(__MK66FX1M0__) // For LPUART just pass baud straight in. | #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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
serial6_begin(baud); | serial6_begin(baud); | ||||
serial6_format(format); } | serial6_format(format); } | ||||
#else | #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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
serial6_begin(BAUD2DIV3(baud)); | serial6_begin(BAUD2DIV3(baud)); | ||||
serial6_format(format); } | serial6_format(format); } |
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#include <Arduino.h> | |||||
#include "HardwareSerial.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(); | |||||
} | |||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#include <Arduino.h> | |||||
#include "HardwareSerial.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(); | |||||
} |
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#include <Arduino.h> | |||||
#include "HardwareSerial.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(); | |||||
} |
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#include <Arduino.h> | |||||
#include "HardwareSerial.h" | #include "HardwareSerial.h" | ||||
#ifdef HAS_KINETISK_UART3 | #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 | #endif |
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#include <Arduino.h> | |||||
#include "HardwareSerial.h" | #include "HardwareSerial.h" | ||||
#ifdef HAS_KINETISK_UART4 | #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 | #endif |
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#include <Arduino.h> | |||||
#include "HardwareSerial.h" | #include "HardwareSerial.h" | ||||
#if defined(HAS_KINETISK_UART5) || defined (HAS_KINETISK_LPUART0) | #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 | #endif |
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||||
*/ | */ | ||||
#include "Arduino.h" | |||||
#include <Arduino.h> | |||||
#include "IPAddress.h" | #include "IPAddress.h" | ||||
size_t IPAddress::printTo(Print& p) const | size_t IPAddress::printTo(Print& p) const |
OPTIONS = -DF_CPU=48000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH -DUSING_MAKEFILE | OPTIONS = -DF_CPU=48000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH -DUSING_MAKEFILE | ||||
# options needed by many Arduino libraries to configure for Teensy 3.x | # 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-m4" for Teensy 3.x | ||||
# use "cortex-m0plus" for Teensy LC | # use "cortex-m0plus" for Teensy LC |
// developed for Teensyduino have made their way back into | // developed for Teensyduino have made their way back into | ||||
// Arduino's code base. :-) | // 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) | size_t Print::write(const uint8_t *buffer, size_t size) | ||||
{ | { | ||||
if (buffer == nullptr) return 0; | |||||
size_t count = 0; | size_t count = 0; | ||||
while (size--) count += write(*buffer++); | while (size--) count += write(*buffer++); | ||||
return count; | return count; | ||||
#endif | #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) | size_t Print::printFloat(double number, uint8_t digits) | ||||
{ | { | ||||
uint8_t sign=0; | uint8_t sign=0; |
// BYTE was defined in very old versions of Arduino | // BYTE was defined in very old versions of Arduino | ||||
// maybe this now causes more trouble than it's worth? | // maybe this now causes more trouble than it's worth? | ||||
#ifndef BYTE | |||||
#define BYTE 0 | |||||
#endif | |||||
//#ifndef BYTE | |||||
//#define BYTE 0 | |||||
//#endif | |||||
class __FlashStringHelper; | class __FlashStringHelper; | ||||
size_t print(unsigned int n) { return printNumber(n, 10, 0); } | size_t print(unsigned int n) { return printNumber(n, 10, 0); } | ||||
size_t print(long n); | size_t print(long n); | ||||
size_t print(unsigned long n) { return printNumber(n, 10, 0); } | 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(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(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(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(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(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(double n, int digits = 2) { return printFloat(n, digits); } | ||||
size_t print(const Printable &obj) { return obj.printTo(*this); } | size_t print(const Printable &obj) { return obj.printTo(*this); } | ||||
size_t println(unsigned int n) { return print(n) + println(); } | size_t println(unsigned int n) { return print(n) + println(); } | ||||
size_t println(long 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(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(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(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(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(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(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(double n, int digits = 2) { return print(n, digits) + println(); } | ||||
size_t println(const Printable &obj) { return obj.printTo(*this) + println(); } | size_t println(const Printable &obj) { return obj.printTo(*this) + println(); } | ||||
int getWriteError() { return write_error; } | int getWriteError() { return write_error; } | ||||
void clearWriteError() { setWriteError(0); } | 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, ...); | int printf(const __FlashStringHelper *format, ...); | ||||
protected: | protected: | ||||
void setWriteError(int err = 1) { write_error = err; } | void setWriteError(int err = 1) { write_error = err; } | ||||
#else | #else | ||||
size_t printNumber(unsigned long n, uint8_t base, uint8_t sign); | size_t printNumber(unsigned long n, uint8_t base, uint8_t sign); | ||||
#endif | #endif | ||||
size_t printNumber64(uint64_t n, uint8_t base, uint8_t sign); | |||||
}; | }; | ||||
// The preferred way to set SPI speed is with SPI.beginTransaction() | // 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 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_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 | #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2)) //(120 / 2) * ((1+0)/4) = 15 MHz |
parsing functions based on TextFinder library by Michael Margolis | 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 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 | #define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field | ||||
// as find but search ends if the terminator string is found | // as find but search ends if the terminator string is found | ||||
bool Stream::findUntil(const char *target, const char *terminator) | 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 | // reads data from the stream until the target string of the given length is found | ||||
size_t index = 0; // maximum target string length is 64k bytes! | size_t index = 0; // maximum target string length is 64k bytes! | ||||
size_t termIndex = 0; | size_t termIndex = 0; | ||||
int c; | 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){ | while( (c = timedRead()) > 0){ | ||||
if( c == target[index]){ | if( c == target[index]){ | ||||
//////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); | //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); | ||||
// | // | ||||
size_t Stream::readBytes(char *buffer, size_t length) | size_t Stream::readBytes(char *buffer, size_t length) | ||||
{ | { | ||||
if (buffer == nullptr) return 0; | |||||
size_t count = 0; | size_t count = 0; | ||||
while (count < length) { | while (count < length) { | ||||
int c = timedRead(); | int c = timedRead(); | ||||
size_t Stream::readBytesUntil(char terminator, 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; | if (length < 1) return 0; | ||||
length--; | length--; | ||||
size_t index = 0; | size_t index = 0; |
* SOFTWARE. | * 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 | // IntervalTimer based tone. This allows tone() to share the timers with other | ||||
// libraries, rather than permanently hogging one PIT timer even for projects | // libraries, rather than permanently hogging one PIT timer even for projects |
public: | 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 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 | virtual void stop() =0; // Finish with the UDP socket | ||||
// Sending UDP packets | // Sending UDP packets |
// that fits into the ASCII character set. | // that fits into the ASCII character set. | ||||
inline boolean isAscii(int c) | inline boolean isAscii(int c) | ||||
{ | { | ||||
return ( isascii (c) == 0 ? false : true); | |||||
return ((c & ~0x7F) != 0 ? false : true); | |||||
} | } | ||||
// ASCII character set, by clearing the high-order bits. | // ASCII character set, by clearing the high-order bits. | ||||
inline int toAscii(int c) | inline int toAscii(int c) | ||||
{ | { | ||||
return toascii (c); | |||||
return (c & 0x7F); | |||||
} | } | ||||
#include "avr_emulation.h" | #include "avr_emulation.h" | ||||
#include "usb_serial.h" | #include "usb_serial.h" | ||||
#include "usb_serial2.h" | |||||
#include "usb_serial3.h" | |||||
#include "usb_seremu.h" | #include "usb_seremu.h" | ||||
#include "usb_keyboard.h" | #include "usb_keyboard.h" | ||||
#include "usb_mouse.h" | #include "usb_mouse.h" |
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||||
*/ | */ | ||||
#include "WString.h" | |||||
#include <Arduino.h> | |||||
/*********************************************/ | /*********************************************/ | ||||
/* Character Access */ | /* Character Access */ | ||||
/*********************************************/ | /*********************************************/ | ||||
const char String::zerotermination = 0; | |||||
char String::charAt(unsigned int loc) const | char String::charAt(unsigned int loc) const | ||||
{ | { | ||||
return operator[](loc); | return operator[](loc); |
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const; | 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 | void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const | ||||
{getBytes((unsigned char *)buf, bufsize, index);} | {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 | // search | ||||
int indexOf( char ch ) const; | int indexOf( char ch ) const; | ||||
// for more information http://www.artima.com/cppsource/safebool.html | // for more information http://www.artima.com/cppsource/safebool.html | ||||
typedef void (String::*StringIfHelperType)() const; | typedef void (String::*StringIfHelperType)() const; | ||||
void StringIfHelper() const {} | void StringIfHelper() const {} | ||||
static const char zerotermination; | |||||
public: | public: | ||||
operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } | operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } | ||||
}; | }; |
// the alternate clock is connected to OSCERCLK (16 MHz). | // 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 2 to 12 MHz for 16 bit mode | ||||
// datasheet says ADC clock should be 1 to 18 MHz for 8-12 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_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_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 | #define ADC_CFG1_10BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 15 MHz | ||||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz | #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 | #define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz | ||||
#else | #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 | #endif | ||||
void analog_init(void) | void analog_init(void) | ||||
} else { | } else { | ||||
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2 | 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; | *(volatile aliased_int16_t *)&(DAC0_DAT0L) = val; | ||||
#elif defined(__MKL26Z64__) | #elif defined(__MKL26Z64__) | ||||
} else { | } else { | ||||
DAC1_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2 | 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; | *(volatile aliased_int16_t *)&(DAC1_DAT0L) = val; | ||||
} | } |
* THE SOFTWARE. | * THE SOFTWARE. | ||||
*/ | */ | ||||
// Guidelines for editing this file: | |||||
// https://forum.pjrc.com/threads/34537-Teensy-LC-Increase-EEPROM-Size/page2 | |||||
#ifndef _AVR_EEPROM_H_ | #ifndef _AVR_EEPROM_H_ | ||||
#define _AVR_EEPROM_H_ 1 | #define _AVR_EEPROM_H_ 1 | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#define PROGMEM | #define PROGMEM | ||||
#define FLASHMEM | |||||
#define PGM_P const char * | #define PGM_P const char * | ||||
#define PSTR(str) (str) | #define PSTR(str) (str) | ||||
*/ | */ | ||||
#include "avr_emulation.h" | |||||
#include <Arduino.h> | |||||
#include "SPIFIFO.h" | #include "SPIFIFO.h" | ||||
uint8_t SPCRemulation::pinout = 0; | uint8_t SPCRemulation::pinout = 0; |
int ret = 0; | int ret = 0; | ||||
if (digitalReadFast(14)) ret |= (1<<0); | if (digitalReadFast(14)) ret |= (1<<0); | ||||
if (digitalReadFast(15)) ret |= (1<<1); | 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(17)) ret |= (1<<3); | ||||
if (digitalReadFast(18)) ret |= (1<<4); | if (digitalReadFast(18)) ret |= (1<<4); | ||||
if (digitalReadFast(19)) ret |= (1<<5); | if (digitalReadFast(19)) ret |= (1<<5); |
char * ultoa(unsigned long val, char *buf, int radix); | char * ultoa(unsigned long val, char *buf, int radix); | ||||
char * ltoa(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) __attribute__((always_inline, unused)); | ||||
static inline char * utoa(unsigned int val, char *buf, int radix) { return ultoa(val, buf, radix); } | 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)); | static inline char * itoa(int val, char *buf, int radix) __attribute__((always_inline, unused)); |
#define CORE_PIN32_PORTSET GPIOB_PSOR | #define CORE_PIN32_PORTSET GPIOB_PSOR | ||||
#define CORE_PIN33_PORTSET GPIOA_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_PIN0_PORTCLEAR GPIOB_PCOR | ||||
#define CORE_PIN1_PORTCLEAR GPIOB_PCOR | #define CORE_PIN1_PORTCLEAR GPIOB_PCOR | ||||
#define CORE_PIN2_PORTCLEAR GPIOD_PCOR | #define CORE_PIN2_PORTCLEAR GPIOD_PCOR | ||||
#define CORE_PIN25_PORTSET FGPIOE_PSOR | #define CORE_PIN25_PORTSET FGPIOE_PSOR | ||||
#define CORE_PIN26_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_PIN0_PORTCLEAR FGPIOB_PCOR | ||||
#define CORE_PIN1_PORTCLEAR FGPIOB_PCOR | #define CORE_PIN1_PORTCLEAR FGPIOB_PCOR | ||||
#define CORE_PIN2_PORTCLEAR FGPIOD_PCOR | #define CORE_PIN2_PORTCLEAR FGPIOD_PCOR | ||||
#define CORE_PIN62_PORTSET GPIOE_PSOR | #define CORE_PIN62_PORTSET GPIOE_PSOR | ||||
#define CORE_PIN63_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_PIN0_PORTCLEAR GPIOB_PCOR | ||||
#define CORE_PIN1_PORTCLEAR GPIOB_PCOR | #define CORE_PIN1_PORTCLEAR GPIOB_PCOR | ||||
#define CORE_PIN2_PORTCLEAR GPIOD_PCOR | #define CORE_PIN2_PORTCLEAR GPIOD_PCOR | ||||
} | } | ||||
} | } | ||||
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); | 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) __attribute__((always_inline, unused)); | ||||
static inline uint8_t digitalReadFast(uint8_t pin) | static inline uint8_t digitalReadFast(uint8_t pin) | ||||
void _reboot_Teensyduino_(void) __attribute__((noreturn)); | void _reboot_Teensyduino_(void) __attribute__((noreturn)); | ||||
void _restart_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 yield(void); | ||||
void delay(uint32_t msec); | void delay(uint32_t msec); | ||||
static inline void delayMicroseconds(uint32_t) __attribute__((always_inline, unused)); | static inline void delayMicroseconds(uint32_t) __attribute__((always_inline, unused)); | ||||
static inline void delayMicroseconds(uint32_t usec) | 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; | uint32_t n = usec * 80; | ||||
#elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
uint32_t n = usec * 72; | uint32_t n = usec * 72; | ||||
#endif | #endif | ||||
#ifdef KINETISL | #ifdef KINETISL | ||||
"sub %0, #1" "\n\t" | "sub %0, #1" "\n\t" | ||||
"bne L_%=_delayMicroseconds" "\n" | |||||
: "+l" (n) : | |||||
#else | #else | ||||
"subs %0, #1" "\n\t" | "subs %0, #1" "\n\t" | ||||
#endif | |||||
"bne L_%=_delayMicroseconds" "\n" | "bne L_%=_delayMicroseconds" "\n" | ||||
: "+r" (n) : | : "+r" (n) : | ||||
#endif | |||||
); | ); | ||||
} | } | ||||
} | } | ||||
#endif | #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 | |||||
); | |||||
} | |||||
* SOFTWARE. | * 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 "kinetis.h" | ||||
#include <avr/eeprom.h> | #include <avr/eeprom.h> | ||||
//#include "HardwareSerial.h" | //#include "HardwareSerial.h" |
#define ASCII_20 KEY_SPACE // 32 | #define ASCII_20 KEY_SPACE // 32 | ||||
#define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | ||||
#define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | #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_24 KEY_4 + SHIFT_MASK // 36 $ | ||||
#define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | ||||
#define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | ||||
#define ASCII_20 KEY_SPACE // 32 | #define ASCII_20 KEY_SPACE // 32 | ||||
#define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | ||||
#define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | #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_24 KEY_4 + SHIFT_MASK // 36 $ | ||||
#define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | ||||
#define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & |
#endif // end of board-specific definitions | #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 | #define F_PLL 240000000 | ||||
#ifndef F_BUS | #ifndef F_BUS | ||||
#define F_BUS 60000000 | #define F_BUS 60000000 | ||||
#define PORTA_PCR0 (*(volatile uint32_t *)0x40049000) // Pin Control Register n | #define PORTA_PCR0 (*(volatile uint32_t *)0x40049000) // Pin Control Register n | ||||
#define PORT_PCR_ISF ((uint32_t)0x01000000) // Interrupt Status Flag | #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(n) ((uint32_t)(((n) & 15) << 16)) // Interrupt Configuration | ||||
#define PORT_PCR_IRQC_MASK ((uint32_t)0x000F0000) | #define PORT_PCR_IRQC_MASK ((uint32_t)0x000F0000) | ||||
#define PORT_PCR_LK ((uint32_t)0x00008000) // Lock Register | #define PORT_PCR_LK ((uint32_t)0x00008000) // Lock Register | ||||
#define FTM0_CONF (*(volatile uint32_t *)0x40038084) // Configuration | #define FTM0_CONF (*(volatile uint32_t *)0x40038084) // Configuration | ||||
#define FTM_CONF_GTBEOUT 0x400 // Global Time Base Output | #define FTM_CONF_GTBEOUT 0x400 // Global Time Base Output | ||||
#define FTM_CONF_GTBEEN 0x200 // Global Time Base Enable | #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 FTM0_FLTPOL (*(volatile uint32_t *)0x40038088) // FTM Fault Input Polarity | ||||
#define FTM_FLTPOL_FLT3POL 0x08 // Fault Input 3 Polarity | #define FTM_FLTPOL_FLT3POL 0x08 // Fault Input 3 Polarity | ||||
#define FTM_FLTPOL_FLT2POL 0x04 // Fault Input 2 Polarity | #define FTM_FLTPOL_FLT2POL 0x04 // Fault Input 2 Polarity | ||||
#define ENET_EIR_TS_AVAIL ((uint32_t)0x00010000) // Transmit Timestamp Available | #define ENET_EIR_TS_AVAIL ((uint32_t)0x00010000) // Transmit Timestamp Available | ||||
#define ENET_EIR_TS_TIMER ((uint32_t)0x00008000) // Timestamp Timer | #define ENET_EIR_TS_TIMER ((uint32_t)0x00008000) // Timestamp Timer | ||||
#define ENET_EIMR (*(volatile uint32_t *)0x400C0008) // Interrupt Mask Register | #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 (*(volatile uint32_t *)0x400C0010) // Receive Descriptor Active Register | ||||
#define ENET_RDAR_RDAR ((uint32_t)0x01000000) | #define ENET_RDAR_RDAR ((uint32_t)0x01000000) | ||||
#define ENET_TDAR (*(volatile uint32_t *)0x400C0014) // Transmit Descriptor Active Register | #define ENET_TDAR (*(volatile uint32_t *)0x400C0014) // Transmit Descriptor Active Register | ||||
#define SPI1_MH (KINETISL_SPI1.MH) // Match High | #define SPI1_MH (KINETISL_SPI1.MH) // Match High | ||||
#define SPI1_DL (KINETISL_SPI1.DL) // Data Low | #define SPI1_DL (KINETISL_SPI1.DL) // Data Low | ||||
#define SPI1_DH (KINETISL_SPI1.DH) // Data High | #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 | #define SPI1_C3 (KINETISL_SPI1.C3) // Control Register 3 | ||||
#endif | #endif | ||||
extern void (* _VectorsRam[NVIC_NUM_INTERRUPTS+16])(void); | extern void (* _VectorsRam[NVIC_NUM_INTERRUPTS+16])(void); | ||||
extern void (* const _VectorsFlash[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 | #ifdef __cplusplus | ||||
} | } | ||||
#endif | #endif |
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#include "WProgram.h" | |||||
#include <Arduino.h> | |||||
extern "C" int main(void) | extern "C" int main(void) | ||||
{ | { |
UART0_C2 = UART_C2_TE; | UART0_C2 = UART_C2_TE; | ||||
PORTB_PCR17 = PORT_PCR_MUX(3); | PORTB_PCR17 = PORT_PCR_MUX(3); | ||||
#endif | #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)) { | if (!(RTC_CR & RTC_CR_OSCE)) { | ||||
RTC_SR = 0; | RTC_SR = 0; | ||||
RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE; | RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE; | ||||
SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode | SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode | ||||
while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN | while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN | ||||
#endif | #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_C5 = MCG_C5_PRDIV0(0); | ||||
MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(14); | MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(14); | ||||
#elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
#endif | #endif | ||||
#endif | #endif | ||||
// now program the clock dividers | // 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 | // config divisors: 240 MHz core, 60 MHz bus, 30 MHz flash, USB = 240 / 5 | ||||
// TODO: gradual ramp-up for HSRUN mode | // TODO: gradual ramp-up for HSRUN mode | ||||
#if F_BUS == 60000000 | #if F_BUS == 60000000 | ||||
#elif F_BUS == 72000000 | #elif F_BUS == 72000000 | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(7); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(7); | ||||
#elif F_BUS == 108000000 | #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 | #else | ||||
#error "This F_CPU & F_BUS combination is not supported" | #error "This F_CPU & F_BUS combination is not supported" | ||||
#endif | #endif | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV4(1); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV4(1); | ||||
#endif | #endif | ||||
#else | #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 | #endif | ||||
#if F_CPU > 16000000 | #if F_CPU > 16000000 | ||||
// wait for PLL clock to be used | // wait for PLL clock to be used | ||||
while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) ; | while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) ; | ||||
// now we're in PEE mode | // 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 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); | SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_IRC48SEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); | ||||
#else | #else | ||||
// USB uses PLL clock | |||||
SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); | SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); | ||||
#endif | #endif | ||||
#elif defined(KINETISL) | #elif defined(KINETISL) | ||||
SMC_PMCTRL = SMC_PMCTRL_RUNM(2); // VLPR mode :-) | SMC_PMCTRL = SMC_PMCTRL_RUNM(2); // VLPR mode :-) | ||||
#endif | #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 | // initialize the SysTick counter | ||||
SYST_RVR = (F_CPU / 1000) - 1; | SYST_RVR = (F_CPU / 1000) - 1; | ||||
SYST_CVR = 0; | SYST_CVR = 0; | ||||
startup_late_hook(); | startup_late_hook(); | ||||
main(); | main(); | ||||
while (1) ; | while (1) ; | ||||
} | } | ||||
// the peripheral speed (F_BUS). Serial1 & Serial2 baud | // the peripheral speed (F_BUS). Serial1 & Serial2 baud | ||||
// rates will be impacted, but most other peripherals | // rates will be impacted, but most other peripherals | ||||
// will continue functioning at the same speed. | // 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 | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // ok | ||||
#elif F_CPU == 240000000 && F_BUS == 80000000 | #elif F_CPU == 240000000 && F_BUS == 80000000 | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok | ||||
SMC_PMCTRL = SMC_PMCTRL_RUNM(3); | SMC_PMCTRL = SMC_PMCTRL_RUNM(3); | ||||
while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) {;} // wait | while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) {;} // wait | ||||
// Then configure clock for full speed | // 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); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7); | ||||
#elif F_CPU == 240000000 && F_BUS == 80000000 | #elif F_CPU == 240000000 && F_BUS == 80000000 | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 7); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 7); |
RAM (rwx) : ORIGIN = 0x1FFFE000, LENGTH = 16K | RAM (rwx) : ORIGIN = 0x1FFFE000, LENGTH = 16K | ||||
} | } | ||||
ENTRY(_VectorsFlash) | |||||
SECTIONS | SECTIONS | ||||
{ | { | ||||
} > RAM | } > RAM | ||||
_estack = ORIGIN(RAM) + LENGTH(RAM); | _estack = ORIGIN(RAM) + LENGTH(RAM); | ||||
_teensy_model_identifier = 0x1D; | |||||
} | } | ||||
RAM (rwx) : ORIGIN = 0x1FFF8000, LENGTH = 64K | RAM (rwx) : ORIGIN = 0x1FFF8000, LENGTH = 64K | ||||
} | } | ||||
ENTRY(_VectorsFlash) | |||||
SECTIONS | SECTIONS | ||||
{ | { | ||||
} > RAM | } > RAM | ||||
_estack = ORIGIN(RAM) + LENGTH(RAM); | _estack = ORIGIN(RAM) + LENGTH(RAM); | ||||
_teensy_model_identifier = 0x21; | |||||
} | } | ||||
MEMORY | MEMORY | ||||
{ | { | ||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K | FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K | ||||
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 192K | |||||
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 262136 | |||||
} | } | ||||
ENTRY(_VectorsFlash) | |||||
SECTIONS | SECTIONS | ||||
{ | { | ||||
} > RAM | } > RAM | ||||
_estack = ORIGIN(RAM) + LENGTH(RAM); | _estack = ORIGIN(RAM) + LENGTH(RAM); | ||||
_teensy_model_identifier = 0x1F; | |||||
} | } | ||||
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K | RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K | ||||
} | } | ||||
ENTRY(_VectorsFlash) | |||||
SECTIONS | SECTIONS | ||||
{ | { | ||||
} > RAM | } > RAM | ||||
_estack = ORIGIN(RAM) + LENGTH(RAM); | _estack = ORIGIN(RAM) + LENGTH(RAM); | ||||
_teensy_model_identifier = 0x22; | |||||
} | } | ||||
RAM (rwx) : ORIGIN = 0x1FFFF800, LENGTH = 8K | RAM (rwx) : ORIGIN = 0x1FFFF800, LENGTH = 8K | ||||
} | } | ||||
ENTRY(_VectorsFlash) | |||||
SECTIONS | SECTIONS | ||||
{ | { | ||||
} > RAM | } > RAM | ||||
_estack = ORIGIN(RAM) + LENGTH(RAM); | _estack = ORIGIN(RAM) + LENGTH(RAM); | ||||
_teensy_model_identifier = 0x20; | |||||
} | } | ||||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) <= 12) ? (p) + 14 : -1)) | #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 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) | #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 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) | #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 | #endif | ||||
#define digitalPinToPCICR(p) ((volatile uint8_t *)0) | #define digitalPinToPCICR(p) ((volatile uint8_t *)0) |
// The Pin Config Register is used to look up the correct interrupt table | // The Pin Config Register is used to look up the correct interrupt table | ||||
// for the corresponding port. | // for the corresponding port. | ||||
inline voidFuncPtr* getIsrTable(volatile uint32_t *config) { | |||||
static inline voidFuncPtr* getIsrTable(volatile uint32_t *config) { | |||||
voidFuncPtr* isr_table = NULL; | voidFuncPtr* isr_table = NULL; | ||||
if(&PORTA_PCR0 <= config && config <= &PORTA_PCR31) isr_table = isr_table_portA; | 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; | else if(&PORTB_PCR0 <= config && config <= &PORTB_PCR31) isr_table = isr_table_portB; | ||||
#endif | #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_MOD (61440 - 1) | ||||
#define DEFAULT_FTM_PRESCALE 2 | #define DEFAULT_FTM_PRESCALE 2 | ||||
#elif F_TIMER == 108000000 | #elif F_TIMER == 108000000 | ||||
TPM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); | TPM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); | ||||
#endif | #endif | ||||
analog_init(); | 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 | // 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/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 | // 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(); | usb_init(); | ||||
delay(350); | |||||
delay(TEENSY_INIT_USB_DELAY_AFTER); | |||||
} | } | ||||
} | } | ||||
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) | uint8_t digitalRead(uint8_t pin) | ||||
{ | { | ||||
if (pin >= CORE_NUM_DIGITAL) return 0; | if (pin >= CORE_NUM_DIGITAL) return 0; | ||||
} | } | ||||
// TODO: verify these result in correct timeouts... | // 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 | #define PULSEIN_LOOPS_PER_USEC 33 | ||||
#elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
#define PULSEIN_LOOPS_PER_USEC 31 | #define PULSEIN_LOOPS_PER_USEC 31 |
#define rts_assert() *(rts_pin+8) = rts_mask; | #define rts_assert() *(rts_pin+8) = rts_mask; | ||||
#define rts_deassert() *(rts_pin+4) = rts_mask; | #define rts_deassert() *(rts_pin+4) = rts_mask; | ||||
#endif | #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_head = 0; | ||||
static volatile uint16_t tx_buffer_tail = 0; | static volatile uint16_t tx_buffer_tail = 0; | ||||
#else | #else | ||||
static volatile uint8_t tx_buffer_head = 0; | static volatile uint8_t tx_buffer_head = 0; | ||||
static volatile uint8_t tx_buffer_tail = 0; | static volatile uint8_t tx_buffer_tail = 0; | ||||
#endif | #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_head = 0; | ||||
static volatile uint16_t rx_buffer_tail = 0; | static volatile uint16_t rx_buffer_tail = 0; | ||||
#else | #else | ||||
case 26: CORE_PIN26_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | case 26: CORE_PIN26_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | ||||
#endif | #endif | ||||
} | } | ||||
UART0_S1; | |||||
UART0_D; // clear leftover error status | |||||
rx_buffer_head = 0; | rx_buffer_head = 0; | ||||
rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); |
#define rts_assert() *(rts_pin+8) = rts_mask; | #define rts_assert() *(rts_pin+8) = rts_mask; | ||||
#define rts_deassert() *(rts_pin+4) = rts_mask; | #define rts_deassert() *(rts_pin+4) = rts_mask; | ||||
#endif | #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_head = 0; | ||||
static volatile uint16_t tx_buffer_tail = 0; | static volatile uint16_t tx_buffer_tail = 0; | ||||
#else | #else | ||||
static volatile uint8_t tx_buffer_head = 0; | static volatile uint8_t tx_buffer_head = 0; | ||||
static volatile uint8_t tx_buffer_tail = 0; | static volatile uint8_t tx_buffer_tail = 0; | ||||
#endif | #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_head = 0; | ||||
static volatile uint16_t rx_buffer_tail = 0; | static volatile uint16_t rx_buffer_tail = 0; | ||||
#else | #else | ||||
CORE_PIN9_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); // PTC3 | 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 | CORE_PIN10_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); // PTC4 | ||||
#endif | #endif | ||||
UART1_S1; | |||||
UART1_D; // clear leftover error status | |||||
rx_buffer_head = 0; | rx_buffer_head = 0; | ||||
rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); |
#define rts_assert() *(rts_pin+8) = rts_mask; | #define rts_assert() *(rts_pin+8) = rts_mask; | ||||
#define rts_deassert() *(rts_pin+4) = rts_mask; | #define rts_deassert() *(rts_pin+4) = rts_mask; | ||||
#endif | #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_head = 0; | ||||
static volatile uint16_t tx_buffer_tail = 0; | static volatile uint16_t tx_buffer_tail = 0; | ||||
#else | #else | ||||
static volatile uint8_t tx_buffer_head = 0; | static volatile uint8_t tx_buffer_head = 0; | ||||
static volatile uint8_t tx_buffer_tail = 0; | static volatile uint8_t tx_buffer_tail = 0; | ||||
#endif | #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_head = 0; | ||||
static volatile uint16_t rx_buffer_tail = 0; | static volatile uint16_t rx_buffer_tail = 0; | ||||
#else | #else | ||||
case 20: CORE_PIN20_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | case 20: CORE_PIN20_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | ||||
} | } | ||||
#endif | #endif | ||||
UART2_S1; | |||||
UART2_D; // clear leftover error status | |||||
rx_buffer_head = 0; | rx_buffer_head = 0; | ||||
rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); |
static volatile uint8_t *rts_pin=NULL; | static volatile uint8_t *rts_pin=NULL; | ||||
#define rts_assert() *rts_pin = 0 | #define rts_assert() *rts_pin = 0 | ||||
#define rts_deassert() *rts_pin = 1 | #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_head = 0; | ||||
static volatile uint16_t tx_buffer_tail = 0; | static volatile uint16_t tx_buffer_tail = 0; | ||||
#else | #else | ||||
static volatile uint8_t tx_buffer_head = 0; | static volatile uint8_t tx_buffer_head = 0; | ||||
static volatile uint8_t tx_buffer_tail = 0; | static volatile uint8_t tx_buffer_tail = 0; | ||||
#endif | #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_head = 0; | ||||
static volatile uint16_t rx_buffer_tail = 0; | static volatile uint16_t rx_buffer_tail = 0; | ||||
#else | #else | ||||
case 32: CORE_PIN32_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; // PTC4 | case 32: CORE_PIN32_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; // PTC4 | ||||
case 62: CORE_PIN62_CONFIG = 0; break; | case 62: CORE_PIN62_CONFIG = 0; break; | ||||
} | } | ||||
UART3_S1; | |||||
UART3_D; // clear leftover error status | |||||
rx_buffer_head = 0; | rx_buffer_head = 0; | ||||
rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); |
static volatile uint8_t *rts_pin=NULL; | static volatile uint8_t *rts_pin=NULL; | ||||
#define rts_assert() *rts_pin = 0 | #define rts_assert() *rts_pin = 0 | ||||
#define rts_deassert() *rts_pin = 1 | #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_head = 0; | ||||
static volatile uint16_t tx_buffer_tail = 0; | static volatile uint16_t tx_buffer_tail = 0; | ||||
#else | #else | ||||
static volatile uint8_t tx_buffer_head = 0; | static volatile uint8_t tx_buffer_head = 0; | ||||
static volatile uint8_t tx_buffer_tail = 0; | static volatile uint8_t tx_buffer_tail = 0; | ||||
#endif | #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_head = 0; | ||||
static volatile uint16_t rx_buffer_tail = 0; | static volatile uint16_t rx_buffer_tail = 0; | ||||
#else | #else | ||||
UART4_C2 = 0; | UART4_C2 = 0; | ||||
CORE_PIN34_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | 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); | 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_head = 0; | ||||
rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); |
static volatile uint8_t *rts_pin=NULL; | static volatile uint8_t *rts_pin=NULL; | ||||
#define rts_assert() *rts_pin = 0 | #define rts_assert() *rts_pin = 0 | ||||
#define rts_deassert() *rts_pin = 1 | #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_head = 0; | ||||
static volatile uint16_t tx_buffer_tail = 0; | static volatile uint16_t tx_buffer_tail = 0; | ||||
#else | #else | ||||
static volatile uint8_t tx_buffer_head = 0; | static volatile uint8_t tx_buffer_head = 0; | ||||
static volatile uint8_t tx_buffer_tail = 0; | static volatile uint8_t tx_buffer_tail = 0; | ||||
#endif | #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_head = 0; | ||||
static volatile uint16_t rx_buffer_tail = 0; | static volatile uint16_t rx_buffer_tail = 0; | ||||
#else | #else | ||||
UART5_C2 = 0; | UART5_C2 = 0; | ||||
CORE_PIN47_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | 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); | 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_head = 0; | ||||
rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); |
} | } | ||||
} | } | ||||
#endif // HAS_KINETISK_UART4 | |||||
#endif // HAS_KINETISK_LPUART0 |
#include <Arduino.h> | |||||
void serialEvent() __attribute__((weak)); | |||||
void serialEvent() { | |||||
} | |||||
uint8_t _serialEvent_default PROGMEM = 1; |
#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; |
#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; |
#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; |
#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 |
#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 |
#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 |
#include <Arduino.h> | |||||
void serialEventUSB1() __attribute__((weak)); | |||||
void serialEventUSB1() {} | |||||
uint8_t _serialEventUSB1_default PROGMEM = 1; |
#include <Arduino.h> | |||||
void serialEventUSB2() __attribute__((weak)); | |||||
void serialEventUSB2() {} | |||||
uint8_t _serialEventUSB2_default PROGMEM = 1; |
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#include <Arduino.h> | |||||
#include "usb_dev.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 | #ifdef AUDIO_INTERFACE // defined by usb_dev.h -> usb_desc.h | ||||
#if F_CPU >= 20000000 | #if F_CPU >= 20000000 |
#ifdef BCD_DEVICE | #ifdef BCD_DEVICE | ||||
LSB(BCD_DEVICE), MSB(BCD_DEVICE), // bcdDevice | LSB(BCD_DEVICE), MSB(BCD_DEVICE), // bcdDevice | ||||
#else | #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, | 0x00, 0x02, | ||||
#endif | |||||
#endif | #endif | ||||
1, // iManufacturer | 1, // iManufacturer | ||||
2, // iProduct | 2, // iProduct | ||||
0x95, 0x01, // Report Count (1) | 0x95, 0x01, // Report Count (1) | ||||
0x09, 0x56, // Usage (Scan Time) | 0x09, 0x56, // Usage (Scan Time) | ||||
0x81, 0x02, // Input (variable,absolute) | 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) | 0x05, 0x0D, // Usage Page (Digitizers) | ||||
0x09, 0x55, // Usage (Contact Count Maximum) | 0x09, 0x55, // Usage (Contact Count Maximum) | ||||
0x25, MULTITOUCH_FINGERS, // Logical Maximum (10) | 0x25, MULTITOUCH_FINGERS, // Logical Maximum (10) | ||||
#define CDC_DATA_INTERFACE_DESC_SIZE 0 | #define CDC_DATA_INTERFACE_DESC_SIZE 0 | ||||
#endif | #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 | #ifdef MIDI_INTERFACE | ||||
#if !defined(MIDI_NUM_CABLES) || MIDI_NUM_CABLES < 1 || MIDI_NUM_CABLES > 16 | #if !defined(MIDI_NUM_CABLES) || MIDI_NUM_CABLES < 1 || MIDI_NUM_CABLES > 16 | ||||
#error "MIDI_NUM_CABLES must be defined between 1 to 16" | #error "MIDI_NUM_CABLES must be defined between 1 to 16" | ||||
0x02, // bFunctionClass | 0x02, // bFunctionClass | ||||
0x02, // bFunctionSubClass | 0x02, // bFunctionSubClass | ||||
0x01, // bFunctionProtocol | 0x01, // bFunctionProtocol | ||||
4, // iFunction | |||||
0, // iFunction | |||||
#endif | #endif | ||||
#ifdef CDC_DATA_INTERFACE | #ifdef CDC_DATA_INTERFACE | ||||
0, // bInterval | 0, // bInterval | ||||
#endif // CDC_DATA_INTERFACE | #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 | #ifdef MIDI_INTERFACE | ||||
// Standard MS Interface Descriptor, | // Standard MS Interface Descriptor, | ||||
9, // bLength | 9, // bLength | ||||
0x06, // bInterfaceClass (0x06 = still image) | 0x06, // bInterfaceClass (0x06 = still image) | ||||
0x01, // bInterfaceSubClass | 0x01, // bInterfaceSubClass | ||||
0x01, // bInterfaceProtocol | 0x01, // bInterfaceProtocol | ||||
4, // iInterface | |||||
0, // iInterface | |||||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | ||||
7, // bLength | 7, // bLength | ||||
5, // bDescriptorType | 5, // bDescriptorType |
#include <stddef.h> | #include <stddef.h> | ||||
#define ENDPOINT_UNUSED 0x00 | #define ENDPOINT_UNUSED 0x00 | ||||
#define ENDPOINT_TRANSIMIT_ONLY 0x15 | |||||
#define ENDPOINT_TRANSMIT_ONLY 0x15 | |||||
#define ENDPOINT_RECEIVE_ONLY 0x19 | #define ENDPOINT_RECEIVE_ONLY 0x19 | ||||
#define ENDPOINT_TRANSMIT_AND_RECEIVE 0x1D | #define ENDPOINT_TRANSMIT_AND_RECEIVE 0x1D | ||||
#define ENDPOINT_RECEIVE_ISOCHRONOUS 0x18 | #define ENDPOINT_RECEIVE_ISOCHRONOUS 0x18 | ||||
#define CDC_ACM_SIZE 16 | #define CDC_ACM_SIZE 16 | ||||
#define CDC_RX_SIZE 64 | #define CDC_RX_SIZE 64 | ||||
#define CDC_TX_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 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) | #elif defined(USB_KEYBOARDONLY) | ||||
#define VENDOR_ID 0x16C0 | #define VENDOR_ID 0x16C0 | ||||
#define KEYMEDIA_ENDPOINT 4 | #define KEYMEDIA_ENDPOINT 4 | ||||
#define KEYMEDIA_SIZE 8 | #define KEYMEDIA_SIZE 8 | ||||
#define KEYMEDIA_INTERVAL 4 | #define KEYMEDIA_INTERVAL 4 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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) | #elif defined(USB_HID) | ||||
#define VENDOR_ID 0x16C0 | #define VENDOR_ID 0x16C0 | ||||
#define JOYSTICK_ENDPOINT 4 | #define JOYSTICK_ENDPOINT 4 | ||||
#define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | #define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | ||||
#define JOYSTICK_INTERVAL 2 | #define JOYSTICK_INTERVAL 2 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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) | #elif defined(USB_SERIAL_HID) | ||||
#define VENDOR_ID 0x16C0 | #define VENDOR_ID 0x16C0 | ||||
#define JOYSTICK_ENDPOINT 6 | #define JOYSTICK_ENDPOINT 6 | ||||
#define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | #define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | ||||
#define JOYSTICK_INTERVAL 1 | #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 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) | #elif defined(USB_TOUCHSCREEN) | ||||
#define VENDOR_ID 0x16C0 | #define VENDOR_ID 0x16C0 | ||||
#define KEYMEDIA_INTERVAL 4 | #define KEYMEDIA_INTERVAL 4 | ||||
#define MULTITOUCH_INTERFACE 3 // Touchscreen | #define MULTITOUCH_INTERFACE 3 // Touchscreen | ||||
#define MULTITOUCH_ENDPOINT 5 | #define MULTITOUCH_ENDPOINT 5 | ||||
#define MULTITOUCH_SIZE 8 | |||||
#define MULTITOUCH_SIZE 16 | |||||
#define MULTITOUCH_FINGERS 10 | #define MULTITOUCH_FINGERS 10 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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) | #elif defined(USB_HID_TOUCHSCREEN) | ||||
#define VENDOR_ID 0x16C0 | #define VENDOR_ID 0x16C0 | ||||
#define MOUSE_INTERVAL 2 | #define MOUSE_INTERVAL 2 | ||||
#define MULTITOUCH_INTERFACE 4 // Touchscreen | #define MULTITOUCH_INTERFACE 4 // Touchscreen | ||||
#define MULTITOUCH_ENDPOINT 5 | #define MULTITOUCH_ENDPOINT 5 | ||||
#define MULTITOUCH_SIZE 8 | |||||
#define MULTITOUCH_SIZE 16 | |||||
#define MULTITOUCH_FINGERS 10 | #define MULTITOUCH_FINGERS 10 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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) | #elif defined(USB_MIDI) | ||||
#define VENDOR_ID 0x16C0 | #define VENDOR_ID 0x16C0 | ||||
#define MIDI_TX_SIZE 64 | #define MIDI_TX_SIZE 64 | ||||
#define MIDI_RX_ENDPOINT 4 | #define MIDI_RX_ENDPOINT 4 | ||||
#define MIDI_RX_SIZE 64 | #define MIDI_RX_SIZE 64 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#elif defined(USB_MIDI4) | #elif defined(USB_MIDI4) | ||||
#define MIDI_TX_SIZE 64 | #define MIDI_TX_SIZE 64 | ||||
#define MIDI_RX_ENDPOINT 4 | #define MIDI_RX_ENDPOINT 4 | ||||
#define MIDI_RX_SIZE 64 | #define MIDI_RX_SIZE 64 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#elif defined(USB_MIDI16) | #elif defined(USB_MIDI16) | ||||
#define MIDI_TX_SIZE 64 | #define MIDI_TX_SIZE 64 | ||||
#define MIDI_RX_ENDPOINT 4 | #define MIDI_RX_ENDPOINT 4 | ||||
#define MIDI_RX_SIZE 64 | #define MIDI_RX_SIZE 64 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#elif defined(USB_MIDI_SERIAL) | #elif defined(USB_MIDI_SERIAL) | ||||
#define MIDI_TX_SIZE 64 | #define MIDI_TX_SIZE 64 | ||||
#define MIDI_RX_ENDPOINT 5 | #define MIDI_RX_ENDPOINT 5 | ||||
#define MIDI_RX_SIZE 64 | #define MIDI_RX_SIZE 64 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#elif defined(USB_MIDI4_SERIAL) | #elif defined(USB_MIDI4_SERIAL) | ||||
#define MIDI_TX_SIZE 64 | #define MIDI_TX_SIZE 64 | ||||
#define MIDI_RX_ENDPOINT 5 | #define MIDI_RX_ENDPOINT 5 | ||||
#define MIDI_RX_SIZE 64 | #define MIDI_RX_SIZE 64 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#elif defined(USB_MIDI16_SERIAL) | #elif defined(USB_MIDI16_SERIAL) | ||||
#define MIDI_TX_SIZE 64 | #define MIDI_TX_SIZE 64 | ||||
#define MIDI_RX_ENDPOINT 5 | #define MIDI_RX_ENDPOINT 5 | ||||
#define MIDI_RX_SIZE 64 | #define MIDI_RX_SIZE 64 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#elif defined(USB_RAWHID) | #elif defined(USB_RAWHID) | ||||
#define SEREMU_RX_ENDPOINT 2 | #define SEREMU_RX_ENDPOINT 2 | ||||
#define SEREMU_RX_SIZE 32 | #define SEREMU_RX_SIZE 32 | ||||
#define SEREMU_RX_INTERVAL 2 | #define SEREMU_RX_INTERVAL 2 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#elif defined(USB_FLIGHTSIM) | #elif defined(USB_FLIGHTSIM) | ||||
#define SEREMU_RX_ENDPOINT 2 | #define SEREMU_RX_ENDPOINT 2 | ||||
#define SEREMU_RX_SIZE 32 | #define SEREMU_RX_SIZE 32 | ||||
#define SEREMU_RX_INTERVAL 2 | #define SEREMU_RX_INTERVAL 2 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#elif defined(USB_FLIGHTSIM_JOYSTICK) | #elif defined(USB_FLIGHTSIM_JOYSTICK) | ||||
#define VENDOR_ID 0x16C0 | #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 {'T','e','e','n','s','y','d','u','i','n','o'} | ||||
#define MANUFACTURER_NAME_LEN 11 | #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'} | #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'} | ||||
#define JOYSTICK_ENDPOINT 5 | #define JOYSTICK_ENDPOINT 5 | ||||
#define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | #define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | ||||
#define JOYSTICK_INTERVAL 1 | #define JOYSTICK_INTERVAL 1 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#elif defined(USB_MTPDISK) | #elif defined(USB_MTPDISK) | ||||
#define SEREMU_RX_ENDPOINT 2 | #define SEREMU_RX_ENDPOINT 2 | ||||
#define SEREMU_RX_SIZE 32 | #define SEREMU_RX_SIZE 32 | ||||
#define SEREMU_RX_INTERVAL 2 | #define SEREMU_RX_INTERVAL 2 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | ||||
// TODO: Should ENDPOINT4_CONFIG be ENDPOINT_TRANSMIT_ONLY ??? | |||||
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#elif defined(USB_AUDIO) | #elif defined(USB_AUDIO) | ||||
#define AUDIO_RX_ENDPOINT 4 | #define AUDIO_RX_ENDPOINT 4 | ||||
#define AUDIO_RX_SIZE 180 | #define AUDIO_RX_SIZE 180 | ||||
#define AUDIO_SYNC_ENDPOINT 5 | #define AUDIO_SYNC_ENDPOINT 5 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | ||||
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | ||||
#define AUDIO_RX_ENDPOINT 7 | #define AUDIO_RX_ENDPOINT 7 | ||||
#define AUDIO_RX_SIZE 180 | #define AUDIO_RX_SIZE 180 | ||||
#define AUDIO_SYNC_ENDPOINT 8 | #define AUDIO_SYNC_ENDPOINT 8 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | ||||
#define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | #define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | ||||
#define AUDIO_RX_ENDPOINT 7 | #define AUDIO_RX_ENDPOINT 7 | ||||
#define AUDIO_RX_SIZE 180 | #define AUDIO_RX_SIZE 180 | ||||
#define AUDIO_SYNC_ENDPOINT 8 | #define AUDIO_SYNC_ENDPOINT 8 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | ||||
#define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | #define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | ||||
#define MULTITOUCH_ENDPOINT 15 | #define MULTITOUCH_ENDPOINT 15 | ||||
#define MULTITOUCH_SIZE 8 | #define MULTITOUCH_SIZE 8 | ||||
#define MULTITOUCH_FINGERS 10 | #define MULTITOUCH_FINGERS 10 | ||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | #define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | ||||
#define ENDPOINT3_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 ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | ||||
#define ENDPOINT7_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 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 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 ENDPOINT13_CONFIG (ENDPOINT_RECEIVE_ISOCHRONOUS|ENDPOINT_TRANSMIT_ISOCHRONOUS) | ||||
#define ENDPOINT14_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | #define ENDPOINT14_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | ||||
#define ENDPOINT15_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
#define ENDPOINT15_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
#endif | #endif | ||||
#include "usb_mem.h" | #include "usb_mem.h" | ||||
#include <string.h> // for memset | #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 | // buffer descriptor table | ||||
typedef struct { | typedef struct { | ||||
//serial_print("desc: not found\n"); | //serial_print("desc: not found\n"); | ||||
endpoint0_stall(); | endpoint0_stall(); | ||||
return; | return; | ||||
#if defined(CDC_STATUS_INTERFACE) | |||||
case 0x2221: // CDC_SET_CONTROL_LINE_STATE | 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"); | //serial_print("set control line state\n"); | ||||
break; | break; | ||||
#ifdef CDC_STATUS_INTERFACE | |||||
case 0x2321: // CDC_SEND_BREAK | case 0x2321: // CDC_SEND_BREAK | ||||
break; | break; | ||||
case 0x2021: // CDC_SET_LINE_CODING | case 0x2021: // CDC_SET_LINE_CODING | ||||
case 0x01: // OUT transaction received from host | case 0x01: // OUT transaction received from host | ||||
case 0x02: | case 0x02: | ||||
//serial_print("PID=OUT\n"); | //serial_print("PID=OUT\n"); | ||||
#ifdef CDC_STATUS_INTERFACE | |||||
if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) { | if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) { | ||||
int i; | 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); | endpoint0_transmit(NULL, 0); | ||||
} | } | ||||
#endif | |||||
#ifdef KEYBOARD_INTERFACE | #ifdef KEYBOARD_INTERFACE | ||||
if (setup.word1 == 0x02000921 && setup.word2 == ((1<<16)|KEYBOARD_INTERFACE)) { | if (setup.word1 == 0x02000921 && setup.word2 == ((1<<16)|KEYBOARD_INTERFACE)) { | ||||
keyboard_leds = buf[0]; | keyboard_leds = buf[0]; | ||||
return usb_queue_byte_count(tx_first[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) | uint32_t usb_tx_packet_count(uint32_t endpoint) | ||||
{ | { | ||||
const usb_packet_t *p; | const usb_packet_t *p; | ||||
{ | { | ||||
// TODO: initialize R0 with a code.... | // TODO: initialize R0 with a code.... | ||||
__asm__ volatile("bkpt"); | __asm__ volatile("bkpt"); | ||||
__builtin_unreachable(); | |||||
} | } | ||||
if (t == 0) usb_serial_flush_callback(); | if (t == 0) usb_serial_flush_callback(); | ||||
} | } | ||||
#endif | #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 | #ifdef SEREMU_INTERFACE | ||||
t = usb_seremu_transmit_flush_timer; | t = usb_seremu_transmit_flush_timer; | ||||
if (t) { | if (t) { | ||||
usb_init_serialnumber(); | 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].desc = 0; | ||||
table[i].addr = 0; | table[i].addr = 0; | ||||
} | } | ||||
#ifdef HAS_KINETIS_MPU | #ifdef HAS_KINETIS_MPU | ||||
MPU_RGDAAC0 |= 0x03000000; | MPU_RGDAAC0 |= 0x03000000; | ||||
#endif | #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 | // 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_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 | | USB0_CLK_RECOVER_CTRL = USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN | |
return usb_rx_byte_count_data[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 | #ifdef SEREMU_INTERFACE | ||||
extern volatile uint8_t usb_seremu_transmit_flush_timer; | extern volatile uint8_t usb_seremu_transmit_flush_timer; | ||||
extern void usb_seremu_flush_callback(void); | extern void usb_seremu_flush_callback(void); | ||||
} | } | ||||
#endif | #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 | #else // F_CPU < 20000000 | ||||
#ifdef __cplusplus | #ifdef __cplusplus |
FlightSimInteger * FlightSimInteger::last = NULL; | FlightSimInteger * FlightSimInteger::last = NULL; | ||||
FlightSimFloat * FlightSimFloat::first = NULL; | FlightSimFloat * FlightSimFloat::first = NULL; | ||||
FlightSimFloat * FlightSimFloat::last = 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::enabled = 0; | ||||
uint8_t FlightSimClass::request_id_messages = 0; | uint8_t FlightSimClass::request_id_messages = 0; | ||||
FlightSimClass::xmit(buf, 4, NULL, 0); | 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() | FlightSimInteger::FlightSimInteger() | ||||
{ | { | ||||
data.b[2] = p[8]; | data.b[2] = p[8]; | ||||
data.b[3] = p[9]; | data.b[3] = p[9]; | ||||
item->update(data.f); | 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; | break; | ||||
case 0x03: // enable/disable | case 0x03: // enable/disable | ||||
for (FlightSimCommand *p = FlightSimCommand::first; p; p = p->next) { | for (FlightSimCommand *p = FlightSimCommand::first; p; p = p->next) { | ||||
p->identify(); | 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) { | for (FlightSimInteger *p = FlightSimInteger::first; p; p = p->next) { | ||||
p->identify(); | p->identify(); | ||||
// TODO: send any dirty data | // TODO: send any dirty data |
friend class FlightSimCommand; | friend class FlightSimCommand; | ||||
friend class FlightSimInteger; | friend class FlightSimInteger; | ||||
friend class FlightSimFloat; | friend class FlightSimFloat; | ||||
/// JB | |||||
friend class FlightSimEvent; | |||||
friend class FlightSimData; | |||||
/// JB End | |||||
}; | }; | ||||
friend class FlightSimClass; | 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 | class FlightSimInteger | ||||
{ | { |
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#include "WProgram.h" | |||||
#include <Arduino.h> | |||||
#include "usb_desc.h" | #include "usb_desc.h" | ||||
#if F_CPU >= 20000000 | #if F_CPU >= 20000000 | ||||
#endif | #endif | ||||
#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 | #ifdef MIDI_INTERFACE | ||||
usb_midi_class usbMIDI; | usb_midi_class usbMIDI; | ||||
#endif | #endif | ||||
#else // F_CPU < 20 MHz | #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; | usb_serial_class Serial; | ||||
#elif (USB_DISABLED) | #elif (USB_DISABLED) | ||||
usb_serial_class Serial; | usb_serial_class Serial; | ||||
#endif | #endif | ||||
#endif // F_CPU | #endif // F_CPU | ||||
void serialEvent() __attribute__((weak)); | |||||
void serialEvent() {} |
// When the PC isn't listening, how long do we wait before discarding data? | // When the PC isn't listening, how long do we wait before discarding data? | ||||
#define TX_TIMEOUT_MSEC 30 | #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) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | ||||
#elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
// When the PC isn't listening, how long do we wait before discarding data? | // When the PC isn't listening, how long do we wait before discarding data? | ||||
#define TX_TIMEOUT_MSEC 50 | #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) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | ||||
#elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
void set_key4(uint8_t c) { keyboard_keys[3] = c; } | void set_key4(uint8_t c) { keyboard_keys[3] = c; } | ||||
void set_key5(uint8_t c) { keyboard_keys[4] = c; } | void set_key5(uint8_t c) { keyboard_keys[4] = c; } | ||||
void set_key6(uint8_t c) { keyboard_keys[5] = c; } | void set_key6(uint8_t c) { keyboard_keys[5] = c; } | ||||
#ifdef KEYMEDIA_INTERFACE | |||||
void set_media(uint16_t c) { | void set_media(uint16_t c) { | ||||
if (c == 0) { | if (c == 0) { | ||||
usb_keymedia_release_all(); | usb_keymedia_release_all(); | ||||
press(c); | press(c); | ||||
} | } | ||||
} | } | ||||
#endif | |||||
void send_now(void) { usb_keyboard_send(); } | void send_now(void) { usb_keyboard_send(); } | ||||
void press(uint16_t n) { usb_keyboard_press_keycode(n); } | void press(uint16_t n) { usb_keyboard_press_keycode(n); } | ||||
void release(uint16_t n) { usb_keyboard_release_keycode(n); } | void release(uint16_t n) { usb_keyboard_release_keycode(n); } |
// When the PC isn't listening, how long do we wait before discarding data? | // When the PC isn't listening, how long do we wait before discarding data? | ||||
#define TX_TIMEOUT_MSEC 40 | #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) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | ||||
#elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | ||||
#endif | #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) | void usb_midi_write_packed(uint32_t n) | ||||
{ | { | ||||
uint32_t index, wait_count=0; | uint32_t index, wait_count=0; | ||||
} else { | } else { | ||||
tx_packet->len = MIDI_TX_SIZE; | tx_packet->len = MIDI_TX_SIZE; | ||||
usb_tx(MIDI_TX_ENDPOINT, tx_packet); | usb_tx(MIDI_TX_ENDPOINT, tx_packet); | ||||
tx_packet = usb_malloc(); | |||||
tx_packet = NULL; | |||||
} | } | ||||
tx_noautoflush = 0; | tx_noautoflush = 0; | ||||
} | } | ||||
if (tx_noautoflush == 0 && tx_packet && tx_packet->index > 0) { | if (tx_noautoflush == 0 && tx_packet && tx_packet->index > 0) { | ||||
tx_packet->len = tx_packet->index * 4; | tx_packet->len = tx_packet->index * 4; | ||||
usb_tx(MIDI_TX_ENDPOINT, tx_packet); | usb_tx(MIDI_TX_ENDPOINT, tx_packet); | ||||
tx_packet = usb_malloc(); | |||||
tx_packet = NULL; | |||||
} | } | ||||
} | } | ||||
// When the PC isn't listening, how long do we wait before discarding data? | // When the PC isn't listening, how long do we wait before discarding data? | ||||
#define TX_TIMEOUT_MSEC 30 | #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) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | ||||
#elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
// too short, we risk losing data during the stalls that are common with ordinary desktop | // 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. | // software. If it's too long, we stall the user's program when no software is running. | ||||
#define TX_TIMEOUT_MSEC 30 | #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) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | ||||
#elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
// too short, we risk losing data during the stalls that are common with ordinary desktop | // 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. | // software. If it's too long, we stall the user's program when no software is running. | ||||
#define TX_TIMEOUT_MSEC 70 | #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) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | ||||
#elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
#if F_CPU >= 20000000 && !defined(USB_DISABLED) | #if F_CPU >= 20000000 && !defined(USB_DISABLED) | ||||
#include "core_pins.h" // for millis() | |||||
// C language implementation | // C language implementation | ||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
extern "C" { | extern "C" { | ||||
int usb_serial_write(const void *buffer, uint32_t size); | int usb_serial_write(const void *buffer, uint32_t size); | ||||
int usb_serial_write_buffer_free(void); | int usb_serial_write_buffer_free(void); | ||||
void usb_serial_flush_output(void); | void usb_serial_flush_output(void); | ||||
void usb_serial_flush_callback(void); | |||||
extern uint32_t usb_cdc_line_coding[2]; | extern uint32_t usb_cdc_line_coding[2]; | ||||
extern volatile uint32_t usb_cdc_line_rtsdtr_millis; | extern volatile uint32_t usb_cdc_line_rtsdtr_millis; | ||||
extern volatile uint32_t systick_millis_count; | extern volatile uint32_t systick_millis_count; | ||||
uint8_t numbits(void) { return usb_cdc_line_coding[1] >> 16; } | 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 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; } | 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 readBytes(char *buffer, size_t length) { | ||||
size_t count=0; | size_t count=0; |
/* 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 |
/* 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_ |
/* 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 |
/* 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_ |
// 5: Y msb | // 5: Y msb | ||||
// 6: scan time lsb | // 6: scan time lsb | ||||
// 7: scan time msb | // 7: scan time msb | ||||
// 8: contact count | |||||
// Called by the start-of-frame interrupt. | // Called by the start-of-frame interrupt. | ||||
// | // | ||||
void usb_touchscreen_update_callback(void) | void usb_touchscreen_update_callback(void) | ||||
{ | { | ||||
uint8_t contact_count = 0; | |||||
if (scan_index == 0) { | if (scan_index == 0) { | ||||
if (usb_tx_packet_count(MULTITOUCH_ENDPOINT) > 1) { | if (usb_tx_packet_count(MULTITOUCH_ENDPOINT) > 1) { | ||||
// wait to begin another scan if if more than | // wait to begin another scan if if more than | ||||
} | } | ||||
scan_timestamp = millis() * 10; | scan_timestamp = millis() * 10; | ||||
scan_count = 0; | 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) { | while (scan_index < MULTITOUCH_FINGERS) { | ||||
uint32_t press = pressure[scan_index]; | uint32_t press = pressure[scan_index]; | ||||
uint32_t id = contactid[scan_index]; | uint32_t id = contactid[scan_index]; | ||||
*(tx_packet->buf + 5) = ypos[scan_index] >> 8; | *(tx_packet->buf + 5) = ypos[scan_index] >> 8; | ||||
*(tx_packet->buf + 6) = scan_timestamp; | *(tx_packet->buf + 6) = scan_timestamp; | ||||
*(tx_packet->buf + 7) = scan_timestamp >> 8; | *(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); | usb_tx(MULTITOUCH_ENDPOINT, tx_packet); | ||||
scan_index++; | scan_index++; | ||||
return; | return; |
#ifdef ENDPOINT_UNUSED | #ifdef ENDPOINT_UNUSED | ||||
#undef ENDPOINT_UNUSED | #undef ENDPOINT_UNUSED | ||||
#endif | #endif | ||||
#ifdef ENDPOINT_TRANSIMIT_ONLY | |||||
#undef ENDPOINT_TRANSIMIT_ONLY | |||||
#ifdef ENDPOINT_TRANSMIT_ONLY | |||||
#undef ENDPOINT_TRANSMIT_ONLY | |||||
#endif | #endif | ||||
#ifdef ENDPOINT_RECEIVE_ONLY | #ifdef ENDPOINT_RECEIVE_ONLY | ||||
#undef ENDPOINT_RECEIVE_ONLY | #undef ENDPOINT_RECEIVE_ONLY | ||||
#ifdef CDC_TX_SIZE | #ifdef CDC_TX_SIZE | ||||
#undef CDC_TX_SIZE | #undef CDC_TX_SIZE | ||||
#endif | #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 | #ifdef SEREMU_INTERFACE | ||||
#undef SEREMU_INTERFACE | #undef SEREMU_INTERFACE | ||||
#endif | #endif |
#include <stdint.h> | #include <stdint.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <stdbool.h> | |||||
#include "binary.h" | #include "binary.h" | ||||
#include "core_id.h" | #include "core_id.h" | ||||
#include "core_pins.h" | #include "core_pins.h" | ||||
{ | { | ||||
long x = _x, in_min = _in_min, in_max = _in_max, out_min = _out_min, out_max = _out_max; | long x = _x, in_min = _in_min, in_max = _in_max, out_min = _out_min, out_max = _out_max; | ||||
// Arduino's traditional algorithm | // 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 | // 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)) { | 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; | return (x - in_min) * (out_max - out_min+1) / (in_max - in_min+1) + out_min; | ||||
} else { | } else { | ||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; | 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 | // 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> | template <class T, class A, class B, class C, class D> | ||||
{ | { | ||||
return (x - (T)in_min) * ((T)out_max - (T)out_min) / ((T)in_max - (T)in_min) + (T)out_min; | 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> | #include <utility> | ||||
// https://forum.pjrc.com/threads/44596-Teensyduino-1-37-Beta-2-(Arduino-1-8-3-support)?p=145150&viewfull=1#post145150 | // 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> | template<class A, class B> | ||||
typedef bool boolean; | typedef bool boolean; | ||||
#else | #else | ||||
typedef uint8_t boolean; | typedef uint8_t boolean; | ||||
#define false 0 | |||||
#define true (!false) | |||||
#endif | #endif | ||||
#endif | #endif |
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#include "core_pins.h" | |||||
#include "HardwareSerial.h" | |||||
#include "usb_serial.h" | |||||
#include "usb_seremu.h" | |||||
#include <Arduino.h> | |||||
#include "EventResponder.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) __attribute__ ((weak)); | ||||
void yield(void) | void yield(void) | ||||
{ | { | ||||
static uint8_t running=0; | static uint8_t running=0; | ||||
if (!yield_active_check_flags) return; // nothing to do | |||||
if (running) return; // TODO: does this need to be atomic? | if (running) return; // TODO: does this need to be atomic? | ||||
running = 1; | 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 | #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 | #endif | ||||
if (yield_active_check_flags & YIELD_CHECK_HARDWARE_SERIAL) { | |||||
HardwareSerial::processSerialEventsList(); | |||||
} | |||||
running = 0; | running = 0; | ||||
EventResponder::runFromYield(); | |||||
if (yield_active_check_flags & YIELD_CHECK_EVENT_RESPONDER) EventResponder::runFromYield(); | |||||
}; | }; |
// This header file is in the public domain. | |||||
#ifndef Arduino_h | |||||
#define Arduino_h | |||||
#include "WProgram.h" | |||||
#include "pins_arduino.h" | |||||
#endif |
/* 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"); | |||||
} | |||||