Please use this Github issue *only for reporting a specific problem*. | |||||
Please **do not use Github issues for project troubleshooting.** Post on the PJRC Forum for Teensy-related troubleshooting. | |||||
https://forum.pjrc.com/forum.php | |||||
General suggestions for new features should also be discussed on the forum. Github issues for new features are usually only appropriate after decisions are made via forum discussion. | |||||
Also check out the most common troubleshooting page: | |||||
https://www.pjrc.com/teensy/troubleshoot.html | |||||
Before reporting any issue, please make sure you are using the latest Teensyduino version. | |||||
https://www.pjrc.com/teensy/td_download.html | |||||
If a beta test version is available, please check whether it fixes the issue. | |||||
When reporting any issue, please try to provide complete information. The following are almost always needed: | |||||
- A complete copy of the code (which can be copied into Arduino and run on a Teensy board) which reproduces the problem is usually needed to investigate any issue. Please try to trim your program to the minimum necessary, ideally not depending on extra hardware if possible. But a complete program that can be copied into Arduino without guesswork is essential. Please do not submit this Github issue with only code fragments or a vague description of code to recreate the issue. | |||||
- Which Teensy board(s) are you using. | |||||
- If other hardware is needed to reproduce the issue, please provide links or part numbers where this hardware can be purchased. Very specific details showing how the hardware is connected also help. Post photos if needed. | |||||
- Which version of Teensyduino and Arduino were used, what Tools menu settings were chosen, and which operating system was used. If other software is needed, please be specific. |
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: | ||||
# language keywords - Arduino doesn't define these, but probably should | # language keywords - Arduino doesn't define these, but probably should | ||||
volatile LITERAL2 | |||||
volatile LITERAL1 | |||||
constexpr LITERAL1 | |||||
alignas LITERAL1 | |||||
alignof LITERAL1 | |||||
nullptr LITERAL1 | |||||
noexcept LITERAL1 | |||||
static_assert LITERAL1 | |||||
thread_local LITERAL1 | |||||
# teensy specific functions | # teensy specific functions | ||||
elapsedMillis LITERAL2 | |||||
elapsedMicros LITERAL2 | |||||
elapsedMillis LITERAL1 | |||||
elapsedMicros LITERAL1 | |||||
readString KEYWORD2 | readString KEYWORD2 | ||||
readStringUntil KEYWORD2 | readStringUntil KEYWORD2 | ||||
analogReadRes KEYWORD2 | analogReadRes KEYWORD2 | ||||
transmitterEnable KEYWORD2 | transmitterEnable KEYWORD2 | ||||
attachRts KEYWORD2 | attachRts KEYWORD2 | ||||
attachCts KEYWORD2 | attachCts KEYWORD2 | ||||
PROGMEM LITERAL2 | |||||
DMAMEM LITERAL2 | |||||
FASTRUN LITERAL2 | |||||
PROGMEM LITERAL1 | |||||
FLASHMEM LITERAL1 | |||||
DMAMEM LITERAL1 | |||||
FASTRUN LITERAL1 | |||||
Serial4 KEYWORD1 | |||||
Serial5 KEYWORD1 | |||||
Serial6 KEYWORD1 | |||||
Serial7 KEYWORD1 | |||||
setRX KEYWORD2 | |||||
setTX KEYWORD2 | |||||
write9bit KEYWORD2 | |||||
clear KEYWORD2 | |||||
EventResponder LITERAL1 | |||||
EventResponderRef LITERAL1 | |||||
attachImmediate KEYWORD2 | |||||
triggerEvent KEYWORD2 | |||||
clearEvent KEYWORD2 | |||||
getStatus KEYWORD2 | |||||
getData KEYWORD2 | |||||
setContext KEYWORD2 | |||||
getContext KEYWORD2 | |||||
waitForEvent KEYWORD2 | |||||
MillisTimer LITERAL1 | |||||
beginRepeating KEYWORD2 | |||||
# removed by Arduino 1.0, but still in Teensyduino | |||||
BYTE LITERAL2 | |||||
# removed by Arduino 1.0, now also removed from Teensyduino | |||||
#BYTE LITERAL1 | |||||
# Arduino constants | # Arduino constants | ||||
A0 LITERAL1 | A0 LITERAL1 | ||||
A20 LITERAL1 | A20 LITERAL1 | ||||
A21 LITERAL1 | A21 LITERAL1 | ||||
A22 LITERAL1 | A22 LITERAL1 | ||||
A23 LITERAL1 | |||||
A24 LITERAL1 | |||||
A25 LITERAL1 | |||||
A26 LITERAL1 | |||||
SS LITERAL1 | SS LITERAL1 | ||||
MOSI LITERAL1 | MOSI LITERAL1 | ||||
MISO LITERAL1 | MISO LITERAL1 | ||||
NOT_AN_INTERRUPT LITERAL1 | NOT_AN_INTERRUPT LITERAL1 | ||||
digitalPinToInterrupt KEYWORD2 | digitalPinToInterrupt KEYWORD2 | ||||
# HardwareSerial modes | |||||
SERIAL_7E1 LITERAL1 | |||||
SERIAL_7O1 LITERAL1 | |||||
SERIAL_8N1 LITERAL1 | |||||
SERIAL_8E1 LITERAL1 | |||||
SERIAL_8O1 LITERAL1 | |||||
SERIAL_7E1_RXINV LITERAL1 | |||||
SERIAL_7O1_RXINV LITERAL1 | |||||
SERIAL_8N1_RXINV LITERAL1 | |||||
SERIAL_8E1_RXINV LITERAL1 | |||||
SERIAL_8O1_RXINV LITERAL1 | |||||
SERIAL_7E1_TXINV LITERAL1 | |||||
SERIAL_7O1_TXINV LITERAL1 | |||||
SERIAL_8N1_TXINV LITERAL1 | |||||
SERIAL_8E1_TXINV LITERAL1 | |||||
SERIAL_8O1_TXINV LITERAL1 | |||||
SERIAL_7E1_RXINV_TXINV LITERAL1 | |||||
SERIAL_7O1_RXINV_TXINV LITERAL1 | |||||
SERIAL_8N1_RXINV_TXINV LITERAL1 | |||||
SERIAL_8E1_RXINV_TXINV LITERAL1 | |||||
SERIAL_8O1_RXINV_TXINV LITERAL1 | |||||
SERIAL_8E2 LITERAL1 | |||||
SERIAL_8O2 LITERAL1 | |||||
SERIAL_8E2_RXINV LITERAL1 | |||||
SERIAL_8O2_RXINV LITERAL1 | |||||
SERIAL_8E2_TXINV LITERAL1 | |||||
SERIAL_8O2_TXINV LITERAL1 | |||||
SERIAL_8E2_RXINV_TXINV LITERAL1 | |||||
SERIAL_8O2_RXINV_TXINV LITERAL1 | |||||
SERIAL_8N2 LITERAL1 | |||||
SERIAL_8N2_RXINV LITERAL1 | |||||
SERIAL_8N2_TXINV LITERAL1 | |||||
SERIAL_8N2_RXINV_TXINV LITERAL1 | |||||
SERIAL_9N1 LITERAL1 | |||||
SERIAL_9E1 LITERAL1 | |||||
SERIAL_9O1 LITERAL1 | |||||
SERIAL_9N1_RXINV LITERAL1 | |||||
SERIAL_9E1_RXINV LITERAL1 | |||||
SERIAL_9O1_RXINV LITERAL1 | |||||
SERIAL_9N1_TXINV LITERAL1 | |||||
SERIAL_9E1_TXINV LITERAL1 | |||||
SERIAL_9O1_TXINV LITERAL1 | |||||
SERIAL_9N1_RXINV_TXINV LITERAL1 | |||||
SERIAL_9E1_RXINV_TXINV LITERAL1 | |||||
SERIAL_9O1_RXINV_TXINV LITERAL1 | |||||
# Teensy 3.x advanced pin states | # Teensy 3.x advanced pin states | ||||
OUTPUT_OPENDRAIN LITERAL1 | OUTPUT_OPENDRAIN LITERAL1 | ||||
INPUT_PULLUP LITERAL1 | |||||
INPUT_PULLDOWN LITERAL1 | |||||
INPUT_PULLUP LITERAL1 | |||||
INPUT_PULLDOWN LITERAL1 | |||||
INPUT_DISABLE LITERAL1 | |||||
# String functions | # String functions | ||||
copy KEYWORD2 | copy KEYWORD2 | ||||
KEY_MEDIA_PREV_TRACK LITERAL1 | KEY_MEDIA_PREV_TRACK LITERAL1 | ||||
KEY_MEDIA_STOP LITERAL1 | KEY_MEDIA_STOP LITERAL1 | ||||
KEY_MEDIA_EJECT LITERAL1 | KEY_MEDIA_EJECT LITERAL1 | ||||
KEY_MEDIA_PLAY LITERAL1 | |||||
KEY_MEDIA_PAUSE LITERAL1 | |||||
KEY_MEDIA_RECORD LITERAL1 | |||||
KEY_MEDIA_REWIND LITERAL1 | |||||
KEY_MEDIA_FAST_FORWARD LITERAL1 | |||||
KEY_MEDIA_PLAY_SKIP LITERAL1 | |||||
KEY_SYSTEM_POWER_DOWN LITERAL1 | |||||
KEY_SYSTEM_SLEEP LITERAL1 | |||||
KEY_SYSTEM_WAKE_UP LITERAL1 | |||||
KEY_A LITERAL1 | KEY_A LITERAL1 | ||||
KEY_B LITERAL1 | KEY_B LITERAL1 | ||||
KEY_C LITERAL1 | KEY_C LITERAL1 | ||||
usbMIDI KEYWORD1 | usbMIDI KEYWORD1 | ||||
sendNoteOff KEYWORD2 | sendNoteOff KEYWORD2 | ||||
sendNoteOn KEYWORD2 | sendNoteOn KEYWORD2 | ||||
sendAfterTouchPoly KEYWORD2 | |||||
sendPolyPressure KEYWORD2 | sendPolyPressure KEYWORD2 | ||||
sendControlChange KEYWORD2 | sendControlChange KEYWORD2 | ||||
sendProgramChange KEYWORD2 | sendProgramChange KEYWORD2 | ||||
sendAfterTouch KEYWORD2 | sendAfterTouch KEYWORD2 | ||||
sendPitchBend KEYWORD2 | sendPitchBend KEYWORD2 | ||||
sendSysEx KEYWORD2 | sendSysEx KEYWORD2 | ||||
sendRealTime KEYWORD2 | |||||
sendTimeCodeQuarterFrame KEYWORD2 | |||||
sendSongPosition KEYWORD2 | |||||
sendSongSelect KEYWORD2 | |||||
sendTuneRequest KEYWORD2 | |||||
beginRpn KEYWORD2 | |||||
sendRpnValue KEYWORD2 | |||||
sendRpnValue KEYWORD2 | |||||
sendRpnIncrement KEYWORD2 | |||||
sendRpnDecrement KEYWORD2 | |||||
endRpn KEYWORD2 | |||||
beginNrpn KEYWORD2 | |||||
sendNrpnValue KEYWORD2 | |||||
sendNrpnValue KEYWORD2 | |||||
sendNrpnIncrement KEYWORD2 | |||||
sendNrpnDecrement KEYWORD2 | |||||
endNrpn KEYWORD2 | |||||
send KEYWORD2 | |||||
analog2velocity KEYWORD2 | analog2velocity KEYWORD2 | ||||
getType KEYWORD2 | getType KEYWORD2 | ||||
getCable KEYWORD2 | |||||
getChannel KEYWORD2 | getChannel KEYWORD2 | ||||
getData1 KEYWORD2 | getData1 KEYWORD2 | ||||
getData2 KEYWORD2 | getData2 KEYWORD2 | ||||
setHandleProgramChange KEYWORD2 | setHandleProgramChange KEYWORD2 | ||||
setHandleAfterTouch KEYWORD2 | setHandleAfterTouch KEYWORD2 | ||||
setHandlePitchChange KEYWORD2 | setHandlePitchChange KEYWORD2 | ||||
setHandlePitchChange KEYWORD2 | |||||
NoteOff LITERAL1 | NoteOff LITERAL1 | ||||
NoteOn LITERAL1 | NoteOn LITERAL1 | ||||
AfterTouchPoly LITERAL1 | AfterTouchPoly LITERAL1 | ||||
AfterTouchChannel LITERAL1 | AfterTouchChannel LITERAL1 | ||||
PitchBend LITERAL1 | PitchBend LITERAL1 | ||||
SystemExclusive LITERAL1 | SystemExclusive LITERAL1 | ||||
TimeCodeQuarterFrame LITERAL1 | |||||
SongPosition LITERAL1 | |||||
SongSelect LITERAL1 | |||||
TuneRequest LITERAL1 | |||||
Clock LITERAL1 | |||||
Start LITERAL1 | |||||
Continue LITERAL1 | |||||
Stop LITERAL1 | |||||
ActiveSensing LITERAL1 | |||||
SystemReset LITERAL1 | |||||
midiEventPacket_t LITERAL1 | |||||
MidiUSB KEYWORD1 | |||||
sendMIDI KEYWORD2 | |||||
# USB RawHID | # USB RawHID | ||||
RawHID KEYWORD1 | RawHID KEYWORD1 |
// empty Keyboard.h file, for compability with Arduino's Keyboard examples |
#ifndef MIDIUSB_h | |||||
#define MIDIUSB_h | |||||
// For compatibility with Arduino's MIDIUSB library | |||||
#ifdef __cplusplus | |||||
#if !defined(USB_MIDI) | |||||
#error "Please select MIDI in Tools > USB Type to use MIDIUSB.h" | |||||
#endif | |||||
#include "usb_api.h" | |||||
typedef struct { | |||||
struct { | |||||
uint8_t header; | |||||
uint8_t byte1; | |||||
uint8_t byte2; | |||||
uint8_t byte3; | |||||
}; | |||||
} midiEventPacket_t; | |||||
class MIDI_ | |||||
{ | |||||
public: | |||||
constexpr MIDI_(void) { } | |||||
uint32_t available(void) { | |||||
return usbMIDI.midiusb_available(); | |||||
} | |||||
midiEventPacket_t read(void) { | |||||
midiEventPacket_t event; | |||||
usbMIDI.midiusb_read((uint8_t *)&event); | |||||
return event; | |||||
} | |||||
void flush(void) { | |||||
usbMIDI.send_now(); | |||||
} | |||||
void sendMIDI(midiEventPacket_t event) { | |||||
usbMIDI.send_raw(event.header, event.byte1, event.byte2, event.byte3); | |||||
} | |||||
size_t write(const uint8_t *buffer, size_t size) { | |||||
// TODO - is this really needed? | |||||
return 0; | |||||
} | |||||
operator bool() { | |||||
// TODO - is this really needed? | |||||
return true; | |||||
} | |||||
}; | |||||
extern MIDI_ MidiUSB; | |||||
#endif // __cplusplus | |||||
#endif // MIDIUSB_h |
// empty Mouse.h file, for compability with Arduino's Mouse examples |
#define HEX 16 | #define HEX 16 | ||||
#define OCT 8 | #define OCT 8 | ||||
#define BIN 2 | #define BIN 2 | ||||
#define BYTE 0 | |||||
// BYTE was defined in very old versions of Arduino | |||||
// maybe this now causes more trouble than it's worth? | |||||
//#ifndef BYTE | |||||
//#define BYTE 0 | |||||
//#endif | |||||
class __FlashStringHelper; | class __FlashStringHelper; | ||||
#if ARDUINO >= 100 | |||||
class Print | class Print | ||||
{ | { | ||||
public: | public: | ||||
Print() : write_error(0) {} | |||||
virtual size_t write(uint8_t b); | |||||
constexpr Print() : write_error(0) {} | |||||
virtual size_t write(uint8_t b) = 0; | |||||
size_t write(const char *str) { return write((const uint8_t *)str, strlen(str)); } | size_t write(const char *str) { return write((const uint8_t *)str, strlen(str)); } | ||||
virtual size_t write(const uint8_t *buffer, size_t size); | virtual size_t write(const uint8_t *buffer, size_t size); | ||||
virtual int availableForWrite(void) { return 0; } | |||||
virtual void flush() { } | |||||
size_t write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); } | size_t write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); } | ||||
size_t print(const String &s); | size_t print(const String &s); | ||||
size_t print(char c) { return write((uint8_t)c); } | size_t print(char c) { return write((uint8_t)c); } | ||||
size_t printFloat(double n, uint8_t digits); | size_t printFloat(double n, uint8_t digits); | ||||
}; | }; | ||||
#else | |||||
class Print | |||||
{ | |||||
public: | |||||
virtual void write(uint8_t); | |||||
virtual void write(const char *str); | |||||
virtual void write(const uint8_t *buffer, size_t size); | |||||
void print(const String &s); | |||||
void print(char c) { write((uint8_t)c); } | |||||
void print(const char s[]) { write(s); } | |||||
void print(const __FlashStringHelper *f); | |||||
void print(uint8_t b) { write(b); } | |||||
void print(int n) { print((long)n); } | |||||
void print(unsigned int n) { printNumber(n, 0, 10); } | |||||
void print(long n); | |||||
void print(unsigned long n) { printNumber(n, 0, 10); } | |||||
void print(unsigned char n, int base) { printNumber(n, 0, base); } | |||||
void print(int n, int base) { (base == 10) ? print(n) : printNumber(n, 0, base); } | |||||
void print(unsigned int n, int base) { printNumber(n, 0, base); } | |||||
void print(long n, int base) { (base == 10) ? print(n) : printNumber(n, 0, base); } | |||||
void print(unsigned long n, int base) { printNumber(n, 0, base); } | |||||
void print(double n, int digits = 2) { printFloat(n, digits); } | |||||
void println(void); | |||||
void println(const String &s) { print(s); println(); } | |||||
void println(char c) { print(c); println(); } | |||||
void println(const char s[]) { print(s); println(); } | |||||
void println(const __FlashStringHelper *f) { print(f); println(); } | |||||
void println(uint8_t b) { print(b); println(); } | |||||
void println(int n) { print(n); println(); } | |||||
void println(unsigned int n) { print(n); println(); } | |||||
void println(long n) { print(n); println(); } | |||||
void println(unsigned long n) { print(n); println(); } | |||||
void println(unsigned char n, int base) { print(n, base); println(); } | |||||
void println(int n, int base) { print(n, base); println(); } | |||||
void println(unsigned int n, int base) { print(n, base); println(); } | |||||
void println(long n, int base) { print(n, base); println(); } | |||||
void println(unsigned long n, int base) { print(n, base); println(); } | |||||
void println(double n, int digits = 2) { print(n, digits); println(); } | |||||
private: | |||||
void printNumberDec(unsigned long n, uint8_t sign); | |||||
void printNumberHex(unsigned long n); | |||||
void printNumberBin(unsigned long n); | |||||
void printNumberAny(unsigned long n, uint8_t base); | |||||
inline size_t printNumber(unsigned long n, uint8_t sign, uint8_t base) __attribute__((always_inline)) { | |||||
if (base == 0) { write((uint8_t)n); return; } | |||||
if (base == 10 || base < 2) { printNumberDec(n, sign); return; } | |||||
if (base == 16) { printNumberHex(n); return; } | |||||
if (base == 2) { printNumberBin(n); return; } | |||||
printNumberAny(n, base); | |||||
} | |||||
void printFloat(double n, uint8_t digits); | |||||
}; | |||||
#endif | |||||
#endif | #endif |
} | } | ||||
// find returns true if the target string is found | // find returns true if the target string is found | ||||
bool Stream::find(char *target) | |||||
bool Stream::find(const char *target) | |||||
{ | { | ||||
return findUntil(target, NULL); | return findUntil(target, NULL); | ||||
} | } | ||||
// reads data from the stream until the target string of given length is found | // reads data from the stream until the target string of given length is found | ||||
// returns true if target string is found, false if timed out | // returns true if target string is found, false if timed out | ||||
bool Stream::find(char *target, size_t length) | |||||
bool Stream::find(const char *target, size_t length) | |||||
{ | { | ||||
return findUntil(target, length, NULL, 0); | return findUntil(target, length, NULL, 0); | ||||
} | } | ||||
// 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(char *target, char *terminator) | |||||
bool Stream::findUntil(const char *target, char *terminator) | |||||
{ | { | ||||
return findUntil(target, strlen(target), terminator, strlen(terminator)); | return findUntil(target, strlen(target), terminator, strlen(terminator)); | ||||
} | } | ||||
// 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 | ||||
// search terminated if the terminator string is found | // search terminated if the terminator string is found | ||||
// returns true if target string is found, false if terminated or timed out | // returns true if target string is found, false if terminated or timed out | ||||
bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen) | |||||
bool Stream::findUntil(const char *target, size_t targetLen, char *terminator, size_t termLen) | |||||
{ | { | ||||
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; |
virtual void flush() = 0; | virtual void flush() = 0; | ||||
void setTimeout(unsigned long timeout); | void setTimeout(unsigned long timeout); | ||||
bool find(char *target); | |||||
bool find(uint8_t *target) { return find ((char *)target); } | |||||
bool find(char *target, size_t length); | |||||
bool find(uint8_t *target, size_t length) { return find ((char *)target, length); } | |||||
bool findUntil(char *target, char *terminator); | |||||
bool findUntil(uint8_t *target, char *terminator) { return findUntil((char *)target, terminator); } | |||||
bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); | |||||
bool findUntil(uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((char *)target, targetLen, terminate, termLen); } | |||||
bool find(const char *target); | |||||
bool find(const uint8_t *target) { return find ((const char *)target); } | |||||
bool find(const char *target, size_t length); | |||||
bool find(const uint8_t *target, size_t length) { return find ((const char *)target, length); } | |||||
bool findUntil(const char *target, char *terminator); | |||||
bool findUntil(const uint8_t *target, char *terminator) { return findUntil((const char *)target, terminator); } | |||||
bool findUntil(const char *target, size_t targetLen, char *terminate, size_t termLen); | |||||
bool findUntil(const uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((const char *)target, targetLen, terminate, termLen); } | |||||
long parseInt(); | long parseInt(); | ||||
long parseInt(char skipChar); | long parseInt(char skipChar); | ||||
float parseFloat(); | float parseFloat(); |
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 |
uint8_t tmp2 = tmp; | uint8_t tmp2 = tmp; | ||||
asm volatile( | asm volatile( | ||||
"L_%=_loop:" // 1 to load | "L_%=_loop:" // 1 to load | ||||
"subi %0, 1" "\n\t" // 2 | |||||
"subi %0, 1" "\n\t" // 1 | |||||
"nop" "\n\t" // 1 | |||||
"brne L_%=_loop" "\n\t" // 2 (1 on last) | "brne L_%=_loop" "\n\t" // 2 (1 on last) | ||||
: "=d" (tmp2) | : "=d" (tmp2) | ||||
: "0" (tmp2) | : "0" (tmp2) |
#define KEY_MEDIA_PREV_TRACK ( 0xB6 | 0xE400 ) | #define KEY_MEDIA_PREV_TRACK ( 0xB6 | 0xE400 ) | ||||
#define KEY_MEDIA_STOP ( 0xB7 | 0xE400 ) | #define KEY_MEDIA_STOP ( 0xB7 | 0xE400 ) | ||||
#define KEY_MEDIA_EJECT ( 0xB8 | 0xE400 ) | #define KEY_MEDIA_EJECT ( 0xB8 | 0xE400 ) | ||||
#define KEY_MEDIA_RANDOM_PLAY ( 0xB0 | 0xE400 ) | |||||
#define KEY_MEDIA_RANDOM_PLAY ( 0xB9 | 0xE400 ) | |||||
#define KEY_MEDIA_PLAY_PAUSE ( 0xCD | 0xE400 ) | #define KEY_MEDIA_PLAY_PAUSE ( 0xCD | 0xE400 ) | ||||
#define KEY_MEDIA_PLAY_SKIP ( 0xCE | 0xE400 ) | #define KEY_MEDIA_PLAY_SKIP ( 0xCE | 0xE400 ) | ||||
#define KEY_MEDIA_MUTE ( 0xE2 | 0xE400 ) | #define KEY_MEDIA_MUTE ( 0xE2 | 0xE400 ) | ||||
#define KEYPAD_9 ( 97 | 0xF000 ) | #define KEYPAD_9 ( 97 | 0xF000 ) | ||||
#define KEYPAD_0 ( 98 | 0xF000 ) | #define KEYPAD_0 ( 98 | 0xF000 ) | ||||
#define KEYPAD_PERIOD ( 99 | 0xF000 ) | #define KEYPAD_PERIOD ( 99 | 0xF000 ) | ||||
#define KEY_NON_US_BS ( 100 | 0xF000 ) | |||||
#define KEY_MENU ( 101 | 0xF000 ) | #define KEY_MENU ( 101 | 0xF000 ) | ||||
#define KEY_F13 ( 104 | 0xF000 ) | #define KEY_F13 ( 104 | 0xF000 ) | ||||
#define KEY_F14 ( 105 | 0xF000 ) | #define KEY_F14 ( 105 | 0xF000 ) | ||||
#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; | ||||
// For compatibility with some ESP8266 programs | |||||
#include <avr/pgmspace.h> |
#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 bitRead(value, bit) (((value) >> (bit)) & 0x01) | #define bitRead(value, bit) (((value) >> (bit)) & 0x01) | ||||
#define bitSet(value, bit) ((value) |= (1UL << (bit))) | #define bitSet(value, bit) ((value) |= (1UL << (bit))) | ||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) | #define bitClear(value, bit) ((value) &= ~(1UL << (bit))) | ||||
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) | |||||
#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet((value), (bit)) : bitClear((value), (bit))) | |||||
typedef unsigned int word; | typedef unsigned int word; | ||||
#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. | |||||
#ifndef Arduino_h | |||||
#define Arduino_h | |||||
#include "WProgram.h" | #include "WProgram.h" | ||||
#include "pins_arduino.h" | #include "pins_arduino.h" | ||||
#endif |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
*/ | */ | ||||
#include <string.h> // for memcpy | |||||
#include <Arduino.h> | |||||
#include "AudioStream.h" | #include "AudioStream.h" | ||||
#if defined(__MKL26Z64__) | |||||
#define MAX_AUDIO_MEMORY 6144 | |||||
#elif defined(__MK20DX128__) | |||||
#define MAX_AUDIO_MEMORY 12288 | |||||
#elif defined(__MK20DX256__) | |||||
#define MAX_AUDIO_MEMORY 49152 | |||||
#elif defined(__MK64FX512__) | |||||
#define MAX_AUDIO_MEMORY 163840 | |||||
#elif defined(__MK66FX1M0__) | |||||
#define MAX_AUDIO_MEMORY 229376 | |||||
#endif | |||||
#define NUM_MASKS (((MAX_AUDIO_MEMORY / AUDIO_BLOCK_SAMPLES / 2) + 31) / 32) | |||||
audio_block_t * AudioStream::memory_pool; | audio_block_t * AudioStream::memory_pool; | ||||
uint32_t AudioStream::memory_pool_available_mask[6]; | |||||
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 = 0; | ||||
uint16_t AudioStream::cpu_cycles_total_max = 0; | uint16_t AudioStream::cpu_cycles_total_max = 0; | ||||
uint8_t AudioStream::memory_used = 0; | |||||
uint8_t AudioStream::memory_used_max = 0; | |||||
uint16_t AudioStream::memory_used = 0; | |||||
uint16_t AudioStream::memory_used_max = 0; | |||||
void AudioStream::initialize_memory(audio_block_t *data, unsigned int num) | void AudioStream::initialize_memory(audio_block_t *data, unsigned int num) | ||||
{ | { | ||||
unsigned int i; | unsigned int i; | ||||
unsigned int maxnum = MAX_AUDIO_MEMORY / AUDIO_BLOCK_SAMPLES / 2; | |||||
//Serial.println("AudioStream initialize_memory"); | //Serial.println("AudioStream initialize_memory"); | ||||
//delay(10); | //delay(10); | ||||
if (num > 192) num = 192; | |||||
if (num > maxnum) num = maxnum; | |||||
__disable_irq(); | __disable_irq(); | ||||
memory_pool = data; | memory_pool = data; | ||||
for (i=0; i < 6; i++) { | |||||
memory_pool_first_mask = 0; | |||||
for (i=0; i < NUM_MASKS; i++) { | |||||
memory_pool_available_mask[i] = 0; | memory_pool_available_mask[i] = 0; | ||||
} | } | ||||
for (i=0; i < num; i++) { | for (i=0; i < num; i++) { | ||||
audio_block_t * AudioStream::allocate(void) | audio_block_t * AudioStream::allocate(void) | ||||
{ | { | ||||
uint32_t n, index, avail; | uint32_t n, index, avail; | ||||
uint32_t *p; | |||||
uint32_t *p, *end; | |||||
audio_block_t *block; | audio_block_t *block; | ||||
uint8_t used; | |||||
uint32_t used; | |||||
p = memory_pool_available_mask; | p = memory_pool_available_mask; | ||||
end = p + NUM_MASKS; | |||||
__disable_irq(); | __disable_irq(); | ||||
do { | |||||
avail = *p; if (avail) break; | |||||
p++; avail = *p; if (avail) break; | |||||
p++; avail = *p; if (avail) break; | |||||
p++; avail = *p; if (avail) break; | |||||
p++; avail = *p; if (avail) break; | |||||
p++; avail = *p; if (avail) break; | |||||
__enable_irq(); | |||||
//Serial.println("alloc:null"); | |||||
return NULL; | |||||
} while (0); | |||||
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); | n = __builtin_clz(avail); | ||||
*p = avail & ~(0x80000000 >> n); | |||||
avail &= ~(0x80000000 >> n); | |||||
*p = avail; | |||||
if (!avail) index++; | |||||
memory_pool_first_mask = index; | |||||
used = memory_used + 1; | used = memory_used + 1; | ||||
memory_used = used; | memory_used = used; | ||||
__enable_irq(); | __enable_irq(); | ||||
// returned to the free pool | // returned to the free pool | ||||
void AudioStream::release(audio_block_t *block) | void AudioStream::release(audio_block_t *block) | ||||
{ | { | ||||
//if (block == NULL) return; | |||||
uint32_t mask = (0x80000000 >> (31 - (block->memory_pool_index & 0x1F))); | uint32_t mask = (0x80000000 >> (31 - (block->memory_pool_index & 0x1F))); | ||||
uint32_t index = block->memory_pool_index >> 5; | uint32_t index = block->memory_pool_index >> 5; | ||||
__disable_irq(); | __disable_irq(); | ||||
if (block->ref_count > 1) { | if (block->ref_count > 1) { | ||||
block->ref_count--; | block->ref_count--; | ||||
//Serial.print("reles:"); | //Serial.print("reles:"); | ||||
//Serial.println((uint32_t)block, HEX); | //Serial.println((uint32_t)block, HEX); | ||||
memory_pool_available_mask[index] |= mask; | memory_pool_available_mask[index] |= mask; | ||||
if (index < memory_pool_first_mask) memory_pool_first_mask = index; | |||||
memory_used--; | memory_used--; | ||||
} | } | ||||
__enable_irq(); | __enable_irq(); | ||||
{ | { | ||||
AudioConnection *p; | AudioConnection *p; | ||||
if (isConnected) return; | |||||
if (dest_index > dst.num_inputs) return; | if (dest_index > dst.num_inputs) return; | ||||
__disable_irq(); | __disable_irq(); | ||||
p = src.destination_list; | p = src.destination_list; | ||||
if (p == NULL) { | if (p == NULL) { | ||||
src.destination_list = this; | src.destination_list = this; | ||||
} else { | } else { | ||||
while (p->next_dest) p = p->next_dest; | |||||
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; | p->next_dest = this; | ||||
} | } | ||||
this->next_dest = NULL; | |||||
src.numConnections++; | |||||
src.active = true; | src.active = true; | ||||
dst.numConnections++; | |||||
dst.active = true; | dst.active = true; | ||||
isConnected = true; | |||||
__enable_irq(); | __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() | // When an object has taken responsibility for calling update_all() |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
#ifndef AudioStream_h | #ifndef AudioStream_h | ||||
#define AudioStream_h | #define AudioStream_h | ||||
#ifndef __ASSEMBLER__ | |||||
#include <stdio.h> // for NULL | #include <stdio.h> // for NULL | ||||
#include <string.h> // for memcpy | #include <string.h> // for memcpy | ||||
#include "kinetis.h" | #include "kinetis.h" | ||||
#endif | |||||
// AUDIO_BLOCK_SAMPLES determines how many samples the audio library processes | |||||
// per update. It may be reduced to achieve lower latency response to events, | |||||
// at the expense of higher interrupt and DMA setup overhead. | |||||
// | |||||
// Less than 32 may not work with some input & output objects. Multiples of 16 | |||||
// should be used, since some synthesis objects generate 16 samples per loop. | |||||
// | |||||
// Some parts of the audio library may have hard-coded dependency on 128 samples. | |||||
// Please report these on the forum with reproducible test cases. | |||||
#if defined(KINETISK) | |||||
#ifndef AUDIO_BLOCK_SAMPLES | |||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#define AUDIO_BLOCK_SAMPLES 128 | #define AUDIO_BLOCK_SAMPLES 128 | ||||
#define AUDIO_SAMPLE_RATE 44117.64706 | |||||
#define AUDIO_SAMPLE_RATE_EXACT 44117.64706 // 48 MHz / 1088, or 96 MHz * 2 / 17 / 256 | |||||
#elif defined(KINETISL) | |||||
#elif defined(__MKL26Z64__) | |||||
#define AUDIO_BLOCK_SAMPLES 64 | #define AUDIO_BLOCK_SAMPLES 64 | ||||
#define AUDIO_SAMPLE_RATE 22058.82353 | |||||
#endif | |||||
#endif | |||||
#ifndef AUDIO_SAMPLE_RATE_EXACT | |||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#define AUDIO_SAMPLE_RATE_EXACT 44117.64706 // 48 MHz / 1088, or 96 MHz * 2 / 17 / 256 | |||||
#elif defined(__MKL26Z64__) | |||||
#define AUDIO_SAMPLE_RATE_EXACT 22058.82353 // 48 MHz / 2176, or 96 MHz * 1 / 17 / 256 | #define AUDIO_SAMPLE_RATE_EXACT 22058.82353 // 48 MHz / 2176, or 96 MHz * 1 / 17 / 256 | ||||
#endif | #endif | ||||
#endif | |||||
#define AUDIO_SAMPLE_RATE AUDIO_SAMPLE_RATE_EXACT | |||||
#ifndef __ASSEMBLER__ | |||||
class AudioStream; | class AudioStream; | ||||
class AudioConnection; | class AudioConnection; | ||||
typedef struct audio_block_struct { | typedef struct audio_block_struct { | ||||
unsigned char ref_count; | |||||
unsigned char memory_pool_index; | |||||
unsigned char reserved1; | |||||
unsigned char reserved2; | |||||
int16_t data[AUDIO_BLOCK_SAMPLES]; | |||||
uint8_t ref_count; | |||||
uint8_t reserved1; | |||||
uint16_t memory_pool_index; | |||||
int16_t data[AUDIO_BLOCK_SAMPLES]; | |||||
} audio_block_t; | } audio_block_t; | ||||
AudioConnection(AudioStream &source, AudioStream &destination) : | AudioConnection(AudioStream &source, AudioStream &destination) : | ||||
src(source), dst(destination), src_index(0), dest_index(0), | src(source), dst(destination), src_index(0), dest_index(0), | ||||
next_dest(NULL) | next_dest(NULL) | ||||
{ connect(); } | |||||
{ isConnected = false; | |||||
connect(); } | |||||
AudioConnection(AudioStream &source, unsigned char sourceOutput, | AudioConnection(AudioStream &source, unsigned char sourceOutput, | ||||
AudioStream &destination, unsigned char destinationInput) : | AudioStream &destination, unsigned char destinationInput) : | ||||
src(source), dst(destination), | src(source), dst(destination), | ||||
src_index(sourceOutput), dest_index(destinationInput), | src_index(sourceOutput), dest_index(destinationInput), | ||||
next_dest(NULL) | next_dest(NULL) | ||||
{ connect(); } | |||||
{ isConnected = false; | |||||
connect(); } | |||||
friend class AudioStream; | friend class AudioStream; | ||||
protected: | |||||
~AudioConnection() { | |||||
disconnect(); | |||||
} | |||||
void disconnect(void); | |||||
void connect(void); | void connect(void); | ||||
protected: | |||||
AudioStream &src; | AudioStream &src; | ||||
AudioStream &dst; | AudioStream &dst; | ||||
unsigned char src_index; | unsigned char src_index; | ||||
unsigned char dest_index; | unsigned char dest_index; | ||||
AudioConnection *next_dest; | AudioConnection *next_dest; | ||||
bool isConnected; | |||||
}; | }; | ||||
next_update = NULL; | next_update = NULL; | ||||
cpu_cycles = 0; | cpu_cycles = 0; | ||||
cpu_cycles_max = 0; | cpu_cycles_max = 0; | ||||
numConnections = 0; | |||||
} | } | ||||
static void initialize_memory(audio_block_t *data, unsigned int num); | static void initialize_memory(audio_block_t *data, unsigned int num); | ||||
int processorUsage(void) { return CYCLE_COUNTER_APPROX_PERCENT(cpu_cycles); } | int processorUsage(void) { return CYCLE_COUNTER_APPROX_PERCENT(cpu_cycles); } | ||||
int processorUsageMax(void) { return CYCLE_COUNTER_APPROX_PERCENT(cpu_cycles_max); } | int processorUsageMax(void) { return CYCLE_COUNTER_APPROX_PERCENT(cpu_cycles_max); } | ||||
void processorUsageMaxReset(void) { cpu_cycles_max = cpu_cycles; } | void processorUsageMaxReset(void) { cpu_cycles_max = cpu_cycles; } | ||||
bool isActive(void) { return active; } | |||||
uint16_t cpu_cycles; | uint16_t cpu_cycles; | ||||
uint16_t cpu_cycles_max; | uint16_t cpu_cycles_max; | ||||
static uint16_t cpu_cycles_total; | static uint16_t cpu_cycles_total; | ||||
static uint16_t cpu_cycles_total_max; | static uint16_t cpu_cycles_total_max; | ||||
static uint8_t memory_used; | |||||
static uint8_t memory_used_max; | |||||
static uint16_t memory_used; | |||||
static uint16_t memory_used_max; | |||||
protected: | protected: | ||||
bool active; | bool active; | ||||
unsigned char num_inputs; | unsigned char num_inputs; | ||||
static void update_all(void) { NVIC_SET_PENDING(IRQ_SOFTWARE); } | static void update_all(void) { NVIC_SET_PENDING(IRQ_SOFTWARE); } | ||||
friend void software_isr(void); | friend void software_isr(void); | ||||
friend class AudioConnection; | friend class AudioConnection; | ||||
uint8_t numConnections; | |||||
private: | private: | ||||
AudioConnection *destination_list; | AudioConnection *destination_list; | ||||
audio_block_t **inputQueue; | audio_block_t **inputQueue; | ||||
static AudioStream *first_update; // for update_all | static AudioStream *first_update; // for update_all | ||||
AudioStream *next_update; // for update_all | AudioStream *next_update; // for update_all | ||||
static audio_block_t *memory_pool; | static audio_block_t *memory_pool; | ||||
static uint32_t memory_pool_available_mask[6]; | |||||
static uint32_t memory_pool_available_mask[]; | |||||
static uint16_t memory_pool_first_mask; | |||||
}; | }; | ||||
#endif | #endif | ||||
#endif |
/* | |||||
Client.h - Base class that provides Client | |||||
Copyright (c) 2011 Adrian McEwen. All right reserved. | |||||
This library is free software; you can redistribute it and/or | |||||
modify it under the terms of the GNU Lesser General Public | |||||
License as published by the Free Software Foundation; either | |||||
version 2.1 of the License, or (at your option) any later version. | |||||
This library is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
Lesser General Public License for more details. | |||||
You should have received a copy of the GNU Lesser General Public | |||||
License along with this library; if not, write to the Free Software | |||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |||||
*/ | |||||
#if ARDUINO >= 100 | #if ARDUINO >= 100 | ||||
#ifndef client_h | #ifndef client_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 "DMAChannel.h" | #include "DMAChannel.h" | ||||
#if DMA_NUM_CHANNELS > 16 | |||||
#undef DMA_NUM_CHANNELS | |||||
#define DMA_NUM_CHANNELS 16 | |||||
#if DMA_NUM_CHANNELS <= 16 | |||||
#define DMA_MAX_CHANNELS DMA_NUM_CHANNELS | |||||
#else | |||||
#define DMA_MAX_CHANNELS 16 | |||||
#endif | #endif | ||||
uint32_t ch = 0; | uint32_t ch = 0; | ||||
__disable_irq(); | __disable_irq(); | ||||
if (!force_initialization && TCD && channel < DMA_NUM_CHANNELS | |||||
if (!force_initialization && TCD && channel < DMA_MAX_CHANNELS | |||||
&& (dma_channel_allocated_mask & (1 << channel)) | && (dma_channel_allocated_mask & (1 << channel)) | ||||
&& (uint32_t)TCD == (uint32_t)(0x40009000 + channel * 32)) { | && (uint32_t)TCD == (uint32_t)(0x40009000 + channel * 32)) { | ||||
// DMA channel already allocated | // DMA channel already allocated | ||||
__enable_irq(); | __enable_irq(); | ||||
break; | break; | ||||
} | } | ||||
if (++ch >= DMA_NUM_CHANNELS) { | |||||
if (++ch >= DMA_MAX_CHANNELS) { | |||||
__enable_irq(); | __enable_irq(); | ||||
TCD = (TCD_t *)0; | TCD = (TCD_t *)0; | ||||
channel = DMA_NUM_CHANNELS; | |||||
channel = DMA_MAX_CHANNELS; | |||||
return; // no more channels available | return; // no more channels available | ||||
// attempts to use this object will hardfault | // attempts to use this object will hardfault | ||||
} | } | ||||
channel = ch; | channel = ch; | ||||
SIM_SCGC7 |= SIM_SCGC7_DMA; | SIM_SCGC7 |= SIM_SCGC7_DMA; | ||||
SIM_SCGC6 |= SIM_SCGC6_DMAMUX; | SIM_SCGC6 |= SIM_SCGC6_DMAMUX; | ||||
DMA_CR = DMA_CR_EMLM | DMA_CR_EDBG ; // minor loop mapping is available | |||||
#if DMA_NUM_CHANNELS <= 16 | |||||
DMA_CR = DMA_CR_EMLM | DMA_CR_EDBG; // minor loop mapping is available | |||||
#else | |||||
DMA_CR = DMA_CR_GRP1PRI| DMA_CR_EMLM | DMA_CR_EDBG; | |||||
#endif | |||||
DMA_CERQ = ch; | DMA_CERQ = ch; | ||||
DMA_CERR = ch; | DMA_CERR = ch; | ||||
DMA_CEEI = ch; | DMA_CEEI = ch; | ||||
void DMAChannel::release(void) | void DMAChannel::release(void) | ||||
{ | { | ||||
if (channel >= DMA_NUM_CHANNELS) return; | |||||
if (channel >= DMA_MAX_CHANNELS) return; | |||||
DMA_CERQ = channel; | DMA_CERQ = channel; | ||||
__disable_irq(); | __disable_irq(); | ||||
dma_channel_allocated_mask &= ~(1 << channel); | dma_channel_allocated_mask &= ~(1 << channel); | ||||
__enable_irq(); | __enable_irq(); | ||||
channel = DMA_NUM_CHANNELS; | |||||
channel = DMA_MAX_CHANNELS; | |||||
TCD = (TCD_t *)0; | TCD = (TCD_t *)0; | ||||
} | } | ||||
uint32_t ch = 0; | uint32_t ch = 0; | ||||
__disable_irq(); | __disable_irq(); | ||||
if (!force_initialization && CFG && channel < DMA_NUM_CHANNELS | |||||
if (!force_initialization && CFG && channel < DMA_MAX_CHANNELS | |||||
&& (dma_channel_allocated_mask & (1 << channel)) | && (dma_channel_allocated_mask & (1 << channel)) | ||||
&& (uint32_t)CFG == (uint32_t)(0x40008100 + channel * 16)) { | && (uint32_t)CFG == (uint32_t)(0x40008100 + channel * 16)) { | ||||
// DMA channel already allocated | // DMA channel already allocated | ||||
__enable_irq(); | __enable_irq(); | ||||
break; | break; | ||||
} | } | ||||
if (++ch >= DMA_NUM_CHANNELS) { | |||||
if (++ch >= DMA_MAX_CHANNELS) { | |||||
__enable_irq(); | __enable_irq(); | ||||
CFG = (CFG_t *)0; | CFG = (CFG_t *)0; | ||||
channel = DMA_NUM_CHANNELS; | |||||
channel = DMA_MAX_CHANNELS; | |||||
return; // no more channels available | return; // no more channels available | ||||
// attempts to use this object will hardfault | // attempts to use this object will hardfault | ||||
} | } | ||||
void DMAChannel::release(void) | void DMAChannel::release(void) | ||||
{ | { | ||||
if (channel >= DMA_NUM_CHANNELS) return; | |||||
if (channel >= DMA_MAX_CHANNELS) return; | |||||
CFG->DSR_BCR = DMA_DSR_BCR_DONE; | CFG->DSR_BCR = DMA_DSR_BCR_DONE; | ||||
__disable_irq(); | __disable_irq(); | ||||
dma_channel_allocated_mask &= ~(1 << channel); | dma_channel_allocated_mask &= ~(1 << channel); |
/* 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 DMAChannel_h_ | #ifndef DMAChannel_h_ | ||||
#define DMAChannel_h_ | #define DMAChannel_h_ | ||||
class DMABaseClass { | class DMABaseClass { | ||||
public: | public: | ||||
typedef struct __attribute__((packed)) { | |||||
typedef struct __attribute__((packed, aligned(4))) { | |||||
volatile const void * volatile SADDR; | volatile const void * volatile SADDR; | ||||
int16_t SOFF; | int16_t SOFF; | ||||
union { uint16_t ATTR; | union { uint16_t ATTR; | ||||
// Set the number of transfers (number of triggers until complete) | // Set the number of transfers (number of triggers until complete) | ||||
void transferCount(unsigned int len) { | void transferCount(unsigned int len) { | ||||
if (len > 32767) return; | |||||
if (len >= 512) { | |||||
if (!(TCD->BITER & DMA_TCD_BITER_ELINK)) { | |||||
if (len > 32767) return; | |||||
TCD->BITER = len; | TCD->BITER = len; | ||||
TCD->CITER = len; | TCD->CITER = len; | ||||
} else { | } else { | ||||
if (len > 511) return; | |||||
TCD->BITER = (TCD->BITER & 0xFE00) | len; | TCD->BITER = (TCD->BITER & 0xFE00) | len; | ||||
TCD->CITER = (TCD->CITER & 0xFE00) | len; | TCD->CITER = (TCD->CITER & 0xFE00) | len; | ||||
} | } | ||||
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; | ||||
class DMABaseClass { | class DMABaseClass { | ||||
public: | public: | ||||
typedef struct __attribute__((packed)) { | |||||
typedef struct __attribute__((packed, aligned(4))) { | |||||
volatile const void * volatile SAR; | volatile const void * volatile SAR; | ||||
volatile void * volatile DAR; | volatile void * volatile DAR; | ||||
volatile uint32_t DSR_BCR; | volatile uint32_t DSR_BCR; | ||||
uint32_t mod = len2mod(len); | uint32_t mod = len2mod(len); | ||||
if (mod == 0) return; | if (mod == 0) return; | ||||
CFG->DAR = p; | CFG->DAR = p; | ||||
CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC | |||||
CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(2) | DMA_DCR_DINC | |||||
| DMA_DCR_DMOD(mod); | | DMA_DCR_DMOD(mod); | ||||
CFG->DSR_BCR = len; | CFG->DSR_BCR = len; | ||||
} | } | ||||
uint32_t mod = len2mod(len); | uint32_t mod = len2mod(len); | ||||
if (mod == 0) return; | if (mod == 0) return; | ||||
CFG->DAR = p; | CFG->DAR = p; | ||||
CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC | |||||
CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(0) | DMA_DCR_DINC | |||||
| DMA_DCR_DMOD(mod); | | DMA_DCR_DMOD(mod); | ||||
CFG->DSR_BCR = len; | CFG->DSR_BCR = len; | ||||
} | } | ||||
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); | |||||
} | } | ||||
} | } | ||||
/* EventResponder - Simple event-based programming for Arduino | |||||
* Copyright 2017 Paul Stoffregen | |||||
* | |||||
* 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: | |||||
* | |||||
* The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | |||||
* | |||||
* 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. | |||||
*/ | |||||
/* EventResponder is an experimental API, almost certain to | |||||
* incompatibly change as it develops. Please understand any | |||||
* programs you write now using EventResponder may need to be | |||||
* updated as EventResponder develops. | |||||
* | |||||
* Please post EventResponder post your feedback here: | |||||
* https://forum.pjrc.com/threads/44723-Arduino-Events | |||||
*/ | |||||
#include <Arduino.h> | |||||
#include "EventResponder.h" | |||||
EventResponder * EventResponder::firstYield = nullptr; | |||||
EventResponder * EventResponder::lastYield = nullptr; | |||||
EventResponder * EventResponder::firstInterrupt = nullptr; | |||||
EventResponder * EventResponder::lastInterrupt = nullptr; | |||||
bool EventResponder::runningFromYield = false; | |||||
// TODO: interrupt disable/enable needed in many places!!! | |||||
void EventResponder::triggerEventNotImmediate() | |||||
{ | |||||
bool irq = disableInterrupts(); | |||||
if (_triggered == false) { | |||||
// not already triggered | |||||
if (_type == EventTypeYield) { | |||||
// normal type, called from yield() | |||||
if (firstYield == nullptr) { | |||||
_next = nullptr; | |||||
_prev = nullptr; | |||||
firstYield = this; | |||||
lastYield = this; | |||||
} else { | |||||
_next = nullptr; | |||||
_prev = lastYield; | |||||
_prev->_next = this; | |||||
lastYield = this; | |||||
} | |||||
} else if (_type == EventTypeInterrupt) { | |||||
// interrupt, called from software interrupt | |||||
if (firstInterrupt == nullptr) { | |||||
_next = nullptr; | |||||
_prev = nullptr; | |||||
firstInterrupt = this; | |||||
lastInterrupt = this; | |||||
} else { | |||||
_next = nullptr; | |||||
_prev = lastInterrupt; | |||||
_prev->_next = this; | |||||
lastInterrupt = this; | |||||
} | |||||
SCB_ICSR = SCB_ICSR_PENDSVSET; // set PendSV interrupt | |||||
} else { | |||||
// detached, easy :-) | |||||
} | |||||
_triggered = true; | |||||
} | |||||
enableInterrupts(irq); | |||||
} | |||||
void pendablesrvreq_isr(void) | |||||
{ | |||||
EventResponder::runFromInterrupt(); | |||||
} | |||||
void EventResponder::runFromInterrupt() | |||||
{ | |||||
while (1) { | |||||
bool irq = disableInterrupts(); | |||||
EventResponder *first = firstInterrupt; | |||||
if (first) { | |||||
firstInterrupt = first->_next; | |||||
if (firstInterrupt) { | |||||
firstInterrupt->_prev = nullptr; | |||||
} else { | |||||
lastInterrupt = nullptr; | |||||
} | |||||
enableInterrupts(irq); | |||||
first->_triggered = false; | |||||
(*(first->_function))(*first); | |||||
} else { | |||||
enableInterrupts(irq); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
bool EventResponder::clearEvent() | |||||
{ | |||||
bool ret = false; | |||||
bool irq = disableInterrupts(); | |||||
if (_triggered) { | |||||
if (_type == EventTypeYield) { | |||||
if (_prev) { | |||||
_prev->_next = _next; | |||||
} else { | |||||
firstYield = _next; | |||||
} | |||||
if (_next) { | |||||
_next->_prev = _prev; | |||||
} else { | |||||
lastYield = _prev; | |||||
} | |||||
} else if (_type == EventTypeInterrupt) { | |||||
if (_prev) { | |||||
_prev->_next = _next; | |||||
} else { | |||||
firstInterrupt = _next; | |||||
} | |||||
if (_next) { | |||||
_next->_prev = _prev; | |||||
} else { | |||||
lastInterrupt = _prev; | |||||
} | |||||
} | |||||
_triggered = false; | |||||
ret = true; | |||||
} | |||||
enableInterrupts(irq); | |||||
return ret; | |||||
} | |||||
// this detach must be called with interrupts disabled | |||||
void EventResponder::detachNoInterrupts() | |||||
{ | |||||
if (_type == EventTypeYield) { | |||||
if (_triggered) { | |||||
if (_prev) { | |||||
_prev->_next = _next; | |||||
} else { | |||||
firstYield = _next; | |||||
} | |||||
if (_next) { | |||||
_next->_prev = _prev; | |||||
} else { | |||||
lastYield = _prev; | |||||
} | |||||
} | |||||
_type = EventTypeDetached; | |||||
} else if (_type == EventTypeInterrupt) { | |||||
if (_triggered) { | |||||
if (_prev) { | |||||
_prev->_next = _next; | |||||
} else { | |||||
firstInterrupt = _next; | |||||
} | |||||
if (_next) { | |||||
_next->_prev = _prev; | |||||
} else { | |||||
lastInterrupt = _prev; | |||||
} | |||||
} | |||||
_type = EventTypeDetached; | |||||
} | |||||
} | |||||
//------------------------------------------------------------- | |||||
MillisTimer * MillisTimer::listWaiting = nullptr; | |||||
MillisTimer * MillisTimer::listActive = nullptr; | |||||
void MillisTimer::begin(unsigned long milliseconds, EventResponderRef event) | |||||
{ | |||||
if (_state != TimerOff) end(); | |||||
if (!milliseconds) return; | |||||
_event = &event; | |||||
_ms = (milliseconds > 2)? milliseconds-2 : 0; | |||||
_reload = 0; | |||||
addToWaitingList(); | |||||
} | |||||
void MillisTimer::beginRepeating(unsigned long milliseconds, EventResponderRef event) | |||||
{ | |||||
if (_state != TimerOff) end(); | |||||
if (!milliseconds) return; | |||||
_event = &event; | |||||
_ms = (milliseconds > 2)? milliseconds-2 : 0; | |||||
_reload = milliseconds; | |||||
addToWaitingList(); | |||||
} | |||||
void MillisTimer::addToWaitingList() | |||||
{ | |||||
_prev = nullptr; | |||||
bool irq = disableTimerInterrupt(); | |||||
_next = listWaiting; | |||||
listWaiting = this; // TODO: use STREX to avoid interrupt disable | |||||
_state = TimerWaiting; | |||||
enableTimerInterrupt(irq); | |||||
} | |||||
void MillisTimer::addToActiveList() // only called by runFromTimer() | |||||
{ | |||||
if (listActive == nullptr) { | |||||
// list is empty, easy case | |||||
_next = nullptr; | |||||
_prev = nullptr; | |||||
listActive = this; | |||||
} else if (_ms < listActive->_ms) { | |||||
// this timer triggers before any on the list | |||||
_next = listActive; | |||||
_prev = nullptr; | |||||
listActive->_prev = this; | |||||
// Decrement the next items wait time be our wait time as to properly handle waits for all other items... | |||||
listActive->_ms -= _ms; | |||||
listActive = this; | |||||
} else { | |||||
// add this timer somewhere after the first already on the list | |||||
MillisTimer *timer = listActive; | |||||
while (timer->_next) { | |||||
_ms -= timer->_ms; | |||||
timer = timer->_next; | |||||
if (_ms < timer->_ms) { | |||||
// found the right place in the middle of list | |||||
_next = timer; | |||||
_prev = timer->_prev; | |||||
timer->_prev = this; | |||||
_prev->_next = this; | |||||
timer->_ms -= _ms; | |||||
_state = TimerActive; | |||||
return; | |||||
} | |||||
} | |||||
// add this time at the end of the list | |||||
_ms -= timer->_ms; | |||||
_next = nullptr; | |||||
_prev = timer; | |||||
timer->_next = this; | |||||
} | |||||
_state = TimerActive; | |||||
} | |||||
void MillisTimer::end() | |||||
{ | |||||
bool irq = disableTimerInterrupt(); | |||||
TimerStateType s = _state; | |||||
if (s == TimerActive) { | |||||
if (_next) { | |||||
_next->_prev = _prev; | |||||
_next->_ms += _ms; // add in the rest of our timing to next entry... | |||||
} | |||||
if (_prev) { | |||||
_prev->_next = _next; | |||||
} else { | |||||
listActive = _next; | |||||
} | |||||
_state = TimerOff; | |||||
} else if (s == TimerWaiting) { | |||||
if (listWaiting == this) { | |||||
listWaiting = _next; | |||||
} else { | |||||
MillisTimer *timer = listWaiting; | |||||
while (timer) { | |||||
if (timer->_next == this) { | |||||
timer->_next = _next; | |||||
break; | |||||
} | |||||
timer = timer->_next; | |||||
} | |||||
} | |||||
_state = TimerOff; | |||||
} | |||||
enableTimerInterrupt(irq); | |||||
} | |||||
void MillisTimer::runFromTimer() | |||||
{ | |||||
MillisTimer *timer = listActive; | |||||
while (timer) { | |||||
if (timer->_ms > 0) { | |||||
timer->_ms--; | |||||
break; | |||||
} else { | |||||
MillisTimer *next = timer->_next; | |||||
if (next) next->_prev = nullptr; | |||||
listActive = next; | |||||
timer->_state = TimerOff; | |||||
EventResponderRef event = *(timer->_event); | |||||
event.triggerEvent(0, timer); | |||||
if (timer->_reload) { | |||||
timer->_ms = timer->_reload; | |||||
timer->addToActiveList(); | |||||
} | |||||
timer = listActive; | |||||
} | |||||
} | |||||
bool irq = disableTimerInterrupt(); | |||||
MillisTimer *waiting = listWaiting; | |||||
listWaiting = nullptr; // TODO: use STREX to avoid interrupt disable | |||||
enableTimerInterrupt(irq); | |||||
while (waiting) { | |||||
MillisTimer *next = waiting->_next; | |||||
waiting->addToActiveList(); | |||||
waiting = next; | |||||
} | |||||
} | |||||
// Long ago you could install your own systick interrupt handler by just | |||||
// creating your own systick_isr() function. No longer. But if you | |||||
// *really* want to commandeer systick, you can still do so by writing | |||||
// your function into the RAM-based vector table. | |||||
// | |||||
// _VectorsRam[15] = my_systick_function; | |||||
// | |||||
// However, for long-term portability, use a MillisTimer object to | |||||
// generate an event every millisecond, and attach your function to | |||||
// its EventResponder. You can attach as a software interrupt, so your | |||||
// code will run at lower interrupt priority for better compatibility | |||||
// with libraries using mid-to-high priority interrupts. | |||||
extern "C" volatile uint32_t systick_millis_count; | |||||
void systick_isr(void) | |||||
{ | |||||
systick_millis_count++; | |||||
MillisTimer::runFromTimer(); | |||||
} | |||||
/* EventResponder - Simple event-based programming for Arduino | |||||
* Copyright 2017 Paul Stoffregen | |||||
* | |||||
* 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: | |||||
* | |||||
* The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | |||||
* | |||||
* 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. | |||||
*/ | |||||
/* EventResponder is an experimental API, almost certain to | |||||
* incompatibly change as it develops. Please understand any | |||||
* programs you write now using EventResponder may need to be | |||||
* updated as EventResponder develops. | |||||
* | |||||
* Please post your EventResponder feedback here: | |||||
* https://forum.pjrc.com/threads/44723-Arduino-Events | |||||
*/ | |||||
#if !defined(EventResponder_h) && defined(__cplusplus) | |||||
#define EventResponder_h | |||||
#include <Arduino.h> | |||||
/* EventResponder lets you control how your program responds to an event. | |||||
* Imagine a basketball or football (American soccer) player who gets the | |||||
* ball. Usually they will pass to another player who has the best | |||||
* opportunity to score. Similarly in Arduino programming, events are | |||||
* often triggered within interrupts or other timing sensitive code. | |||||
* EventResponder can call your function a short time later, giving you | |||||
* the ability to use Arduino functions and libraries which would not | |||||
* be safe to use from an interrupt. However, some situations do call | |||||
* for the most immediate response, even if doing so is more difficult. | |||||
* EventResponder lets you choose how your function will be called, | |||||
* without editing the timers or libraries which trigger the events. | |||||
* | |||||
* Event handling functions called by EventResponder should complete | |||||
* their work quickly. Avoid delays or operations which may take | |||||
* substantial time. While your function runs, no other event functions | |||||
* (attached the same way) are able to run. | |||||
* | |||||
* If your EventResponder is triggered more than once before your | |||||
* function can run, only the last trigger is used. Prior triggering, | |||||
* including the status integer and data pointer, are overwritten and | |||||
* your function is called only one time, based on the last trigger | |||||
* event. | |||||
*/ | |||||
class EventResponder; | |||||
typedef EventResponder& EventResponderRef; | |||||
typedef void (*EventResponderFunction)(EventResponderRef); | |||||
class EventResponder | |||||
{ | |||||
public: | |||||
constexpr EventResponder() { | |||||
} | |||||
~EventResponder() { | |||||
detach(); | |||||
} | |||||
enum EventType { // these are not meant for public consumption... | |||||
EventTypeDetached = 0, // no function is called | |||||
EventTypeYield, // function is called from yield() | |||||
EventTypeImmediate, // function is called immediately | |||||
EventTypeInterrupt, // function is called from interrupt | |||||
EventTypeThread // function is run as a new thread | |||||
}; | |||||
// Attach a function to be called from yield(). This should be the | |||||
// default way to use EventResponder. Calls from yield() allow use | |||||
// of Arduino libraries, String, Serial, etc. | |||||
void attach(EventResponderFunction function, uint8_t priority=128) { | |||||
bool irq = disableInterrupts(); | |||||
detachNoInterrupts(); | |||||
_function = function; | |||||
_type = EventTypeYield; | |||||
enableInterrupts(irq); | |||||
} | |||||
// Attach a function to be called immediately. This provides the | |||||
// fastest possible response, but your function must be carefully | |||||
// designed. | |||||
void attachImmediate(EventResponderFunction function) { | |||||
bool irq = disableInterrupts(); | |||||
detachNoInterrupts(); | |||||
_function = function; | |||||
_type = EventTypeImmediate; | |||||
enableInterrupts(irq); | |||||
} | |||||
// Attach a function to be called from a low priority interrupt. | |||||
// Boards not supporting software triggered interrupts will implement | |||||
// this as attachImmediate. On ARM and other platforms with software | |||||
// interrupts, this allow fast interrupt-based response, but with less | |||||
// disruption to other libraries requiring their own interrupts. | |||||
void attachInterrupt(EventResponderFunction function, uint8_t priority=128) { | |||||
bool irq = disableInterrupts(); | |||||
detachNoInterrupts(); | |||||
_function = function; | |||||
_type = EventTypeInterrupt; | |||||
SCB_SHPR3 |= 0x00FF0000; // configure PendSV, lowest priority | |||||
enableInterrupts(irq); | |||||
} | |||||
// Attach a function to be called as its own thread. Boards not running | |||||
// a RTOS or pre-emptive scheduler shall implement this as attach(). | |||||
void attachThread(EventResponderFunction function, void *param=nullptr) { | |||||
attach(function); // for non-RTOS usage, compile as default attach | |||||
} | |||||
// Do not call any function. The user's program must occasionally check | |||||
// whether the event has occurred, or use one of the wait functions. | |||||
void detach() { | |||||
bool irq = disableInterrupts(); | |||||
detachNoInterrupts(); | |||||
enableInterrupts(irq); | |||||
} | |||||
// Trigger the event. An optional status code and data may be provided. | |||||
// The code triggering the event does NOT control which of the above | |||||
// response methods will be used. | |||||
virtual void triggerEvent(int status=0, void *data=nullptr) { | |||||
_status = status; | |||||
_data = data; | |||||
if (_type == EventTypeImmediate) { | |||||
(*_function)(*this); | |||||
} else { | |||||
triggerEventNotImmediate(); | |||||
} | |||||
} | |||||
// Clear an event which has been triggered, but has not yet caused a | |||||
// function to be called. | |||||
bool clearEvent(); | |||||
// Get the event's status code. Typically this will indicate if the event was | |||||
// triggered due to successful completion, or how much data was successfully | |||||
// processed (positive numbers) or an error (negative numbers). The | |||||
// exact meaning of this status code depends on the code or library which | |||||
// triggers the event. | |||||
int getStatus() { return _status; } | |||||
// Get the optional data pointer associated with the event. Often this | |||||
// will be NULL, or will be the object instance which triggered the event. | |||||
// Some libraries may use this to pass data associated with the event. | |||||
void * getData() { return _data; } | |||||
// An optional "context" may be associated with each EventResponder. | |||||
// When more than one EventResponder has the same function attached, these | |||||
// may be used to allow the function to obtain extra information needed | |||||
// depending on which EventResponder called it. | |||||
void setContext(void *context) { _context = context; } | |||||
void * getContext() { return _context; } | |||||
// Wait for event(s) to occur. These are most likely to be useful when | |||||
// used with a scheduler or RTOS. | |||||
bool waitForEvent(EventResponderRef event, int timeout); | |||||
EventResponder * waitForEvent(EventResponder *list, int listsize, int timeout); | |||||
static void runFromYield() { | |||||
// First, check if yield was called from an interrupt | |||||
// never call normal handler functions from any interrupt context | |||||
uint32_t ipsr; | |||||
__asm__ volatile("mrs %0, ipsr\n" : "=r" (ipsr)::); | |||||
if (ipsr != 0) return; | |||||
// Next, check if any events have been triggered | |||||
bool irq = disableInterrupts(); | |||||
EventResponder *first = firstYield; | |||||
if (first == nullptr) { | |||||
enableInterrupts(irq); | |||||
return; | |||||
} | |||||
// Finally, make sure we're not being recursively called, | |||||
// which can happen if the user's function does anything | |||||
// that calls yield. | |||||
if (runningFromYield) { | |||||
enableInterrupts(irq); | |||||
return; | |||||
} | |||||
// Ok, update the runningFromYield flag and process event | |||||
runningFromYield = true; | |||||
firstYield = first->_next; | |||||
if (firstYield) { | |||||
firstYield->_prev = nullptr; | |||||
} else { | |||||
lastYield = nullptr; | |||||
} | |||||
enableInterrupts(irq); | |||||
first->_triggered = false; | |||||
(*(first->_function))(*first); | |||||
runningFromYield = false; | |||||
} | |||||
static void runFromInterrupt(); | |||||
operator bool() { return _triggered; } | |||||
protected: | |||||
void triggerEventNotImmediate(); | |||||
void detachNoInterrupts(); | |||||
int _status = 0; | |||||
EventResponderFunction _function = nullptr; | |||||
void *_data = nullptr; | |||||
void *_context = nullptr; | |||||
EventResponder *_next = nullptr; | |||||
EventResponder *_prev = nullptr; | |||||
EventType _type = EventTypeDetached; | |||||
bool _triggered = false; | |||||
static EventResponder *firstYield; | |||||
static EventResponder *lastYield; | |||||
static EventResponder *firstInterrupt; | |||||
static EventResponder *lastInterrupt; | |||||
static bool runningFromYield; | |||||
private: | |||||
static bool disableInterrupts() { | |||||
uint32_t primask; | |||||
__asm__ volatile("mrs %0, primask\n" : "=r" (primask)::); | |||||
__disable_irq(); | |||||
return (primask == 0) ? true : false; | |||||
} | |||||
static void enableInterrupts(bool doit) { | |||||
if (doit) __enable_irq(); | |||||
} | |||||
}; | |||||
class MillisTimer | |||||
{ | |||||
public: | |||||
constexpr MillisTimer() { | |||||
} | |||||
~MillisTimer() { | |||||
end(); | |||||
} | |||||
void begin(unsigned long milliseconds, EventResponderRef event); | |||||
void beginRepeating(unsigned long milliseconds, EventResponderRef event); | |||||
void end(); | |||||
static void runFromTimer(); | |||||
private: | |||||
void addToWaitingList(); | |||||
void addToActiveList(); | |||||
unsigned long _ms = 0; | |||||
unsigned long _reload = 0; | |||||
MillisTimer *_next = nullptr; | |||||
MillisTimer *_prev = nullptr; | |||||
EventResponder *_event = nullptr; | |||||
enum TimerStateType { | |||||
TimerOff = 0, | |||||
TimerWaiting, | |||||
TimerActive | |||||
}; | |||||
volatile TimerStateType _state = TimerOff; | |||||
static MillisTimer *listWaiting; // single linked list of waiting to start timers | |||||
static MillisTimer *listActive; // double linked list of running timers | |||||
static bool disableTimerInterrupt() { | |||||
uint32_t primask; | |||||
__asm__ volatile("mrs %0, primask\n" : "=r" (primask)::); | |||||
__disable_irq(); | |||||
return (primask == 0) ? true : false; | |||||
} | |||||
static void enableTimerInterrupt(bool doit) { | |||||
if (doit) __enable_irq(); | |||||
} | |||||
}; | |||||
#endif |
/* 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.... | |||||
*/ | |||||
#ifndef FS_H | |||||
#define FS_H | |||||
#ifdef __cplusplus | |||||
#include "Stream.h" | |||||
#include "WString.h" | |||||
class File : public Stream { | |||||
public: | |||||
constexpr File() {} | |||||
enum SeekMode { | |||||
SeekSet = 0, | |||||
SeekCur = 1, | |||||
SeekEnd = 2 | |||||
}; | |||||
virtual size_t read(void *buf, size_t nbyte); | |||||
virtual size_t write(const void *buf, size_t size); | |||||
virtual int available(); | |||||
virtual int read(); | |||||
virtual int peek(); | |||||
virtual void flush(); | |||||
virtual bool seek(uint32_t pos, int mode); | |||||
virtual uint32_t position() const; | |||||
virtual uint32_t size() const; | |||||
virtual void close(); | |||||
virtual operator bool() const; | |||||
//virtual const char* name() const; // why does ESP have this in File? | |||||
bool seek(uint32_t pos) { | |||||
return seek(pos, SeekSet); | |||||
} | |||||
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); | |||||
} | |||||
// 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); | |||||
}; | |||||
class Dir { | |||||
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()); | |||||
} | |||||
}; | |||||
#endif // __cplusplus | |||||
#endif // FS_H |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
#include "kinetis.h" | #include "kinetis.h" | ||||
// uncomment to enable 9 bit formats | |||||
// Uncomment to enable 9 bit formats. These are default disabled to save memory. | |||||
//#define SERIAL_9BIT_SUPPORT | //#define SERIAL_9BIT_SUPPORT | ||||
// | |||||
// On Windows & Linux, this file is in Arduino's hardware/teensy/avr/cores/teensy3 | |||||
// folder. The Windows installer puts Arduino in C:\Program Files (x86)\Arduino | |||||
// On Macintosh, you must control-click Arduino and select "Show Package Contents", then | |||||
// look in Contents/Java/hardware/teensy/avr/cores/teensy3 to find this file. | |||||
// | |||||
// Teensy 3.x boards support 9 bit mode on all their serial ports | |||||
// Teensy LC only supports 9 bit mode on Serial1. Serial2 & Serial3 can't use 9 bits. | |||||
#define SERIAL_7E1 0x02 | #define SERIAL_7E1 0x02 | ||||
#define SERIAL_7O1 0x03 | #define SERIAL_7O1 0x03 | ||||
#define SERIAL_8N1 0x00 | #define SERIAL_8N1 0x00 | ||||
#define SERIAL_8N2 0x04 | |||||
#define SERIAL_8E1 0x06 | #define SERIAL_8E1 0x06 | ||||
#define SERIAL_8O1 0x07 | #define SERIAL_8O1 0x07 | ||||
#define SERIAL_7E1_RXINV 0x12 | #define SERIAL_7E1_RXINV 0x12 | ||||
#define SERIAL_7O1_RXINV 0x13 | #define SERIAL_7O1_RXINV 0x13 | ||||
#define SERIAL_8N1_RXINV 0x10 | #define SERIAL_8N1_RXINV 0x10 | ||||
#define SERIAL_8N2_RXINV 0x14 | |||||
#define SERIAL_8E1_RXINV 0x16 | #define SERIAL_8E1_RXINV 0x16 | ||||
#define SERIAL_8O1_RXINV 0x17 | #define SERIAL_8O1_RXINV 0x17 | ||||
#define SERIAL_7E1_TXINV 0x22 | #define SERIAL_7E1_TXINV 0x22 | ||||
#define SERIAL_7O1_TXINV 0x23 | #define SERIAL_7O1_TXINV 0x23 | ||||
#define SERIAL_8N1_TXINV 0x20 | #define SERIAL_8N1_TXINV 0x20 | ||||
#define SERIAL_8N2_TXINV 0x24 | |||||
#define SERIAL_8E1_TXINV 0x26 | #define SERIAL_8E1_TXINV 0x26 | ||||
#define SERIAL_8O1_TXINV 0x27 | #define SERIAL_8O1_TXINV 0x27 | ||||
#define SERIAL_7E1_RXINV_TXINV 0x32 | #define SERIAL_7E1_RXINV_TXINV 0x32 | ||||
#define SERIAL_7O1_RXINV_TXINV 0x33 | #define SERIAL_7O1_RXINV_TXINV 0x33 | ||||
#define SERIAL_8N1_RXINV_TXINV 0x30 | #define SERIAL_8N1_RXINV_TXINV 0x30 | ||||
#define SERIAL_8N2_RXINV_TXINV 0x34 | |||||
#define SERIAL_8E1_RXINV_TXINV 0x36 | #define SERIAL_8E1_RXINV_TXINV 0x36 | ||||
#define SERIAL_8O1_RXINV_TXINV 0x37 | #define SERIAL_8O1_RXINV_TXINV 0x37 | ||||
#ifdef SERIAL_9BIT_SUPPORT | #ifdef SERIAL_9BIT_SUPPORT | ||||
#define SERIAL_9E1_RXINV_TXINV 0xBE | #define SERIAL_9E1_RXINV_TXINV 0xBE | ||||
#define SERIAL_9O1_RXINV_TXINV 0xBF | #define SERIAL_9O1_RXINV_TXINV 0xBF | ||||
#endif | #endif | ||||
// Teensy LC and 3.5 and 3.6 Uarts have 1/2 bit stop setting | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(KINETISL) | |||||
#define SERIAL_2STOP_BITS 0x100 | |||||
#define SERIAL_8E2 (SERIAL_8E1 | SERIAL_2STOP_BITS) | |||||
#define SERIAL_8O2 (SERIAL_8O1 | SERIAL_2STOP_BITS) | |||||
#define SERIAL_8E2_RXINV (SERIAL_8E1_RXINV | SERIAL_2STOP_BITS) | |||||
#define SERIAL_8O2_RXINV (SERIAL_8O1_RXINV | SERIAL_2STOP_BITS) | |||||
#define SERIAL_8E2_TXINV (SERIAL_8E1_TXINV | SERIAL_2STOP_BITS) | |||||
#define SERIAL_8O2_TXINV (SERIAL_8O1_TXINV | SERIAL_2STOP_BITS) | |||||
#define SERIAL_8E2_RXINV_TXINV (SERIAL_8E1_RXINV_TXINV | SERIAL_2STOP_BITS) | |||||
#define SERIAL_8O2_RXINV_TXINV (SERIAL_8O1_RXINV_TXINV | SERIAL_2STOP_BITS) | |||||
#define SERIAL_8N2 (SERIAL_8N1 | SERIAL_2STOP_BITS) | |||||
#define SERIAL_8N2_RXINV (SERIAL_8N1_RXINV | SERIAL_2STOP_BITS) | |||||
#define SERIAL_8N2_TXINV (SERIAL_8N1_TXINV | SERIAL_2STOP_BITS) | |||||
#define SERIAL_8N2_RXINV_TXINV (SERIAL_8N1_RXINV_TXINV | SERIAL_2STOP_BITS) | |||||
#else | |||||
// for Teensy 3.0-3.2 we can fake 2 stop bits by using 9 bit mode | |||||
#define SERIAL_8N2 0x04 | |||||
#define SERIAL_8N2_RXINV 0x14 | |||||
#define SERIAL_8N2_TXINV 0x24 | |||||
#define SERIAL_8N2_RXINV_TXINV 0x34 | |||||
#endif | |||||
// bit0: parity, 0=even, 1=odd | // bit0: parity, 0=even, 1=odd | ||||
// bit1: parity, 0=disable, 1=enable | // bit1: parity, 0=disable, 1=enable | ||||
// bit2: mode, 1=9bit, 0=8bit | // bit2: mode, 1=9bit, 0=8bit | ||||
int serial3_peek(void); | int serial3_peek(void); | ||||
void serial3_clear(void); | void serial3_clear(void); | ||||
void serial4_begin(uint32_t divisor); | |||||
void serial4_format(uint32_t format); | |||||
void serial4_end(void); | |||||
void serial4_set_transmit_pin(uint8_t pin); | |||||
void serial4_set_rx(uint8_t pin); | |||||
void serial4_set_tx(uint8_t pin, uint8_t opendrain); | |||||
int serial4_set_rts(uint8_t pin); | |||||
int serial4_set_cts(uint8_t pin); | |||||
void serial4_putchar(uint32_t c); | |||||
void serial4_write(const void *buf, unsigned int count); | |||||
void serial4_flush(void); | |||||
int serial4_write_buffer_free(void); | |||||
int serial4_available(void); | |||||
int serial4_getchar(void); | |||||
int serial4_peek(void); | |||||
void serial4_clear(void); | |||||
void serial5_begin(uint32_t divisor); | |||||
void serial5_format(uint32_t format); | |||||
void serial5_end(void); | |||||
void serial5_set_transmit_pin(uint8_t pin); | |||||
void serial5_set_rx(uint8_t pin); | |||||
void serial5_set_tx(uint8_t pin, uint8_t opendrain); | |||||
int serial5_set_rts(uint8_t pin); | |||||
int serial5_set_cts(uint8_t pin); | |||||
void serial5_putchar(uint32_t c); | |||||
void serial5_write(const void *buf, unsigned int count); | |||||
void serial5_flush(void); | |||||
int serial5_write_buffer_free(void); | |||||
int serial5_available(void); | |||||
int serial5_getchar(void); | |||||
int serial5_peek(void); | |||||
void serial5_clear(void); | |||||
void serial6_begin(uint32_t divisor); | |||||
void serial6_format(uint32_t format); | |||||
void serial6_end(void); | |||||
void serial6_set_transmit_pin(uint8_t pin); | |||||
void serial6_set_rx(uint8_t pin); | |||||
void serial6_set_tx(uint8_t pin, uint8_t opendrain); | |||||
int serial6_set_rts(uint8_t pin); | |||||
int serial6_set_cts(uint8_t pin); | |||||
void serial6_putchar(uint32_t c); | |||||
void serial6_write(const void *buf, unsigned int count); | |||||
void serial6_flush(void); | |||||
int serial6_write_buffer_free(void); | |||||
int serial6_available(void); | |||||
int serial6_getchar(void); | |||||
int serial6_peek(void); | |||||
void serial6_clear(void); | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
} | } | ||||
#endif | #endif | ||||
class HardwareSerial : public Stream | class HardwareSerial : public Stream | ||||
{ | { | ||||
public: | public: | ||||
constexpr HardwareSerial() {} | |||||
virtual void begin(uint32_t baud) { serial_begin(BAUD2DIV(baud)); } | virtual void begin(uint32_t baud) { serial_begin(BAUD2DIV(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)); | ||||
virtual void flush(void) { serial_flush(); } | virtual void flush(void) { serial_flush(); } | ||||
virtual void clear(void) { serial_clear(); } | virtual void clear(void) { serial_clear(); } | ||||
virtual int availableForWrite(void) { return serial_write_buffer_free(); } | virtual int availableForWrite(void) { return serial_write_buffer_free(); } | ||||
using Print::write; | |||||
virtual size_t write(uint8_t c) { serial_putchar(c); return 1; } | virtual size_t write(uint8_t c) { serial_putchar(c); return 1; } | ||||
virtual size_t write(unsigned long n) { return write((uint8_t)n); } | virtual size_t write(unsigned long n) { return write((uint8_t)n); } | ||||
virtual size_t write(long n) { return write((uint8_t)n); } | virtual size_t write(long n) { return write((uint8_t)n); } | ||||
class HardwareSerial2 : public HardwareSerial | class HardwareSerial2 : public HardwareSerial | ||||
{ | { | ||||
public: | public: | ||||
constexpr HardwareSerial2() {} | |||||
virtual void begin(uint32_t baud) { serial2_begin(BAUD2DIV2(baud)); } | virtual void begin(uint32_t baud) { serial2_begin(BAUD2DIV2(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)); | ||||
virtual void flush(void) { serial2_flush(); } | virtual void flush(void) { serial2_flush(); } | ||||
virtual void clear(void) { serial2_clear(); } | virtual void clear(void) { serial2_clear(); } | ||||
virtual int availableForWrite(void) { return serial2_write_buffer_free(); } | virtual int availableForWrite(void) { return serial2_write_buffer_free(); } | ||||
using Print::write; | |||||
virtual size_t write(uint8_t c) { serial2_putchar(c); return 1; } | virtual size_t write(uint8_t c) { serial2_putchar(c); return 1; } | ||||
virtual size_t write(unsigned long n) { return write((uint8_t)n); } | virtual size_t write(unsigned long n) { return write((uint8_t)n); } | ||||
virtual size_t write(long n) { return write((uint8_t)n); } | virtual size_t write(long n) { return write((uint8_t)n); } | ||||
class HardwareSerial3 : public HardwareSerial | class HardwareSerial3 : public HardwareSerial | ||||
{ | { | ||||
public: | public: | ||||
constexpr HardwareSerial3() {} | |||||
virtual void begin(uint32_t baud) { serial3_begin(BAUD2DIV3(baud)); } | virtual void begin(uint32_t baud) { serial3_begin(BAUD2DIV3(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)); | ||||
virtual void flush(void) { serial3_flush(); } | virtual void flush(void) { serial3_flush(); } | ||||
virtual void clear(void) { serial3_clear(); } | virtual void clear(void) { serial3_clear(); } | ||||
virtual int availableForWrite(void) { return serial3_write_buffer_free(); } | virtual int availableForWrite(void) { return serial3_write_buffer_free(); } | ||||
using Print::write; | |||||
virtual size_t write(uint8_t c) { serial3_putchar(c); return 1; } | virtual size_t write(uint8_t c) { serial3_putchar(c); return 1; } | ||||
virtual size_t write(unsigned long n) { return write((uint8_t)n); } | virtual size_t write(unsigned long n) { return write((uint8_t)n); } | ||||
virtual size_t write(long n) { return write((uint8_t)n); } | virtual size_t write(long n) { return write((uint8_t)n); } | ||||
extern HardwareSerial3 Serial3; | extern HardwareSerial3 Serial3; | ||||
extern void serialEvent3(void); | extern void serialEvent3(void); | ||||
class HardwareSerial4 : public HardwareSerial | |||||
{ | |||||
public: | |||||
constexpr HardwareSerial4() {} | |||||
virtual void begin(uint32_t baud) { serial4_begin(BAUD2DIV3(baud)); } | |||||
virtual void begin(uint32_t baud, uint32_t format) { | |||||
serial4_begin(BAUD2DIV3(baud)); | |||||
serial4_format(format); } | |||||
virtual void end(void) { serial4_end(); } | |||||
virtual void transmitterEnable(uint8_t pin) { serial4_set_transmit_pin(pin); } | |||||
virtual void setRX(uint8_t pin) { serial4_set_rx(pin); } | |||||
virtual void setTX(uint8_t pin, bool opendrain=false) { serial4_set_tx(pin, opendrain); } | |||||
virtual bool attachRts(uint8_t pin) { return serial4_set_rts(pin); } | |||||
virtual bool attachCts(uint8_t pin) { return serial4_set_cts(pin); } | |||||
virtual int available(void) { return serial4_available(); } | |||||
virtual int peek(void) { return serial4_peek(); } | |||||
virtual int read(void) { return serial4_getchar(); } | |||||
virtual void flush(void) { serial4_flush(); } | |||||
virtual void clear(void) { serial4_clear(); } | |||||
virtual int availableForWrite(void) { return serial4_write_buffer_free(); } | |||||
using Print::write; | |||||
virtual size_t write(uint8_t c) { serial4_putchar(c); return 1; } | |||||
virtual size_t write(unsigned long n) { return write((uint8_t)n); } | |||||
virtual size_t write(long n) { return write((uint8_t)n); } | |||||
virtual size_t write(unsigned int n) { return write((uint8_t)n); } | |||||
virtual size_t write(int n) { return write((uint8_t)n); } | |||||
virtual size_t write(const uint8_t *buffer, size_t size) | |||||
{ serial4_write(buffer, size); return size; } | |||||
virtual size_t write(const char *str) { size_t len = strlen(str); | |||||
serial4_write((const uint8_t *)str, len); | |||||
return len; } | |||||
virtual size_t write9bit(uint32_t c) { serial4_putchar(c); return 1; } | |||||
operator bool() { return true; } | |||||
}; | |||||
extern HardwareSerial4 Serial4; | |||||
extern void serialEvent4(void); | |||||
class HardwareSerial5 : public HardwareSerial | |||||
{ | |||||
public: | |||||
constexpr HardwareSerial5() {} | |||||
virtual void begin(uint32_t baud) { serial5_begin(BAUD2DIV3(baud)); } | |||||
virtual void begin(uint32_t baud, uint32_t format) { | |||||
serial5_begin(BAUD2DIV3(baud)); | |||||
serial5_format(format); } | |||||
virtual void end(void) { serial5_end(); } | |||||
virtual void transmitterEnable(uint8_t pin) { serial5_set_transmit_pin(pin); } | |||||
virtual void setRX(uint8_t pin) { serial5_set_rx(pin); } | |||||
virtual void setTX(uint8_t pin, bool opendrain=false) { serial5_set_tx(pin, opendrain); } | |||||
virtual bool attachRts(uint8_t pin) { return serial5_set_rts(pin); } | |||||
virtual bool attachCts(uint8_t pin) { return serial5_set_cts(pin); } | |||||
virtual int available(void) { return serial5_available(); } | |||||
virtual int peek(void) { return serial5_peek(); } | |||||
virtual int read(void) { return serial5_getchar(); } | |||||
virtual void flush(void) { serial5_flush(); } | |||||
virtual void clear(void) { serial5_clear(); } | |||||
virtual int availableForWrite(void) { return serial5_write_buffer_free(); } | |||||
using Print::write; | |||||
virtual size_t write(uint8_t c) { serial5_putchar(c); return 1; } | |||||
virtual size_t write(unsigned long n) { return write((uint8_t)n); } | |||||
virtual size_t write(long n) { return write((uint8_t)n); } | |||||
virtual size_t write(unsigned int n) { return write((uint8_t)n); } | |||||
virtual size_t write(int n) { return write((uint8_t)n); } | |||||
virtual size_t write(const uint8_t *buffer, size_t size) | |||||
{ serial5_write(buffer, size); return size; } | |||||
virtual size_t write(const char *str) { size_t len = strlen(str); | |||||
serial5_write((const uint8_t *)str, len); | |||||
return len; } | |||||
virtual size_t write9bit(uint32_t c) { serial5_putchar(c); return 1; } | |||||
operator bool() { return true; } | |||||
}; | |||||
extern HardwareSerial5 Serial5; | |||||
extern void serialEvent5(void); | |||||
class HardwareSerial6 : public HardwareSerial | |||||
{ | |||||
public: | |||||
constexpr HardwareSerial6() {} | |||||
#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, uint32_t format) { | |||||
serial6_begin(baud); | |||||
serial6_format(format); } | |||||
#else | |||||
virtual void begin(uint32_t baud) { serial6_begin(BAUD2DIV3(baud)); } | |||||
virtual void begin(uint32_t baud, uint32_t format) { | |||||
serial6_begin(BAUD2DIV3(baud)); | |||||
serial6_format(format); } | |||||
#endif | |||||
virtual void end(void) { serial6_end(); } | |||||
virtual void transmitterEnable(uint8_t pin) { serial6_set_transmit_pin(pin); } | |||||
virtual void setRX(uint8_t pin) { serial6_set_rx(pin); } | |||||
virtual void setTX(uint8_t pin, bool opendrain=false) { serial6_set_tx(pin, opendrain); } | |||||
virtual bool attachRts(uint8_t pin) { return serial6_set_rts(pin); } | |||||
virtual bool attachCts(uint8_t pin) { return serial6_set_cts(pin); } | |||||
virtual int available(void) { return serial6_available(); } | |||||
virtual int peek(void) { return serial6_peek(); } | |||||
virtual int read(void) { return serial6_getchar(); } | |||||
virtual void flush(void) { serial6_flush(); } | |||||
virtual void clear(void) { serial6_clear(); } | |||||
virtual int availableForWrite(void) { return serial6_write_buffer_free(); } | |||||
using Print::write; | |||||
virtual size_t write(uint8_t c) { serial6_putchar(c); return 1; } | |||||
virtual size_t write(unsigned long n) { return write((uint8_t)n); } | |||||
virtual size_t write(long n) { return write((uint8_t)n); } | |||||
virtual size_t write(unsigned int n) { return write((uint8_t)n); } | |||||
virtual size_t write(int n) { return write((uint8_t)n); } | |||||
virtual size_t write(const uint8_t *buffer, size_t size) | |||||
{ serial6_write(buffer, size); return size; } | |||||
virtual size_t write(const char *str) { size_t len = strlen(str); | |||||
serial6_write((const uint8_t *)str, len); | |||||
return len; } | |||||
virtual size_t write9bit(uint32_t c) { serial6_putchar(c); return 1; } | |||||
operator bool() { return true; } | |||||
}; | |||||
extern HardwareSerial6 Serial6; | |||||
extern void serialEvent6(void); | |||||
#endif | #endif | ||||
#endif | #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 "HardwareSerial.h" | #include "HardwareSerial.h" | ||||
HardwareSerial Serial1; | HardwareSerial Serial1; |
/* 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 "HardwareSerial.h" | #include "HardwareSerial.h" | ||||
HardwareSerial2 Serial2; | HardwareSerial2 Serial2; |
/* 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 "HardwareSerial.h" | #include "HardwareSerial.h" | ||||
HardwareSerial3 Serial3; | HardwareSerial3 Serial3; |
/* 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 "HardwareSerial.h" | |||||
#ifdef HAS_KINETISK_UART3 | |||||
HardwareSerial4 Serial4; | |||||
void serialEvent4() __attribute__((weak)); | |||||
void serialEvent4() {} | |||||
#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 "HardwareSerial.h" | |||||
#ifdef HAS_KINETISK_UART4 | |||||
HardwareSerial5 Serial5; | |||||
void serialEvent5() __attribute__((weak)); | |||||
void serialEvent5() {} | |||||
#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 "HardwareSerial.h" | |||||
#if defined(HAS_KINETISK_UART5) || defined (HAS_KINETISK_LPUART0) | |||||
HardwareSerial6 Serial6; | |||||
void serialEvent6() __attribute__((weak)); | |||||
void serialEvent6() {} | |||||
#endif |
#include "Arduino.h" | |||||
/* | |||||
IPAddress.cpp - Base class that provides IPAddress | |||||
Copyright (c) 2011 Adrian McEwen. All right reserved. | |||||
This library is free software; you can redistribute it and/or | |||||
modify it under the terms of the GNU Lesser General Public | |||||
License as published by the Free Software Foundation; either | |||||
version 2.1 of the License, or (at your option) any later version. | |||||
This library is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
Lesser General Public License for more details. | |||||
You should have received a copy of the GNU Lesser General Public | |||||
License along with this library; if not, write to the Free Software | |||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |||||
*/ | |||||
#include <Arduino.h> | |||||
#include "IPAddress.h" | #include "IPAddress.h" | ||||
size_t IPAddress::printTo(Print& p) const | size_t IPAddress::printTo(Print& p) const |
/* Copyright (c) 2013 Daniel Gilbert, loglow@gmail.com | |||||
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: | |||||
The above copyright notice and this permission notice shall be included in all | |||||
copies or substantial portions of the Software. | |||||
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. */ | |||||
/* 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 "IntervalTimer.h" | #include "IntervalTimer.h" | ||||
static void dummy_funct(void); | |||||
// ------------------------------------------------------------ | |||||
// static class variables need to be reiterated here before use | |||||
// ------------------------------------------------------------ | |||||
bool IntervalTimer::PIT_enabled; | |||||
bool IntervalTimer::PIT_used[]; | |||||
IntervalTimer::ISR IntervalTimer::PIT_ISR[]; | |||||
// ------------------------------------------------------------ | |||||
// these are the ISRs (Interrupt Service Routines) that get | |||||
// called by each PIT timer when it fires. they're defined here | |||||
// so that they can auto-clear themselves and so the user can | |||||
// specify a custom ISR and reassign it as needed | |||||
// ------------------------------------------------------------ | |||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
void pit0_isr() { PIT_TFLG0 = 1; IntervalTimer::PIT_ISR[0](); } | |||||
void pit1_isr() { PIT_TFLG1 = 1; IntervalTimer::PIT_ISR[1](); } | |||||
void pit2_isr() { PIT_TFLG2 = 1; IntervalTimer::PIT_ISR[2](); } | |||||
void pit3_isr() { PIT_TFLG3 = 1; IntervalTimer::PIT_ISR[3](); } | |||||
#define NUM_CHANNELS 4 | |||||
static void (*funct_table[4])(void) = {dummy_funct, dummy_funct, dummy_funct, dummy_funct}; | |||||
#elif defined(KINETISL) | #elif defined(KINETISL) | ||||
void pit_isr() { | |||||
if (PIT_TFLG0) { PIT_TFLG0 = 1; IntervalTimer::PIT_ISR[0](); } | |||||
if (!IntervalTimer::PIT_enabled) return; | |||||
if (PIT_TFLG1) { PIT_TFLG1 = 1; IntervalTimer::PIT_ISR[1](); } | |||||
} | |||||
#define NUM_CHANNELS 2 | |||||
static void (*funct_table[2])(void) = {dummy_funct, dummy_funct}; | |||||
uint8_t IntervalTimer::nvic_priorites[2] = {255, 255}; | |||||
#endif | #endif | ||||
// ------------------------------------------------------------ | |||||
// this function inits and starts the timer, using the specified | |||||
// function as a callback and the period provided. must be passed | |||||
// the name of a function taking no arguments and returning void. | |||||
// make sure this function can complete within the time allowed. | |||||
// attempts to allocate a timer using available resources, | |||||
// returning true on success or false in case of failure. | |||||
// period is specified as number of bus cycles | |||||
// ------------------------------------------------------------ | |||||
bool IntervalTimer::beginCycles(ISR newISR, uint32_t newValue) { | |||||
// if this interval timer is already running, stop it | |||||
if (status == TIMER_PIT) { | |||||
stop_PIT(); | |||||
status = TIMER_OFF; | |||||
} | |||||
// store callback pointer | |||||
myISR = newISR; | |||||
// attempt to allocate this timer | |||||
if (allocate_PIT(newValue)) status = TIMER_PIT; | |||||
else status = TIMER_OFF; | |||||
// check for success and return | |||||
if (status != TIMER_OFF) return true; | |||||
return false; | |||||
bool IntervalTimer::beginCycles(void (*funct)(), uint32_t cycles) | |||||
{ | |||||
if (channel) { | |||||
channel->TCTRL = 0; | |||||
channel->TFLG = 1; | |||||
} else { | |||||
SIM_SCGC6 |= SIM_SCGC6_PIT; | |||||
__asm__ volatile("nop"); // solves timing problem on Teensy 3.5 | |||||
PIT_MCR = 1; | |||||
channel = KINETISK_PIT_CHANNELS; | |||||
while (1) { | |||||
if (channel->TCTRL == 0) break; | |||||
if (++channel >= KINETISK_PIT_CHANNELS + NUM_CHANNELS) { | |||||
channel = NULL; | |||||
return false; | |||||
} | |||||
} | |||||
} | |||||
int index = channel - KINETISK_PIT_CHANNELS; | |||||
funct_table[index] = funct; | |||||
channel->LDVAL = cycles; | |||||
channel->TCTRL = 3; | |||||
#if defined(KINETISK) | |||||
NVIC_SET_PRIORITY(IRQ_PIT_CH0 + index, nvic_priority); | |||||
NVIC_ENABLE_IRQ(IRQ_PIT_CH0 + index); | |||||
#elif defined(KINETISL) | |||||
nvic_priorites[index] = nvic_priority; | |||||
if (nvic_priorites[0] <= nvic_priorites[1]) { | |||||
NVIC_SET_PRIORITY(IRQ_PIT, nvic_priorites[0]); | |||||
} else { | |||||
NVIC_SET_PRIORITY(IRQ_PIT, nvic_priorites[1]); | |||||
} | |||||
NVIC_ENABLE_IRQ(IRQ_PIT); | |||||
#endif | |||||
return true; | |||||
} | } | ||||
// ------------------------------------------------------------ | |||||
// stop the timer if it's currently running, using its status | |||||
// to determine what hardware resources the timer may be using | |||||
// ------------------------------------------------------------ | |||||
void IntervalTimer::end() { | void IntervalTimer::end() { | ||||
if (status == TIMER_PIT) stop_PIT(); | |||||
status = TIMER_OFF; | |||||
if (channel) { | |||||
int index = channel - KINETISK_PIT_CHANNELS; | |||||
#if defined(KINETISK) | |||||
NVIC_DISABLE_IRQ(IRQ_PIT_CH0 + index); | |||||
#elif defined(KINETISL) | |||||
// TODO: disable IRQ_PIT, but only if both instances ended | |||||
#endif | |||||
funct_table[index] = dummy_funct; | |||||
channel->TCTRL = 0; | |||||
#if defined(KINETISL) | |||||
nvic_priorites[index] = 255; | |||||
if (nvic_priorites[0] <= nvic_priorites[1]) { | |||||
NVIC_SET_PRIORITY(IRQ_PIT, nvic_priorites[0]); | |||||
} else { | |||||
NVIC_SET_PRIORITY(IRQ_PIT, nvic_priorites[1]); | |||||
} | |||||
#endif | |||||
channel = 0; | |||||
} | |||||
} | } | ||||
// ------------------------------------------------------------ | |||||
// enables the PIT clock bit, the master PIT reg, and sets flag | |||||
// ------------------------------------------------------------ | |||||
void IntervalTimer::enable_PIT() { | |||||
SIM_SCGC6 |= SIM_SCGC6_PIT; | |||||
PIT_MCR = 0; | |||||
PIT_enabled = true; | |||||
#if defined(KINETISK) | |||||
void pit0_isr() | |||||
{ | |||||
PIT_TFLG0 = 1; | |||||
funct_table[0](); | |||||
} | } | ||||
// ------------------------------------------------------------ | |||||
// disables the master PIT reg, the PIT clock bit, and unsets flag | |||||
// ------------------------------------------------------------ | |||||
void IntervalTimer::disable_PIT() { | |||||
PIT_MCR = 1; | |||||
SIM_SCGC6 &= ~SIM_SCGC6_PIT; | |||||
PIT_enabled = false; | |||||
void pit1_isr() { | |||||
PIT_TFLG1 = 1; | |||||
funct_table[1](); | |||||
} | } | ||||
// ------------------------------------------------------------ | |||||
// enables the PIT clock if not already enabled, then checks to | |||||
// see if any PITs are available for use. if one is available, | |||||
// it's initialized and started with the specified value, and | |||||
// the function returns true, otherwise it returns false | |||||
// ------------------------------------------------------------ | |||||
bool IntervalTimer::allocate_PIT(uint32_t newValue) { | |||||
// enable clock to the PIT module if necessary | |||||
if (!PIT_enabled) enable_PIT(); | |||||
// check for an available PIT, and if so, start it | |||||
for (uint8_t id = 0; id < NUM_PIT; id++) { | |||||
if (!PIT_used[id]) { | |||||
PIT_id = id; | |||||
start_PIT(newValue); | |||||
PIT_used[id] = true; | |||||
return true; | |||||
} | |||||
} | |||||
// no PIT available | |||||
return false; | |||||
void pit2_isr() { | |||||
PIT_TFLG2 = 1; | |||||
funct_table[2](); | |||||
} | } | ||||
// ------------------------------------------------------------ | |||||
// configuters a PIT's registers, function pointer, and enables | |||||
// interrupts, effectively starting the timer upon completion | |||||
// ------------------------------------------------------------ | |||||
void IntervalTimer::start_PIT(uint32_t newValue) { | |||||
// point to the correct registers | |||||
PIT_LDVAL = &PIT_LDVAL0 + PIT_id * 4; | |||||
PIT_TCTRL = &PIT_TCTRL0 + PIT_id * 4; | |||||
// point to the correct PIT ISR | |||||
PIT_ISR[PIT_id] = myISR; | |||||
// write value to register and enable interrupt | |||||
*PIT_TCTRL = 0; | |||||
*PIT_LDVAL = newValue; | |||||
*PIT_TCTRL = 3; | |||||
#if defined(KINETISK) | |||||
IRQ_PIT_CH = IRQ_PIT_CH0 + PIT_id; | |||||
NVIC_SET_PRIORITY(IRQ_PIT_CH, nvic_priority); | |||||
NVIC_ENABLE_IRQ(IRQ_PIT_CH); | |||||
#elif defined(KINETISL) | |||||
NVIC_SET_PRIORITY(IRQ_PIT, nvic_priority); // TODO: use the higher of both channels, shared irq | |||||
NVIC_ENABLE_IRQ(IRQ_PIT); | |||||
#endif | |||||
void pit3_isr() { | |||||
PIT_TFLG3 = 1; | |||||
funct_table[3](); | |||||
} | } | ||||
// ------------------------------------------------------------ | |||||
// stops an active PIT by disabling its interrupt, writing to | |||||
// its control register, and freeing up its state for future use. | |||||
// also, if no PITs remain in use, disables the core PIT clock | |||||
// ------------------------------------------------------------ | |||||
void IntervalTimer::stop_PIT() { | |||||
// disable interrupt and PIT | |||||
*PIT_TCTRL = 0; | |||||
#if defined(KINETISK) | |||||
NVIC_DISABLE_IRQ(IRQ_PIT_CH); | |||||
#elif defined(KINETISL) | #elif defined(KINETISL) | ||||
NVIC_DISABLE_IRQ(IRQ_PIT); | |||||
#endif | |||||
// free PIT for future use | |||||
PIT_used[PIT_id] = false; | |||||
// check if we're still using any PIT | |||||
for (uint8_t id = 0; id < NUM_PIT; id++) { | |||||
if (PIT_used[id]) return; | |||||
} | |||||
// none used, disable PIT clock | |||||
disable_PIT(); | |||||
void pit_isr() { | |||||
if (PIT_TFLG0) { | |||||
PIT_TFLG0 = 1; | |||||
funct_table[0](); | |||||
} | |||||
if (PIT_TFLG1) { | |||||
PIT_TFLG1 = 1; | |||||
funct_table[1](); | |||||
} | |||||
} | } | ||||
#endif | |||||
static void dummy_funct(void) | |||||
{ | |||||
} | |||||
/* Copyright (c) 2013 Daniel Gilbert, loglow@gmail.com | |||||
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: | |||||
The above copyright notice and this permission notice shall be included in all | |||||
copies or substantial portions of the Software. | |||||
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. */ | |||||
/* 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 __INTERVALTIMER_H__ | #ifndef __INTERVALTIMER_H__ | ||||
#define __INTERVALTIMER_H__ | #define __INTERVALTIMER_H__ | ||||
#endif | #endif | ||||
class IntervalTimer { | class IntervalTimer { | ||||
private: | |||||
typedef void (*ISR)(); | |||||
typedef volatile uint32_t* reg; | |||||
enum {TIMER_OFF, TIMER_PIT}; | |||||
#if defined(KINETISK) | |||||
static const uint8_t NUM_PIT = 4; | |||||
#elif defined(KINETISL) | |||||
static const uint8_t NUM_PIT = 2; | |||||
#endif | |||||
static const uint32_t MAX_PERIOD = UINT32_MAX / (F_BUS / 1000000.0); | |||||
static void enable_PIT(); | |||||
static void disable_PIT(); | |||||
static bool PIT_enabled; | |||||
static bool PIT_used[NUM_PIT]; | |||||
static ISR PIT_ISR[NUM_PIT]; | |||||
bool allocate_PIT(uint32_t newValue); | |||||
void start_PIT(uint32_t newValue); | |||||
void stop_PIT(); | |||||
bool status; | |||||
uint8_t PIT_id; | |||||
reg PIT_LDVAL; | |||||
reg PIT_TCTRL; | |||||
uint8_t IRQ_PIT_CH; | |||||
uint8_t nvic_priority; | |||||
ISR myISR; | |||||
bool beginCycles(ISR newISR, uint32_t cycles); | |||||
public: | |||||
IntervalTimer() { status = TIMER_OFF; nvic_priority = 128; } | |||||
~IntervalTimer() { end(); } | |||||
bool begin(ISR newISR, unsigned int newPeriod) { | |||||
if (newPeriod == 0 || newPeriod > MAX_PERIOD) return false; | |||||
uint32_t newValue = (F_BUS / 1000000) * newPeriod - 1; | |||||
return beginCycles(newISR, newValue); | |||||
} | |||||
bool begin(ISR newISR, int newPeriod) { | |||||
if (newPeriod < 0) return false; | |||||
return begin(newISR, (unsigned int)newPeriod); | |||||
} | |||||
bool begin(ISR newISR, unsigned long newPeriod) { | |||||
return begin(newISR, (unsigned int)newPeriod); | |||||
} | |||||
bool begin(ISR newISR, long newPeriod) { | |||||
return begin(newISR, (int)newPeriod); | |||||
} | |||||
bool begin(ISR newISR, float newPeriod) { | |||||
if (newPeriod <= 0 || newPeriod > MAX_PERIOD) return false; | |||||
uint32_t newValue = (float)(F_BUS / 1000000) * newPeriod - 0.5; | |||||
if (newValue < 40) return false; | |||||
return beginCycles(newISR, newValue); | |||||
} | |||||
bool begin(ISR newISR, double newPeriod) { | |||||
return begin(newISR, (float)newPeriod); | |||||
} | |||||
void end(); | |||||
void priority(uint8_t n) { | |||||
nvic_priority = n; | |||||
if (PIT_enabled) NVIC_SET_PRIORITY(IRQ_PIT_CH, n); | |||||
} | |||||
operator IRQ_NUMBER_t() { | |||||
if (PIT_enabled) { | |||||
#if defined(KINETISK) | |||||
return (IRQ_NUMBER_t)(IRQ_PIT_CH + PIT_id); | |||||
#elif defined(KINETISL) | |||||
return IRQ_PIT; | |||||
#endif | |||||
} | |||||
return (IRQ_NUMBER_t)NVIC_NUM_INTERRUPTS; | |||||
} | |||||
#if defined(KINETISK) | |||||
friend void pit0_isr(); | |||||
friend void pit1_isr(); | |||||
friend void pit2_isr(); | |||||
friend void pit3_isr(); | |||||
#elif defined(KINETISL) | |||||
friend void pit_isr(); | |||||
#endif | |||||
private: | |||||
static const uint32_t MAX_PERIOD = UINT32_MAX / (F_BUS / 1000000.0); | |||||
public: | |||||
IntervalTimer() { | |||||
channel = NULL; | |||||
nvic_priority = 128; | |||||
} | |||||
~IntervalTimer() { | |||||
end(); | |||||
} | |||||
bool begin(void (*funct)(), unsigned int microseconds) { | |||||
if (microseconds == 0 || microseconds > MAX_PERIOD) return false; | |||||
uint32_t cycles = (F_BUS / 1000000) * microseconds - 1; | |||||
if (cycles < 36) return false; | |||||
return beginCycles(funct, cycles); | |||||
} | |||||
bool begin(void (*funct)(), int microseconds) { | |||||
if (microseconds < 0) return false; | |||||
return begin(funct, (unsigned int)microseconds); | |||||
} | |||||
bool begin(void (*funct)(), unsigned long microseconds) { | |||||
return begin(funct, (unsigned int)microseconds); | |||||
} | |||||
bool begin(void (*funct)(), long microseconds) { | |||||
return begin(funct, (int)microseconds); | |||||
} | |||||
bool begin(void (*funct)(), float microseconds) { | |||||
if (microseconds <= 0 || microseconds > MAX_PERIOD) return false; | |||||
uint32_t cycles = (float)(F_BUS / 1000000) * microseconds - 0.5; | |||||
if (cycles < 36) return false; | |||||
return beginCycles(funct, cycles); | |||||
} | |||||
bool begin(void (*funct)(), double microseconds) { | |||||
return begin(funct, (float)microseconds); | |||||
} | |||||
void update(unsigned int microseconds) { | |||||
if (microseconds == 0 || microseconds > MAX_PERIOD) return; | |||||
uint32_t cycles = (F_BUS / 1000000) * microseconds - 1; | |||||
if (cycles < 36) return; | |||||
if (channel) channel->LDVAL = cycles; | |||||
} | |||||
void update(int microseconds) { | |||||
if (microseconds < 0) return; | |||||
return update((unsigned int)microseconds); | |||||
} | |||||
void update(unsigned long microseconds) { | |||||
return update((unsigned int)microseconds); | |||||
} | |||||
void update(long microseconds) { | |||||
return update((int)microseconds); | |||||
} | |||||
void update(float microseconds) { | |||||
if (microseconds <= 0 || microseconds > MAX_PERIOD) return; | |||||
uint32_t cycles = (float)(F_BUS / 1000000) * microseconds - 0.5; | |||||
if (cycles < 36) return; | |||||
if (channel) channel->LDVAL = cycles; | |||||
} | |||||
void update(double microseconds) { | |||||
return update((float)microseconds); | |||||
} | |||||
void end(); | |||||
void priority(uint8_t n) { | |||||
nvic_priority = n; | |||||
#if defined(KINETISK) | |||||
if (channel) { | |||||
int index = channel - KINETISK_PIT_CHANNELS; | |||||
NVIC_SET_PRIORITY(IRQ_PIT_CH0 + index, nvic_priority); | |||||
} | |||||
#elif defined(KINETISL) | |||||
if (channel) { | |||||
int index = channel - KINETISK_PIT_CHANNELS; | |||||
nvic_priorites[index] = nvic_priority; | |||||
if (nvic_priorites[0] <= nvic_priorites[1]) { | |||||
NVIC_SET_PRIORITY(IRQ_PIT, nvic_priorites[0]); | |||||
} else { | |||||
NVIC_SET_PRIORITY(IRQ_PIT, nvic_priorites[1]); | |||||
} | |||||
} | |||||
#endif | |||||
} | |||||
operator IRQ_NUMBER_t() { | |||||
if (channel) { | |||||
#if defined(KINETISK) | |||||
int index = channel - KINETISK_PIT_CHANNELS; | |||||
return (IRQ_NUMBER_t)(IRQ_PIT_CH0 + index); | |||||
#elif defined(KINETISL) | |||||
return IRQ_PIT; | |||||
#endif | |||||
} | |||||
return (IRQ_NUMBER_t)NVIC_NUM_INTERRUPTS; | |||||
} | |||||
private: | |||||
KINETISK_PIT_CHANNEL_t *channel; | |||||
uint8_t nvic_priority; | |||||
#if defined(KINETISL) | |||||
static uint8_t nvic_priorites[2]; | |||||
#endif | |||||
bool beginCycles(void (*funct)(), uint32_t cycles); | |||||
}; | }; | ||||
// empty Keyboard.h file, for compability with Arduino's Keyboard examples | |||||
// This header file is in the public domain. |
#ifndef MIDIUSB_h | |||||
#define MIDIUSB_h | |||||
// For compatibility with Arduino's MIDIUSB library | |||||
#include "usb_midi.h" | |||||
#ifdef __cplusplus | |||||
#if !defined(USB_MIDI) && !defined(USB_MIDI4) && !defined(USB_MIDI16) && !defined(USB_MIDI_SERIAL) && !defined(USB_MIDI4_SERIAL) && !defined(USB_MIDI16_SERIAL) && !defined(USB_MIDI_AUDIO_SERIAL) && !defined(USB_MIDI16_AUDIO_SERIAL) && !defined(USB_EVERYTHING) | |||||
#error "Please select MIDI in Tools > USB Type to use MIDIUSB.h" | |||||
#endif | |||||
typedef struct { | |||||
union { | |||||
struct { | |||||
uint8_t header; | |||||
uint8_t byte1; | |||||
uint8_t byte2; | |||||
uint8_t byte3; | |||||
}; | |||||
uint32_t word; | |||||
}; | |||||
} midiEventPacket_t; | |||||
class MIDI_ | |||||
{ | |||||
public: | |||||
constexpr MIDI_(void) { } | |||||
uint32_t available(void) { | |||||
return usb_midi_available(); | |||||
} | |||||
midiEventPacket_t read(void) { | |||||
midiEventPacket_t event; | |||||
event.word = usb_midi_read_message(); | |||||
return event; | |||||
} | |||||
void flush(void) { | |||||
usb_midi_flush_output(); | |||||
} | |||||
void sendMIDI(midiEventPacket_t event) { | |||||
usb_midi_write_packed(event.word); | |||||
} | |||||
size_t write(const uint8_t *buffer, size_t size) { | |||||
// TODO - is this really needed? | |||||
return 0; | |||||
} | |||||
operator bool() { | |||||
// TODO - is this really needed? | |||||
return true; | |||||
} | |||||
}; | |||||
extern MIDI_ MidiUSB; | |||||
#endif // __cplusplus | |||||
#endif // MIDIUSB_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. | |||||
# set your MCU type here, or make command line `make MCU=MK20DX256` | # set your MCU type here, or make command line `make MCU=MK20DX256` | ||||
MCU=MK20DX256 | MCU=MK20DX256 | ||||
#MCU=MKL26Z64 | |||||
#MCU=MK64FX512 | |||||
#MCU=MK66FX1M0 | |||||
# make it lower case | # make it lower case | ||||
LOWER_MCU := $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(MCU))))))))))))))))))))))))))) | LOWER_MCU := $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(MCU))))))))))))))))))))))))))) | ||||
ifndef NO_ARDUINO | ifndef NO_ARDUINO | ||||
# Path to your arduino installation | # Path to your arduino installation | ||||
ARDUINOPATH ?= ../../../../.. | ARDUINOPATH ?= ../../../../.. | ||||
#ARDUINOPATH ?= ../../../.. | |||||
endif | endif | ||||
# configurable options | # configurable options | ||||
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.0 | |||||
OPTIONS += -D__$(MCU)__ -DARDUINO=10600 -DTEENSYDUINO=121 | |||||
# options needed by many Arduino libraries to configure for Teensy 3.x | |||||
OPTIONS += -D__$(MCU)__ -DARDUINO=10805 -DTEENSYDUINO=144 | |||||
# use "cortex-m4" for Teensy 3.x | |||||
# use "cortex-m0plus" for Teensy LC | |||||
CPUARCH = cortex-m4 | |||||
#CPUARCH = cortex-m0plus | |||||
# Other Makefiles and project templates for Teensy 3.x: | # Other Makefiles and project templates for Teensy 3.x: | ||||
ifdef ARDUINOPATH | ifdef ARDUINOPATH | ||||
# path location for Teensy Loader, teensy_post_compile and teensy_reboot | |||||
TOOLSPATH = $(abspath $(ARDUINOPATH)/hardware/tools) # on Linux | |||||
# path location for Teensy Loader, teensy_post_compile and teensy_reboot (on Linux) | |||||
TOOLSPATH = $(abspath $(ARDUINOPATH)/hardware/tools) | |||||
# path location for Arduino libraries (currently not used) | # path location for Arduino libraries (currently not used) | ||||
LIBRARYPATH = $(abspath $(ARDUINOPATH)/libraries) | LIBRARYPATH = $(abspath $(ARDUINOPATH)/libraries) | ||||
#************************************************************************ | #************************************************************************ | ||||
# CPPFLAGS = compiler options for C and C++ | # CPPFLAGS = compiler options for C and C++ | ||||
CPPFLAGS = -Wall -g -Os -mcpu=cortex-m4 -mthumb -MMD $(OPTIONS) -I. | |||||
CPPFLAGS = -Wall -g -Os -mcpu=$(CPUARCH) -mthumb -MMD $(OPTIONS) -I. | |||||
# compiler options for C++ only | # compiler options for C++ only | ||||
CXXFLAGS = -std=gnu++0x -felide-constructors -fno-exceptions -fno-rtti | |||||
CXXFLAGS = -std=gnu++14 -felide-constructors -fno-exceptions -fno-rtti | |||||
# compiler options for C only | # compiler options for C only | ||||
CFLAGS = | CFLAGS = | ||||
# linker options | # linker options | ||||
LDFLAGS = -Os -Wl,--gc-sections,--defsym=__rtc_localtime=0 --specs=nano.specs -mcpu=cortex-m4 -mthumb -T$(MCU_LD) | |||||
LDFLAGS = -Os -Wl,--gc-sections,--defsym=__rtc_localtime=0 --specs=nano.specs -mcpu=$(CPUARCH) -mthumb -T$(MCU_LD) | |||||
# additional libraries to link | # additional libraries to link | ||||
LIBS = -lm | LIBS = -lm |
// empty Mouse.h file, for compability with Arduino's Mouse examples | |||||
// This header file is in the public domain. |
/* | |||||
Print.cpp - Base class that provides print() and println() | |||||
Copyright (c) 2008 David A. Mellis. All right reserved. | |||||
many modifications, by Paul Stoffregen <paul@pjrc.com> | |||||
This library is free software; you can redistribute it and/or | |||||
modify it under the terms of the GNU Lesser General Public | |||||
License as published by the Free Software Foundation; either | |||||
version 2.1 of the License, or (at your option) any later version. | |||||
This library is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
Lesser General Public License for more details. | |||||
You should have received a copy of the GNU Lesser General Public | |||||
License along with this library; if not, write to the Free Software | |||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |||||
Modified 23 November 2006 by David A. Mellis | |||||
/* 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 <stdio.h> | |||||
//#include <string.h> | |||||
#include <inttypes.h> | |||||
//#include <math.h> | |||||
//#include <avr/pgmspace.h> | |||||
//#include "wiring.h" | |||||
#include "Print.h" | |||||
// Long ago this file contained code from Arduino.cc, which was | |||||
// Copyright (c) 2008 David A. Mellis. No substantial portion of | |||||
// Arduino's original code remains. In fact, several improvements | |||||
// developed for Teensyduino have made their way back into | |||||
// Arduino's code base. :-) | |||||
#include <Arduino.h> | |||||
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; | ||||
int _write(int file, char *ptr, int len) | int _write(int file, char *ptr, int len) | ||||
{ | { | ||||
((class Print *)file)->write((uint8_t *)ptr, len); | ((class Print *)file)->write((uint8_t *)ptr, len); | ||||
return 0; | |||||
return len; | |||||
} | } | ||||
} | } | ||||
uint8_t sign=0; | uint8_t sign=0; | ||||
size_t count=0; | size_t count=0; | ||||
if (isnan(number)) return print("nan"); | |||||
if (isinf(number)) return print("inf"); | |||||
if (number > 4294967040.0f) return print("ovf"); // constant determined empirically | |||||
if (number <-4294967040.0f) return print("ovf"); // constant determined empirically | |||||
// Handle negative numbers | // Handle negative numbers | ||||
if (number < 0.0) { | if (number < 0.0) { | ||||
sign = 1; | sign = 1; |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
#define HEX 16 | #define HEX 16 | ||||
#define OCT 8 | #define OCT 8 | ||||
#define BIN 2 | #define BIN 2 | ||||
#define BYTE 0 | |||||
// BYTE was defined in very old versions of Arduino | |||||
// maybe this now causes more trouble than it's worth? | |||||
//#ifndef BYTE | |||||
//#define BYTE 0 | |||||
//#endif | |||||
class __FlashStringHelper; | class __FlashStringHelper; | ||||
class Print | class Print | ||||
{ | { | ||||
public: | public: | ||||
Print() : write_error(0) {} | |||||
constexpr Print() : write_error(0) {} | |||||
virtual size_t write(uint8_t b) = 0; | virtual size_t write(uint8_t b) = 0; | ||||
size_t write(const char *str) { return write((const uint8_t *)str, strlen(str)); } | size_t write(const char *str) { return write((const uint8_t *)str, strlen(str)); } | ||||
virtual size_t write(const uint8_t *buffer, size_t size); | virtual size_t write(const uint8_t *buffer, size_t size); | ||||
virtual int availableForWrite(void) { return 0; } | |||||
virtual void flush() { } | |||||
size_t write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); } | size_t write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); } | ||||
size_t print(const String &s); | size_t print(const String &s); | ||||
size_t print(char c) { return write((uint8_t)c); } | size_t print(char c) { return write((uint8_t)c); } |
/* 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 _SPIFIFO_h_ | #ifndef _SPIFIFO_h_ | ||||
#define _SPIFIFO_h_ | #define _SPIFIFO_h_ | ||||
#ifdef KINETISK | #ifdef KINETISK | ||||
#if F_BUS == 60000000 | |||||
// The preferred way to set SPI speed is with SPI.beginTransaction() | |||||
#if F_BUS == 128000000 | |||||
#define HAS_SPIFIFO | |||||
#define SPI_CLOCK_24MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0)) //(128 / 3) * ((1+0)/2) = 21.3MHz | |||||
#define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2)) //(128 / 2) * ((1+0)/4) | |||||
#define SPI_CLOCK_12MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(2)) //(128 / 3) * ((1+0)/4) = 10.6 MHz | |||||
#define SPI_CLOCK_8MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(6)) //(128 / 2) * ((1+0)/8) | |||||
#define SPI_CLOCK_6MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(6)) //(128 / 3) * ((1+0)/8) = 5.3 MHz | |||||
#define SPI_CLOCK_4MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(6)) //(128 / 5) * ((1+0)/8) = 3.2MHz | |||||
#elif F_BUS == 120000000 | |||||
#define HAS_SPIFIFO | |||||
#define SPI_CLOCK_24MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(120 / 5) * ((1+1)/2) | |||||
#define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2)) //(120 / 2) * ((1+0)/4) = 15 MHz | |||||
#define SPI_CLOCK_12MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(0)) //(120 / 5) * ((1+0)/2) | |||||
#define SPI_CLOCK_8MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(4) | SPI_CTAR_DBR) //(120 / 5) * ((1+1)/6) | |||||
#define SPI_CLOCK_6MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(2)) //(120 / 5) * ((1+0)/4) | |||||
#define SPI_CLOCK_4MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(4)) //(120 / 5) * ((1+0)/6) | |||||
#elif F_BUS == 108000000 | |||||
#define HAS_SPIFIFO | |||||
#define SPI_CLOCK_24MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(108 / 5) * ((1+1)/2) = 21.6 MHz | |||||
#define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2)) //(108 / 2) * ((1+0)/4) = 13.5 MHz | |||||
#define SPI_CLOCK_12MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(4) | SPI_CTAR_DBR) //(108 / 3) * ((1+1)/6) | |||||
#define SPI_CLOCK_8MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(4) | SPI_CTAR_DBR) //(108 / 5) * ((1+1)/6) = 7.2 MHz | |||||
#define SPI_CLOCK_6MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(4)) //(108 / 3) * ((1+0)/6) | |||||
#define SPI_CLOCK_4MHz (SPI_CTAR_PBR(5) | SPI_CTAR_BR(2)) //(108 / 7) * ((1+0)/4) = 3.86 MHz | |||||
#elif F_BUS == 96000000 | |||||
#define HAS_SPIFIFO | |||||
#define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(96 / 2) * ((1+0)/2) | |||||
#define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(4) | SPI_CTAR_DBR) //(96 / 2) * ((1+1)/6) | |||||
#define SPI_CLOCK_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(6) | SPI_CTAR_DBR) //(96 / 2) * ((1+1)/8) | |||||
#define SPI_CLOCK_8MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(2)) //(96 / 3) * ((1+0)/4) | |||||
#define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(6)) //(96 / 2) * ((1+0)/8) | |||||
#define SPI_CLOCK_4MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(6)) //(96 / 3) * ((1+0)/8) | |||||
#elif F_BUS == 90000000 | |||||
#define HAS_SPIFIFO | |||||
#define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(90 / 2) * ((1+0)/2) = 22.5 MHz | |||||
#define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(4) | SPI_CTAR_DBR) //(90 / 2) * ((1+1)/6) = 15 MHz | |||||
#define SPI_CLOCK_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(6) | SPI_CTAR_DBR) //(90 / 2) * ((1+1)/8) = 11.25 MHz | |||||
#define SPI_CLOCK_8MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(4)) //(90 / 2) * ((1+0)/6) = 7.5 MHz | |||||
#define SPI_CLOCK_6MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(4) | SPI_CTAR_DBR) //(90 / 5) * ((1+1)/6) | |||||
#define SPI_CLOCK_4MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(6)) //(90 / 3) * ((1+0)/8) = 3.75 MHz | |||||
#elif F_BUS == 80000000 | |||||
#define HAS_SPIFIFO | |||||
#define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(80 / 2) * ((1+0)/2) = 20 MHz | |||||
#define SPI_CLOCK_16MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(80 / 5) * ((1+1)/2) | |||||
#define SPI_CLOCK_12MHz (SPI_CTAR_PBR(5) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(80 / 7) * ((1+1)/2) = 11.42 MHz | |||||
#define SPI_CLOCK_8MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(0)) //(80 / 5) * ((1+0)/2) | |||||
#define SPI_CLOCK_6MHz (SPI_CTAR_PBR(5) | SPI_CTAR_BR(0)) //(80 / 7) * ((1+0)/2) = 5.7 MHz | |||||
#define SPI_CLOCK_4MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(2)) //(80 / 5) * ((1+0)/4) | |||||
#elif F_BUS == 72000000 | |||||
#define HAS_SPIFIFO | |||||
#define SPI_CLOCK_24MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(72 / 3) * ((1+1)/2) | |||||
#define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(4) | SPI_CTAR_DBR) //(72 / 2) * ((1+1)/6) = 12 MHz | |||||
#define SPI_CLOCK_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(4) | SPI_CTAR_DBR) //(72 / 2) * ((1+1)/6) | |||||
#define SPI_CLOCK_8MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(4) | SPI_CTAR_DBR) //(72 / 3) * ((1+1)/6) | |||||
#define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(4)) //(72 / 2) * ((1+0)/6) | |||||
#define SPI_CLOCK_4MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(4)) //(72 / 3) * ((1+0)/6) | |||||
#elif F_BUS == 64000000 | |||||
#define HAS_SPIFIFO | |||||
#define SPI_CLOCK_24MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(64 / 3) * ((1+1)/2) = 21.3 MHz | |||||
#define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(64 / 2) * ((1+0)/2) | |||||
#define SPI_CLOCK_12MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0)) //(64 / 3) * ((1+0)/2) = 10.67 MHz | |||||
#define SPI_CLOCK_8MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2)) //(64 / 2) * ((1+0)/4) | |||||
#define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(4)) //(64 / 2) * ((1+0)/6) = 5.3 MHz | |||||
#define SPI_CLOCK_4MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(6)) //(64 / 2) * ((1+0)/8) | |||||
#elif F_BUS == 60000000 | |||||
#define HAS_SPIFIFO | #define HAS_SPIFIFO | ||||
#define SPI_CLOCK_24MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(60 / 3) * ((1+1)/2) = 20 MHz | #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(60 / 3) * ((1+1)/2) = 20 MHz | ||||
#define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(60 / 2) * ((1+0)/2) = 15 MHz | #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(60 / 2) * ((1+0)/2) = 15 MHz | ||||
class SPIFIFOclass | class SPIFIFOclass | ||||
{ | { | ||||
public: | public: | ||||
inline void begin(uint8_t pin, uint32_t speed, uint32_t mode=SPI_MODE0) __attribute__((always_inline)) { | |||||
inline void begin(uint8_t pin, uint32_t speed, uint32_t mode=SPI_MODE0) __attribute__((always_inline, deprecated)) { | |||||
uint32_t p, ctar = speed; | uint32_t p, ctar = speed; | ||||
SIM_SCGC6 |= SIM_SCGC6_SPI0; | SIM_SCGC6 |= SIM_SCGC6_SPI0; | ||||
} else if (pin == 15) { // PTC0 | } else if (pin == 15) { // PTC0 | ||||
CORE_PIN15_CONFIG = PORT_PCR_MUX(2); | CORE_PIN15_CONFIG = PORT_PCR_MUX(2); | ||||
p = 0x10; | p = 0x10; | ||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
} else if (pin == 26) { | |||||
CORE_PIN26_CONFIG = PORT_PCR_MUX(2); | |||||
p = 0x01; | |||||
#endif | |||||
} else { | } else { | ||||
reg = portOutputRegister(pin); | reg = portOutputRegister(pin); | ||||
pinMode(pin, OUTPUT); | pinMode(pin, OUTPUT); |
/* | |||||
Server.h - Base class that provides Server | |||||
Copyright (c) 2011 Adrian McEwen. All right reserved. | |||||
This library is free software; you can redistribute it and/or | |||||
modify it under the terms of the GNU Lesser General Public | |||||
License as published by the Free Software Foundation; either | |||||
version 2.1 of the License, or (at your option) any later version. | |||||
This library is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
Lesser General Public License for more details. | |||||
You should have received a copy of the GNU Lesser General Public | |||||
License along with this library; if not, write to the Free Software | |||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |||||
*/ | |||||
#if ARDUINO >= 100 | #if ARDUINO >= 100 | ||||
#ifndef server_h | #ifndef server_h | ||||
#define server_h | #define server_h | ||||
#include "Print.h" | |||||
class Server : public Print { | class Server : public Print { | ||||
public: | public: | ||||
virtual void begin() =0; | virtual void begin() =0; |
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 | ||||
} | } | ||||
// find returns true if the target string is found | // find returns true if the target string is found | ||||
bool Stream::find(char *target) | |||||
bool Stream::find(const char *target) | |||||
{ | { | ||||
return findUntil(target, NULL); | return findUntil(target, NULL); | ||||
} | } | ||||
// reads data from the stream until the target string of given length is found | // reads data from the stream until the target string of given length is found | ||||
// returns true if target string is found, false if timed out | // returns true if target string is found, false if timed out | ||||
bool Stream::find(char *target, size_t length) | |||||
bool Stream::find(const char *target, size_t length) | |||||
{ | { | ||||
return findUntil(target, length, NULL, 0); | return findUntil(target, length, NULL, 0); | ||||
} | } | ||||
// 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(char *target, 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 | ||||
// search terminated if the terminator string is found | // search terminated if the terminator string is found | ||||
// returns true if target string is found, false if terminated or timed out | // returns true if target string is found, false if terminated or timed out | ||||
bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen) | |||||
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen) | |||||
{ | { | ||||
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); | ||||
boolean isNegative = false; | boolean isNegative = false; | ||||
boolean isFraction = false; | boolean isFraction = false; | ||||
long value = 0; | long value = 0; | ||||
char c; | |||||
int c; | |||||
float fraction = 1.0; | float fraction = 1.0; | ||||
c = peekNextDigit(); | c = peekNextDigit(); | ||||
// | // | ||||
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; | ||||
String Stream::readString(size_t max) | String Stream::readString(size_t max) | ||||
{ | { | ||||
String str; | String str; | ||||
size_t length = str.length(); | |||||
size_t length = 0; | |||||
while (length < max) { | while (length < max) { | ||||
int c = timedRead(); | int c = timedRead(); | ||||
if (c < 0) { | if (c < 0) { | ||||
} | } | ||||
if (c == 0) break; | if (c == 0) break; | ||||
str += (char)c; | str += (char)c; | ||||
length++; | |||||
} | } | ||||
return str; | return str; | ||||
} | } | ||||
String Stream::readStringUntil(char terminator, size_t max) | String Stream::readStringUntil(char terminator, size_t max) | ||||
{ | { | ||||
String str; | String str; | ||||
size_t length = str.length(); | |||||
size_t length = 0; | |||||
while (length < max) { | while (length < max) { | ||||
int c = timedRead(); | int c = timedRead(); | ||||
if (c < 0) { | if (c < 0) { | ||||
} | } | ||||
if (c == 0 || c == terminator) break; | if (c == 0 || c == terminator) break; | ||||
str += (char)c; | str += (char)c; | ||||
length++; | |||||
} | } | ||||
return str; | return str; | ||||
} | } | ||||
class Stream : public Print | class Stream : public Print | ||||
{ | { | ||||
public: | public: | ||||
Stream() : _timeout(1000), read_error(0) {} | |||||
constexpr Stream() : _timeout(1000), read_error(0) {} | |||||
virtual int available() = 0; | virtual int available() = 0; | ||||
virtual int read() = 0; | virtual int read() = 0; | ||||
virtual int peek() = 0; | virtual int peek() = 0; | ||||
virtual void flush() = 0; | |||||
void setTimeout(unsigned long timeout); | void setTimeout(unsigned long timeout); | ||||
bool find(char *target); | |||||
bool find(uint8_t *target) { return find ((char *)target); } | |||||
bool find(char *target, size_t length); | |||||
bool find(uint8_t *target, size_t length) { return find ((char *)target, length); } | |||||
bool findUntil(char *target, char *terminator); | |||||
bool findUntil(uint8_t *target, char *terminator) { return findUntil((char *)target, terminator); } | |||||
bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); | |||||
bool findUntil(uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((char *)target, targetLen, terminate, termLen); } | |||||
bool find(const char *target); | |||||
bool find(const uint8_t *target) { return find ((const char *)target); } | |||||
bool find(const String &target) { return find(target.c_str()); } | |||||
bool find(const char *target, size_t length); | |||||
bool find(const uint8_t *target, size_t length) { return find ((const char *)target, length); } | |||||
bool find(const String &target, size_t length) { return find(target.c_str(), length); } | |||||
bool findUntil(const char *target, const char *terminator); | |||||
bool findUntil(const uint8_t *target, const char *terminator) { return findUntil((const char *)target, terminator); } | |||||
bool findUntil(const String &target, const char *terminator) { return findUntil(target.c_str(), terminator); } | |||||
bool findUntil(const char *target, const String &terminator) { return findUntil(target, terminator.c_str()); } | |||||
bool findUntil(const String &target, const String &terminator) { return findUntil(target.c_str(), terminator.c_str()); } | |||||
bool findUntil(const char *target, size_t targetLen, const char *terminate, size_t termLen); | |||||
bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen) {return findUntil((const char *)target, targetLen, terminate, termLen); } | |||||
bool findUntil(const String &target, size_t targetLen, const char *terminate, size_t termLen); | |||||
bool findUntil(const char *target, size_t targetLen, const String &terminate, size_t termLen); | |||||
bool findUntil(const String &target, size_t targetLen, const String &terminate, size_t termLen); | |||||
long parseInt(); | long parseInt(); | ||||
long parseInt(char skipChar); | long parseInt(char skipChar); | ||||
float parseFloat(); | float parseFloat(); | ||||
float parseFloat(char skipChar); | float parseFloat(char skipChar); | ||||
size_t readBytes(char *buffer, size_t length); | size_t readBytes(char *buffer, size_t length); | ||||
size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); } | |||||
size_t readBytes(uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); } | |||||
size_t readBytesUntil(char terminator, char *buffer, size_t length); | size_t readBytesUntil(char terminator, char *buffer, size_t length); | ||||
size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length) { return readBytesUntil(terminator, (char *)buffer, length); } | size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length) { return readBytesUntil(terminator, (char *)buffer, length); } | ||||
String readString(size_t max = 120); | String readString(size_t max = 120); |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
* 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 | ||||
} else { | } else { | ||||
count = 0xFFFFFFFD; | count = 0xFFFFFFFD; | ||||
} | } | ||||
if (frequency < 1) frequency = 1; // minimum is 1 Hz | |||||
usec = (float)500000.0 / (float)frequency; | usec = (float)500000.0 / (float)frequency; | ||||
config = portConfigRegister(pin); | config = portConfigRegister(pin); | ||||
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 |
/* | /* | ||||
WCharacter.h - Character utility functions for Wiring & Arduino | WCharacter.h - Character utility functions for Wiring & Arduino | ||||
Copyright (c) 2010 Hernando Barragan. All right reserved. | Copyright (c) 2010 Hernando Barragan. All right reserved. | ||||
This library is free software; you can redistribute it and/or | This library is free software; you can redistribute it and/or | ||||
modify it under the terms of the GNU Lesser General Public | modify it under the terms of the GNU Lesser General Public | ||||
License as published by the Free Software Foundation; either | License as published by the Free Software Foundation; either | ||||
version 2.1 of the License, or (at your option) any later version. | version 2.1 of the License, or (at your option) any later version. | ||||
This library is distributed in the hope that it will be useful, | This library is distributed in the hope that it will be useful, | ||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
Lesser General Public License for more details. | Lesser General Public License for more details. | ||||
You should have received a copy of the GNU Lesser General Public | You should have received a copy of the GNU Lesser General Public | ||||
License along with this library; if not, write to the Free Software | License along with this library; if not, write to the Free Software | ||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
// This header file is in the public domain. | |||||
#include "wiring.h" | #include "wiring.h" |
/* | |||||
Part of the Wiring project - http://wiring.org.co | |||||
Copyright (c) 2004-06 Hernando Barragan | |||||
Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/ | |||||
This library is free software; you can redistribute it and/or | |||||
modify it under the terms of the GNU Lesser General Public | |||||
License as published by the Free Software Foundation; either | |||||
version 2.1 of the License, or (at your option) any later version. | |||||
This library is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
Lesser General Public License for more details. | |||||
You should have received a copy of the GNU Lesser General | |||||
Public License along with this library; if not, write to the | |||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||||
Boston, MA 02111-1307 USA | |||||
*/ | |||||
#include <stdint.h> | #include <stdint.h> | ||||
static uint32_t seed; | static uint32_t seed; | ||||
if (newseed > 0) seed = newseed; | if (newseed > 0) seed = newseed; | ||||
} | } | ||||
void srandom(uint32_t newseed) | |||||
void srandom(unsigned int newseed) | |||||
{ | { | ||||
seed = newseed; | seed = newseed; | ||||
} | } | ||||
uint32_t random(void) | |||||
int32_t random(void) | |||||
{ | { | ||||
int32_t hi, lo, x; | int32_t hi, lo, x; | ||||
return random(diff) + howsmall; | return random(diff) + howsmall; | ||||
} | } | ||||
long map(long x, long in_min, long in_max, long out_min, long out_max) | |||||
{ | |||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; | |||||
} | |||||
unsigned int makeWord(unsigned int w) { return w; } | unsigned int makeWord(unsigned int w) { return w; } | ||||
unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; } | unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; } | ||||
/* 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 WProgram_h | #ifndef WProgram_h | ||||
#define WProgram_h | #define WProgram_h | ||||
#include "usb_touch.h" | #include "usb_touch.h" | ||||
#include "usb_undef.h" // do not allow usb_desc.h stuff to leak to user programs | #include "usb_undef.h" // do not allow usb_desc.h stuff to leak to user programs | ||||
//#include "WCharacter.h" | |||||
#include "WCharacter.h" | |||||
#include "WString.h" | #include "WString.h" | ||||
#include "elapsedMillis.h" | #include "elapsedMillis.h" | ||||
#include "IntervalTimer.h" | #include "IntervalTimer.h" | ||||
void noTone(uint8_t pin); | void noTone(uint8_t pin); | ||||
// WMath prototypes | // WMath prototypes | ||||
uint32_t random(void); | |||||
int32_t random(void); | |||||
uint32_t random(uint32_t howbig); | uint32_t random(uint32_t howbig); | ||||
int32_t random(int32_t howsmall, int32_t howbig); | int32_t random(int32_t howsmall, int32_t howbig); | ||||
void randomSeed(uint32_t newseed); | void randomSeed(uint32_t newseed); | ||||
void srandom(uint32_t newseed); | |||||
long map(long, long, long, long, long); | |||||
void srandom(unsigned int newseed); | |||||
#include "pins_arduino.h" | #include "pins_arduino.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> | |||||
/*********************************************/ | /*********************************************/ | ||||
String & String::append(const char *cstr, unsigned int length) | String & String::append(const char *cstr, unsigned int length) | ||||
{ | { | ||||
unsigned int newlen = len + length; | unsigned int newlen = len + length; | ||||
bool self = false; | |||||
unsigned int buffer_offset; | |||||
if ( (cstr >= buffer) && (cstr < (buffer+len) ) ) { | |||||
self = true; | |||||
buffer_offset = (unsigned int)(cstr-buffer); | |||||
} | |||||
if (length == 0 || !reserve(newlen)) return *this; | if (length == 0 || !reserve(newlen)) return *this; | ||||
strcpy(buffer + len, cstr); | |||||
if ( self ) { | |||||
memcpy(buffer + len, buffer+buffer_offset, length); | |||||
buffer[newlen] = 0; | |||||
} | |||||
else | |||||
strcpy(buffer + len, cstr); | |||||
len = newlen; | len = newlen; | ||||
return *this; | return *this; | ||||
} | } | ||||
int String::lastIndexOf(char ch, unsigned int fromIndex) const | int String::lastIndexOf(char ch, unsigned int fromIndex) const | ||||
{ | { | ||||
if (fromIndex >= len || fromIndex < 0) return -1; | |||||
if (fromIndex >= len) return -1; | |||||
char tempchar = buffer[fromIndex + 1]; | char tempchar = buffer[fromIndex + 1]; | ||||
buffer[fromIndex + 1] = '\0'; | buffer[fromIndex + 1] = '\0'; | ||||
char* temp = strrchr( buffer, ch ); | char* temp = strrchr( buffer, ch ); | ||||
int String::lastIndexOf(const String &s2, unsigned int fromIndex) const | int String::lastIndexOf(const String &s2, unsigned int fromIndex) const | ||||
{ | { | ||||
if (s2.len == 0 || len == 0 || s2.len > len || fromIndex < 0) return -1; | |||||
if (s2.len == 0 || len == 0 || s2.len > len) return -1; | |||||
if (fromIndex >= len) fromIndex = len - 1; | if (fromIndex >= len) fromIndex = len - 1; | ||||
int found = -1; | int found = -1; | ||||
for (char *p = buffer; p <= buffer + fromIndex; p++) { | for (char *p = buffer; p <= buffer + fromIndex; p++) { |
#include <ctype.h> | #include <ctype.h> | ||||
#include "avr_functions.h" | #include "avr_functions.h" | ||||
// Not needed here, but some libs assume WString.h or Print.h | |||||
// gives them PROGMEM and other AVR stuff. | |||||
#include "avr/pgmspace.h" | |||||
// When compiling programs with this class, the following gcc parameters | // When compiling programs with this class, the following gcc parameters | ||||
// dramatically increase performance and memory (RAM) efficiency, typically | // dramatically increase performance and memory (RAM) efficiency, typically | ||||
// with little or no increase in code size. | // with little or no increase in code size. | ||||
void init(void); | void init(void); | ||||
unsigned char changeBuffer(unsigned int maxStrLen); | unsigned char changeBuffer(unsigned int maxStrLen); | ||||
String & append(const char *cstr, unsigned int length); | String & append(const char *cstr, unsigned int length); | ||||
private: | |||||
// allow for "if (s)" without the complications of an operator bool(). | |||||
// for more information http://www.artima.com/cppsource/safebool.html | |||||
typedef void (String::*StringIfHelperType)() const; | |||||
void StringIfHelper() const {} | |||||
public: | |||||
operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } | |||||
}; | }; | ||||
class StringSumHelper : public String | class StringSumHelper : public String |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
#include "core_pins.h" | #include "core_pins.h" | ||||
//#include "HardwareSerial.h" | //#include "HardwareSerial.h" | ||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) // ugly hack for now... | |||||
#define __MK20DX256__ | |||||
#endif | |||||
static uint8_t calibrating; | static uint8_t calibrating; | ||||
static uint8_t analog_right_shift = 0; | static uint8_t analog_right_shift = 0; | ||||
static uint8_t analog_config_bits = 10; | static uint8_t analog_config_bits = 10; | ||||
// 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 == 60000000 | |||||
#if F_BUS == 128000000 | |||||
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(3) + ADC_CFG1_ADICLK(1) // 8 MHz | |||||
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 16 MHz | |||||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 16 MHz | |||||
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 16 MHz | |||||
#elif F_BUS == 120000000 | |||||
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(3) + ADC_CFG1_ADICLK(1) // 7.5 MHz | |||||
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 15 MHz | |||||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 15 MHz | |||||
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 15 MHz | |||||
#elif F_BUS == 108000000 | |||||
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(3) + ADC_CFG1_ADICLK(1) // 7 MHz | |||||
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 14 MHz | |||||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 14 MHz | |||||
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 14 MHz | |||||
#elif F_BUS == 96000000 | |||||
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 12 MHz | |||||
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 12 MHz | |||||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 12 MHz | |||||
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 24 MHz | |||||
#elif F_BUS == 90000000 | |||||
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 11.25 MHz | |||||
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 11.25 MHz | |||||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 11.25 MHz | |||||
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 22.5 MHz | |||||
#elif F_BUS == 80000000 | |||||
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 10 MHz | |||||
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 10 MHz | |||||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 10 MHz | |||||
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 20 MHz | |||||
#elif F_BUS == 72000000 | |||||
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 9 MHz | |||||
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 18 MHz | |||||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 18 MHz | |||||
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 18 MHz | |||||
#elif F_BUS == 64000000 | |||||
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 8 MHz | |||||
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 16 MHz | |||||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 16 MHz | |||||
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 16 MHz | |||||
#elif F_BUS == 60000000 | |||||
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 7.5 MHz | #define ADC_CFG1_16BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 7.5 MHz | ||||
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 15 MHz | #define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 15 MHz | ||||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 15 MHz | #define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 15 MHz | ||||
#define ADC_CFG1_8BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 15 MHz | #define ADC_CFG1_8BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 15 MHz | ||||
#elif F_BUS == 56000000 | |||||
#elif F_BUS == 56000000 || F_BUS == 54000000 | |||||
#define ADC_CFG1_16BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 7 MHz | #define ADC_CFG1_16BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 7 MHz | ||||
#define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 14 MHz | #define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 14 MHz | ||||
#define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 14 MHz | #define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 14 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 60, 56, 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) | ||||
{ | { | ||||
uint32_t num; | uint32_t num; | ||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) | |||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
VREF_TRM = 0x60; | VREF_TRM = 0x60; | ||||
VREF_SC = 0xE1; // enable 1.2 volt ref | VREF_SC = 0xE1; // enable 1.2 volt ref | ||||
#endif | #endif | ||||
if (analog_config_bits == 8) { | if (analog_config_bits == 8) { | ||||
ADC0_CFG1 = ADC_CFG1_8BIT + ADC_CFG1_MODE(0); | ADC0_CFG1 = ADC_CFG1_8BIT + ADC_CFG1_MODE(0); | ||||
ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3); | ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3); | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_CFG1 = ADC_CFG1_8BIT + ADC_CFG1_MODE(0); | ADC1_CFG1 = ADC_CFG1_8BIT + ADC_CFG1_MODE(0); | ||||
ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3); | ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3); | ||||
#endif | #endif | ||||
} else if (analog_config_bits == 10) { | } else if (analog_config_bits == 10) { | ||||
ADC0_CFG1 = ADC_CFG1_10BIT + ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP; | ADC0_CFG1 = ADC_CFG1_10BIT + ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP; | ||||
ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3); | ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3); | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_CFG1 = ADC_CFG1_10BIT + ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP; | ADC1_CFG1 = ADC_CFG1_10BIT + ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP; | ||||
ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3); | ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3); | ||||
#endif | #endif | ||||
} else if (analog_config_bits == 12) { | } else if (analog_config_bits == 12) { | ||||
ADC0_CFG1 = ADC_CFG1_12BIT + ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP; | ADC0_CFG1 = ADC_CFG1_12BIT + ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP; | ||||
ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2); | ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2); | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_CFG1 = ADC_CFG1_12BIT + ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP; | ADC1_CFG1 = ADC_CFG1_12BIT + ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP; | ||||
ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2); | ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2); | ||||
#endif | #endif | ||||
} else { | } else { | ||||
ADC0_CFG1 = ADC_CFG1_16BIT + ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP; | ADC0_CFG1 = ADC_CFG1_16BIT + ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP; | ||||
ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2); | ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2); | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_CFG1 = ADC_CFG1_16BIT + ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP; | ADC1_CFG1 = ADC_CFG1_16BIT + ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP; | ||||
ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2); | ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2); | ||||
#endif | #endif | ||||
} else { | } else { | ||||
ADC0_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref | ADC0_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref | ||||
} | } | ||||
#elif defined(__MK20DX256__) | |||||
#elif defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
if (analog_reference_internal) { | if (analog_reference_internal) { | ||||
ADC0_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref | ADC0_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref | ||||
ADC1_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref | ADC1_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref | ||||
num = analog_num_average; | num = analog_num_average; | ||||
if (num <= 1) { | if (num <= 1) { | ||||
ADC0_SC3 = ADC_SC3_CAL; // begin cal | ADC0_SC3 = ADC_SC3_CAL; // begin cal | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_SC3 = ADC_SC3_CAL; // begin cal | ADC1_SC3 = ADC_SC3_CAL; // begin cal | ||||
#endif | #endif | ||||
} else if (num <= 4) { | } else if (num <= 4) { | ||||
ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(0); | ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(0); | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(0); | ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(0); | ||||
#endif | #endif | ||||
} else if (num <= 8) { | } else if (num <= 8) { | ||||
ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(1); | ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(1); | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(1); | ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(1); | ||||
#endif | #endif | ||||
} else if (num <= 16) { | } else if (num <= 16) { | ||||
ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(2); | ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(2); | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(2); | ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(2); | ||||
#endif | #endif | ||||
} else { | } else { | ||||
ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(3); | ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(3); | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(3); | ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(3); | ||||
#endif | #endif | ||||
} | } | ||||
uint16_t sum; | uint16_t sum; | ||||
//serial_print("wait_for_cal\n"); | //serial_print("wait_for_cal\n"); | ||||
#if defined(__MK20DX128__) | |||||
while (ADC0_SC3 & ADC_SC3_CAL) { | |||||
#if defined(HAS_KINETIS_ADC0) && defined(HAS_KINETIS_ADC1) | |||||
while ((ADC0_SC3 & ADC_SC3_CAL) || (ADC1_SC3 & ADC_SC3_CAL)) { | |||||
// wait | // wait | ||||
} | } | ||||
#elif defined(__MK20DX256__) | |||||
while ((ADC0_SC3 & ADC_SC3_CAL) || (ADC1_SC3 & ADC_SC3_CAL)) { | |||||
#elif defined(HAS_KINETIS_ADC0) | |||||
while (ADC0_SC3 & ADC_SC3_CAL) { | |||||
// wait | // wait | ||||
} | } | ||||
#endif | #endif | ||||
//serial_print("ADC0_MG = "); | //serial_print("ADC0_MG = "); | ||||
//serial_phex16(sum); | //serial_phex16(sum); | ||||
//serial_print("\n"); | //serial_print("\n"); | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
sum = ADC1_CLPS + ADC1_CLP4 + ADC1_CLP3 + ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0; | sum = ADC1_CLPS + ADC1_CLP4 + ADC1_CLP3 + ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0; | ||||
sum = (sum / 2) | 0x8000; | sum = (sum / 2) | 0x8000; | ||||
ADC1_PG = sum; | ADC1_PG = sum; | ||||
// VREFH/VREFL - connected as the primary reference option | // VREFH/VREFL - connected as the primary reference option | ||||
// 1.2 V VREF_OUT - connected as the VALT reference option | // 1.2 V VREF_OUT - connected as the VALT reference option | ||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) | |||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#define DEFAULT 0 | #define DEFAULT 0 | ||||
#define INTERNAL 2 | #define INTERNAL 2 | ||||
#define INTERNAL1V2 2 | #define INTERNAL1V2 2 | ||||
analog_reference_internal = 1; | analog_reference_internal = 1; | ||||
if (calibrating) { | if (calibrating) { | ||||
ADC0_SC3 = 0; // cancel cal | ADC0_SC3 = 0; // cancel cal | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_SC3 = 0; // cancel cal | ADC1_SC3 = 0; // cancel cal | ||||
#endif | #endif | ||||
} | } | ||||
analog_reference_internal = 0; | analog_reference_internal = 0; | ||||
if (calibrating) { | if (calibrating) { | ||||
ADC0_SC3 = 0; // cancel cal | ADC0_SC3 = 0; // cancel cal | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_SC3 = 0; // cancel cal | ADC1_SC3 = 0; // cancel cal | ||||
#endif | #endif | ||||
} | } | ||||
analog_right_shift = config - bits; | analog_right_shift = config - bits; | ||||
if (config != analog_config_bits) { | if (config != analog_config_bits) { | ||||
analog_config_bits = config; | analog_config_bits = config; | ||||
if (calibrating) ADC0_SC3 = 0; // cancel cal | |||||
if (calibrating) { | |||||
ADC0_SC3 = 0; // cancel cal | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_SC3 = 0; | |||||
#endif | |||||
} | |||||
analog_init(); | analog_init(); | ||||
} | } | ||||
} | } | ||||
} else if (num <= 4) { | } else if (num <= 4) { | ||||
num = 4; | num = 4; | ||||
ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(0); | ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(0); | ||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(0); | |||||
#endif | |||||
} else if (num <= 8) { | } else if (num <= 8) { | ||||
num = 8; | num = 8; | ||||
ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(1); | ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(1); | ||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(1); | |||||
#endif | |||||
} else if (num <= 16) { | } else if (num <= 16) { | ||||
num = 16; | num = 16; | ||||
ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(2); | ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(2); | ||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(2); | |||||
#endif | |||||
} else { | } else { | ||||
num = 32; | num = 32; | ||||
ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(3); | ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(3); | ||||
#ifdef HAS_KINETIS_ADC1 | |||||
ADC1_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(3); | |||||
#endif | |||||
} | } | ||||
analog_num_average = num; | analog_num_average = num; | ||||
} | } | ||||
// The SC1A register is used for both software and hardware trigger modes of operation. | // The SC1A register is used for both software and hardware trigger modes of operation. | ||||
#if defined(__MK20DX128__) | #if defined(__MK20DX128__) | ||||
static const uint8_t channel2sc1a[] = { | |||||
5, 14, 8, 9, 13, 12, 6, 7, 15, 4, | |||||
0, 19, 3, 21, 26, 22, 23 | |||||
static const uint8_t pin2sc1a[] = { | |||||
5, 14, 8, 9, 13, 12, 6, 7, 15, 4, 0, 19, 3, 21, // 0-13 -> A0-A13 | |||||
5, 14, 8, 9, 13, 12, 6, 7, 15, 4, // 14-23 are A0-A9 | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 24-33 are digital only | |||||
0, 19, 3, 21, // 34-37 are A10-A13 | |||||
26, // 38 is temp sensor | |||||
22, // 39 is vref | |||||
23 // 40 is unused analog pin | |||||
}; | }; | ||||
#elif defined(__MK20DX256__) | #elif defined(__MK20DX256__) | ||||
static const uint8_t channel2sc1a[] = { | |||||
5, 14, 8, 9, 13, 12, 6, 7, 15, 4, | |||||
0, 19, 3, 19+128, 26, 18+128, 23, | |||||
5+192, 5+128, 4+128, 6+128, 7+128, 4+192 | |||||
// A15 26 E1 ADC1_SE5a 5+64 | |||||
// A16 27 C9 ADC1_SE5b 5 | |||||
// A17 28 C8 ADC1_SE4b 4 | |||||
// A18 29 C10 ADC1_SE6b 6 | |||||
// A19 30 C11 ADC1_SE7b 7 | |||||
// A20 31 E0 ADC1_SE4a 4+64 | |||||
static const uint8_t pin2sc1a[] = { | |||||
5, 14, 8, 9, 13, 12, 6, 7, 15, 4, 0, 19, 3, 19+128, // 0-13 -> A0-A13 | |||||
5, 14, 8, 9, 13, 12, 6, 7, 15, 4, // 14-23 are A0-A9 | |||||
255, 255, // 24-25 are digital only | |||||
5+192, 5+128, 4+128, 6+128, 7+128, 4+192, // 26-31 are A15-A20 | |||||
255, 255, // 32-33 are digital only | |||||
0, 19, 3, 19+128, // 34-37 are A10-A13 | |||||
26, // 38 is temp sensor, | |||||
18+128, // 39 is vref | |||||
23 // 40 is A14 | |||||
}; | }; | ||||
#elif defined(__MKL26Z64__) | #elif defined(__MKL26Z64__) | ||||
static const uint8_t channel2sc1a[] = { | |||||
5, 14, 8, 9, 13, 12, 6, 7, 15, 11, | |||||
0, 4+64, 23, 26, 27 | |||||
static const uint8_t pin2sc1a[] = { | |||||
5, 14, 8, 9, 13, 12, 6, 7, 15, 11, 0, 4+64, 23, // 0-12 -> A0-A12 | |||||
255, // 13 is digital only (no A13 alias) | |||||
5, 14, 8, 9, 13, 12, 6, 7, 15, 11, 0, 4+64, 23, // 14-26 are A0-A12 | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 27-37 unused | |||||
26, // 38=temperature | |||||
27 // 39=bandgap ref (PMC_REGSC |= PMC_REGSC_BGBE) | |||||
}; | |||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
static const uint8_t pin2sc1a[] = { | |||||
5, 14, 8, 9, 13, 12, 6, 7, 15, 4, 3, 19+128, 14+128, 15+128, // 0-13 -> A0-A13 | |||||
5, 14, 8, 9, 13, 12, 6, 7, 15, 4, // 14-23 are A0-A9 | |||||
255, 255, 255, 255, 255, 255, 255, // 24-30 are digital only | |||||
14+128, 15+128, 17, 18, 4+128, 5+128, 6+128, 7+128, 17+128, // 31-39 are A12-A20 | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, // 40-48 are digital only | |||||
10+128, 11+128, // 49-50 are A23-A24 | |||||
255, 255, 255, 255, 255, 255, 255, // 51-57 are digital only | |||||
255, 255, 255, 255, 255, 255, // 58-63 (sd card pins) are digital only | |||||
3, 19+128, // 64-65 are A10-A11 | |||||
23, 23+128,// 66-67 are A21-A22 (DAC pins) | |||||
1, 1+128, // 68-69 are A25-A26 (unused USB host port on Teensy 3.5) | |||||
26, // 70 is Temperature Sensor | |||||
18+128 // 71 is Vref | |||||
}; | }; | ||||
#endif | #endif | ||||
// TODO: perhaps this should store the NVIC priority, so it works recursively? | // TODO: perhaps this should store the NVIC priority, so it works recursively? | ||||
static volatile uint8_t analogReadBusyADC0 = 0; | static volatile uint8_t analogReadBusyADC0 = 0; | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
static volatile uint8_t analogReadBusyADC1 = 0; | static volatile uint8_t analogReadBusyADC1 = 0; | ||||
#endif | #endif | ||||
int analogRead(uint8_t pin) | int analogRead(uint8_t pin) | ||||
{ | { | ||||
int result; | int result; | ||||
uint8_t index, channel; | |||||
uint8_t channel; | |||||
//serial_phex(pin); | //serial_phex(pin); | ||||
//serial_print(" "); | //serial_print(" "); | ||||
#if defined(__MK20DX128__) | |||||
if (pin <= 13) { | |||||
index = pin; // 0-13 refer to A0-A13 | |||||
} else if (pin <= 23) { | |||||
index = pin - 14; // 14-23 are A0-A9 | |||||
} else if (pin >= 34 && pin <= 40) { | |||||
index = pin - 24; // 34-37 are A10-A13, 38 is temp sensor, | |||||
// 39 is vref, 40 is unused analog pin | |||||
} else { | |||||
return 0; | |||||
} | |||||
#elif defined(__MK20DX256__) | |||||
if (pin <= 13) { | |||||
index = pin; // 0-13 refer to A0-A13 | |||||
} else if (pin <= 23) { | |||||
index = pin - 14; // 14-23 are A0-A9 | |||||
} else if (pin >= 26 && pin <= 31) { | |||||
index = pin - 9; // 26-31 are A15-A20 | |||||
} else if (pin >= 34 && pin <= 40) { | |||||
index = pin - 24; // 34-37 are A10-A13, 38 is temp sensor, | |||||
// 39 is vref, 40 is A14 | |||||
} else { | |||||
return 0; | |||||
} | |||||
#elif defined(__MKL26Z64__) | |||||
if (pin <= 12) { | |||||
index = pin; // 0-12 refer to A0-A12 | |||||
} else if (pin >= 14 && pin <= 26) { | |||||
index = pin - 14; // 14-26 are A0-A12 | |||||
} else if (pin >= 38 && pin <= 39) { | |||||
index = pin - 25; // 38=temperature | |||||
// 39=bandgap ref (PMC_REGSC |= PMC_REGSC_BGBE) | |||||
} else { | |||||
return 0; | |||||
} | |||||
#endif | |||||
//serial_phex(index); | |||||
//serial_print(" "); | |||||
if (pin >= sizeof(pin2sc1a)) return 0; | |||||
channel = pin2sc1a[pin]; | |||||
if (channel == 255) return 0; | |||||
channel = channel2sc1a[index]; | |||||
//serial_phex(channel); | |||||
//serial_print(" "); | |||||
//serial_print("analogRead"); | |||||
//return 0; | |||||
if (calibrating) wait_for_cal(); | if (calibrating) wait_for_cal(); | ||||
//pin = 5; // PTD1/SE5b, pin 14, analog 0 | |||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
if (channel & 0x80) goto beginADC1; | if (channel & 0x80) goto beginADC1; | ||||
#endif | #endif | ||||
yield(); | yield(); | ||||
} | } | ||||
#if defined(__MK20DX256__) | |||||
#ifdef HAS_KINETIS_ADC1 | |||||
beginADC1: | beginADC1: | ||||
__disable_irq(); | __disable_irq(); | ||||
startADC1: | startADC1: | ||||
//serial_print("startADC0\n"); | |||||
//serial_print("startADC1\n"); | |||||
// ADC1_CFG2[MUXSEL] bit selects between ADCx_SEn channels a and b. | // ADC1_CFG2[MUXSEL] bit selects between ADCx_SEn channels a and b. | ||||
if (channel & 0x40) { | if (channel & 0x40) { | ||||
ADC1_CFG2 &= ~ADC_CFG2_MUXSEL; | ADC1_CFG2 &= ~ADC_CFG2_MUXSEL; | ||||
#endif | #endif | ||||
} | } | ||||
typedef int16_t __attribute__((__may_alias__)) aliased_int16_t; | |||||
void analogWriteDAC0(int val) | void analogWriteDAC0(int val) | ||||
{ | { | ||||
#if defined(__MK20DX256__) | |||||
#if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
SIM_SCGC2 |= SIM_SCGC2_DAC0; | SIM_SCGC2 |= SIM_SCGC2_DAC0; | ||||
if (analog_reference_internal) { | if (analog_reference_internal) { | ||||
DAC0_C0 = DAC_C0_DACEN; // 1.2V ref is DACREF_1 | DAC0_C0 = DAC_C0_DACEN; // 1.2V ref is DACREF_1 | ||||
} 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; | |||||
*(int16_t *)&(DAC0_DAT0L) = val; | |||||
__asm__ ("usat %[value], #12, %[value]\n\t" : [value] "+r" (val)); // 0 <= val <= 4095 | |||||
*(volatile aliased_int16_t *)&(DAC0_DAT0L) = val; | |||||
#elif defined(__MKL26Z64__) | #elif defined(__MKL26Z64__) | ||||
SIM_SCGC6 |= SIM_SCGC6_DAC0; | SIM_SCGC6 |= SIM_SCGC6_DAC0; | ||||
if (analog_reference_internal == 0) { | if (analog_reference_internal == 0) { | ||||
} | } | ||||
if (val < 0) val = 0; | if (val < 0) val = 0; | ||||
else if (val > 4095) val = 4095; | else if (val > 4095) val = 4095; | ||||
*(int16_t *)&(DAC0_DAT0L) = val; | |||||
*(volatile aliased_int16_t *)&(DAC0_DAT0L) = val; | |||||
#endif | #endif | ||||
} | } | ||||
} 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; | |||||
*(int16_t *)&(DAC1_DAT0L) = val; | |||||
__asm__ ("usat %[value], #12, %[value]\n\t" : [value] "+r" (val)); // 0 <= val <= 4095 | |||||
*(volatile aliased_int16_t *)&(DAC1_DAT0L) = val; | |||||
} | } | ||||
#endif | #endif | ||||
* 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 | ||||
// This header file is in the public domain. |
#define vsprintf_P(s, ...) vsprintf((s), __VA_ARGS__) | #define vsprintf_P(s, ...) vsprintf((s), __VA_ARGS__) | ||||
#define vsnprintf_P(s, n, ...) vsnprintf((s), (n), __VA_ARGS__) | #define vsnprintf_P(s, n, ...) vsnprintf((s), (n), __VA_ARGS__) | ||||
#define fprintf_P(fp, ...) fprintf((fp), __VA_ARGS__) | #define fprintf_P(fp, ...) fprintf((fp), __VA_ARGS__) | ||||
#define strlen_PF(a) strlen((a)) | |||||
#define strnlen_PF(src, len) strnlen((src), (len)) | |||||
#define memcpy_PF(dest, src, len) memcpy((dest), (src), (len)) | |||||
#define strcpy_PF(dest, src) strcpy((dest), (src)) | |||||
#define strncpy_PF(dest, src, len) strncpy((dest), (src), (len)) | |||||
#define strcat_PF(dest, src) strcat((dest), (src)) | |||||
#define strlcat_PF(dest, src, len) strlcat((dest), (src), (len)) | |||||
#define strncat_PF(dest, src, len) strncat((dest), (src), (len)) | |||||
#define strcmp_PF(s1, s2) strcmp((s1), (s2)) | |||||
#define strncmp_PF(s1, s2, n) strncmp((s1), (s2), (n)) | |||||
#define strcasecmp_PF(s1, s2) strcasecmp((s1), (s2)) | |||||
#define strncasecmp_PF(s1, s2, n) strncasecmp((s1), (s2), (n)) | |||||
#define strstr_PF(s1, s2) strstr((s1), (s2)) | |||||
#define strlcpy_PF(dest, src, n) strlcpy((dest), (src), (n)) | |||||
#define memcmp_PF(s1, s2, n) memcmp((s1), (s2), (n)) | |||||
#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) | #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) | ||||
#if 0 | |||||
#define pgm_read_word(addr) (*(const unsigned short *)(addr)) | #define pgm_read_word(addr) (*(const unsigned short *)(addr)) | ||||
#define pgm_read_dword(addr) (*(const unsigned long *)(addr)) | #define pgm_read_dword(addr) (*(const unsigned long *)(addr)) | ||||
#define pgm_read_float(addr) (*(const float *)(addr)) | #define pgm_read_float(addr) (*(const float *)(addr)) | ||||
#else | |||||
#define pgm_read_word(addr) ({ \ | |||||
typeof(addr) _addr = (addr); \ | |||||
*(const unsigned short *)(_addr); \ | |||||
}) | |||||
#define pgm_read_dword(addr) ({ \ | |||||
typeof(addr) _addr = (addr); \ | |||||
*(const unsigned long *)(_addr); \ | |||||
}) | |||||
#define pgm_read_float(addr) ({ \ | |||||
typeof(addr) _addr = (addr); \ | |||||
*(const float *)(_addr); \ | |||||
}) | |||||
#define pgm_read_ptr(addr) ({ \ | |||||
typeof(addr) _addr = (addr); \ | |||||
*(void * const *)(_addr); \ | |||||
}) | |||||
#endif | |||||
#define pgm_read_byte_near(addr) pgm_read_byte(addr) | #define pgm_read_byte_near(addr) pgm_read_byte(addr) | ||||
#define pgm_read_word_near(addr) pgm_read_word(addr) | #define pgm_read_word_near(addr) pgm_read_word(addr) | ||||
#define pgm_read_dword_near(addr) pgm_read_dword(addr) | #define pgm_read_dword_near(addr) pgm_read_dword(addr) | ||||
#define pgm_read_float_near(addr) pgm_read_float(addr) | #define pgm_read_float_near(addr) pgm_read_float(addr) | ||||
#define pgm_read_ptr_near(addr) pgm_read_ptr(addr) | |||||
#define pgm_read_byte_far(addr) pgm_read_byte(addr) | #define pgm_read_byte_far(addr) pgm_read_byte(addr) | ||||
#define pgm_read_word_far(addr) pgm_read_word(addr) | #define pgm_read_word_far(addr) pgm_read_word(addr) | ||||
#define pgm_read_dword_far(addr) pgm_read_dword(addr) | #define pgm_read_dword_far(addr) pgm_read_dword(addr) | ||||
#define pgm_read_float_far(addr) pgm_read_float(addr) | #define pgm_read_float_far(addr) pgm_read_float(addr) | ||||
#define pgm_read_ptr_far(addr) pgm_read_ptr(addr) | |||||
#endif | #endif |
#define set_sleep_mode(mode) // TODO: actually set the mode... | #define set_sleep_mode(mode) // TODO: actually set the mode... | ||||
#define sleep_enable() | #define sleep_enable() | ||||
#define sleep_disable() | #define sleep_disable() | ||||
#define sleep_cpu() (asm("wfi")) | |||||
#define sleep_cpu() ({__asm__ volatile("wfi");}) | |||||
#define sleep_bod_disable() | #define sleep_bod_disable() | ||||
#define sleep_mode() sleep_cpu() | |||||
#define sleep_mode() ({__asm__ volatile("wfi");}) | |||||
// workaround for early versions of Nordic's BLE library | // workaround for early versions of Nordic's BLE library | ||||
// EIMSK moved to a dummy byte in avr_emulation... | // EIMSK moved to a dummy byte in avr_emulation... |
// This header file is in the public domain. | |||||
#ifndef _AVR_WDT_H_ | #ifndef _AVR_WDT_H_ | ||||
#define _AVR_WDT_H_ | #define _AVR_WDT_H_ | ||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
*/ | */ | ||||
#include "avr_emulation.h" | |||||
#include <Arduino.h> | |||||
#include "SPIFIFO.h" | #include "SPIFIFO.h" | ||||
uint8_t SPCRemulation::pinout = 0; | uint8_t SPCRemulation::pinout = 0; | ||||
SPCRemulation SPCR; | |||||
#if defined(KINETISL) | #if defined(KINETISL) | ||||
uint8_t SPCR1emulation::pinout = 0; | uint8_t SPCR1emulation::pinout = 0; | ||||
SPCR1emulation SPCR1; | |||||
#endif | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
uint8_t SPCR1emulation::pinout = 0; | |||||
SPCR1emulation SPCR1; | |||||
uint8_t SPCR2emulation::pinout = 0; | |||||
SPCR2emulation SPCR2; | |||||
#endif | #endif | ||||
#ifdef HAS_SPIFIFO | #ifdef HAS_SPIFIFO | ||||
uint8_t SPIFIFOclass::pcs = 0; | uint8_t SPIFIFOclass::pcs = 0; |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
public: | public: | ||||
inline int operator & (int val) const __attribute__((always_inline)) { | inline int operator & (int val) const __attribute__((always_inline)) { | ||||
int ret = 0; | int ret = 0; | ||||
if ((val & (1<<0)) && digitalReadFast(8)) ret |= (1<<0); | |||||
if ((val & (1<<1)) && digitalReadFast(9)) ret |= (1<<1); | |||||
if ((val & (1<<2)) && digitalReadFast(10)) ret |= (1<<2); | |||||
if ((val & (1<<3)) && digitalReadFast(11)) ret |= (1<<3); | |||||
if ((val & (1<<4)) && digitalReadFast(12)) ret |= (1<<4); | |||||
if ((val & (1<<5)) && digitalReadFast(13)) ret |= (1<<5); | |||||
if ((val & (1<<0)) && digitalReadFast(14)) ret |= (1<<0); | |||||
if ((val & (1<<1)) && digitalReadFast(15)) ret |= (1<<1); | |||||
if ((val & (1<<2)) && digitalReadFast(16)) ret |= (1<<2); | |||||
if ((val & (1<<3)) && digitalReadFast(17)) ret |= (1<<3); | |||||
if ((val & (1<<4)) && digitalReadFast(18)) ret |= (1<<4); | |||||
if ((val & (1<<5)) && digitalReadFast(19)) ret |= (1<<5); | |||||
return ret; | return ret; | ||||
} | } | ||||
operator int () const __attribute__((always_inline)) { | operator int () const __attribute__((always_inline)) { | ||||
int ret = 0; | int ret = 0; | ||||
if (digitalReadFast(8)) ret |= (1<<0); | |||||
if (digitalReadFast(9)) ret |= (1<<1); | |||||
if (digitalReadFast(10)) ret |= (1<<2); | |||||
if (digitalReadFast(11)) ret |= (1<<3); | |||||
if (digitalReadFast(12)) ret |= (1<<4); | |||||
if (digitalReadFast(13)) ret |= (1<<5); | |||||
if (digitalReadFast(14)) ret |= (1<<0); | |||||
if (digitalReadFast(15)) ret |= (1<<1); | |||||
if (digitalReadFast(16)) ret |= (1<<2); | |||||
if (digitalReadFast(17)) ret |= (1<<3); | |||||
if (digitalReadFast(18)) ret |= (1<<4); | |||||
if (digitalReadFast(19)) ret |= (1<<5); | |||||
return ret; | return ret; | ||||
} | } | ||||
}; | }; | ||||
uint32_t ctar = SPI0_CTAR0; | uint32_t ctar = SPI0_CTAR0; | ||||
if (val & (1<<DORD)) ctar |= SPI_CTAR_LSBFE; // TODO: use bitband | if (val & (1<<DORD)) ctar |= SPI_CTAR_LSBFE; // TODO: use bitband | ||||
if (val & (1<<CPOL)) ctar |= SPI_CTAR_CPOL; | if (val & (1<<CPOL)) ctar |= SPI_CTAR_CPOL; | ||||
if ((val & 3) == 1) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 2) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 3) { | |||||
// TODO: implement - is this ever really needed | |||||
} | |||||
if (val & (1<<CPHA) && !(ctar & SPI_CTAR_CPHA)) { | if (val & (1<<CPHA) && !(ctar & SPI_CTAR_CPHA)) { | ||||
ctar |= SPI_CTAR_CPHA; | ctar |= SPI_CTAR_CPHA; | ||||
// TODO: clear SPI_CTAR_CSSCK, set SPI_CTAR_ASC | |||||
ctar &= 0xFFFF00FF; | |||||
ctar |= SPI_CTAR_ASC(ctar & 15); | |||||
} | |||||
if ((val & 3) != 0) { | |||||
uint32_t br = ctar & 15; | |||||
uint32_t priorval; | |||||
if (br <= 1) priorval = 0; | |||||
else if (br <= 4) priorval = 1; | |||||
else if (br <= 6) priorval = 2; | |||||
else priorval = 3; | |||||
uint32_t newval = priorval | (val & 3); | |||||
if (newval != priorval) { | |||||
if (newval == 0) br = 1; | |||||
else if (newval == 0) br = 4; | |||||
else if (newval == 0) br = 6; | |||||
else br = 7; | |||||
ctar &= 0xFFFF00F0; // clear BR, ASC, CSSCK | |||||
if ((ctar & SPI_CTAR_CPHA)) { | |||||
ctar |= SPI_CTAR_BR(br) | SPI_CTAR_ASC(br); | |||||
} else { | |||||
ctar |= SPI_CTAR_BR(br) | SPI_CTAR_CSSCK(br); | |||||
} | |||||
} | |||||
} | } | ||||
update_ctar(ctar); | update_ctar(ctar); | ||||
} | } | ||||
uint32_t ctar = SPI0_CTAR0; | uint32_t ctar = SPI0_CTAR0; | ||||
if (!(val & (1<<DORD))) ctar &= ~SPI_CTAR_LSBFE; // TODO: use bitband | if (!(val & (1<<DORD))) ctar &= ~SPI_CTAR_LSBFE; // TODO: use bitband | ||||
if (!(val & (1<<CPOL))) ctar &= ~SPI_CTAR_CPOL; | if (!(val & (1<<CPOL))) ctar &= ~SPI_CTAR_CPOL; | ||||
if ((val & 3) == 0) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 1) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 2) { | |||||
// TODO: implement - is this ever really needed | |||||
} | |||||
if (!(val & (1<<CPHA)) && (ctar & SPI_CTAR_CPHA)) { | if (!(val & (1<<CPHA)) && (ctar & SPI_CTAR_CPHA)) { | ||||
ctar &= ~SPI_CTAR_CPHA; | ctar &= ~SPI_CTAR_CPHA; | ||||
// TODO: set SPI_CTAR_ASC, clear SPI_CTAR_CSSCK | |||||
ctar &= 0xFFFF00FF; | |||||
ctar |= SPI_CTAR_CSSCK(ctar & 15); | |||||
} | |||||
if ((val & 3) != 3) { | |||||
uint32_t br = ctar & 15; | |||||
uint32_t priorval; | |||||
if (br <= 1) priorval = 0; | |||||
else if (br <= 4) priorval = 1; | |||||
else if (br <= 6) priorval = 2; | |||||
else priorval = 3; | |||||
uint32_t newval = priorval & (val & 3); | |||||
if (newval != priorval) { | |||||
if (newval == 0) br = 1; | |||||
else if (newval == 0) br = 4; | |||||
else if (newval == 0) br = 6; | |||||
else br = 7; | |||||
ctar &= 0xFFFF00F0; // clear BR, ASC, CSSCK | |||||
if ((ctar & SPI_CTAR_CPHA)) { | |||||
ctar |= SPI_CTAR_BR(br) | SPI_CTAR_ASC(br); | |||||
} else { | |||||
ctar |= SPI_CTAR_BR(br) | SPI_CTAR_CSSCK(br); | |||||
} | |||||
} | |||||
} | } | ||||
update_ctar(ctar); | update_ctar(ctar); | ||||
} | } | ||||
if ((val & (1<<DORD)) && (SPI0_CTAR0 & SPI_CTAR_LSBFE)) ret |= (1<<DORD); | if ((val & (1<<DORD)) && (SPI0_CTAR0 & SPI_CTAR_LSBFE)) ret |= (1<<DORD); | ||||
if ((val & (1<<CPOL)) && (SPI0_CTAR0 & SPI_CTAR_CPOL)) ret |= (1<<CPOL); | if ((val & (1<<CPOL)) && (SPI0_CTAR0 & SPI_CTAR_CPOL)) ret |= (1<<CPOL); | ||||
if ((val & (1<<CPHA)) && (SPI0_CTAR0 & SPI_CTAR_CPHA)) ret |= (1<<CPHA); | if ((val & (1<<CPHA)) && (SPI0_CTAR0 & SPI_CTAR_CPHA)) ret |= (1<<CPHA); | ||||
if ((val & 3) == 3) { | |||||
if ((val & 3) != 0) { | |||||
uint32_t dbr = SPI0_CTAR0 & 15; | uint32_t dbr = SPI0_CTAR0 & 15; | ||||
uint32_t spr10; | |||||
if (dbr <= 1) { | if (dbr <= 1) { | ||||
spr10 = 0; | |||||
} else if (dbr <= 4) { | } else if (dbr <= 4) { | ||||
ret |= (1<<SPR0); | |||||
spr10 |= (1<<SPR0); | |||||
} else if (dbr <= 6) { | } else if (dbr <= 6) { | ||||
ret |= (1<<SPR1); | |||||
spr10 |= (1<<SPR1); | |||||
} else { | } else { | ||||
ret |= (1<<SPR1)|(1<<SPR0); | |||||
spr10 |= (1<<SPR1)|(1<<SPR0); | |||||
} | } | ||||
} else if ((val & 3) == 1) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 2) { | |||||
// TODO: implement - is this ever really needed | |||||
ret |= spr10 & (val & 3); | |||||
} | } | ||||
if (val & (1<<SPE) && (!(SPI0_MCR & SPI_MCR_MDIS))) ret |= (1<<SPE); | if (val & (1<<SPE) && (!(SPI0_MCR & SPI_MCR_MDIS))) ret |= (1<<SPE); | ||||
if (val & (1<<MSTR) && (SPI0_MCR & SPI_MCR_MSTR)) ret |= (1<<MSTR); | if (val & (1<<MSTR) && (SPI0_MCR & SPI_MCR_MSTR)) ret |= (1<<MSTR); | ||||
return ret; | return ret; | ||||
} | } | ||||
inline void setMOSI(uint8_t pin) __attribute__((always_inline)) { | inline void setMOSI(uint8_t pin) __attribute__((always_inline)) { | ||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
uint8_t newpinout = pinout; | |||||
// More than two options so now 2 bits | |||||
if (pin == 11) newpinout &= ~3; | |||||
if (pin == 7) newpinout =(newpinout & ~0x3) | 1; | |||||
if (pin == 28) newpinout = (newpinout & ~0x3) | 2; | |||||
if ((SIM_SCGC6 & SIM_SCGC6_SPI0) && newpinout != pinout) { | |||||
// First unconfigure previous pin | |||||
switch (pinout & 3) { | |||||
case 0: CORE_PIN11_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); break; | |||||
case 1: CORE_PIN7_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); break; | |||||
default: CORE_PIN28_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
} | |||||
switch (newpinout & 3) { | |||||
case 0: CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); break; | |||||
case 1: CORE_PIN7_CONFIG = PORT_PCR_MUX(2); break; | |||||
default: CORE_PIN28_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
} | |||||
pinout = newpinout; | |||||
#else | |||||
uint8_t newpinout = pinout; | |||||
if (pin == 11) newpinout &= ~1; | |||||
if (pin == 7) newpinout |= 1; | |||||
if ((SIM_SCGC6 & SIM_SCGC6_SPI0) && newpinout != pinout) { | |||||
if ((newpinout & 1) == 0) { | |||||
CORE_PIN7_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); | |||||
} else { | |||||
CORE_PIN11_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
CORE_PIN7_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
} | |||||
pinout = newpinout; | |||||
#endif | |||||
} | |||||
inline void setMOSI_soft(uint8_t pin) __attribute__((always_inline)) { | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
if (pin == 11) pinout &= ~3; | |||||
if (pin == 7) pinout = (pinout & ~0x3) | 1; | |||||
if (pin == 28) pinout = (pinout & ~0x3) | 2; | |||||
#else | |||||
if (pin == 11) pinout &= ~1; | if (pin == 11) pinout &= ~1; | ||||
if (pin == 7) pinout |= 1; | |||||
if (pin == 7) pinout |= 1; | |||||
#endif | |||||
} | } | ||||
inline void setMISO(uint8_t pin) __attribute__((always_inline)) { | inline void setMISO(uint8_t pin) __attribute__((always_inline)) { | ||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
uint8_t newpinout = pinout; | |||||
// More than two options so now 2 bits | |||||
if (pin == 12) newpinout &= ~0xc; | |||||
if (pin == 8) newpinout =(newpinout & ~0xc) | 4; | |||||
if (pin == 39) newpinout = (newpinout & ~0xc) | 8; | |||||
if ((SIM_SCGC6 & SIM_SCGC6_SPI0) && newpinout != pinout) { | |||||
// First unconfigure previous pin | |||||
switch (pinout & 0xc) { | |||||
case 0: CORE_PIN12_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); break; | |||||
case 0x4: CORE_PIN8_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); break; | |||||
default: CORE_PIN39_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
} | |||||
switch (newpinout & 0xc) { | |||||
case 0: CORE_PIN12_CONFIG = PORT_PCR_MUX(2); break; | |||||
case 0x4: CORE_PIN8_CONFIG = PORT_PCR_MUX(2); break; | |||||
default: CORE_PIN39_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
} | |||||
pinout = newpinout; | |||||
#else | |||||
uint8_t newpinout = pinout; | |||||
if (pin == 12) newpinout &= ~2; | |||||
if (pin == 8) newpinout |= 2; | |||||
if ((SIM_SCGC6 & SIM_SCGC6_SPI0) && newpinout != pinout) { | |||||
if ((newpinout & 2) == 0) { | |||||
CORE_PIN8_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
CORE_PIN12_CONFIG = PORT_PCR_MUX(2); | |||||
} else { | |||||
CORE_PIN12_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
CORE_PIN8_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
} | |||||
pinout = newpinout; | |||||
#endif | |||||
} | |||||
inline void setMISO_soft(uint8_t pin) __attribute__((always_inline)) { | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
if (pin == 12) pinout &= ~0xc; | |||||
if (pin == 8) pinout = (pinout & ~0xc) | 4; | |||||
if (pin == 39) pinout = (pinout & ~0xc) | 8; | |||||
#else | |||||
if (pin == 12) pinout &= ~2; | if (pin == 12) pinout &= ~2; | ||||
if (pin == 8) pinout |= 2; | |||||
if (pin == 8) pinout |= 2; | |||||
#endif | |||||
} | } | ||||
inline void setSCK(uint8_t pin) __attribute__((always_inline)) { | inline void setSCK(uint8_t pin) __attribute__((always_inline)) { | ||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
uint8_t newpinout = pinout; | |||||
// More than two options so now 2 bits | |||||
if (pin == 13) newpinout &= ~0x30; | |||||
if (pin == 14) newpinout =(newpinout & ~0x30) | 0x10; | |||||
if (pin == 27) newpinout = (newpinout & ~0x30) | 0x20; | |||||
if ((SIM_SCGC6 & SIM_SCGC6_SPI0) && newpinout != pinout) { | |||||
// First unconfigure previous pin | |||||
switch (pinout & 0x30) { | |||||
case 0: CORE_PIN13_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); break; | |||||
case 0x10: CORE_PIN14_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); break; | |||||
default: CORE_PIN27_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
} | |||||
switch (newpinout & 0x30) { | |||||
case 0: CORE_PIN13_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); break; | |||||
case 0x10: CORE_PIN14_CONFIG = PORT_PCR_MUX(2); break; | |||||
default: CORE_PIN27_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
} | |||||
pinout = newpinout; | |||||
#else | |||||
uint8_t newpinout = pinout; | |||||
if (pin == 13) newpinout &= ~4; | |||||
if (pin == 14) newpinout |= 4; | |||||
if ((SIM_SCGC6 & SIM_SCGC6_SPI0) && newpinout != pinout) { | |||||
if ((newpinout & 4) == 0) { | |||||
CORE_PIN14_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
CORE_PIN13_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); | |||||
} else { | |||||
CORE_PIN13_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
CORE_PIN14_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
} | |||||
pinout = newpinout; | |||||
#endif | |||||
} | |||||
inline void setSCK_soft(uint8_t pin) __attribute__((always_inline)) { | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
if (pin == 13) pinout &= ~0x30; | |||||
if (pin == 14) pinout = (pinout & ~0x30) | 0x10; | |||||
if (pin == 27) pinout = (pinout & ~0x30) | 0x20; | |||||
#else | |||||
if (pin == 13) pinout &= ~4; | if (pin == 13) pinout &= ~4; | ||||
if (pin == 14) pinout |= 4; | if (pin == 14) pinout |= 4; | ||||
#endif | |||||
} | } | ||||
friend class SPSRemulation; | friend class SPSRemulation; | ||||
friend class SPIFIFOclass; | friend class SPIFIFOclass; | ||||
public: | public: | ||||
inline void enable_pins(void) __attribute__((always_inline)) { | inline void enable_pins(void) __attribute__((always_inline)) { | ||||
//serial_print("enable_pins\n"); | //serial_print("enable_pins\n"); | ||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
switch (pinout & 3) { | |||||
case 0: CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); break; | |||||
case 1: CORE_PIN7_CONFIG = PORT_PCR_MUX(2); break; | |||||
default: CORE_PIN28_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
switch (pinout & 0xc) { | |||||
case 0: CORE_PIN12_CONFIG = PORT_PCR_MUX(2); break; | |||||
case 0x4: CORE_PIN8_CONFIG = PORT_PCR_MUX(2); break; | |||||
default: CORE_PIN39_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
switch (pinout & 0x30) { | |||||
case 0: CORE_PIN13_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); break; | |||||
case 0x10: CORE_PIN14_CONFIG = PORT_PCR_MUX(2); break; | |||||
default: CORE_PIN27_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
#else | |||||
if ((pinout & 1) == 0) { | if ((pinout & 1) == 0) { | ||||
CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); // DOUT/MOSI = 11 (PTC6) | CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); // DOUT/MOSI = 11 (PTC6) | ||||
} else { | } else { | ||||
} else { | } else { | ||||
CORE_PIN14_CONFIG = PORT_PCR_MUX(2); // SCK = 14 (PTD1) | CORE_PIN14_CONFIG = PORT_PCR_MUX(2); // SCK = 14 (PTD1) | ||||
} | } | ||||
#endif | |||||
} | } | ||||
inline void disable_pins(void) __attribute__((always_inline)) { | inline void disable_pins(void) __attribute__((always_inline)) { | ||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
switch (pinout & 3) { | |||||
case 0: CORE_PIN11_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); break; | |||||
case 1: CORE_PIN7_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); break; | |||||
default: CORE_PIN28_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
} | |||||
switch (pinout & 0xc) { | |||||
case 0: CORE_PIN12_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); break; | |||||
case 0x4: CORE_PIN8_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); break; | |||||
default: CORE_PIN39_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
} | |||||
switch (pinout & 0x30) { | |||||
case 0: CORE_PIN13_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); break; | |||||
case 0x10: CORE_PIN14_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); break; | |||||
default: CORE_PIN27_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
} | |||||
#else | |||||
//serial_print("disable_pins\n"); | //serial_print("disable_pins\n"); | ||||
if ((pinout & 1) == 0) { | if ((pinout & 1) == 0) { | ||||
CORE_PIN11_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | CORE_PIN11_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | ||||
} else { | } else { | ||||
CORE_PIN14_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | CORE_PIN14_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | ||||
} | } | ||||
#endif | |||||
} | } | ||||
}; | }; | ||||
extern SPCRemulation SPCR; | extern SPCRemulation SPCR; | ||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
class SPCR1emulation | |||||
{ | |||||
public: | |||||
inline SPCR1emulation & operator = (int val) __attribute__((always_inline)) { | |||||
uint32_t ctar, mcr, sim6; | |||||
//serial_print("SPCR="); | |||||
//serial_phex(val); | |||||
//serial_print("\n"); | |||||
sim6 = SIM_SCGC6; | |||||
if (!(sim6 & SIM_SCGC6_SPI1)) { | |||||
//serial_print("init1\n"); | |||||
SIM_SCGC6 = sim6 | SIM_SCGC6_SPI1; | |||||
SPI1_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1); | |||||
} | |||||
if (!(val & (1<<SPE))) { | |||||
SPI1_MCR |= SPI_MCR_MDIS; // TODO: use bitband for atomic access | |||||
} | |||||
ctar = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1); | |||||
if (val & (1<<DORD)) ctar |= SPI_CTAR_LSBFE; | |||||
if (val & (1<<CPOL)) ctar |= SPI_CTAR_CPOL; | |||||
if (val & (1<<CPHA)) { | |||||
ctar |= SPI_CTAR_CPHA; | |||||
if ((val & 3) == 0) { | |||||
ctar |= SPI_CTAR_BR(1) | SPI_CTAR_ASC(1); | |||||
} else if ((val & 3) == 1) { | |||||
ctar |= SPI_CTAR_BR(4) | SPI_CTAR_ASC(4); | |||||
} else if ((val & 3) == 2) { | |||||
ctar |= SPI_CTAR_BR(6) | SPI_CTAR_ASC(6); | |||||
} else { | |||||
ctar |= SPI_CTAR_BR(7) | SPI_CTAR_ASC(7); | |||||
} | |||||
} else { | |||||
if ((val & 3) == 0) { | |||||
ctar |= SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1); | |||||
} else if ((val & 3) == 1) { | |||||
ctar |= SPI_CTAR_BR(4) | SPI_CTAR_CSSCK(4); | |||||
} else if ((val & 3) == 2) { | |||||
ctar |= SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(6); | |||||
} else { | |||||
ctar |= SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(7); | |||||
} | |||||
} | |||||
ctar |= (SPI1_CTAR0 & SPI_CTAR_DBR); | |||||
update_ctar(ctar); | |||||
mcr = SPI_MCR_DCONF(0) | SPI_MCR_PCSIS(0x1F); | |||||
if (val & (1<<MSTR)) mcr |= SPI_MCR_MSTR; | |||||
if (val & (1<<SPE)) { | |||||
mcr &= ~(SPI_MCR_MDIS | SPI_MCR_HALT); | |||||
SPI1_MCR = mcr; | |||||
enable_pins(); | |||||
} else { | |||||
mcr |= (SPI_MCR_MDIS | SPI_MCR_HALT); | |||||
SPI1_MCR = mcr; | |||||
disable_pins(); | |||||
} | |||||
//serial_print("MCR:"); | |||||
//serial_phex32(SPI1_MCR); | |||||
//serial_print(", CTAR0:"); | |||||
//serial_phex32(SPI1_CTAR0); | |||||
//serial_print("\n"); | |||||
return *this; | |||||
} | |||||
inline SPCR1emulation & operator |= (int val) __attribute__((always_inline)) { | |||||
uint32_t sim6; | |||||
//serial_print("SPCR |= "); | |||||
//serial_phex(val); | |||||
//serial_print("\n"); | |||||
sim6 = SIM_SCGC6; | |||||
if (!(sim6 & SIM_SCGC6_SPI1)) { | |||||
//serial_print("init2\n"); | |||||
SIM_SCGC6 = sim6 | SIM_SCGC6_SPI1; | |||||
SPI1_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1) | SPI_CTAR_BR(1); | |||||
} | |||||
if (val & ((1<<DORD)|(1<<CPOL)|(1<<CPHA)|3)) { | |||||
uint32_t ctar = SPI1_CTAR0; | |||||
if (val & (1<<DORD)) ctar |= SPI_CTAR_LSBFE; // TODO: use bitband | |||||
if (val & (1<<CPOL)) ctar |= SPI_CTAR_CPOL; | |||||
if ((val & 3) == 1) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 2) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 3) { | |||||
// TODO: implement - is this ever really needed | |||||
} | |||||
if (val & (1<<CPHA) && !(ctar & SPI_CTAR_CPHA)) { | |||||
ctar |= SPI_CTAR_CPHA; | |||||
// TODO: clear SPI_CTAR_CSSCK, set SPI_CTAR_ASC | |||||
} | |||||
update_ctar(ctar); | |||||
} | |||||
if (val & (1<<MSTR)) SPI1_MCR |= SPI_MCR_MSTR; | |||||
if (val & (1<<SPE)) { | |||||
SPI1_MCR &= ~(SPI_MCR_MDIS | SPI_MCR_HALT); | |||||
enable_pins(); | |||||
} | |||||
//serial_print("MCR:"); | |||||
//serial_phex32(SPI1_MCR); | |||||
//serial_print(", CTAR0:"); | |||||
//serial_phex32(SPI1_CTAR0); | |||||
//serial_print("\n"); | |||||
return *this; | |||||
} | |||||
inline SPCR1emulation & operator &= (int val) __attribute__((always_inline)) { | |||||
//serial_print("SPCR &= "); | |||||
//serial_phex(val); | |||||
//serial_print("\n"); | |||||
SIM_SCGC6 |= SIM_SCGC6_SPI1; | |||||
if (!(val & (1<<SPE))) { | |||||
SPI1_MCR |= (SPI_MCR_MDIS | SPI_MCR_HALT); | |||||
disable_pins(); | |||||
} | |||||
if ((val & ((1<<DORD)|(1<<CPOL)|(1<<CPHA)|3)) != ((1<<DORD)|(1<<CPOL)|(1<<CPHA)|3)) { | |||||
uint32_t ctar = SPI1_CTAR0; | |||||
if (!(val & (1<<DORD))) ctar &= ~SPI_CTAR_LSBFE; // TODO: use bitband | |||||
if (!(val & (1<<CPOL))) ctar &= ~SPI_CTAR_CPOL; | |||||
if ((val & 3) == 0) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 1) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 2) { | |||||
// TODO: implement - is this ever really needed | |||||
} | |||||
if (!(val & (1<<CPHA)) && (ctar & SPI_CTAR_CPHA)) { | |||||
ctar &= ~SPI_CTAR_CPHA; | |||||
// TODO: set SPI_CTAR_ASC, clear SPI_CTAR_CSSCK | |||||
} | |||||
update_ctar(ctar); | |||||
} | |||||
if (!(val & (1<<MSTR))) SPI1_MCR &= ~SPI_MCR_MSTR; | |||||
return *this; | |||||
} | |||||
inline int operator & (int val) const __attribute__((always_inline)) { | |||||
int ret = 0; | |||||
//serial_print("SPCR & "); | |||||
//serial_phex(val); | |||||
//serial_print(" MCR:"); | |||||
//serial_phex32(SPI1_MCR); | |||||
//serial_print(", CTAR0:"); | |||||
//serial_phex32(SPI1_CTAR0); | |||||
//serial_print("\n"); | |||||
//serial_print("\n"); | |||||
SIM_SCGC6 |= SIM_SCGC6_SPI1; | |||||
if ((val & (1<<DORD)) && (SPI1_CTAR0 & SPI_CTAR_LSBFE)) ret |= (1<<DORD); | |||||
if ((val & (1<<CPOL)) && (SPI1_CTAR0 & SPI_CTAR_CPOL)) ret |= (1<<CPOL); | |||||
if ((val & (1<<CPHA)) && (SPI1_CTAR0 & SPI_CTAR_CPHA)) ret |= (1<<CPHA); | |||||
if ((val & 3) == 3) { | |||||
uint32_t dbr = SPI1_CTAR0 & 15; | |||||
if (dbr <= 1) { | |||||
} else if (dbr <= 4) { | |||||
ret |= (1<<SPR0); | |||||
} else if (dbr <= 6) { | |||||
ret |= (1<<SPR1); | |||||
} else { | |||||
ret |= (1<<SPR1)|(1<<SPR0); | |||||
} | |||||
} else if ((val & 3) == 1) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 2) { | |||||
// TODO: implement - is this ever really needed | |||||
} | |||||
if (val & (1<<SPE) && (!(SPI1_MCR & SPI_MCR_MDIS))) ret |= (1<<SPE); | |||||
if (val & (1<<MSTR) && (SPI1_MCR & SPI_MCR_MSTR)) ret |= (1<<MSTR); | |||||
//serial_print("ret = "); | |||||
//serial_phex(ret); | |||||
//serial_print("\n"); | |||||
return ret; | |||||
} | |||||
inline void setMOSI(uint8_t pin) __attribute__((always_inline)) { | |||||
// More options, so 2 bits | |||||
pinout &= ~3; | |||||
switch (pin) { | |||||
case 0: break; | |||||
case 21: pinout |= 1; break; | |||||
case 61: pinout |= 2; break; | |||||
case 59: pinout |= 3; break; | |||||
} | |||||
} | |||||
inline void setMISO(uint8_t pin) __attribute__((always_inline)) { | |||||
// More options, so 2 bits | |||||
pinout &= ~0xc; | |||||
switch (pin) { | |||||
case 1: break; | |||||
case 5: pinout |= 0x4; break; | |||||
case 61: pinout |= 0x8; break; | |||||
case 59: pinout |= 0xc; break; | |||||
} | |||||
} | |||||
inline void setSCK(uint8_t pin) __attribute__((always_inline)) { | |||||
// More options, so 2 bits | |||||
pinout &= ~0x30; | |||||
switch (pin) { | |||||
case 32: break; | |||||
case 20: pinout |= 0x10; break; | |||||
case 60: pinout |= 0x20; break; | |||||
} | |||||
} | |||||
inline void enable_pins(void) __attribute__((always_inline)) { | |||||
//serial_print("enable_pins\n"); | |||||
// MOSI (SOUT) | |||||
switch (pinout & 0x3) { | |||||
case 0: CORE_PIN0_CONFIG = PORT_PCR_MUX(2); break; | |||||
case 1: CORE_PIN21_CONFIG = PORT_PCR_MUX(7); break; | |||||
case 2: CORE_PIN61_CONFIG = PORT_PCR_MUX(7); break; | |||||
case 3: CORE_PIN59_CONFIG = PORT_PCR_MUX(2); break; | |||||
} | |||||
// MISO (SIN) | |||||
switch (pinout & 0xc) { | |||||
case 0x0: CORE_PIN1_CONFIG = PORT_PCR_MUX(2); break; | |||||
case 0x4: CORE_PIN5_CONFIG = PORT_PCR_MUX(7); break; | |||||
case 0x8: CORE_PIN61_CONFIG = PORT_PCR_MUX(2); break; | |||||
case 0xc: CORE_PIN59_CONFIG = PORT_PCR_MUX(7); break; | |||||
} | |||||
// SCK | |||||
switch (pinout & 0x30) { | |||||
case 0x0: CORE_PIN32_CONFIG = PORT_PCR_MUX(2); break; | |||||
case 0x10: CORE_PIN20_CONFIG = PORT_PCR_MUX(7); break; | |||||
case 0x20: CORE_PIN60_CONFIG = PORT_PCR_MUX(2); break; | |||||
} | |||||
} | |||||
inline void disable_pins(void) __attribute__((always_inline)) { | |||||
switch (pinout & 0x3) { | |||||
case 0: CORE_PIN0_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break; | |||||
case 1: CORE_PIN21_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break; | |||||
case 2: CORE_PIN61_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break; | |||||
case 3: CORE_PIN59_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break; | |||||
} | |||||
switch (pinout & 0xc) { | |||||
case 0x0: CORE_PIN1_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break; | |||||
case 0x4: CORE_PIN5_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break; | |||||
case 0x8: CORE_PIN61_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break; | |||||
case 0xc: CORE_PIN59_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break; | |||||
} | |||||
switch (pinout & 0x30) { | |||||
case 0x0: CORE_PIN32_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break; | |||||
case 0x10: CORE_PIN20_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break; | |||||
case 0x20: CORE_PIN60_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break; | |||||
} | |||||
} | |||||
friend class SPIFIFO1class; | |||||
private: | |||||
static uint8_t pinout; | |||||
static inline void update_ctar(uint32_t ctar) __attribute__((always_inline)) { | |||||
if (SPI1_CTAR0 == ctar) return; | |||||
uint32_t mcr = SPI1_MCR; | |||||
if (mcr & SPI_MCR_MDIS) { | |||||
SPI1_CTAR0 = ctar; | |||||
} else { | |||||
SPI1_MCR = mcr | SPI_MCR_MDIS | SPI_MCR_HALT; | |||||
SPI1_CTAR0 = ctar; | |||||
SPI1_MCR = mcr; | |||||
} | |||||
} | |||||
}; | |||||
extern SPCR1emulation SPCR1; | |||||
//////////////////// | |||||
// SPI2 | |||||
class SPCR2emulation | |||||
{ | |||||
public: | |||||
inline SPCR2emulation & operator = (int val) __attribute__((always_inline)) { | |||||
uint32_t ctar, mcr, sim3; | |||||
//serial_print("SPCR="); | |||||
//serial_phex(val); | |||||
//serial_print("\n"); | |||||
sim3 = SIM_SCGC3; | |||||
if (!(sim3 & SIM_SCGC3_SPI2)) { | |||||
//serial_print("init1\n"); | |||||
SIM_SCGC3 = sim3 | SIM_SCGC3_SPI2; | |||||
SPI2_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1); | |||||
} | |||||
if (!(val & (1<<SPE))) { | |||||
SPI2_MCR |= SPI_MCR_MDIS; // TODO: use bitband for atomic access | |||||
} | |||||
ctar = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1); | |||||
if (val & (1<<DORD)) ctar |= SPI_CTAR_LSBFE; | |||||
if (val & (1<<CPOL)) ctar |= SPI_CTAR_CPOL; | |||||
if (val & (1<<CPHA)) { | |||||
ctar |= SPI_CTAR_CPHA; | |||||
if ((val & 3) == 0) { | |||||
ctar |= SPI_CTAR_BR(1) | SPI_CTAR_ASC(1); | |||||
} else if ((val & 3) == 1) { | |||||
ctar |= SPI_CTAR_BR(4) | SPI_CTAR_ASC(4); | |||||
} else if ((val & 3) == 2) { | |||||
ctar |= SPI_CTAR_BR(6) | SPI_CTAR_ASC(6); | |||||
} else { | |||||
ctar |= SPI_CTAR_BR(7) | SPI_CTAR_ASC(7); | |||||
} | |||||
} else { | |||||
if ((val & 3) == 0) { | |||||
ctar |= SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1); | |||||
} else if ((val & 3) == 1) { | |||||
ctar |= SPI_CTAR_BR(4) | SPI_CTAR_CSSCK(4); | |||||
} else if ((val & 3) == 2) { | |||||
ctar |= SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(6); | |||||
} else { | |||||
ctar |= SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(7); | |||||
} | |||||
} | |||||
ctar |= (SPI2_CTAR0 & SPI_CTAR_DBR); | |||||
update_ctar(ctar); | |||||
mcr = SPI_MCR_DCONF(0) | SPI_MCR_PCSIS(0x1F); | |||||
if (val & (1<<MSTR)) mcr |= SPI_MCR_MSTR; | |||||
if (val & (1<<SPE)) { | |||||
mcr &= ~(SPI_MCR_MDIS | SPI_MCR_HALT); | |||||
SPI2_MCR = mcr; | |||||
enable_pins(); | |||||
} else { | |||||
mcr |= (SPI_MCR_MDIS | SPI_MCR_HALT); | |||||
SPI2_MCR = mcr; | |||||
disable_pins(); | |||||
} | |||||
//serial_print("MCR:"); | |||||
//serial_phex32(SPI2_MCR); | |||||
//serial_print(", CTAR0:"); | |||||
//serial_phex32(SPI2_CTAR0); | |||||
//serial_print("\n"); | |||||
return *this; | |||||
} | |||||
inline SPCR2emulation & operator |= (int val) __attribute__((always_inline)) { | |||||
uint32_t sim3; | |||||
//serial_print("SPCR |= "); | |||||
//serial_phex(val); | |||||
//serial_print("\n"); | |||||
sim3 = SIM_SCGC3; | |||||
if (!(sim3 & SIM_SCGC3_SPI2)) { | |||||
//serial_print("init2\n"); | |||||
SIM_SCGC6 = sim3 | SIM_SCGC3_SPI2; | |||||
SPI2_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1) | SPI_CTAR_BR(1); | |||||
} | |||||
if (val & ((1<<DORD)|(1<<CPOL)|(1<<CPHA)|3)) { | |||||
uint32_t ctar = SPI2_CTAR0; | |||||
if (val & (1<<DORD)) ctar |= SPI_CTAR_LSBFE; // TODO: use bitband | |||||
if (val & (1<<CPOL)) ctar |= SPI_CTAR_CPOL; | |||||
if ((val & 3) == 1) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 2) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 3) { | |||||
// TODO: implement - is this ever really needed | |||||
} | |||||
if (val & (1<<CPHA) && !(ctar & SPI_CTAR_CPHA)) { | |||||
ctar |= SPI_CTAR_CPHA; | |||||
// TODO: clear SPI_CTAR_CSSCK, set SPI_CTAR_ASC | |||||
} | |||||
update_ctar(ctar); | |||||
} | |||||
if (val & (1<<MSTR)) SPI2_MCR |= SPI_MCR_MSTR; | |||||
if (val & (1<<SPE)) { | |||||
SPI2_MCR &= ~(SPI_MCR_MDIS | SPI_MCR_HALT); | |||||
enable_pins(); | |||||
} | |||||
//serial_print("MCR:"); | |||||
//serial_phex32(SPI2_MCR); | |||||
//serial_print(", CTAR0:"); | |||||
//serial_phex32(SPI2_CTAR0); | |||||
//serial_print("\n"); | |||||
return *this; | |||||
} | |||||
inline SPCR2emulation & operator &= (int val) __attribute__((always_inline)) { | |||||
//serial_print("SPCR &= "); | |||||
//serial_phex(val); | |||||
//serial_print("\n"); | |||||
SIM_SCGC3 |= SIM_SCGC3_SPI2; | |||||
if (!(val & (1<<SPE))) { | |||||
SPI2_MCR |= (SPI_MCR_MDIS | SPI_MCR_HALT); | |||||
disable_pins(); | |||||
} | |||||
if ((val & ((1<<DORD)|(1<<CPOL)|(1<<CPHA)|3)) != ((1<<DORD)|(1<<CPOL)|(1<<CPHA)|3)) { | |||||
uint32_t ctar = SPI2_CTAR0; | |||||
if (!(val & (1<<DORD))) ctar &= ~SPI_CTAR_LSBFE; // TODO: use bitband | |||||
if (!(val & (1<<CPOL))) ctar &= ~SPI_CTAR_CPOL; | |||||
if ((val & 3) == 0) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 1) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 2) { | |||||
// TODO: implement - is this ever really needed | |||||
} | |||||
if (!(val & (1<<CPHA)) && (ctar & SPI_CTAR_CPHA)) { | |||||
ctar &= ~SPI_CTAR_CPHA; | |||||
// TODO: set SPI_CTAR_ASC, clear SPI_CTAR_CSSCK | |||||
} | |||||
update_ctar(ctar); | |||||
} | |||||
if (!(val & (1<<MSTR))) SPI2_MCR &= ~SPI_MCR_MSTR; | |||||
return *this; | |||||
} | |||||
inline int operator & (int val) const __attribute__((always_inline)) { | |||||
int ret = 0; | |||||
//serial_print("SPCR & "); | |||||
//serial_phex(val); | |||||
//serial_print(" MCR:"); | |||||
//serial_phex32(SPI2_MCR); | |||||
//serial_print(", CTAR0:"); | |||||
//serial_phex32(SPI2_CTAR0); | |||||
//serial_print("\n"); | |||||
//serial_print("\n"); | |||||
SIM_SCGC3 |= SIM_SCGC3_SPI2; | |||||
if ((val & (1<<DORD)) && (SPI2_CTAR0 & SPI_CTAR_LSBFE)) ret |= (1<<DORD); | |||||
if ((val & (1<<CPOL)) && (SPI2_CTAR0 & SPI_CTAR_CPOL)) ret |= (1<<CPOL); | |||||
if ((val & (1<<CPHA)) && (SPI2_CTAR0 & SPI_CTAR_CPHA)) ret |= (1<<CPHA); | |||||
if ((val & 3) == 3) { | |||||
uint32_t dbr = SPI2_CTAR0 & 15; | |||||
if (dbr <= 1) { | |||||
} else if (dbr <= 4) { | |||||
ret |= (1<<SPR0); | |||||
} else if (dbr <= 6) { | |||||
ret |= (1<<SPR1); | |||||
} else { | |||||
ret |= (1<<SPR1)|(1<<SPR0); | |||||
} | |||||
} else if ((val & 3) == 1) { | |||||
// TODO: implement - is this ever really needed | |||||
} else if ((val & 3) == 2) { | |||||
// TODO: implement - is this ever really needed | |||||
} | |||||
if (val & (1<<SPE) && (!(SPI2_MCR & SPI_MCR_MDIS))) ret |= (1<<SPE); | |||||
if (val & (1<<MSTR) && (SPI2_MCR & SPI_MCR_MSTR)) ret |= (1<<MSTR); | |||||
//serial_print("ret = "); | |||||
//serial_phex(ret); | |||||
//serial_print("\n"); | |||||
return ret; | |||||
} | |||||
inline void setMOSI(uint8_t pin) __attribute__((always_inline)) { | |||||
if (pin == 44) pinout &= ~1; | |||||
if (pin == 52) pinout |= 1; | |||||
} | |||||
inline void setMISO(uint8_t pin) __attribute__((always_inline)) { | |||||
if (pin == 45) pinout &= ~2; | |||||
if (pin == 51) pinout |= 2; | |||||
} | |||||
inline void setSCK(uint8_t pin) __attribute__((always_inline)) { | |||||
if (pin == 46) pinout &= ~4; | |||||
if (pin == 53) pinout |= 4; | |||||
} | |||||
inline void enable_pins(void) __attribute__((always_inline)) { | |||||
//serial_print("enable_pins\n"); | |||||
if ((pinout & 1) == 0) { | |||||
CORE_PIN44_CONFIG = PORT_PCR_MUX(2); | |||||
} else { | |||||
CORE_PIN52_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
if ((pinout & 2) == 0) { | |||||
CORE_PIN45_CONFIG = PORT_PCR_MUX(2); | |||||
} else { | |||||
CORE_PIN51_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
if ((pinout & 4) == 0) { | |||||
CORE_PIN46_CONFIG = PORT_PCR_MUX(2); | |||||
} else { | |||||
CORE_PIN53_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
} | |||||
inline void disable_pins(void) __attribute__((always_inline)) { | |||||
//serial_print("disable_pins\n"); | |||||
if ((pinout & 1) == 0) { | |||||
CORE_PIN44_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); | |||||
} else { | |||||
CORE_PIN52_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); | |||||
} | |||||
if ((pinout & 2) == 0) { | |||||
CORE_PIN45_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); | |||||
} else { | |||||
CORE_PIN51_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); | |||||
} | |||||
if ((pinout & 4) == 0) { | |||||
CORE_PIN46_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); | |||||
} else { | |||||
CORE_PIN53_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); | |||||
} | |||||
} | |||||
friend class SPIFIFO1class; | |||||
private: | |||||
static uint8_t pinout; | |||||
static inline void update_ctar(uint32_t ctar) __attribute__((always_inline)) { | |||||
if (SPI2_CTAR0 == ctar) return; | |||||
uint32_t mcr = SPI2_MCR; | |||||
if (mcr & SPI_MCR_MDIS) { | |||||
SPI2_CTAR0 = ctar; | |||||
} else { | |||||
SPI2_MCR = mcr | SPI_MCR_MDIS | SPI_MCR_HALT; | |||||
SPI2_CTAR0 = ctar; | |||||
SPI2_MCR = mcr; | |||||
} | |||||
} | |||||
}; | |||||
extern SPCR2emulation SPCR2; | |||||
#endif | |||||
class SPSRemulation | class SPSRemulation | ||||
{ | { | ||||
public: | public: | ||||
return ret; | return ret; | ||||
} | } | ||||
inline void setMOSI(uint8_t pin) __attribute__((always_inline)) { | inline void setMOSI(uint8_t pin) __attribute__((always_inline)) { | ||||
if (pin == 11) pinout &= ~1; | |||||
if (pin == 7) pinout |= 1; | |||||
uint8_t newpinout = pinout; | |||||
if (pin == 11) newpinout &= ~1; | |||||
if (pin == 7) newpinout |= 1; | |||||
if ((SIM_SCGC4 & SIM_SCGC4_SPI0) && newpinout != pinout) { | |||||
if ((newpinout & 1) == 0) { | |||||
CORE_PIN7_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); | |||||
} else { | |||||
CORE_PIN11_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
CORE_PIN7_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
} | |||||
pinout = newpinout; | |||||
} | } | ||||
inline void setMISO(uint8_t pin) __attribute__((always_inline)) { | inline void setMISO(uint8_t pin) __attribute__((always_inline)) { | ||||
if (pin == 12) pinout &= ~2; | |||||
if (pin == 8) pinout |= 2; | |||||
uint8_t newpinout = pinout; | |||||
if (pin == 12) newpinout &= ~2; | |||||
if (pin == 8) newpinout |= 2; | |||||
if ((SIM_SCGC4 & SIM_SCGC4_SPI0) && newpinout != pinout) { | |||||
if ((newpinout & 2) == 0) { | |||||
CORE_PIN8_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
CORE_PIN12_CONFIG = PORT_PCR_MUX(2); | |||||
} else { | |||||
CORE_PIN12_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
CORE_PIN8_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
} | |||||
pinout = newpinout; | |||||
} | } | ||||
inline void setSCK(uint8_t pin) __attribute__((always_inline)) { | inline void setSCK(uint8_t pin) __attribute__((always_inline)) { | ||||
if (pin == 13) pinout &= ~4; | |||||
if (pin == 14) pinout |= 4; | |||||
uint8_t newpinout = pinout; | |||||
if (pin == 13) newpinout &= ~4; | |||||
if (pin == 14) newpinout |= 4; | |||||
if ((SIM_SCGC4 & SIM_SCGC4_SPI0) && newpinout != pinout) { | |||||
if ((newpinout & 4) == 0) { | |||||
CORE_PIN14_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
CORE_PIN13_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); | |||||
} else { | |||||
CORE_PIN13_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
CORE_PIN14_CONFIG = PORT_PCR_MUX(2); | |||||
} | |||||
} | |||||
pinout = newpinout; | |||||
} | } | ||||
friend class SPSRemulation; | friend class SPSRemulation; | ||||
friend class SPIFIFOclass; | friend class SPIFIFOclass; | ||||
extern SREGemulation SREG; | extern SREGemulation SREG; | ||||
// 22211 | |||||
// 22211 | |||||
// 84062840 | // 84062840 | ||||
// 322111 | |||||
// 322111 | |||||
// 17395173 | // 17395173 | ||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | ||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the |
// This header file is in the public domain. | |||||
#ifndef Binary_h | #ifndef Binary_h | ||||
#define Binary_h | #define Binary_h | ||||
// This header file is in the public domain. | |||||
#ifndef CORE_TEENSY | #ifndef CORE_TEENSY | ||||
#define CORE_TEENSY | #define CORE_TEENSY | ||||
#endif | #endif |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
#include "kinetis.h" | #include "kinetis.h" | ||||
#include "pins_arduino.h" | #include "pins_arduino.h" | ||||
#define HIGH 1 | #define HIGH 1 | ||||
#define LOW 0 | #define LOW 0 | ||||
#define INPUT 0 | #define INPUT 0 | ||||
#define INPUT_PULLUP 2 | #define INPUT_PULLUP 2 | ||||
#define INPUT_PULLDOWN 3 | #define INPUT_PULLDOWN 3 | ||||
#define OUTPUT_OPENDRAIN 4 | #define OUTPUT_OPENDRAIN 4 | ||||
#define INPUT_DISABLE 5 | |||||
#define LSBFIRST 0 | #define LSBFIRST 0 | ||||
#define MSBFIRST 1 | #define MSBFIRST 1 | ||||
#define _BV(n) (1<<(n)) | #define _BV(n) (1<<(n)) | ||||
#define CORE_NUM_INTERRUPT 24 // really only 18, but 6 "holes" | #define CORE_NUM_INTERRUPT 24 // really only 18, but 6 "holes" | ||||
#define CORE_NUM_ANALOG 13 | #define CORE_NUM_ANALOG 13 | ||||
#define CORE_NUM_PWM 10 | #define CORE_NUM_PWM 10 | ||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#define CORE_NUM_TOTAL_PINS 40 | |||||
#define CORE_NUM_DIGITAL 40 | |||||
#define CORE_NUM_INTERRUPT 40 | |||||
#define CORE_NUM_ANALOG 23 | |||||
#elif defined(__MK64FX512__) | |||||
#define CORE_NUM_TOTAL_PINS 64 | |||||
#define CORE_NUM_DIGITAL 64 | |||||
#define CORE_NUM_INTERRUPT 64 | |||||
#define CORE_NUM_ANALOG 27 | |||||
#define CORE_NUM_PWM 20 | #define CORE_NUM_PWM 20 | ||||
#elif defined(__MK66FX1M0__) | |||||
#define CORE_NUM_TOTAL_PINS 64 | |||||
#define CORE_NUM_DIGITAL 64 | |||||
#define CORE_NUM_INTERRUPT 64 | |||||
#define CORE_NUM_ANALOG 25 | |||||
#define CORE_NUM_PWM 22 | |||||
#endif | |||||
// These MAX_PIN_PORTx values have the highest Kinetis pin index | |||||
// that is used for a given port. | |||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) | |||||
#define CORE_MAX_PIN_PORTA 13 | |||||
#define CORE_MAX_PIN_PORTB 19 | |||||
#define CORE_MAX_PIN_PORTC 11 | |||||
#define CORE_MAX_PIN_PORTD 7 | |||||
#define CORE_MAX_PIN_PORTE 1 | |||||
#elif defined(__MKL26Z64__) | |||||
#define CORE_MAX_PIN_PORTA 2 | |||||
#define CORE_MAX_PIN_PORTB 17 | |||||
#define CORE_MAX_PIN_PORTC 7 | |||||
#define CORE_MAX_PIN_PORTD 7 | |||||
#define CORE_MAX_PIN_PORTE 30 | |||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#define CORE_MAX_PIN_PORTA 29 | |||||
#define CORE_MAX_PIN_PORTB 23 | |||||
#define CORE_MAX_PIN_PORTC 11 | |||||
#define CORE_MAX_PIN_PORTD 15 | |||||
#define CORE_MAX_PIN_PORTE 26 | |||||
#endif | #endif | ||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) | #if defined(__MK20DX128__) || defined(__MK20DX256__) | ||||
#define CORE_PIN0_BIT 16 | #define CORE_PIN0_BIT 16 | ||||
#define CORE_PIN37_BIT 10 | #define CORE_PIN37_BIT 10 | ||||
#define CORE_PIN38_BIT 11 | #define CORE_PIN38_BIT 11 | ||||
#define CORE_PIN39_BIT 17 | #define CORE_PIN39_BIT 17 | ||||
#define CORE_PIN40_BIT 28 | |||||
#define CORE_PIN41_BIT 29 | |||||
#define CORE_PIN42_BIT 26 | |||||
#define CORE_PIN43_BIT 20 | |||||
#define CORE_PIN44_BIT 22 | |||||
#define CORE_PIN45_BIT 23 | |||||
#define CORE_PIN46_BIT 21 | |||||
#define CORE_PIN47_BIT 8 | |||||
#define CORE_PIN48_BIT 9 | |||||
#define CORE_PIN49_BIT 4 | |||||
#define CORE_PIN50_BIT 5 | |||||
#define CORE_PIN51_BIT 14 | |||||
#define CORE_PIN52_BIT 13 | |||||
#define CORE_PIN53_BIT 12 | |||||
#define CORE_PIN54_BIT 15 | |||||
#define CORE_PIN55_BIT 11 | |||||
#define CORE_PIN56_BIT 10 | |||||
#define CORE_PIN57_BIT 11 | |||||
#define CORE_PIN58_BIT 0 | |||||
#define CORE_PIN59_BIT 1 | |||||
#define CORE_PIN60_BIT 2 | |||||
#define CORE_PIN61_BIT 3 | |||||
#define CORE_PIN62_BIT 4 | |||||
#define CORE_PIN63_BIT 5 | |||||
#define CORE_PIN0_BITMASK (1<<(CORE_PIN0_BIT)) | #define CORE_PIN0_BITMASK (1<<(CORE_PIN0_BIT)) | ||||
#define CORE_PIN1_BITMASK (1<<(CORE_PIN1_BIT)) | #define CORE_PIN1_BITMASK (1<<(CORE_PIN1_BIT)) | ||||
#define CORE_PIN37_BITMASK (1<<(CORE_PIN37_BIT)) | #define CORE_PIN37_BITMASK (1<<(CORE_PIN37_BIT)) | ||||
#define CORE_PIN38_BITMASK (1<<(CORE_PIN38_BIT)) | #define CORE_PIN38_BITMASK (1<<(CORE_PIN38_BIT)) | ||||
#define CORE_PIN39_BITMASK (1<<(CORE_PIN39_BIT)) | #define CORE_PIN39_BITMASK (1<<(CORE_PIN39_BIT)) | ||||
#define CORE_PIN40_BITMASK (1<<(CORE_PIN40_BIT)) | |||||
#define CORE_PIN41_BITMASK (1<<(CORE_PIN41_BIT)) | |||||
#define CORE_PIN42_BITMASK (1<<(CORE_PIN42_BIT)) | |||||
#define CORE_PIN43_BITMASK (1<<(CORE_PIN43_BIT)) | |||||
#define CORE_PIN44_BITMASK (1<<(CORE_PIN44_BIT)) | |||||
#define CORE_PIN45_BITMASK (1<<(CORE_PIN45_BIT)) | |||||
#define CORE_PIN46_BITMASK (1<<(CORE_PIN46_BIT)) | |||||
#define CORE_PIN47_BITMASK (1<<(CORE_PIN47_BIT)) | |||||
#define CORE_PIN48_BITMASK (1<<(CORE_PIN48_BIT)) | |||||
#define CORE_PIN49_BITMASK (1<<(CORE_PIN49_BIT)) | |||||
#define CORE_PIN50_BITMASK (1<<(CORE_PIN50_BIT)) | |||||
#define CORE_PIN51_BITMASK (1<<(CORE_PIN51_BIT)) | |||||
#define CORE_PIN52_BITMASK (1<<(CORE_PIN52_BIT)) | |||||
#define CORE_PIN53_BITMASK (1<<(CORE_PIN53_BIT)) | |||||
#define CORE_PIN54_BITMASK (1<<(CORE_PIN54_BIT)) | |||||
#define CORE_PIN55_BITMASK (1<<(CORE_PIN55_BIT)) | |||||
#define CORE_PIN56_BITMASK (1<<(CORE_PIN56_BIT)) | |||||
#define CORE_PIN57_BITMASK (1<<(CORE_PIN57_BIT)) | |||||
#define CORE_PIN58_BITMASK (1<<(CORE_PIN58_BIT)) | |||||
#define CORE_PIN59_BITMASK (1<<(CORE_PIN59_BIT)) | |||||
#define CORE_PIN60_BITMASK (1<<(CORE_PIN60_BIT)) | |||||
#define CORE_PIN61_BITMASK (1<<(CORE_PIN61_BIT)) | |||||
#define CORE_PIN62_BITMASK (1<<(CORE_PIN62_BIT)) | |||||
#define CORE_PIN63_BITMASK (1<<(CORE_PIN63_BIT)) | |||||
#define CORE_PIN0_PORTREG GPIOB_PDOR | #define CORE_PIN0_PORTREG GPIOB_PDOR | ||||
#define CORE_PIN1_PORTREG GPIOB_PDOR | #define CORE_PIN1_PORTREG GPIOB_PDOR | ||||
#define CORE_PIN37_PORTREG GPIOC_PDOR | #define CORE_PIN37_PORTREG GPIOC_PDOR | ||||
#define CORE_PIN38_PORTREG GPIOC_PDOR | #define CORE_PIN38_PORTREG GPIOC_PDOR | ||||
#define CORE_PIN39_PORTREG GPIOA_PDOR | #define CORE_PIN39_PORTREG GPIOA_PDOR | ||||
#define CORE_PIN40_PORTREG GPIOA_PDOR | |||||
#define CORE_PIN41_PORTREG GPIOA_PDOR | |||||
#define CORE_PIN42_PORTREG GPIOA_PDOR | |||||
#define CORE_PIN43_PORTREG GPIOB_PDOR | |||||
#define CORE_PIN44_PORTREG GPIOB_PDOR | |||||
#define CORE_PIN45_PORTREG GPIOB_PDOR | |||||
#define CORE_PIN46_PORTREG GPIOB_PDOR | |||||
#define CORE_PIN47_PORTREG GPIOD_PDOR | |||||
#define CORE_PIN48_PORTREG GPIOD_PDOR | |||||
#define CORE_PIN49_PORTREG GPIOB_PDOR | |||||
#define CORE_PIN50_PORTREG GPIOB_PDOR | |||||
#define CORE_PIN51_PORTREG GPIOD_PDOR | |||||
#define CORE_PIN52_PORTREG GPIOD_PDOR | |||||
#define CORE_PIN53_PORTREG GPIOD_PDOR | |||||
#define CORE_PIN54_PORTREG GPIOD_PDOR | |||||
#define CORE_PIN55_PORTREG GPIOD_PDOR | |||||
#define CORE_PIN56_PORTREG GPIOE_PDOR | |||||
#define CORE_PIN57_PORTREG GPIOE_PDOR | |||||
#define CORE_PIN58_PORTREG GPIOE_PDOR | |||||
#define CORE_PIN59_PORTREG GPIOE_PDOR | |||||
#define CORE_PIN60_PORTREG GPIOE_PDOR | |||||
#define CORE_PIN61_PORTREG GPIOE_PDOR | |||||
#define CORE_PIN62_PORTREG GPIOE_PDOR | |||||
#define CORE_PIN63_PORTREG GPIOE_PDOR | |||||
#define CORE_PIN0_PORTSET GPIOB_PSOR | #define CORE_PIN0_PORTSET GPIOB_PSOR | ||||
#define CORE_PIN1_PORTSET GPIOB_PSOR | #define CORE_PIN1_PORTSET GPIOB_PSOR | ||||
#define CORE_PIN37_PORTSET GPIOC_PSOR | #define CORE_PIN37_PORTSET GPIOC_PSOR | ||||
#define CORE_PIN38_PORTSET GPIOC_PSOR | #define CORE_PIN38_PORTSET GPIOC_PSOR | ||||
#define CORE_PIN39_PORTSET GPIOA_PSOR | #define CORE_PIN39_PORTSET GPIOA_PSOR | ||||
#define CORE_PIN40_PORTSET GPIOA_PSOR | |||||
#define CORE_PIN41_PORTSET GPIOA_PSOR | |||||
#define CORE_PIN42_PORTSET GPIOA_PSOR | |||||
#define CORE_PIN43_PORTSET GPIOB_PSOR | |||||
#define CORE_PIN44_PORTSET GPIOB_PSOR | |||||
#define CORE_PIN45_PORTSET GPIOB_PSOR | |||||
#define CORE_PIN46_PORTSET GPIOB_PSOR | |||||
#define CORE_PIN47_PORTSET GPIOD_PSOR | |||||
#define CORE_PIN48_PORTSET GPIOD_PSOR | |||||
#define CORE_PIN49_PORTSET GPIOB_PSOR | |||||
#define CORE_PIN50_PORTSET GPIOB_PSOR | |||||
#define CORE_PIN51_PORTSET GPIOD_PSOR | |||||
#define CORE_PIN52_PORTSET GPIOD_PSOR | |||||
#define CORE_PIN53_PORTSET GPIOD_PSOR | |||||
#define CORE_PIN54_PORTSET GPIOD_PSOR | |||||
#define CORE_PIN55_PORTSET GPIOD_PSOR | |||||
#define CORE_PIN56_PORTSET GPIOE_PSOR | |||||
#define CORE_PIN57_PORTSET GPIOE_PSOR | |||||
#define CORE_PIN58_PORTSET GPIOE_PSOR | |||||
#define CORE_PIN59_PORTSET GPIOE_PSOR | |||||
#define CORE_PIN60_PORTSET GPIOE_PSOR | |||||
#define CORE_PIN61_PORTSET GPIOE_PSOR | |||||
#define CORE_PIN62_PORTSET GPIOE_PSOR | |||||
#define CORE_PIN63_PORTSET GPIOE_PSOR | |||||
#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_PIN37_PORTCLEAR GPIOC_PCOR | #define CORE_PIN37_PORTCLEAR GPIOC_PCOR | ||||
#define CORE_PIN38_PORTCLEAR GPIOC_PCOR | #define CORE_PIN38_PORTCLEAR GPIOC_PCOR | ||||
#define CORE_PIN39_PORTCLEAR GPIOA_PCOR | #define CORE_PIN39_PORTCLEAR GPIOA_PCOR | ||||
#define CORE_PIN40_PORTCLEAR GPIOA_PCOR | |||||
#define CORE_PIN41_PORTCLEAR GPIOA_PCOR | |||||
#define CORE_PIN42_PORTCLEAR GPIOA_PCOR | |||||
#define CORE_PIN43_PORTCLEAR GPIOB_PCOR | |||||
#define CORE_PIN44_PORTCLEAR GPIOB_PCOR | |||||
#define CORE_PIN45_PORTCLEAR GPIOB_PCOR | |||||
#define CORE_PIN46_PORTCLEAR GPIOB_PCOR | |||||
#define CORE_PIN47_PORTCLEAR GPIOD_PCOR | |||||
#define CORE_PIN48_PORTCLEAR GPIOD_PCOR | |||||
#define CORE_PIN49_PORTCLEAR GPIOB_PCOR | |||||
#define CORE_PIN50_PORTCLEAR GPIOB_PCOR | |||||
#define CORE_PIN51_PORTCLEAR GPIOD_PCOR | |||||
#define CORE_PIN52_PORTCLEAR GPIOD_PCOR | |||||
#define CORE_PIN53_PORTCLEAR GPIOD_PCOR | |||||
#define CORE_PIN54_PORTCLEAR GPIOD_PCOR | |||||
#define CORE_PIN55_PORTCLEAR GPIOD_PCOR | |||||
#define CORE_PIN56_PORTCLEAR GPIOE_PCOR | |||||
#define CORE_PIN57_PORTCLEAR GPIOE_PCOR | |||||
#define CORE_PIN58_PORTCLEAR GPIOE_PCOR | |||||
#define CORE_PIN59_PORTCLEAR GPIOE_PCOR | |||||
#define CORE_PIN60_PORTCLEAR GPIOE_PCOR | |||||
#define CORE_PIN61_PORTCLEAR GPIOE_PCOR | |||||
#define CORE_PIN62_PORTCLEAR GPIOE_PCOR | |||||
#define CORE_PIN63_PORTCLEAR GPIOE_PCOR | |||||
#define CORE_PIN0_DDRREG GPIOB_PDDR | #define CORE_PIN0_DDRREG GPIOB_PDDR | ||||
#define CORE_PIN1_DDRREG GPIOB_PDDR | #define CORE_PIN1_DDRREG GPIOB_PDDR | ||||
#define CORE_PIN37_DDRREG GPIOC_PDDR | #define CORE_PIN37_DDRREG GPIOC_PDDR | ||||
#define CORE_PIN38_DDRREG GPIOC_PDDR | #define CORE_PIN38_DDRREG GPIOC_PDDR | ||||
#define CORE_PIN39_DDRREG GPIOA_PDDR | #define CORE_PIN39_DDRREG GPIOA_PDDR | ||||
#define CORE_PIN40_DDRREG GPIOA_PDDR | |||||
#define CORE_PIN41_DDRREG GPIOA_PDDR | |||||
#define CORE_PIN42_DDRREG GPIOA_PDDR | |||||
#define CORE_PIN43_DDRREG GPIOB_PDDR | |||||
#define CORE_PIN44_DDRREG GPIOB_PDDR | |||||
#define CORE_PIN45_DDRREG GPIOB_PDDR | |||||
#define CORE_PIN46_DDRREG GPIOB_PDDR | |||||
#define CORE_PIN47_DDRREG GPIOD_PDDR | |||||
#define CORE_PIN48_DDRREG GPIOD_PDDR | |||||
#define CORE_PIN49_DDRREG GPIOB_PDDR | |||||
#define CORE_PIN50_DDRREG GPIOB_PDDR | |||||
#define CORE_PIN51_DDRREG GPIOD_PDDR | |||||
#define CORE_PIN52_DDRREG GPIOD_PDDR | |||||
#define CORE_PIN53_DDRREG GPIOD_PDDR | |||||
#define CORE_PIN54_DDRREG GPIOD_PDDR | |||||
#define CORE_PIN55_DDRREG GPIOD_PDDR | |||||
#define CORE_PIN56_DDRREG GPIOE_PDDR | |||||
#define CORE_PIN57_DDRREG GPIOE_PDDR | |||||
#define CORE_PIN58_DDRREG GPIOE_PDDR | |||||
#define CORE_PIN59_DDRREG GPIOE_PDDR | |||||
#define CORE_PIN60_DDRREG GPIOE_PDDR | |||||
#define CORE_PIN61_DDRREG GPIOE_PDDR | |||||
#define CORE_PIN62_DDRREG GPIOE_PDDR | |||||
#define CORE_PIN63_DDRREG GPIOE_PDDR | |||||
#define CORE_PIN0_PINREG GPIOB_PDIR | #define CORE_PIN0_PINREG GPIOB_PDIR | ||||
#define CORE_PIN1_PINREG GPIOB_PDIR | #define CORE_PIN1_PINREG GPIOB_PDIR | ||||
#define CORE_PIN37_PINREG GPIOC_PDIR | #define CORE_PIN37_PINREG GPIOC_PDIR | ||||
#define CORE_PIN38_PINREG GPIOC_PDIR | #define CORE_PIN38_PINREG GPIOC_PDIR | ||||
#define CORE_PIN39_PINREG GPIOA_PDIR | #define CORE_PIN39_PINREG GPIOA_PDIR | ||||
#define CORE_PIN40_PINREG GPIOA_PDIR | |||||
#define CORE_PIN41_PINREG GPIOA_PDIR | |||||
#define CORE_PIN42_PINREG GPIOA_PDIR | |||||
#define CORE_PIN43_PINREG GPIOB_PDIR | |||||
#define CORE_PIN44_PINREG GPIOB_PDIR | |||||
#define CORE_PIN45_PINREG GPIOB_PDIR | |||||
#define CORE_PIN46_PINREG GPIOB_PDIR | |||||
#define CORE_PIN47_PINREG GPIOD_PDIR | |||||
#define CORE_PIN48_PINREG GPIOD_PDIR | |||||
#define CORE_PIN49_PINREG GPIOB_PDIR | |||||
#define CORE_PIN50_PINREG GPIOB_PDIR | |||||
#define CORE_PIN51_PINREG GPIOD_PDIR | |||||
#define CORE_PIN52_PINREG GPIOD_PDIR | |||||
#define CORE_PIN53_PINREG GPIOD_PDIR | |||||
#define CORE_PIN54_PINREG GPIOD_PDIR | |||||
#define CORE_PIN55_PINREG GPIOD_PDIR | |||||
#define CORE_PIN56_PINREG GPIOE_PDIR | |||||
#define CORE_PIN57_PINREG GPIOE_PDIR | |||||
#define CORE_PIN58_PINREG GPIOE_PDIR | |||||
#define CORE_PIN59_PINREG GPIOE_PDIR | |||||
#define CORE_PIN60_PINREG GPIOE_PDIR | |||||
#define CORE_PIN61_PINREG GPIOE_PDIR | |||||
#define CORE_PIN62_PINREG GPIOE_PDIR | |||||
#define CORE_PIN63_PINREG GPIOE_PDIR | |||||
#define CORE_PIN0_CONFIG PORTB_PCR16 | #define CORE_PIN0_CONFIG PORTB_PCR16 | ||||
#define CORE_PIN1_CONFIG PORTB_PCR17 | #define CORE_PIN1_CONFIG PORTB_PCR17 | ||||
#define CORE_PIN37_CONFIG PORTC_PCR10 | #define CORE_PIN37_CONFIG PORTC_PCR10 | ||||
#define CORE_PIN38_CONFIG PORTC_PCR11 | #define CORE_PIN38_CONFIG PORTC_PCR11 | ||||
#define CORE_PIN39_CONFIG PORTA_PCR17 | #define CORE_PIN39_CONFIG PORTA_PCR17 | ||||
#define CORE_PIN40_CONFIG PORTA_PCR28 | |||||
#define CORE_PIN41_CONFIG PORTA_PCR29 | |||||
#define CORE_PIN42_CONFIG PORTA_PCR26 | |||||
#define CORE_PIN43_CONFIG PORTB_PCR20 | |||||
#define CORE_PIN44_CONFIG PORTB_PCR22 | |||||
#define CORE_PIN45_CONFIG PORTB_PCR23 | |||||
#define CORE_PIN46_CONFIG PORTB_PCR21 | |||||
#define CORE_PIN47_CONFIG PORTD_PCR8 | |||||
#define CORE_PIN48_CONFIG PORTD_PCR9 | |||||
#define CORE_PIN49_CONFIG PORTB_PCR4 | |||||
#define CORE_PIN50_CONFIG PORTB_PCR5 | |||||
#define CORE_PIN51_CONFIG PORTD_PCR14 | |||||
#define CORE_PIN52_CONFIG PORTD_PCR13 | |||||
#define CORE_PIN53_CONFIG PORTD_PCR12 | |||||
#define CORE_PIN54_CONFIG PORTD_PCR15 | |||||
#define CORE_PIN55_CONFIG PORTD_PCR11 | |||||
#define CORE_PIN56_CONFIG PORTE_PCR10 | |||||
#define CORE_PIN57_CONFIG PORTE_PCR11 | |||||
#define CORE_PIN58_CONFIG PORTE_PCR0 | |||||
#define CORE_PIN59_CONFIG PORTE_PCR1 | |||||
#define CORE_PIN60_CONFIG PORTE_PCR2 | |||||
#define CORE_PIN61_CONFIG PORTE_PCR3 | |||||
#define CORE_PIN62_CONFIG PORTE_PCR4 | |||||
#define CORE_PIN63_CONFIG PORTE_PCR5 | |||||
#define CORE_ADC0_PIN 14 | #define CORE_ADC0_PIN 14 | ||||
#define CORE_ADC1_PIN 15 | #define CORE_ADC1_PIN 15 | ||||
#define CORE_ADC7_PIN 21 | #define CORE_ADC7_PIN 21 | ||||
#define CORE_ADC8_PIN 22 | #define CORE_ADC8_PIN 22 | ||||
#define CORE_ADC9_PIN 23 | #define CORE_ADC9_PIN 23 | ||||
#define CORE_ADC10_PIN 40 | |||||
#define CORE_ADC11_PIN 41 | |||||
#define CORE_ADC10_PIN 64 | |||||
#define CORE_ADC11_PIN 65 | |||||
#define CORE_ADC12_PIN 31 | #define CORE_ADC12_PIN 31 | ||||
#define CORE_ADC13_PIN 32 | #define CORE_ADC13_PIN 32 | ||||
#define CORE_ADC14_PIN 33 | #define CORE_ADC14_PIN 33 | ||||
#define CORE_ADC18_PIN 37 | #define CORE_ADC18_PIN 37 | ||||
#define CORE_ADC19_PIN 38 | #define CORE_ADC19_PIN 38 | ||||
#define CORE_ADC20_PIN 39 | #define CORE_ADC20_PIN 39 | ||||
#define CORE_ADC21_PIN 66 | |||||
#define CORE_ADC22_PIN 67 | |||||
#define CORE_ADC23_PIN 49 | |||||
#define CORE_ADC24_PIN 50 | |||||
#define CORE_ADC25_PIN 68 | |||||
#define CORE_ADC26_PIN 69 | |||||
#define CORE_RXD0_PIN 0 | #define CORE_RXD0_PIN 0 | ||||
#define CORE_TXD0_PIN 1 | #define CORE_TXD0_PIN 1 | ||||
#define CORE_INT37_PIN 37 | #define CORE_INT37_PIN 37 | ||||
#define CORE_INT38_PIN 38 | #define CORE_INT38_PIN 38 | ||||
#define CORE_INT39_PIN 39 | #define CORE_INT39_PIN 39 | ||||
#define CORE_INT40_PIN 40 | |||||
#define CORE_INT41_PIN 41 | |||||
#define CORE_INT42_PIN 42 | |||||
#define CORE_INT43_PIN 43 | |||||
#define CORE_INT44_PIN 44 | |||||
#define CORE_INT45_PIN 45 | |||||
#define CORE_INT46_PIN 46 | |||||
#define CORE_INT47_PIN 47 | |||||
#define CORE_INT48_PIN 48 | |||||
#define CORE_INT49_PIN 49 | |||||
#define CORE_INT50_PIN 50 | |||||
#define CORE_INT51_PIN 51 | |||||
#define CORE_INT52_PIN 52 | |||||
#define CORE_INT53_PIN 53 | |||||
#define CORE_INT54_PIN 54 | |||||
#define CORE_INT55_PIN 55 | |||||
#define CORE_INT56_PIN 56 | |||||
#define CORE_INT57_PIN 57 | |||||
#define CORE_INT58_PIN 58 | |||||
#define CORE_INT59_PIN 59 | |||||
#define CORE_INT60_PIN 60 | |||||
#define CORE_INT61_PIN 61 | |||||
#define CORE_INT62_PIN 62 | |||||
#define CORE_INT63_PIN 63 | |||||
#define CORE_INT_EVERY_PIN 1 | #define CORE_INT_EVERY_PIN 1 | ||||
#endif | #endif | ||||
#if defined(__MK20DX128__) | |||||
#define CORE_FTM0_CH0_PIN 22 | |||||
#define CORE_FTM0_CH1_PIN 23 | |||||
#define CORE_FTM0_CH2_PIN 9 | |||||
#define CORE_FTM0_CH3_PIN 10 | |||||
#define CORE_FTM0_CH4_PIN 6 | |||||
#define CORE_FTM0_CH5_PIN 20 | |||||
#define CORE_FTM0_CH6_PIN 21 | |||||
#define CORE_FTM0_CH7_PIN 5 | |||||
#define CORE_FTM1_CH0_PIN 3 | |||||
#define CORE_FTM1_CH1_PIN 4 | |||||
#elif defined(__MK20DX256__) | |||||
#define CORE_FTM0_CH0_PIN 22 | |||||
#define CORE_FTM0_CH1_PIN 23 | |||||
#define CORE_FTM0_CH2_PIN 9 | |||||
#define CORE_FTM0_CH3_PIN 10 | |||||
#define CORE_FTM0_CH4_PIN 6 | |||||
#define CORE_FTM0_CH5_PIN 20 | |||||
#define CORE_FTM0_CH6_PIN 21 | |||||
#define CORE_FTM0_CH7_PIN 5 | |||||
#define CORE_FTM1_CH0_PIN 3 | |||||
#define CORE_FTM1_CH1_PIN 4 | |||||
#define CORE_FTM2_CH0_PIN 32 | |||||
#define CORE_FTM2_CH1_PIN 25 | |||||
#elif defined(__MKL26Z64__) | |||||
#define CORE_TPM0_CH0_PIN 22 | |||||
#define CORE_TPM0_CH1_PIN 23 | |||||
#define CORE_TPM0_CH2_PIN 9 | |||||
#define CORE_TPM0_CH3_PIN 10 | |||||
#define CORE_TPM0_CH4_PIN 6 | |||||
#define CORE_TPM0_CH5_PIN 20 | |||||
#define CORE_TPM1_CH0_PIN 16 | |||||
#define CORE_TPM1_CH1_PIN 17 | |||||
#define CORE_TPM2_CH0_PIN 3 | |||||
#define CORE_TPM2_CH1_PIN 4 | |||||
#elif defined(__MK64FX512__) | |||||
#define CORE_FTM0_CH0_PIN 22 | |||||
#define CORE_FTM0_CH1_PIN 23 | |||||
#define CORE_FTM0_CH2_PIN 9 | |||||
#define CORE_FTM0_CH3_PIN 10 | |||||
#define CORE_FTM0_CH4_PIN 6 | |||||
#define CORE_FTM0_CH5_PIN 20 | |||||
#define CORE_FTM0_CH6_PIN 21 | |||||
#define CORE_FTM0_CH7_PIN 5 | |||||
#define CORE_FTM1_CH0_PIN 3 | |||||
#define CORE_FTM1_CH1_PIN 4 | |||||
#define CORE_FTM2_CH0_PIN 29 | |||||
#define CORE_FTM2_CH1_PIN 30 | |||||
#define CORE_FTM3_CH0_PIN 2 | |||||
#define CORE_FTM3_CH1_PIN 14 | |||||
#define CORE_FTM3_CH2_PIN 7 | |||||
#define CORE_FTM3_CH3_PIN 8 | |||||
#define CORE_FTM3_CH4_PIN 35 | |||||
#define CORE_FTM3_CH5_PIN 36 | |||||
#define CORE_FTM3_CH6_PIN 37 | |||||
#define CORE_FTM3_CH7_PIN 38 | |||||
#elif defined(__MK66FX1M0__) | |||||
#define CORE_FTM0_CH0_PIN 22 | |||||
#define CORE_FTM0_CH1_PIN 23 | |||||
#define CORE_FTM0_CH2_PIN 9 | |||||
#define CORE_FTM0_CH3_PIN 10 | |||||
#define CORE_FTM0_CH4_PIN 6 | |||||
#define CORE_FTM0_CH5_PIN 20 | |||||
#define CORE_FTM0_CH6_PIN 21 | |||||
#define CORE_FTM0_CH7_PIN 5 | |||||
#define CORE_FTM1_CH0_PIN 3 | |||||
#define CORE_FTM1_CH1_PIN 4 | |||||
#define CORE_FTM2_CH0_PIN 29 | |||||
#define CORE_FTM2_CH1_PIN 30 | |||||
#define CORE_FTM3_CH0_PIN 2 | |||||
#define CORE_FTM3_CH1_PIN 14 | |||||
#define CORE_FTM3_CH2_PIN 7 | |||||
#define CORE_FTM3_CH3_PIN 8 | |||||
#define CORE_FTM3_CH4_PIN 35 | |||||
#define CORE_FTM3_CH5_PIN 36 | |||||
#define CORE_FTM3_CH6_PIN 37 | |||||
#define CORE_FTM3_CH7_PIN 38 | |||||
#define CORE_TPM1_CH0_PIN 16 | |||||
#define CORE_TPM1_CH1_PIN 17 | |||||
#endif | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
CORE_PIN38_PORTSET = CORE_PIN38_BITMASK; | CORE_PIN38_PORTSET = CORE_PIN38_BITMASK; | ||||
} else if (pin == 39) { | } else if (pin == 39) { | ||||
CORE_PIN39_PORTSET = CORE_PIN39_BITMASK; | CORE_PIN39_PORTSET = CORE_PIN39_BITMASK; | ||||
} else if (pin == 40) { | |||||
CORE_PIN40_PORTSET = CORE_PIN40_BITMASK; | |||||
} else if (pin == 41) { | |||||
CORE_PIN41_PORTSET = CORE_PIN41_BITMASK; | |||||
} else if (pin == 42) { | |||||
CORE_PIN42_PORTSET = CORE_PIN42_BITMASK; | |||||
} else if (pin == 43) { | |||||
CORE_PIN43_PORTSET = CORE_PIN43_BITMASK; | |||||
} else if (pin == 44) { | |||||
CORE_PIN44_PORTSET = CORE_PIN44_BITMASK; | |||||
} else if (pin == 45) { | |||||
CORE_PIN45_PORTSET = CORE_PIN45_BITMASK; | |||||
} else if (pin == 46) { | |||||
CORE_PIN46_PORTSET = CORE_PIN46_BITMASK; | |||||
} else if (pin == 47) { | |||||
CORE_PIN47_PORTSET = CORE_PIN47_BITMASK; | |||||
} else if (pin == 48) { | |||||
CORE_PIN48_PORTSET = CORE_PIN48_BITMASK; | |||||
} else if (pin == 49) { | |||||
CORE_PIN49_PORTSET = CORE_PIN49_BITMASK; | |||||
} else if (pin == 50) { | |||||
CORE_PIN50_PORTSET = CORE_PIN50_BITMASK; | |||||
} else if (pin == 51) { | |||||
CORE_PIN51_PORTSET = CORE_PIN51_BITMASK; | |||||
} else if (pin == 52) { | |||||
CORE_PIN52_PORTSET = CORE_PIN52_BITMASK; | |||||
} else if (pin == 53) { | |||||
CORE_PIN53_PORTSET = CORE_PIN53_BITMASK; | |||||
} else if (pin == 54) { | |||||
CORE_PIN54_PORTSET = CORE_PIN54_BITMASK; | |||||
} else if (pin == 55) { | |||||
CORE_PIN55_PORTSET = CORE_PIN55_BITMASK; | |||||
} else if (pin == 56) { | |||||
CORE_PIN56_PORTSET = CORE_PIN56_BITMASK; | |||||
} else if (pin == 57) { | |||||
CORE_PIN57_PORTSET = CORE_PIN57_BITMASK; | |||||
} else if (pin == 58) { | |||||
CORE_PIN58_PORTSET = CORE_PIN58_BITMASK; | |||||
} else if (pin == 59) { | |||||
CORE_PIN59_PORTSET = CORE_PIN59_BITMASK; | |||||
} else if (pin == 60) { | |||||
CORE_PIN60_PORTSET = CORE_PIN60_BITMASK; | |||||
} else if (pin == 61) { | |||||
CORE_PIN61_PORTSET = CORE_PIN61_BITMASK; | |||||
} else if (pin == 62) { | |||||
CORE_PIN62_PORTSET = CORE_PIN62_BITMASK; | |||||
} else if (pin == 63) { | |||||
CORE_PIN63_PORTSET = CORE_PIN63_BITMASK; | |||||
} | } | ||||
#endif | #endif | ||||
} else { | } else { | ||||
CORE_PIN38_PORTCLEAR = CORE_PIN38_BITMASK; | CORE_PIN38_PORTCLEAR = CORE_PIN38_BITMASK; | ||||
} else if (pin == 39) { | } else if (pin == 39) { | ||||
CORE_PIN39_PORTCLEAR = CORE_PIN39_BITMASK; | CORE_PIN39_PORTCLEAR = CORE_PIN39_BITMASK; | ||||
} else if (pin == 40) { | |||||
CORE_PIN40_PORTCLEAR = CORE_PIN40_BITMASK; | |||||
} else if (pin == 41) { | |||||
CORE_PIN41_PORTCLEAR = CORE_PIN41_BITMASK; | |||||
} else if (pin == 42) { | |||||
CORE_PIN42_PORTCLEAR = CORE_PIN42_BITMASK; | |||||
} else if (pin == 43) { | |||||
CORE_PIN43_PORTCLEAR = CORE_PIN43_BITMASK; | |||||
} else if (pin == 44) { | |||||
CORE_PIN44_PORTCLEAR = CORE_PIN44_BITMASK; | |||||
} else if (pin == 45) { | |||||
CORE_PIN45_PORTCLEAR = CORE_PIN45_BITMASK; | |||||
} else if (pin == 46) { | |||||
CORE_PIN46_PORTCLEAR = CORE_PIN46_BITMASK; | |||||
} else if (pin == 47) { | |||||
CORE_PIN47_PORTCLEAR = CORE_PIN47_BITMASK; | |||||
} else if (pin == 48) { | |||||
CORE_PIN48_PORTCLEAR = CORE_PIN48_BITMASK; | |||||
} else if (pin == 49) { | |||||
CORE_PIN49_PORTCLEAR = CORE_PIN49_BITMASK; | |||||
} else if (pin == 50) { | |||||
CORE_PIN50_PORTCLEAR = CORE_PIN50_BITMASK; | |||||
} else if (pin == 51) { | |||||
CORE_PIN51_PORTCLEAR = CORE_PIN51_BITMASK; | |||||
} else if (pin == 52) { | |||||
CORE_PIN52_PORTCLEAR = CORE_PIN52_BITMASK; | |||||
} else if (pin == 53) { | |||||
CORE_PIN53_PORTCLEAR = CORE_PIN53_BITMASK; | |||||
} else if (pin == 54) { | |||||
CORE_PIN54_PORTCLEAR = CORE_PIN54_BITMASK; | |||||
} else if (pin == 55) { | |||||
CORE_PIN55_PORTCLEAR = CORE_PIN55_BITMASK; | |||||
} else if (pin == 56) { | |||||
CORE_PIN56_PORTCLEAR = CORE_PIN56_BITMASK; | |||||
} else if (pin == 57) { | |||||
CORE_PIN57_PORTCLEAR = CORE_PIN57_BITMASK; | |||||
} else if (pin == 58) { | |||||
CORE_PIN58_PORTCLEAR = CORE_PIN58_BITMASK; | |||||
} else if (pin == 59) { | |||||
CORE_PIN59_PORTCLEAR = CORE_PIN59_BITMASK; | |||||
} else if (pin == 60) { | |||||
CORE_PIN60_PORTCLEAR = CORE_PIN60_BITMASK; | |||||
} else if (pin == 61) { | |||||
CORE_PIN61_PORTCLEAR = CORE_PIN61_BITMASK; | |||||
} else if (pin == 62) { | |||||
CORE_PIN62_PORTCLEAR = CORE_PIN62_BITMASK; | |||||
} else if (pin == 63) { | |||||
CORE_PIN63_PORTCLEAR = CORE_PIN63_BITMASK; | |||||
} | } | ||||
#endif | #endif | ||||
} | } | ||||
return (CORE_PIN38_PINREG & CORE_PIN38_BITMASK) ? 1 : 0; | return (CORE_PIN38_PINREG & CORE_PIN38_BITMASK) ? 1 : 0; | ||||
} else if (pin == 39) { | } else if (pin == 39) { | ||||
return (CORE_PIN39_PINREG & CORE_PIN39_BITMASK) ? 1 : 0; | return (CORE_PIN39_PINREG & CORE_PIN39_BITMASK) ? 1 : 0; | ||||
} else if (pin == 40) { | |||||
return (CORE_PIN40_PINREG & CORE_PIN40_BITMASK) ? 1 : 0; | |||||
} else if (pin == 41) { | |||||
return (CORE_PIN41_PINREG & CORE_PIN41_BITMASK) ? 1 : 0; | |||||
} else if (pin == 42) { | |||||
return (CORE_PIN42_PINREG & CORE_PIN42_BITMASK) ? 1 : 0; | |||||
} else if (pin == 43) { | |||||
return (CORE_PIN43_PINREG & CORE_PIN43_BITMASK) ? 1 : 0; | |||||
} else if (pin == 44) { | |||||
return (CORE_PIN44_PINREG & CORE_PIN44_BITMASK) ? 1 : 0; | |||||
} else if (pin == 45) { | |||||
return (CORE_PIN45_PINREG & CORE_PIN45_BITMASK) ? 1 : 0; | |||||
} else if (pin == 46) { | |||||
return (CORE_PIN46_PINREG & CORE_PIN46_BITMASK) ? 1 : 0; | |||||
} else if (pin == 47) { | |||||
return (CORE_PIN47_PINREG & CORE_PIN47_BITMASK) ? 1 : 0; | |||||
} else if (pin == 48) { | |||||
return (CORE_PIN48_PINREG & CORE_PIN48_BITMASK) ? 1 : 0; | |||||
} else if (pin == 49) { | |||||
return (CORE_PIN49_PINREG & CORE_PIN49_BITMASK) ? 1 : 0; | |||||
} else if (pin == 50) { | |||||
return (CORE_PIN50_PINREG & CORE_PIN50_BITMASK) ? 1 : 0; | |||||
} else if (pin == 51) { | |||||
return (CORE_PIN51_PINREG & CORE_PIN51_BITMASK) ? 1 : 0; | |||||
} else if (pin == 52) { | |||||
return (CORE_PIN52_PINREG & CORE_PIN52_BITMASK) ? 1 : 0; | |||||
} else if (pin == 53) { | |||||
return (CORE_PIN53_PINREG & CORE_PIN53_BITMASK) ? 1 : 0; | |||||
} else if (pin == 54) { | |||||
return (CORE_PIN54_PINREG & CORE_PIN54_BITMASK) ? 1 : 0; | |||||
} else if (pin == 55) { | |||||
return (CORE_PIN55_PINREG & CORE_PIN55_BITMASK) ? 1 : 0; | |||||
} else if (pin == 56) { | |||||
return (CORE_PIN56_PINREG & CORE_PIN56_BITMASK) ? 1 : 0; | |||||
} else if (pin == 57) { | |||||
return (CORE_PIN57_PINREG & CORE_PIN57_BITMASK) ? 1 : 0; | |||||
} else if (pin == 58) { | |||||
return (CORE_PIN58_PINREG & CORE_PIN58_BITMASK) ? 1 : 0; | |||||
} else if (pin == 59) { | |||||
return (CORE_PIN59_PINREG & CORE_PIN59_BITMASK) ? 1 : 0; | |||||
} else if (pin == 60) { | |||||
return (CORE_PIN60_PINREG & CORE_PIN60_BITMASK) ? 1 : 0; | |||||
} else if (pin == 61) { | |||||
return (CORE_PIN61_PINREG & CORE_PIN61_BITMASK) ? 1 : 0; | |||||
} else if (pin == 62) { | |||||
return (CORE_PIN62_PINREG & CORE_PIN62_BITMASK) ? 1 : 0; | |||||
} else if (pin == 63) { | |||||
return (CORE_PIN63_PINREG & CORE_PIN63_BITMASK) ? 1 : 0; | |||||
} | } | ||||
#endif | #endif | ||||
else { | else { | ||||
void pinMode(uint8_t pin, uint8_t mode); | void pinMode(uint8_t pin, uint8_t mode); | ||||
void init_pins(void); | void init_pins(void); | ||||
void analogWrite(uint8_t pin, int val); | void analogWrite(uint8_t pin, int val); | ||||
void analogWriteRes(uint32_t bits); | |||||
static inline void analogWriteResolution(uint32_t bits) { analogWriteRes(bits); } | |||||
uint32_t analogWriteRes(uint32_t bits); | |||||
static inline uint32_t analogWriteResolution(uint32_t bits) { return analogWriteRes(bits); } | |||||
void analogWriteFrequency(uint8_t pin, float frequency); | void analogWriteFrequency(uint8_t pin, float frequency); | ||||
void analogWriteDAC0(int val); | void analogWriteDAC0(int val); | ||||
void analogWriteDAC1(int val); | void analogWriteDAC1(int val); | ||||
static inline uint32_t millis(void) __attribute__((always_inline, unused)); | static inline uint32_t millis(void) __attribute__((always_inline, unused)); | ||||
static inline uint32_t millis(void) | static inline uint32_t millis(void) | ||||
{ | { | ||||
return systick_millis_count; // single aligned 32 bit is atomic; | |||||
// Reading a volatile variable to another volatile | |||||
// seems redundant, but isn't for some cases. | |||||
// Eventually this should probably be replaced by a | |||||
// proper memory barrier or other technique. Please | |||||
// do not remove this "redundant" code without | |||||
// carefully verifying the case mentioned here: | |||||
// | |||||
// https://forum.pjrc.com/threads/17469-millis%28%29-on-teensy-3?p=104924&viewfull=1#post104924 | |||||
// | |||||
volatile uint32_t ret = systick_millis_count; // single aligned 32 bit is atomic | |||||
return ret; | |||||
} | } | ||||
uint32_t micros(void); | uint32_t micros(void); | ||||
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 == 192000000 | |||||
#if F_CPU == 256000000 | |||||
uint32_t n = usec * 85; | |||||
#elif F_CPU == 240000000 | |||||
uint32_t n = usec * 80; | |||||
#elif F_CPU == 216000000 | |||||
uint32_t n = usec * 72; | |||||
#elif F_CPU == 192000000 | |||||
uint32_t n = usec * 64; | uint32_t n = usec * 64; | ||||
#elif F_CPU == 180000000 | #elif F_CPU == 180000000 | ||||
uint32_t n = usec * 60; | uint32_t n = usec * 60; | ||||
#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 | |||||
); | ); | ||||
} | } | ||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* 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" | ||||
#if F_CPU > 120000000 && defined(__MK66FX1M0__) | |||||
#include "core_pins.h" // delayMicroseconds() | |||||
#endif | |||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) | #if defined(__MK20DX128__) || defined(__MK20DX256__) | ||||
#define EEPROM_MAX 2048 | #define EEPROM_MAX 2048 | ||||
#define EEPARTITION 0x03 // all 32K dataflash for EEPROM, none for Data | #define EEPARTITION 0x03 // all 32K dataflash for EEPROM, none for Data | ||||
#define EEESPLIT 0x30 // must be 0x30 on these chips | |||||
#elif defined(__MK64FX512__) | #elif defined(__MK64FX512__) | ||||
#define EEPROM_MAX 4096 | #define EEPROM_MAX 4096 | ||||
#define EEPARTITION 0x04 // 64K dataflash for EEPROM, 64K for Data | |||||
#define EEPARTITION 0x05 // all 128K dataflash for EEPROM | |||||
#define EEESPLIT 0x10 // best endurance: 0x00 = first 12%, 0x10 = first 25%, 0x30 = all equal | |||||
#elif defined(__MK66FX1M0__) | #elif defined(__MK66FX1M0__) | ||||
#define EEPROM_MAX 4096 | #define EEPROM_MAX 4096 | ||||
#define EEPARTITION 0x05 // 128K dataflash for EEPROM, 128K for Data | #define EEPARTITION 0x05 // 128K dataflash for EEPROM, 128K for Data | ||||
#define EEESPLIT 0x10 // best endurance: 0x00 = first 12%, 0x10 = first 25%, 0x30 = all equal | |||||
#elif defined(__MKL26Z64__) | #elif defined(__MKL26Z64__) | ||||
#define EEPROM_MAX 255 | #define EEPROM_MAX 255 | ||||
#endif | #endif | ||||
#if E2END < 32 | #if E2END < 32 | ||||
#define EEPROM_SIZE 32 | #define EEPROM_SIZE 32 | ||||
#define EEESIZE 0x39 | |||||
#define EEESIZE 0x09 | |||||
#elif E2END < 64 | #elif E2END < 64 | ||||
#define EEPROM_SIZE 64 | #define EEPROM_SIZE 64 | ||||
#define EEESIZE 0x38 | |||||
#define EEESIZE 0x08 | |||||
#elif E2END < 128 | #elif E2END < 128 | ||||
#define EEPROM_SIZE 128 | #define EEPROM_SIZE 128 | ||||
#define EEESIZE 0x37 | |||||
#define EEESIZE 0x07 | |||||
#elif E2END < 256 | #elif E2END < 256 | ||||
#define EEPROM_SIZE 256 | #define EEPROM_SIZE 256 | ||||
#define EEESIZE 0x36 | |||||
#define EEESIZE 0x06 | |||||
#elif E2END < 512 | #elif E2END < 512 | ||||
#define EEPROM_SIZE 512 | #define EEPROM_SIZE 512 | ||||
#define EEESIZE 0x35 | |||||
#define EEESIZE 0x05 | |||||
#elif E2END < 1024 | #elif E2END < 1024 | ||||
#define EEPROM_SIZE 1024 | #define EEPROM_SIZE 1024 | ||||
#define EEESIZE 0x34 | |||||
#define EEESIZE 0x04 | |||||
#elif E2END < 2048 | #elif E2END < 2048 | ||||
#define EEPROM_SIZE 2048 | #define EEPROM_SIZE 2048 | ||||
#define EEESIZE 0x33 | |||||
#define EEESIZE 0x03 | |||||
#elif E2END < 4096 | #elif E2END < 4096 | ||||
#define EEPROM_SIZE 4096 | #define EEPROM_SIZE 4096 | ||||
#define EEESIZE 0x32 | |||||
#define EEESIZE 0x02 | |||||
#endif | #endif | ||||
// Writing unaligned 16 or 32 bit data is handled automatically when | // Writing unaligned 16 or 32 bit data is handled automatically when | ||||
uint8_t status; | uint8_t status; | ||||
if (FTFL_FCNFG & FTFL_FCNFG_RAMRDY) { | if (FTFL_FCNFG & FTFL_FCNFG_RAMRDY) { | ||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
// FlexRAM is configured as traditional RAM | // FlexRAM is configured as traditional RAM | ||||
// We need to reconfigure for EEPROM usage | // We need to reconfigure for EEPROM usage | ||||
kinetis_hsrun_disable(); | |||||
FTFL_FCCOB0 = 0x80; // PGMPART = Program Partition Command | FTFL_FCCOB0 = 0x80; // PGMPART = Program Partition Command | ||||
FTFL_FCCOB4 = EEESIZE; // EEPROM Size | |||||
FTFL_FCCOB3 = 0; | |||||
FTFL_FCCOB4 = EEESPLIT | EEESIZE; | |||||
FTFL_FCCOB5 = EEPARTITION; | FTFL_FCCOB5 = EEPARTITION; | ||||
__disable_irq(); | __disable_irq(); | ||||
// do_flash_cmd() must execute from RAM. Luckily the C syntax is simple... | // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple... | ||||
(*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&FTFL_FSTAT); | (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&FTFL_FSTAT); | ||||
__enable_irq(); | __enable_irq(); | ||||
kinetis_hsrun_enable(); | |||||
status = FTFL_FSTAT; | status = FTFL_FSTAT; | ||||
if (status & 0x70) { | if (status & 0x70) { | ||||
FTFL_FSTAT = (status & 0x70); | FTFL_FSTAT = (status & 0x70); | ||||
} | } | ||||
// wait for eeprom to become ready (is this really necessary?) | // wait for eeprom to become ready (is this really necessary?) | ||||
while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) { | while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) { | ||||
if (++count > 20000) break; | |||||
if (++count > 200000) break; | |||||
} | } | ||||
} | } | ||||
#define FlexRAM ((uint8_t *)0x14000000) | |||||
#define FlexRAM ((volatile uint8_t *)0x14000000) | |||||
uint8_t eeprom_read_byte(const uint8_t *addr) | uint8_t eeprom_read_byte(const uint8_t *addr) | ||||
{ | { | ||||
if (offset >= EEPROM_SIZE) return; | if (offset >= EEPROM_SIZE) return; | ||||
if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); | if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); | ||||
if (FlexRAM[offset] != value) { | if (FlexRAM[offset] != value) { | ||||
kinetis_hsrun_disable(); | |||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
FlexRAM[offset] = value; | FlexRAM[offset] = value; | ||||
flexram_wait(); | flexram_wait(); | ||||
kinetis_hsrun_enable(); | |||||
} | } | ||||
} | } | ||||
if ((offset & 1) == 0) { | if ((offset & 1) == 0) { | ||||
#endif | #endif | ||||
if (*(uint16_t *)(&FlexRAM[offset]) != value) { | if (*(uint16_t *)(&FlexRAM[offset]) != value) { | ||||
kinetis_hsrun_disable(); | |||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
*(uint16_t *)(&FlexRAM[offset]) = value; | *(uint16_t *)(&FlexRAM[offset]) = value; | ||||
flexram_wait(); | flexram_wait(); | ||||
kinetis_hsrun_enable(); | |||||
} | } | ||||
#ifdef HANDLE_UNALIGNED_WRITES | #ifdef HANDLE_UNALIGNED_WRITES | ||||
} else { | } else { | ||||
if (FlexRAM[offset] != value) { | if (FlexRAM[offset] != value) { | ||||
kinetis_hsrun_disable(); | |||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
FlexRAM[offset] = value; | FlexRAM[offset] = value; | ||||
flexram_wait(); | flexram_wait(); | ||||
kinetis_hsrun_enable(); | |||||
} | } | ||||
if (FlexRAM[offset + 1] != (value >> 8)) { | if (FlexRAM[offset + 1] != (value >> 8)) { | ||||
kinetis_hsrun_disable(); | |||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
FlexRAM[offset + 1] = value >> 8; | FlexRAM[offset + 1] = value >> 8; | ||||
flexram_wait(); | flexram_wait(); | ||||
kinetis_hsrun_enable(); | |||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
case 0: | case 0: | ||||
#endif | #endif | ||||
if (*(uint32_t *)(&FlexRAM[offset]) != value) { | if (*(uint32_t *)(&FlexRAM[offset]) != value) { | ||||
kinetis_hsrun_disable(); | |||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
*(uint32_t *)(&FlexRAM[offset]) = value; | *(uint32_t *)(&FlexRAM[offset]) = value; | ||||
flexram_wait(); | flexram_wait(); | ||||
kinetis_hsrun_enable(); | |||||
} | } | ||||
return; | return; | ||||
#ifdef HANDLE_UNALIGNED_WRITES | #ifdef HANDLE_UNALIGNED_WRITES | ||||
case 2: | case 2: | ||||
if (*(uint16_t *)(&FlexRAM[offset]) != value) { | if (*(uint16_t *)(&FlexRAM[offset]) != value) { | ||||
kinetis_hsrun_disable(); | |||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
*(uint16_t *)(&FlexRAM[offset]) = value; | *(uint16_t *)(&FlexRAM[offset]) = value; | ||||
flexram_wait(); | flexram_wait(); | ||||
kinetis_hsrun_enable(); | |||||
} | } | ||||
if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) { | if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) { | ||||
kinetis_hsrun_disable(); | |||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
*(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16; | *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16; | ||||
flexram_wait(); | flexram_wait(); | ||||
kinetis_hsrun_enable(); | |||||
} | } | ||||
return; | return; | ||||
default: | default: | ||||
if (FlexRAM[offset] != value) { | if (FlexRAM[offset] != value) { | ||||
kinetis_hsrun_disable(); | |||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
FlexRAM[offset] = value; | FlexRAM[offset] = value; | ||||
flexram_wait(); | flexram_wait(); | ||||
kinetis_hsrun_enable(); | |||||
} | } | ||||
if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) { | if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) { | ||||
kinetis_hsrun_disable(); | |||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
*(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8; | *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8; | ||||
flexram_wait(); | flexram_wait(); | ||||
kinetis_hsrun_enable(); | |||||
} | } | ||||
if (FlexRAM[offset + 3] != (value >> 24)) { | if (FlexRAM[offset + 3] != (value >> 24)) { | ||||
kinetis_hsrun_disable(); | |||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
FlexRAM[offset + 3] = value >> 24; | FlexRAM[offset + 3] = value >> 24; | ||||
flexram_wait(); | flexram_wait(); | ||||
kinetis_hsrun_enable(); | |||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
val32 |= (*src++ << 16); | val32 |= (*src++ << 16); | ||||
val32 |= (*src++ << 24); | val32 |= (*src++ << 24); | ||||
if (*(uint32_t *)(&FlexRAM[offset]) != val32) { | if (*(uint32_t *)(&FlexRAM[offset]) != val32) { | ||||
kinetis_hsrun_disable(); | |||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
*(uint32_t *)(&FlexRAM[offset]) = val32; | *(uint32_t *)(&FlexRAM[offset]) = val32; | ||||
flexram_wait(); | flexram_wait(); | ||||
kinetis_hsrun_enable(); | |||||
} | } | ||||
offset += 4; | offset += 4; | ||||
len -= 4; | len -= 4; | ||||
val16 = *src++; | val16 = *src++; | ||||
val16 |= (*src++ << 8); | val16 |= (*src++ << 8); | ||||
if (*(uint16_t *)(&FlexRAM[offset]) != val16) { | if (*(uint16_t *)(&FlexRAM[offset]) != val16) { | ||||
kinetis_hsrun_disable(); | |||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
*(uint16_t *)(&FlexRAM[offset]) = val16; | *(uint16_t *)(&FlexRAM[offset]) = val16; | ||||
flexram_wait(); | flexram_wait(); | ||||
kinetis_hsrun_enable(); | |||||
} | } | ||||
offset += 2; | offset += 2; | ||||
len -= 2; | len -= 2; | ||||
// write 8 bits | // write 8 bits | ||||
uint8_t val8 = *src++; | uint8_t val8 = *src++; | ||||
if (FlexRAM[offset] != val8) { | if (FlexRAM[offset] != val8) { | ||||
kinetis_hsrun_disable(); | |||||
uint8_t stat = FTFL_FSTAT & 0x70; | |||||
if (stat) FTFL_FSTAT = stat; | |||||
FlexRAM[offset] = val8; | FlexRAM[offset] = val8; | ||||
flexram_wait(); | flexram_wait(); | ||||
kinetis_hsrun_enable(); | |||||
} | } | ||||
offset++; | offset++; | ||||
len--; | len--; |
/* Elapsed time types - for easy-to-use measurements of elapsed time | /* Elapsed time types - for easy-to-use measurements of elapsed time | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2011 PJRC.COM, LLC | |||||
* Copyright (c) 2017 PJRC.COM, LLC | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining a copy | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
* of this software and associated documentation files (the "Software"), to deal | * of this software and associated documentation files (the "Software"), to deal |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
#define KEY_MEDIA_PREV_TRACK ( 0xB6 | 0xE400 ) | #define KEY_MEDIA_PREV_TRACK ( 0xB6 | 0xE400 ) | ||||
#define KEY_MEDIA_STOP ( 0xB7 | 0xE400 ) | #define KEY_MEDIA_STOP ( 0xB7 | 0xE400 ) | ||||
#define KEY_MEDIA_EJECT ( 0xB8 | 0xE400 ) | #define KEY_MEDIA_EJECT ( 0xB8 | 0xE400 ) | ||||
#define KEY_MEDIA_RANDOM_PLAY ( 0xB0 | 0xE400 ) | |||||
#define KEY_MEDIA_RANDOM_PLAY ( 0xB9 | 0xE400 ) | |||||
#define KEY_MEDIA_PLAY_PAUSE ( 0xCD | 0xE400 ) | #define KEY_MEDIA_PLAY_PAUSE ( 0xCD | 0xE400 ) | ||||
#define KEY_MEDIA_PLAY_SKIP ( 0xCE | 0xE400 ) | #define KEY_MEDIA_PLAY_SKIP ( 0xCE | 0xE400 ) | ||||
#define KEY_MEDIA_MUTE ( 0xE2 | 0xE400 ) | #define KEY_MEDIA_MUTE ( 0xE2 | 0xE400 ) | ||||
#define KEYPAD_9 ( 97 | 0xF000 ) | #define KEYPAD_9 ( 97 | 0xF000 ) | ||||
#define KEYPAD_0 ( 98 | 0xF000 ) | #define KEYPAD_0 ( 98 | 0xF000 ) | ||||
#define KEYPAD_PERIOD ( 99 | 0xF000 ) | #define KEYPAD_PERIOD ( 99 | 0xF000 ) | ||||
#define KEY_NON_US_BS ( 100 | 0xF000 ) | |||||
#define KEY_MENU ( 101 | 0xF000 ) | #define KEY_MENU ( 101 | 0xF000 ) | ||||
#define KEY_F13 ( 104 | 0xF000 ) | #define KEY_F13 ( 104 | 0xF000 ) | ||||
#define KEY_F14 ( 105 | 0xF000 ) | #define KEY_F14 ( 105 | 0xF000 ) | ||||
#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 & |
#include "WProgram.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 <Arduino.h> | |||||
extern "C" int main(void) | extern "C" int main(void) | ||||
{ | { |
/* ---------------------------------------------------------------------- | /* ---------------------------------------------------------------------- | ||||
* Copyright (C) 2010 ARM Limited. All rights reserved. | |||||
* | |||||
* $Date: 29. November 2010 | |||||
* $Revision: V1.0.3 | |||||
* | |||||
* Project: CMSIS DSP Library | |||||
* Copyright (C) 2010 ARM Limited. All rights reserved. | |||||
* | |||||
* $Date: 29. November 2010 | |||||
* $Revision: V1.0.3 | |||||
* | |||||
* Project: CMSIS DSP Library | |||||
* | * | ||||
* Title: math_helper.c | * Title: math_helper.c | ||||
* | * | ||||
* Description: Definition of all helper functions required. | |||||
* | |||||
* Description: Definition of all helper functions required. | |||||
* | |||||
* Target Processor: Cortex-M4/Cortex-M3 | * Target Processor: Cortex-M4/Cortex-M3 | ||||
* | |||||
* Version 1.0.3 2010/11/29 | |||||
* Re-organized the CMSIS folders and updated documentation. | |||||
* | |||||
* Version 1.0.2 2010/11/11 | |||||
* Documentation updated. | |||||
* | |||||
* Version 1.0.1 2010/10/05 | |||||
* Production release and review comments incorporated. | |||||
* | |||||
* Version 1.0.0 2010/09/20 | |||||
* Production release and review comments incorporated. | |||||
* | |||||
* Version 0.0.7 2010/06/10 | |||||
* Misra-C changes done | |||||
* | |||||
* Version 1.0.3 2010/11/29 | |||||
* Re-organized the CMSIS folders and updated documentation. | |||||
* | |||||
* Version 1.0.2 2010/11/11 | |||||
* Documentation updated. | |||||
* | |||||
* Version 1.0.1 2010/10/05 | |||||
* Production release and review comments incorporated. | |||||
* | |||||
* Version 1.0.0 2010/09/20 | |||||
* Production release and review comments incorporated. | |||||
* | |||||
* Version 0.0.7 2010/06/10 | |||||
* Misra-C changes done | |||||
* -------------------------------------------------------------------- */ | * -------------------------------------------------------------------- */ | ||||
/* ---------------------------------------------------------------------- | /* ---------------------------------------------------------------------- | ||||
* Include standard header files | |||||
* Include standard header files | |||||
* -------------------------------------------------------------------- */ | * -------------------------------------------------------------------- */ | ||||
#include<math.h> | |||||
#include <math.h> | |||||
/* ---------------------------------------------------------------------- | /* ---------------------------------------------------------------------- | ||||
* Include project header files | |||||
* Include project header files | |||||
* -------------------------------------------------------------------- */ | * -------------------------------------------------------------------- */ | ||||
#include "math_helper.h" | #include "math_helper.h" | ||||
float arm_snr_f32(float *pRef, float *pTest, uint32_t buffSize) | float arm_snr_f32(float *pRef, float *pTest, uint32_t buffSize) | ||||
{ | { | ||||
float EnergySignal = 0.0, EnergyError = 0.0; | |||||
uint32_t i; | |||||
float SNR; | |||||
int temp; | |||||
int *test; | |||||
for (i = 0; i < buffSize; i++) | |||||
{ | |||||
/* Checking for a NAN value in pRef array */ | |||||
test = (int *)(&pRef[i]); | |||||
temp = *test; | |||||
if(temp == 0x7FC00000) | |||||
{ | |||||
return(0); | |||||
} | |||||
/* Checking for a NAN value in pTest array */ | |||||
test = (int *)(&pTest[i]); | |||||
temp = *test; | |||||
if(temp == 0x7FC00000) | |||||
{ | |||||
return(0); | |||||
} | |||||
EnergySignal += pRef[i] * pRef[i]; | |||||
EnergyError += (pRef[i] - pTest[i]) * (pRef[i] - pTest[i]); | |||||
} | |||||
float EnergySignal = 0.0; | |||||
float EnergyError = 0.0; | |||||
uint32_t i; | |||||
float SNR; | |||||
int temp; | |||||
int *test; | |||||
for (i = 0; i < buffSize; i++) { | |||||
/* Checking for a NAN value in pRef array */ | |||||
test = (int *)(&pRef[i]); | |||||
temp = *test; | |||||
if (temp == 0x7FC00000) { | |||||
return(0); | |||||
} | |||||
/* Checking for a NAN value in pTest array */ | |||||
test = (int *)(&pTest[i]); | |||||
temp = *test; | |||||
if (temp == 0x7FC00000) { | |||||
return(0); | |||||
} | |||||
EnergySignal += pRef[i] * pRef[i]; | |||||
EnergyError += (pRef[i] - pTest[i]) * (pRef[i] - pTest[i]); | |||||
} | |||||
/* Checking for a NAN value in EnergyError */ | /* Checking for a NAN value in EnergyError */ | ||||
test = (int *)(&EnergyError); | test = (int *)(&EnergyError); | ||||
temp = *test; | |||||
if(temp == 0x7FC00000) | |||||
{ | |||||
return(0); | |||||
} | |||||
SNR = 10 * log10 (EnergySignal / EnergyError); | |||||
temp = *test; | |||||
return (SNR); | |||||
if(temp == 0x7FC00000) { | |||||
return(0); | |||||
} | |||||
SNR = 10 * log10f(EnergySignal / EnergyError); | |||||
return (SNR); | |||||
} | } | ||||
{ | { | ||||
uint32_t i; | uint32_t i; | ||||
for (i = 0; i < numSamples; i++) | |||||
{ | |||||
/* 1048576.0f corresponds to pow(2, 20) */ | |||||
for (i = 0; i < numSamples; i++) { | |||||
/* 1048576.0f corresponds to pow(2, 20) */ | |||||
pOut[i] = (q31_t) (pIn[i] * 1048576.0f); | pOut[i] = (q31_t) (pIn[i] * 1048576.0f); | ||||
pOut[i] += pIn[i] > 0 ? 0.5 : -0.5; | pOut[i] += pIn[i] > 0 ? 0.5 : -0.5; | ||||
if (pIn[i] == (float) 1.0) | |||||
{ | |||||
if (pIn[i] == (float) 1.0) { | |||||
pOut[i] = 0x000FFFFF; | pOut[i] = 0x000FFFFF; | ||||
} | |||||
} | |||||
} | |||||
} | |||||
} | } | ||||
/** | /** |
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | ||||
#if defined (__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) | #if defined (__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) | ||||
/* | |||||
* Let __ARM_FEATURE_UNALIGNED be set by the achitechture and the compiler flags: | |||||
* -munaligned-access | |||||
* -mno-unaligned-access | |||||
* instead of always setting it here. | |||||
* | |||||
#define __ARM_FEATURE_UNALIGNED 1 | #define __ARM_FEATURE_UNALIGNED 1 | ||||
*/ | |||||
/* This memcpy routine is optimised for Cortex-M3/M4 cores with/without | /* This memcpy routine is optimised for Cortex-M3/M4 cores with/without | ||||
unaligned access. | unaligned access. |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
#include "kinetis.h" | #include "kinetis.h" | ||||
#include "core_pins.h" // testing only | #include "core_pins.h" // testing only | ||||
#include "ser_print.h" // testing only | #include "ser_print.h" // testing only | ||||
#include <errno.h> | |||||
// Flash Security Setting. On Teensy 3.2, you can lock the MK20 chip to prevent | |||||
// anyone from reading your code. You CAN still reprogram your Teensy while | |||||
// security is set, but the bootloader will be unable to respond to auto-reboot | |||||
// requests from Arduino. Pressing the program button will cause a full chip | |||||
// erase to gain access, because the bootloader chip is locked out. Normally, | |||||
// erase occurs when uploading begins, so if you press the Program button | |||||
// accidentally, simply power cycling will run your program again. When | |||||
// security is locked, any Program button press causes immediate full erase. | |||||
// Special care must be used with the Program button, because it must be made | |||||
// accessible to initiate reprogramming, but it must not be accidentally | |||||
// pressed when Teensy Loader is not being used to reprogram. To set lock the | |||||
// security change this to 0xDC. Teensy 3.0 and 3.1 do not support security lock. | |||||
#define FSEC 0xDE | |||||
// Flash Options | |||||
#define FOPT 0xF9 | |||||
extern unsigned long _stext; | extern unsigned long _stext; | ||||
extern unsigned long _etext; | extern unsigned long _etext; | ||||
extern int main (void); | extern int main (void); | ||||
void ResetHandler(void); | void ResetHandler(void); | ||||
void _init_Teensyduino_internal_(void); | |||||
void _init_Teensyduino_internal_(void) __attribute__((noinline)); | |||||
void __libc_init_array(void); | void __libc_init_array(void); | ||||
fault_isr(); | fault_isr(); | ||||
} | } | ||||
extern volatile uint32_t systick_millis_count; | |||||
void systick_default_isr(void) | |||||
{ | |||||
systick_millis_count++; | |||||
} | |||||
void nmi_isr(void) __attribute__ ((weak, alias("unused_isr"))); | void nmi_isr(void) __attribute__ ((weak, alias("unused_isr"))); | ||||
void hard_fault_isr(void) __attribute__ ((weak, alias("fault_isr"))); | void hard_fault_isr(void) __attribute__ ((weak, alias("fault_isr"))); | ||||
void memmanage_fault_isr(void) __attribute__ ((weak, alias("fault_isr"))); | void memmanage_fault_isr(void) __attribute__ ((weak, alias("fault_isr"))); | ||||
void svcall_isr(void) __attribute__ ((weak, alias("unused_isr"))); | void svcall_isr(void) __attribute__ ((weak, alias("unused_isr"))); | ||||
void debugmonitor_isr(void) __attribute__ ((weak, alias("unused_isr"))); | void debugmonitor_isr(void) __attribute__ ((weak, alias("unused_isr"))); | ||||
void pendablesrvreq_isr(void) __attribute__ ((weak, alias("unused_isr"))); | void pendablesrvreq_isr(void) __attribute__ ((weak, alias("unused_isr"))); | ||||
void systick_isr(void) __attribute__ ((weak, alias("systick_default_isr"))); | |||||
void systick_isr(void); | |||||
void dma_ch0_isr(void) __attribute__ ((weak, alias("unused_isr"))); | void dma_ch0_isr(void) __attribute__ ((weak, alias("unused_isr"))); | ||||
void dma_ch1_isr(void) __attribute__ ((weak, alias("unused_isr"))); | void dma_ch1_isr(void) __attribute__ ((weak, alias("unused_isr"))); | ||||
__attribute__ ((section(".flashconfig"), used)) | __attribute__ ((section(".flashconfig"), used)) | ||||
const uint8_t flashconfigbytes[16] = { | const uint8_t flashconfigbytes[16] = { | ||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF | |||||
0xFF, 0xFF, 0xFF, 0xFF, FSEC, FOPT, 0xFF, 0xFF | |||||
}; | }; | ||||
void startup_late_hook(void) __attribute__ ((weak, alias("startup_default_late_hook"))); | void startup_late_hook(void) __attribute__ ((weak, alias("startup_default_late_hook"))); | ||||
#ifdef __clang__ | |||||
// Clang seems to generate slightly larger code with Os than gcc | |||||
#if defined(__PURE_CODE__) || !defined(__OPTIMIZE__) || defined(__clang__) | |||||
// cases known to compile too large for 0-0x400 memory region | |||||
__attribute__ ((optimize("-Os"))) | __attribute__ ((optimize("-Os"))) | ||||
#else | #else | ||||
// hopefully all others fit into startup section (below 0x400) | |||||
__attribute__ ((section(".startup"),optimize("-Os"))) | __attribute__ ((section(".startup"),optimize("-Os"))) | ||||
#endif | #endif | ||||
void ResetHandler(void) | void ResetHandler(void) | ||||
SIM_SCGC3 = SIM_SCGC3_ADC1 | SIM_SCGC3_FTM2 | SIM_SCGC3_FTM3; | SIM_SCGC3 = SIM_SCGC3_ADC1 | SIM_SCGC3_FTM2 | SIM_SCGC3_FTM3; | ||||
SIM_SCGC5 = 0x00043F82; // clocks active to all GPIO | SIM_SCGC5 = 0x00043F82; // clocks active to all GPIO | ||||
SIM_SCGC6 = SIM_SCGC6_RTC | SIM_SCGC6_FTM0 | SIM_SCGC6_FTM1 | SIM_SCGC6_ADC0 | SIM_SCGC6_FTFL; | SIM_SCGC6 = SIM_SCGC6_RTC | SIM_SCGC6_FTM0 | SIM_SCGC6_FTM1 | SIM_SCGC6_ADC0 | SIM_SCGC6_FTFL; | ||||
PORTC_PCR5 = PORT_PCR_MUX(1) | PORT_PCR_DSE | PORT_PCR_SRE; | |||||
GPIOC_PDDR |= (1<<5); | |||||
GPIOC_PSOR = (1<<5); | |||||
//PORTC_PCR5 = PORT_PCR_MUX(1) | PORT_PCR_DSE | PORT_PCR_SRE; | |||||
//GPIOC_PDDR |= (1<<5); | |||||
//GPIOC_PSOR = (1<<5); | |||||
//while (1); | //while (1); | ||||
#elif defined(__MKL26Z64__) | #elif defined(__MKL26Z64__) | ||||
SIM_SCGC4 = SIM_SCGC4_USBOTG | 0xF0000030; | SIM_SCGC4 = SIM_SCGC4_USBOTG | 0xF0000030; | ||||
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; | ||||
#else | #else | ||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
// enable capacitors for crystal | // enable capacitors for crystal | ||||
OSC0_CR = OSC_SC8P | OSC_SC2P; | |||||
OSC0_CR = OSC_SC8P | OSC_SC2P | OSC_ERCLKEN; | |||||
#elif defined(KINETISL) | #elif defined(KINETISL) | ||||
// enable capacitors for crystal | // enable capacitors for crystal | ||||
OSC0_CR = OSC_SC8P | OSC_SC2P | OSC_ERCLKEN; | OSC0_CR = OSC_SC8P | OSC_SC2P | OSC_ERCLKEN; | ||||
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 == 192000000 | |||||
#if F_CPU == 256000000 | |||||
//See table in 27.4.6 MCG Control 6 Register (MCG_C6) | |||||
//16 -> Multiply factor 32. 32*8MHz =256MHz | |||||
MCG_C5 = MCG_C5_PRDIV0(0); | |||||
MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(16); | |||||
#elif F_CPU == 240000000 | |||||
MCG_C5 = MCG_C5_PRDIV0(0); | |||||
MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(14); | |||||
#elif F_CPU == 216000000 | |||||
MCG_C5 = MCG_C5_PRDIV0(0); | |||||
MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(11); | |||||
#elif F_CPU == 192000000 | |||||
MCG_C5 = MCG_C5_PRDIV0(0); | MCG_C5 = MCG_C5_PRDIV0(0); | ||||
MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(8); | MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(8); | ||||
#elif F_CPU == 180000000 | #elif F_CPU == 180000000 | ||||
#endif | #endif | ||||
#endif | #endif | ||||
// now program the clock dividers | // now program the clock dividers | ||||
#if F_CPU == 192000000 | |||||
// config divisors: 192 MHz core, 48 MHz bus, 27.4 MHz flash, USB = 192 * 4 | |||||
#if F_CPU == 256000000 | |||||
// config divisors: 256 MHz core, 64 MHz bus, 32 MHz flash, USB = IRC48M | |||||
// TODO: gradual ramp-up for HSRUN mode | |||||
#if F_BUS == 64000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(7); | |||||
#elif F_BUS == 128000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(7); | |||||
#else | |||||
#error "This F_CPU & F_BUS combination is not supported" | |||||
#endif | |||||
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(0); | |||||
#elif F_CPU == 240000000 | |||||
// config divisors: 240 MHz core, 60 MHz bus, 30 MHz flash, USB = 240 / 5 | |||||
// TODO: gradual ramp-up for HSRUN mode | |||||
#if F_BUS == 60000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(7); | |||||
#elif F_BUS == 80000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(7); | |||||
#elif F_BUS == 120000000 | |||||
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(4); | |||||
#elif F_CPU == 216000000 | |||||
// config divisors: 216 MHz core, 54 MHz bus, 27 MHz flash, USB = IRC48M | |||||
// TODO: gradual ramp-up for HSRUN mode | |||||
#if F_BUS == 54000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(7); | |||||
#elif F_BUS == 72000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(7); | |||||
#elif F_BUS == 108000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(7); | |||||
#else | |||||
#error "This F_CPU & F_BUS combination is not supported" | |||||
#endif | |||||
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(0); | |||||
#elif F_CPU == 192000000 | |||||
// config divisors: 192 MHz core, 48 MHz bus, 27.4 MHz flash, USB = 192 / 4 | |||||
// TODO: gradual ramp-up for HSRUN mode | // TODO: gradual ramp-up for HSRUN mode | ||||
#if F_BUS == 48000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(6); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(6); | ||||
#elif F_BUS == 64000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(6); | |||||
#elif F_BUS == 96000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(6); | |||||
#else | |||||
#error "This F_CPU & F_BUS combination is not supported" | |||||
#endif | |||||
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(3); | SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(3); | ||||
#elif F_CPU == 180000000 | #elif F_CPU == 180000000 | ||||
// config divisors: 180 MHz core, 60 MHz bus, 25.7 MHz flash, USB = not feasible | |||||
// config divisors: 180 MHz core, 60 MHz bus, 25.7 MHz flash, USB = IRC48M | |||||
#if F_BUS == 60000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(6); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(6); | ||||
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(6) | SIM_CLKDIV2_USBFRAC; | |||||
#elif F_BUS == 90000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(6); | |||||
#else | |||||
#error "This F_CPU & F_BUS combination is not supported" | |||||
#endif | |||||
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(0); | |||||
#elif F_CPU == 168000000 | #elif F_CPU == 168000000 | ||||
// config divisors: 168 MHz core, 56 MHz bus, 28 MHz flash, USB = 168 * 2 / 7 | // config divisors: 168 MHz core, 56 MHz bus, 28 MHz flash, USB = 168 * 2 / 7 | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(5); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(5); | ||||
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(6) | SIM_CLKDIV2_USBFRAC; | SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(6) | SIM_CLKDIV2_USBFRAC; | ||||
#elif F_CPU == 144000000 | #elif F_CPU == 144000000 | ||||
// config divisors: 144 MHz core, 48 MHz bus, 28.8 MHz flash, USB = 144 / 3 | // config divisors: 144 MHz core, 48 MHz bus, 28.8 MHz flash, USB = 144 / 3 | ||||
#if F_BUS == 48000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(4); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(4); | ||||
#elif F_BUS == 72000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(4); | |||||
#else | |||||
#error "This F_CPU & F_BUS combination is not supported" | |||||
#endif | |||||
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(2); | SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(2); | ||||
#elif F_CPU == 120000000 | #elif F_CPU == 120000000 | ||||
// config divisors: 120 MHz core, 60 MHz bus, 24 MHz flash, USB = 128 * 2 / 5 | // config divisors: 120 MHz core, 60 MHz bus, 24 MHz flash, USB = 128 * 2 / 5 | ||||
#if F_BUS == 60000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(4); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(4); | ||||
#elif F_BUS == 120000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | SIM_CLKDIV1_OUTDIV4(4); | |||||
#else | |||||
#error "This F_CPU & F_BUS combination is not supported" | |||||
#endif | |||||
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(4) | SIM_CLKDIV2_USBFRAC; | SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(4) | SIM_CLKDIV2_USBFRAC; | ||||
#elif F_CPU == 96000000 | #elif F_CPU == 96000000 | ||||
// config divisors: 96 MHz core, 48 MHz bus, 24 MHz flash, USB = 96 / 2 | // config divisors: 96 MHz core, 48 MHz bus, 24 MHz flash, USB = 96 / 2 | ||||
#if F_BUS == 48000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(3); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(3); | ||||
#elif F_BUS == 96000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | SIM_CLKDIV1_OUTDIV4(3); | |||||
#else | |||||
#error "This F_CPU & F_BUS combination is not supported" | |||||
#endif | |||||
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1); | SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1); | ||||
#elif F_CPU == 72000000 | #elif F_CPU == 72000000 | ||||
// config divisors: 72 MHz core, 36 MHz bus, 24 MHz flash, USB = 72 * 2 / 3 | // config divisors: 72 MHz core, 36 MHz bus, 24 MHz flash, USB = 72 * 2 / 3 | ||||
#if F_BUS == 36000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(2); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(2); | ||||
#elif F_BUS == 72000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | SIM_CLKDIV1_OUTDIV4(2); | |||||
#else | |||||
#error "This F_CPU & F_BUS combination is not supported" | |||||
#endif | |||||
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(2) | SIM_CLKDIV2_USBFRAC; | SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(2) | SIM_CLKDIV2_USBFRAC; | ||||
#elif F_CPU == 48000000 | #elif F_CPU == 48000000 | ||||
// config divisors: 48 MHz core, 48 MHz bus, 24 MHz flash, USB = 96 / 2 | // config divisors: 48 MHz core, 48 MHz bus, 24 MHz flash, USB = 96 / 2 | ||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(3); | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV3(1) | SIM_CLKDIV1_OUTDIV4(3); | |||||
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1); | SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1); | ||||
#elif defined(KINETISL) | #elif defined(KINETISL) | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV4(1); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV4(1); | ||||
#elif F_CPU == 24000000 | #elif F_CPU == 24000000 | ||||
// config divisors: 24 MHz core, 24 MHz bus, 24 MHz flash, USB = 96 / 2 | // config divisors: 24 MHz core, 24 MHz bus, 24 MHz flash, USB = 96 / 2 | ||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(3) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(3); | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(3) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV3(3) | SIM_CLKDIV1_OUTDIV4(3); | |||||
SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1); | SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1); | ||||
#elif defined(KINETISL) | #elif defined(KINETISL) | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(3) | SIM_CLKDIV1_OUTDIV4(0); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(3) | SIM_CLKDIV1_OUTDIV4(0); | ||||
#elif F_CPU == 16000000 | #elif F_CPU == 16000000 | ||||
// config divisors: 16 MHz core, 16 MHz bus, 16 MHz flash | // config divisors: 16 MHz core, 16 MHz bus, 16 MHz flash | ||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | SIM_CLKDIV1_OUTDIV4(0); | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | SIM_CLKDIV1_OUTDIV3(0) | SIM_CLKDIV1_OUTDIV4(0); | |||||
#elif defined(KINETISL) | #elif defined(KINETISL) | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV4(0); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV4(0); | ||||
#endif | #endif | ||||
#elif F_CPU == 8000000 | #elif F_CPU == 8000000 | ||||
// config divisors: 8 MHz core, 8 MHz bus, 8 MHz flash | // config divisors: 8 MHz core, 8 MHz bus, 8 MHz flash | ||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(1); | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV3(1) | SIM_CLKDIV1_OUTDIV4(1); | |||||
#elif defined(KINETISL) | #elif defined(KINETISL) | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV4(0); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV4(0); | ||||
#endif | #endif | ||||
// here we can go into vlpr? | // here we can go into vlpr? | ||||
// config divisors: 4 MHz core, 4 MHz bus, 4 MHz flash | // config divisors: 4 MHz core, 4 MHz bus, 4 MHz flash | ||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(3) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(3); | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(3) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV3(3) | SIM_CLKDIV1_OUTDIV4(3); | |||||
#elif defined(KINETISL) | #elif defined(KINETISL) | ||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(3) | SIM_CLKDIV1_OUTDIV4(0); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(3) | SIM_CLKDIV1_OUTDIV4(0); | ||||
#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) | ||||
SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | |||||
| SIM_SOPT2_CLKOUTSEL(6); | |||||
#if F_CPU == 256000000 || F_CPU == 216000000 || F_CPU == 180000000 | |||||
// USB uses IRC48 | |||||
SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_IRC48SEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); | |||||
#else | |||||
// USB uses PLL clock | |||||
SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); | |||||
#endif | |||||
#elif defined(KINETISL) | #elif defined(KINETISL) | ||||
SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_CLKOUTSEL(6) | SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_CLKOUTSEL(6) | ||||
| SIM_SOPT2_UART0SRC(1) | SIM_SOPT2_TPMSRC(1); | | SIM_SOPT2_UART0SRC(1) | SIM_SOPT2_TPMSRC(1); | ||||
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) ; | ||||
} | } | ||||
char *__brkval = (char *)&_ebss; | char *__brkval = (char *)&_ebss; | ||||
#ifndef STACK_MARGIN | |||||
#if defined(__MKL26Z64__) | |||||
#define STACK_MARGIN 512 | |||||
#elif defined(__MK20DX128__) | |||||
#define STACK_MARGIN 1024 | |||||
#elif defined(__MK20DX256__) | |||||
#define STACK_MARGIN 4096 | |||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#define STACK_MARGIN 8192 | |||||
#endif | |||||
#endif | |||||
#pragma GCC diagnostic push | |||||
#pragma GCC diagnostic ignored "-Wunused-parameter" | |||||
void * _sbrk(int incr) | void * _sbrk(int incr) | ||||
{ | { | ||||
char *prev = __brkval; | |||||
__brkval += incr; | |||||
char *prev, *stack; | |||||
prev = __brkval; | |||||
if (incr != 0) { | |||||
__asm__ volatile("mov %0, sp" : "=r" (stack) ::); | |||||
if (prev + incr >= stack - STACK_MARGIN) { | |||||
errno = ENOMEM; | |||||
return (void *)-1; | |||||
} | |||||
__brkval = prev + incr; | |||||
} | |||||
return prev; | return prev; | ||||
} | } | ||||
*g = 1; | *g = 1; | ||||
} | } | ||||
__attribute__((weak)) | |||||
void abort(void) | |||||
{ | |||||
while (1) ; | |||||
} | |||||
#pragma GCC diagnostic pop | |||||
int nvic_execution_priority(void) | int nvic_execution_priority(void) | ||||
{ | { | ||||
int priority=256; | |||||
uint32_t priority=256; | |||||
uint32_t primask, faultmask, basepri, ipsr; | uint32_t primask, faultmask, basepri, ipsr; | ||||
// full algorithm in ARM DDI0403D, page B1-639 | // full algorithm in ARM DDI0403D, page B1-639 | ||||
return priority; | return priority; | ||||
} | } | ||||
#if defined(HAS_KINETIS_HSRUN) && F_CPU > 120000000 | |||||
int kinetis_hsrun_disable(void) | |||||
{ | |||||
if (SMC_PMSTAT == SMC_PMSTAT_HSRUN) { | |||||
// First, reduce the CPU clock speed, but do not change | |||||
// the peripheral speed (F_BUS). Serial1 & Serial2 baud | |||||
// rates will be impacted, but most other peripherals | |||||
// will continue functioning at the same speed. | |||||
#if F_CPU == 256000000 && F_BUS == 64000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // TODO: TEST | |||||
#elif F_CPU == 256000000 && F_BUS == 128000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // TODO: TEST | |||||
#elif F_CPU == 240000000 && F_BUS == 60000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // ok | |||||
#elif F_CPU == 240000000 && F_BUS == 80000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok | |||||
#elif F_CPU == 240000000 && F_BUS == 120000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // ok | |||||
#elif F_CPU == 216000000 && F_BUS == 54000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // ok | |||||
#elif F_CPU == 216000000 && F_BUS == 72000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok | |||||
#elif F_CPU == 216000000 && F_BUS == 108000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // ok | |||||
#elif F_CPU == 192000000 && F_BUS == 48000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // ok | |||||
#elif F_CPU == 192000000 && F_BUS == 64000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok | |||||
#elif F_CPU == 192000000 && F_BUS == 96000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // ok | |||||
#elif F_CPU == 180000000 && F_BUS == 60000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok | |||||
#elif F_CPU == 180000000 && F_BUS == 90000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // ok | |||||
#elif F_CPU == 168000000 && F_BUS == 56000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 5); // ok | |||||
#elif F_CPU == 144000000 && F_BUS == 48000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 5); // ok | |||||
#elif F_CPU == 144000000 && F_BUS == 72000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 5); // ok | |||||
#else | |||||
return 0; | |||||
#endif | |||||
// Then turn off HSRUN mode | |||||
SMC_PMCTRL = SMC_PMCTRL_RUNM(0); | |||||
while (SMC_PMSTAT == SMC_PMSTAT_HSRUN) ; // wait | |||||
return 1; | |||||
} | |||||
return 0; | |||||
} | |||||
int kinetis_hsrun_enable(void) | |||||
{ | |||||
if (SMC_PMSTAT == SMC_PMSTAT_RUN) { | |||||
// Turn HSRUN mode on | |||||
SMC_PMCTRL = SMC_PMCTRL_RUNM(3); | |||||
while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) {;} // wait | |||||
// Then configure clock for full speed | |||||
#if F_CPU == 256000000 && F_BUS == 64000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7); | |||||
#elif F_CPU == 256000000 && F_BUS == 128000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 7); | |||||
#elif F_CPU == 240000000 && F_BUS == 60000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7); | |||||
#elif F_CPU == 240000000 && F_BUS == 80000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 7); | |||||
#elif F_CPU == 240000000 && F_BUS == 120000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 7); | |||||
#elif F_CPU == 216000000 && F_BUS == 54000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7); | |||||
#elif F_CPU == 216000000 && F_BUS == 72000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 7); | |||||
#elif F_CPU == 216000000 && F_BUS == 108000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 7); | |||||
#elif F_CPU == 192000000 && F_BUS == 48000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 6); | |||||
#elif F_CPU == 192000000 && F_BUS == 64000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 6); | |||||
#elif F_CPU == 192000000 && F_BUS == 96000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 6); | |||||
#elif F_CPU == 180000000 && F_BUS == 60000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 6); | |||||
#elif F_CPU == 180000000 && F_BUS == 90000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 6); | |||||
#elif F_CPU == 168000000 && F_BUS == 56000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 5); | |||||
#elif F_CPU == 144000000 && F_BUS == 48000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 4); | |||||
#elif F_CPU == 144000000 && F_BUS == 72000000 | |||||
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 4); | |||||
#else | |||||
return 0; | |||||
#endif | |||||
return 1; | |||||
} | |||||
return 0; | |||||
} | |||||
#endif // HAS_KINETIS_HSRUN && F_CPU > 120000000 | |||||
// This header file is in the public domain. | |||||
#ifndef _mk20dx128_h_ | #ifndef _mk20dx128_h_ | ||||
#define _mk20dx128_h_ | #define _mk20dx128_h_ | ||||
#include "kinetis.h" // mk20dx128.h renamed to kinetis.h | #include "kinetis.h" // mk20dx128.h renamed to kinetis.h |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | * 2. If the Software is incorporated into a build system that allows | ||||
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; | |||||
} | } | ||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
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; | |||||
} | } | ||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
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; | |||||
} | } | ||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
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; | |||||
} | } | ||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2014 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
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; | |||||
} | } | ||||
/* 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. | |||||
* | |||||
* 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 "new.h" | #include "new.h" | ||||
void * operator new(size_t size) | void * operator new(size_t size) | ||||
free(ptr); | free(ptr); | ||||
} | } | ||||
void operator delete(void * ptr, size_t size) | |||||
{ | |||||
free(ptr); | |||||
} | |||||
void operator delete[](void * ptr, size_t size) | |||||
{ | |||||
free(ptr); | |||||
} | |||||
//int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);}; | //int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);}; | ||||
//void __cxa_guard_release (__guard *g) {*(char *)g = 1;}; | //void __cxa_guard_release (__guard *g) {*(char *)g = 1;}; | ||||
//void __cxa_guard_abort (__guard *) {}; | //void __cxa_guard_abort (__guard *) {}; |
/* 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. | |||||
* | |||||
* 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. | |||||
*/ | |||||
/* Header to define new/delete operators as they aren't provided by avr-gcc by default | /* Header to define new/delete operators as they aren't provided by avr-gcc by default | ||||
Taken from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453 | |||||
Adapted from from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453 | |||||
*/ | */ | ||||
#ifndef NEW_H | #ifndef NEW_H | ||||
void * operator new[](size_t size); | void * operator new[](size_t size); | ||||
void operator delete(void * ptr); | void operator delete(void * ptr); | ||||
void operator delete[](void * ptr); | void operator delete[](void * ptr); | ||||
void operator delete(void * ptr, size_t size); | |||||
void operator delete[](void * ptr, size_t size); | |||||
__extension__ typedef int __guard __attribute__((mode (__DI__))); | __extension__ typedef int __guard __attribute__((mode (__DI__))); | ||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
#include "avr_functions.h" | #include "avr_functions.h" | ||||
#include <string.h> | #include <string.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <math.h> | |||||
char * ultoa(unsigned long val, char *buf, int radix) | |||||
char * ultoa(unsigned long val, char *buf, int radix) | |||||
{ | { | ||||
unsigned digit; | unsigned digit; | ||||
int i=0, j; | int i=0, j; | ||||
} | } | ||||
} | } | ||||
#define DTOA_UPPER 0x04 | |||||
char * fcvtf(float, int, int *, int *); | |||||
int isnanf (float x); | |||||
int isinff (float x); | |||||
char * dtostrf(float val, int width, unsigned int precision, char *buf) | char * dtostrf(float val, int width, unsigned int precision, char *buf) | ||||
{ | { | ||||
int decpt, sign, reqd, pad; | int decpt, sign, reqd, pad; | ||||
const char *s, *e; | const char *s, *e; | ||||
char *p; | char *p; | ||||
int awidth = abs(width); | |||||
if (isnanf(val)) { | |||||
int ndigs = (val<0) ? 4 : 3; | |||||
awidth = (awidth > ndigs) ? awidth - ndigs : 0; | |||||
if (width<0) { | |||||
while (awidth) { | |||||
*buf++ = ' '; | |||||
awidth--; | |||||
} | |||||
} | |||||
if (copysignf(1.0f, val)<0) *buf++ = '-'; | |||||
if (DTOA_UPPER) { | |||||
*buf++ = 'N'; *buf++ = 'A'; *buf++ = 'N'; | |||||
} else { | |||||
*buf++ = 'n'; *buf++ = 'a'; *buf++ = 'n'; | |||||
} | |||||
while (awidth) { | |||||
*buf++ = ' '; | |||||
awidth--; | |||||
} | |||||
*buf = 0; | |||||
return buf; | |||||
} | |||||
if (isinff(val)) { | |||||
int ndigs = (val<0) ? 4 : 3; | |||||
awidth = (awidth > ndigs) ? awidth - ndigs : 0; | |||||
if (width<0) { | |||||
while (awidth) { | |||||
*buf++ = ' '; | |||||
awidth--; | |||||
} | |||||
} | |||||
if (val<0) *buf++ = '-'; | |||||
if (DTOA_UPPER) { | |||||
*buf++ = 'I'; *buf++ = 'N'; *buf++ = 'F'; | |||||
} else { | |||||
*buf++ = 'i'; *buf++ = 'n'; *buf++ = 'f'; | |||||
} | |||||
while (awidth) { | |||||
*buf++ = ' '; | |||||
awidth--; | |||||
} | |||||
*buf = 0; | |||||
return buf; | |||||
} | |||||
s = fcvtf(val, precision, &decpt, &sign); | s = fcvtf(val, precision, &decpt, &sign); | ||||
// if only 1 digit in output | |||||
if (precision == 0 && decpt == 0) { | if (precision == 0 && decpt == 0) { | ||||
// round and move decimal point | |||||
s = (*s < '5') ? "0" : "1"; | s = (*s < '5') ? "0" : "1"; | ||||
reqd = 1; | |||||
} else { | |||||
reqd = strlen(s); | |||||
if (reqd > decpt) reqd++; | |||||
if (decpt == 0) reqd++; | |||||
decpt++; | |||||
} | } | ||||
// if all zeros, limit to precision | |||||
if (-decpt > (int)precision) { | |||||
s = "0"; | |||||
decpt = -precision; | |||||
} | |||||
reqd = strlen(s); | |||||
// add 1 for decimal point | |||||
if (reqd > decpt) reqd++; | |||||
// add 1 for zero in front of decimal point | |||||
if (decpt == 0) reqd++; | |||||
// if leading zeros after decimal point | |||||
if (decpt < 0 && precision > 0) { | |||||
// ensure enough trailing zeros, add 2 for '0.' | |||||
reqd = precision + 2; | |||||
if (strlen(s) > precision + decpt) { | |||||
// bug in fcvtf. e.g. 0.012, precision 2 should return 1 instead of 12. | |||||
// However, 1.2, precision 0 returns correct value. So shift values so | |||||
// that decimal point is after the first digit, then convert again | |||||
int newPrecision = precision; | |||||
int newDecimalPoint; | |||||
// shift decimal point | |||||
while (newPrecision > 0) { | |||||
val *= 10.0; | |||||
newPrecision--; | |||||
} | |||||
// round after accounting for leading 0's | |||||
s = fcvtf(val, newPrecision, &newDecimalPoint, &sign); | |||||
// if rounded up to new digit (e.g. 0.09 to 0.1), move decimal point | |||||
if (newDecimalPoint - decpt == precision + 1) decpt++; | |||||
} | |||||
} | |||||
// add 1 for sign if negative | |||||
if (sign) reqd++; | if (sign) reqd++; | ||||
p = buf; | p = buf; | ||||
e = p + reqd; | e = p + reqd; | ||||
pad = width - reqd; | pad = width - reqd; | ||||
else if (decpt < 0 && precision > 0) { | else if (decpt < 0 && precision > 0) { | ||||
*p++ = '0'; | *p++ = '0'; | ||||
*p++ = '.'; | *p++ = '.'; | ||||
e++; | |||||
// print leading zeros | |||||
while ( decpt < 0 ) { | while ( decpt < 0 ) { | ||||
decpt++; | decpt++; | ||||
*p++ = '0'; | *p++ = '0'; | ||||
} | } | ||||
} | } | ||||
// print digits | |||||
while (p < e) { | while (p < e) { | ||||
*p++ = *s++; | *p++ = *s++; | ||||
if (p == e) break; | if (p == e) break; |
// For compatibility with some ESP8266 programs | |||||
#include <avr/pgmspace.h> |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
#include <stdint.h> | #include <stdint.h> | ||||
// A0-A9 are always digital 14-23, for Arduino compatibility | // A0-A9 are always digital 14-23, for Arduino compatibility | ||||
const static uint8_t A0 = 14; | |||||
const static uint8_t A1 = 15; | |||||
const static uint8_t A2 = 16; | |||||
const static uint8_t A3 = 17; | |||||
const static uint8_t A4 = 18; | |||||
const static uint8_t A5 = 19; | |||||
const static uint8_t A6 = 20; | |||||
const static uint8_t A7 = 21; | |||||
const static uint8_t A8 = 22; | |||||
const static uint8_t A9 = 23; | |||||
#define PIN_A0 (14) | |||||
#define PIN_A1 (15) | |||||
#define PIN_A2 (16) | |||||
#define PIN_A3 (17) | |||||
#define PIN_A4 (18) | |||||
#define PIN_A5 (19) | |||||
#define PIN_A6 (20) | |||||
#define PIN_A7 (21) | |||||
#define PIN_A8 (22) | |||||
#define PIN_A9 (23) | |||||
const static uint8_t A0 = PIN_A0; | |||||
const static uint8_t A1 = PIN_A1; | |||||
const static uint8_t A2 = PIN_A2; | |||||
const static uint8_t A3 = PIN_A3; | |||||
const static uint8_t A4 = PIN_A4; | |||||
const static uint8_t A5 = PIN_A5; | |||||
const static uint8_t A6 = PIN_A6; | |||||
const static uint8_t A7 = PIN_A7; | |||||
const static uint8_t A8 = PIN_A8; | |||||
const static uint8_t A9 = PIN_A9; | |||||
#if defined(__MK20DX128__) | #if defined(__MK20DX128__) | ||||
const static uint8_t A10 = 34; | |||||
const static uint8_t A11 = 35; | |||||
const static uint8_t A12 = 36; | |||||
const static uint8_t A13 = 37; | |||||
#define PIN_A10 (34) | |||||
#define PIN_A11 (35) | |||||
#define PIN_A12 (36) | |||||
#define PIN_A13 (37) | |||||
const static uint8_t A10 = PIN_A10; | |||||
const static uint8_t A11 = PIN_A11; | |||||
const static uint8_t A12 = PIN_A12; | |||||
const static uint8_t A13 = PIN_A13; | |||||
#elif defined(__MK20DX256__) | #elif defined(__MK20DX256__) | ||||
const static uint8_t A10 = 34; | |||||
const static uint8_t A11 = 35; | |||||
const static uint8_t A12 = 36; | |||||
const static uint8_t A13 = 37; | |||||
const static uint8_t A14 = 40; | |||||
const static uint8_t A15 = 26; | |||||
const static uint8_t A16 = 27; | |||||
const static uint8_t A17 = 28; | |||||
const static uint8_t A18 = 29; | |||||
const static uint8_t A19 = 30; | |||||
const static uint8_t A20 = 31; | |||||
#define PIN_A10 (34) | |||||
#define PIN_A11 (35) | |||||
#define PIN_A12 (36) | |||||
#define PIN_A13 (37) | |||||
#define PIN_A14 (40) | |||||
#define PIN_A15 (26) | |||||
#define PIN_A16 (27) | |||||
#define PIN_A17 (28) | |||||
#define PIN_A18 (29) | |||||
#define PIN_A19 (30) | |||||
#define PIN_A20 (31) | |||||
const static uint8_t A10 = PIN_A10; | |||||
const static uint8_t A11 = PIN_A11; | |||||
const static uint8_t A12 = PIN_A12; | |||||
const static uint8_t A13 = PIN_A13; | |||||
const static uint8_t A14 = PIN_A14; | |||||
const static uint8_t A15 = PIN_A15; | |||||
const static uint8_t A16 = PIN_A16; | |||||
const static uint8_t A17 = PIN_A17; | |||||
const static uint8_t A18 = PIN_A18; | |||||
const static uint8_t A19 = PIN_A19; | |||||
const static uint8_t A20 = PIN_A20; | |||||
#elif defined(__MKL26Z64__) | #elif defined(__MKL26Z64__) | ||||
const static uint8_t A10 = 24; | |||||
const static uint8_t A11 = 25; | |||||
const static uint8_t A12 = 26; | |||||
#define PIN_A10 (24) | |||||
#define PIN_A11 (25) | |||||
#define PIN_A12 (26) | |||||
const static uint8_t A10 = PIN_A10; | |||||
const static uint8_t A11 = PIN_A11; | |||||
const static uint8_t A12 = PIN_A12; | |||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) | #elif defined(__MK64FX512__) || defined(__MK66FX1M0__) | ||||
const static uint8_t A10 = 40; | |||||
const static uint8_t A11 = 41; | |||||
const static uint8_t A12 = 31; | |||||
const static uint8_t A13 = 32; | |||||
const static uint8_t A14 = 33; | |||||
const static uint8_t A15 = 34; | |||||
const static uint8_t A16 = 35; | |||||
const static uint8_t A17 = 36; | |||||
const static uint8_t A18 = 37; | |||||
const static uint8_t A19 = 38; | |||||
const static uint8_t A20 = 39; | |||||
const static uint8_t A21 = 42; | |||||
const static uint8_t A22 = 43; | |||||
#define PIN_A10 (64) | |||||
#define PIN_A11 (65) | |||||
#define PIN_A12 (31) | |||||
#define PIN_A13 (32) | |||||
#define PIN_A14 (33) | |||||
#define PIN_A15 (34) | |||||
#define PIN_A16 (35) | |||||
#define PIN_A17 (36) | |||||
#define PIN_A18 (37) | |||||
#define PIN_A19 (38) | |||||
#define PIN_A20 (39) | |||||
#define PIN_A21 (66) | |||||
#define PIN_A22 (67) | |||||
#define PIN_A23 (49) | |||||
#define PIN_A24 (50) | |||||
#define PIN_A25 (68) | |||||
#define PIN_A26 (69) | |||||
const static uint8_t A10 = PIN_A10; | |||||
const static uint8_t A11 = PIN_A11; | |||||
const static uint8_t A12 = PIN_A12; | |||||
const static uint8_t A13 = PIN_A13; | |||||
const static uint8_t A14 = PIN_A14; | |||||
const static uint8_t A15 = PIN_A15; | |||||
const static uint8_t A16 = PIN_A16; | |||||
const static uint8_t A17 = PIN_A17; | |||||
const static uint8_t A18 = PIN_A18; | |||||
const static uint8_t A19 = PIN_A19; | |||||
const static uint8_t A20 = PIN_A20; | |||||
const static uint8_t A21 = PIN_A21; | |||||
const static uint8_t A22 = PIN_A22; | |||||
const static uint8_t A23 = PIN_A23; | |||||
const static uint8_t A24 = PIN_A24; | |||||
const static uint8_t A25 = PIN_A25; | |||||
const static uint8_t A26 = PIN_A26; | |||||
#endif | #endif | ||||
#define LED_BUILTIN (13) | |||||
#define PIN_SPI_SS (10) | |||||
#define PIN_SPI_MOSI (11) | |||||
#define PIN_SPI_MISO (12) | |||||
#define PIN_SPI_SCK (13) | |||||
const static uint8_t SS = 10; | const static uint8_t SS = 10; | ||||
const static uint8_t MOSI = 11; | const static uint8_t MOSI = 11; | ||||
const static uint8_t MISO = 12; | const static uint8_t MISO = 12; | ||||
const static uint8_t SCK = 13; | const static uint8_t SCK = 13; | ||||
const static uint8_t LED_BUILTIN = 13; | |||||
#define PIN_WIRE_SDA (18) | |||||
#define PIN_WIRE_SCL (19) | |||||
const static uint8_t SDA = 18; | const static uint8_t SDA = 18; | ||||
const static uint8_t SCL = 19; | const static uint8_t SCL = 19; | ||||
#define PIN_SERIAL_RX (0) | |||||
#define PIN_SERIAL_TX (1) | |||||
#define NUM_DIGITAL_PINS CORE_NUM_DIGITAL | #define NUM_DIGITAL_PINS CORE_NUM_DIGITAL | ||||
#define NUM_ANALOG_INPUTS CORE_NUM_ANALOG | #define NUM_ANALOG_INPUTS CORE_NUM_ANALOG | ||||
#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__) | |||||
#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) | ||||
#define SERIAL_PORT_HARDWARE_OPEN Serial1 | #define SERIAL_PORT_HARDWARE_OPEN Serial1 | ||||
#define SERIAL_PORT_HARDWARE_OPEN1 Serial2 | #define SERIAL_PORT_HARDWARE_OPEN1 Serial2 | ||||
#define SERIAL_PORT_HARDWARE_OPEN2 Serial3 | #define SERIAL_PORT_HARDWARE_OPEN2 Serial3 | ||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#define SERIAL_PORT_HARDWARE3 Serial4 | |||||
#define SERIAL_PORT_HARDWARE4 Serial5 | |||||
#define SERIAL_PORT_HARDWARE5 Serial6 | |||||
#define SERIAL_PORT_HARDWARE_OPEN3 Serial4 | |||||
#define SERIAL_PORT_HARDWARE_OPEN4 Serial5 | |||||
#define SERIAL_PORT_HARDWARE_OPEN5 Serial6 | |||||
#endif | |||||
#define SerialUSB Serial | #define SerialUSB Serial | ||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
{GPIO_BITBAND_PTR(CORE_PIN37_PORTREG, CORE_PIN37_BIT), &CORE_PIN37_CONFIG}, | {GPIO_BITBAND_PTR(CORE_PIN37_PORTREG, CORE_PIN37_BIT), &CORE_PIN37_CONFIG}, | ||||
{GPIO_BITBAND_PTR(CORE_PIN38_PORTREG, CORE_PIN38_BIT), &CORE_PIN38_CONFIG}, | {GPIO_BITBAND_PTR(CORE_PIN38_PORTREG, CORE_PIN38_BIT), &CORE_PIN38_CONFIG}, | ||||
{GPIO_BITBAND_PTR(CORE_PIN39_PORTREG, CORE_PIN39_BIT), &CORE_PIN39_CONFIG}, | {GPIO_BITBAND_PTR(CORE_PIN39_PORTREG, CORE_PIN39_BIT), &CORE_PIN39_CONFIG}, | ||||
{GPIO_BITBAND_PTR(CORE_PIN40_PORTREG, CORE_PIN40_BIT), &CORE_PIN40_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN41_PORTREG, CORE_PIN41_BIT), &CORE_PIN41_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN42_PORTREG, CORE_PIN42_BIT), &CORE_PIN42_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN43_PORTREG, CORE_PIN43_BIT), &CORE_PIN43_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN44_PORTREG, CORE_PIN44_BIT), &CORE_PIN44_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN45_PORTREG, CORE_PIN45_BIT), &CORE_PIN45_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN46_PORTREG, CORE_PIN46_BIT), &CORE_PIN46_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN47_PORTREG, CORE_PIN47_BIT), &CORE_PIN47_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN48_PORTREG, CORE_PIN48_BIT), &CORE_PIN48_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN49_PORTREG, CORE_PIN49_BIT), &CORE_PIN49_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN50_PORTREG, CORE_PIN50_BIT), &CORE_PIN50_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN51_PORTREG, CORE_PIN51_BIT), &CORE_PIN51_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN52_PORTREG, CORE_PIN52_BIT), &CORE_PIN52_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN53_PORTREG, CORE_PIN53_BIT), &CORE_PIN53_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN54_PORTREG, CORE_PIN54_BIT), &CORE_PIN54_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN55_PORTREG, CORE_PIN55_BIT), &CORE_PIN55_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN56_PORTREG, CORE_PIN56_BIT), &CORE_PIN56_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN57_PORTREG, CORE_PIN57_BIT), &CORE_PIN57_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN58_PORTREG, CORE_PIN58_BIT), &CORE_PIN58_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN59_PORTREG, CORE_PIN59_BIT), &CORE_PIN59_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN60_PORTREG, CORE_PIN60_BIT), &CORE_PIN60_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN61_PORTREG, CORE_PIN61_BIT), &CORE_PIN61_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN62_PORTREG, CORE_PIN62_BIT), &CORE_PIN62_CONFIG}, | |||||
{GPIO_BITBAND_PTR(CORE_PIN63_PORTREG, CORE_PIN63_BIT), &CORE_PIN63_CONFIG}, | |||||
#endif | #endif | ||||
}; | }; | ||||
#endif | #endif | ||||
static void dummy_isr() {}; | |||||
typedef void (*voidFuncPtr)(void); | typedef void (*voidFuncPtr)(void); | ||||
volatile static voidFuncPtr intFunc[CORE_NUM_DIGITAL]; | |||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
static void porta_interrupt(void); | |||||
static void portb_interrupt(void); | |||||
static void portc_interrupt(void); | |||||
static void portd_interrupt(void); | |||||
static void porte_interrupt(void); | |||||
#ifdef NO_PORT_ISR_FASTRUN | |||||
static void port_A_isr(void); | |||||
static void port_B_isr(void); | |||||
static void port_C_isr(void); | |||||
static void port_D_isr(void); | |||||
static void port_E_isr(void); | |||||
#else | |||||
static void port_A_isr(void) __attribute__ ((section(".fastrun"), noinline, noclone )); | |||||
static void port_B_isr(void) __attribute__ ((section(".fastrun"), noinline, noclone )); | |||||
static void port_C_isr(void) __attribute__ ((section(".fastrun"), noinline, noclone )); | |||||
static void port_D_isr(void) __attribute__ ((section(".fastrun"), noinline, noclone )); | |||||
static void port_E_isr(void) __attribute__ ((section(".fastrun"), noinline, noclone )); | |||||
#endif | |||||
voidFuncPtr isr_table_portA[CORE_MAX_PIN_PORTA+1] = { [0 ... CORE_MAX_PIN_PORTA] = dummy_isr }; | |||||
voidFuncPtr isr_table_portB[CORE_MAX_PIN_PORTB+1] = { [0 ... CORE_MAX_PIN_PORTB] = dummy_isr }; | |||||
voidFuncPtr isr_table_portC[CORE_MAX_PIN_PORTC+1] = { [0 ... CORE_MAX_PIN_PORTC] = dummy_isr }; | |||||
voidFuncPtr isr_table_portD[CORE_MAX_PIN_PORTD+1] = { [0 ... CORE_MAX_PIN_PORTD] = dummy_isr }; | |||||
voidFuncPtr isr_table_portE[CORE_MAX_PIN_PORTE+1] = { [0 ... CORE_MAX_PIN_PORTE] = dummy_isr }; | |||||
// The Pin Config Register is used to look up the correct interrupt table | |||||
// for the corresponding port. | |||||
static inline voidFuncPtr* getIsrTable(volatile uint32_t *config) { | |||||
voidFuncPtr* isr_table = NULL; | |||||
if(&PORTA_PCR0 <= config && config <= &PORTA_PCR31) isr_table = isr_table_portA; | |||||
else if(&PORTB_PCR0 <= config && config <= &PORTB_PCR31) isr_table = isr_table_portB; | |||||
else if(&PORTC_PCR0 <= config && config <= &PORTC_PCR31) isr_table = isr_table_portC; | |||||
else if(&PORTD_PCR0 <= config && config <= &PORTD_PCR31) isr_table = isr_table_portD; | |||||
else if(&PORTE_PCR0 <= config && config <= &PORTE_PCR31) isr_table = isr_table_portE; | |||||
return isr_table; | |||||
} | |||||
inline uint32_t getPinIndex(volatile uint32_t *config) { | |||||
uintptr_t v = (uintptr_t) config; | |||||
// There are 32 pin config registers for each port, each port starting at a round address. | |||||
// They are spaced 4 bytes apart. | |||||
return (v % 128) / 4; | |||||
} | |||||
#elif defined(KINETISL) | #elif defined(KINETISL) | ||||
volatile static voidFuncPtr intFunc[CORE_NUM_DIGITAL] = { [0 ... CORE_NUM_DIGITAL-1] = dummy_isr }; | |||||
static void porta_interrupt(void); | static void porta_interrupt(void); | ||||
static void portcd_interrupt(void); | static void portcd_interrupt(void); | ||||
#endif | #endif | ||||
} | } | ||||
mask = (mask << 16) | 0x01000000; | mask = (mask << 16) | 0x01000000; | ||||
config = portConfigRegister(pin); | config = portConfigRegister(pin); | ||||
if ((*config & 0x00000700) == 0) { | |||||
// for compatibility with programs which depend | |||||
// on AVR hardware default to input mode. | |||||
pinMode(pin, INPUT); | |||||
} | |||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
attachInterruptVector(IRQ_PORTA, porta_interrupt); | |||||
attachInterruptVector(IRQ_PORTB, portb_interrupt); | |||||
attachInterruptVector(IRQ_PORTC, portc_interrupt); | |||||
attachInterruptVector(IRQ_PORTD, portd_interrupt); | |||||
attachInterruptVector(IRQ_PORTE, porte_interrupt); | |||||
attachInterruptVector(IRQ_PORTA, port_A_isr); | |||||
attachInterruptVector(IRQ_PORTB, port_B_isr); | |||||
attachInterruptVector(IRQ_PORTC, port_C_isr); | |||||
attachInterruptVector(IRQ_PORTD, port_D_isr); | |||||
attachInterruptVector(IRQ_PORTE, port_E_isr); | |||||
voidFuncPtr* isr_table = getIsrTable(config); | |||||
if(!isr_table) return; | |||||
uint32_t pin_index = getPinIndex(config); | |||||
__disable_irq(); | |||||
cfg = *config; | |||||
cfg &= ~0x000F0000; // disable any previous interrupt | |||||
*config = cfg; | |||||
isr_table[pin_index] = function; // set the function pointer | |||||
cfg |= mask; | |||||
*config = cfg; // enable the new interrupt | |||||
__enable_irq(); | |||||
#elif defined(KINETISL) | #elif defined(KINETISL) | ||||
attachInterruptVector(IRQ_PORTA, porta_interrupt); | attachInterruptVector(IRQ_PORTA, porta_interrupt); | ||||
attachInterruptVector(IRQ_PORTCD, portcd_interrupt); | attachInterruptVector(IRQ_PORTCD, portcd_interrupt); | ||||
#endif | |||||
__disable_irq(); | __disable_irq(); | ||||
cfg = *config; | cfg = *config; | ||||
cfg &= ~0x000F0000; // disable any previous interrupt | cfg &= ~0x000F0000; // disable any previous interrupt | ||||
cfg |= mask; | cfg |= mask; | ||||
*config = cfg; // enable the new interrupt | *config = cfg; // enable the new interrupt | ||||
__enable_irq(); | __enable_irq(); | ||||
#endif | |||||
} | } | ||||
void detachInterrupt(uint8_t pin) | void detachInterrupt(uint8_t pin) | ||||
volatile uint32_t *config; | volatile uint32_t *config; | ||||
config = portConfigRegister(pin); | config = portConfigRegister(pin); | ||||
#if defined(KINETISK) | |||||
voidFuncPtr* isr_table = getIsrTable(config); | |||||
if(!isr_table) return; | |||||
uint32_t pin_index = getPinIndex(config); | |||||
__disable_irq(); | __disable_irq(); | ||||
*config = ((*config & ~0x000F0000) | 0x01000000); | *config = ((*config & ~0x000F0000) | 0x01000000); | ||||
intFunc[pin] = NULL; | |||||
isr_table[pin_index] = dummy_isr; | |||||
__enable_irq(); | __enable_irq(); | ||||
#elif defined(KINETISL) | |||||
__disable_irq(); | |||||
*config = ((*config & ~0x000F0000) | 0x01000000); | |||||
intFunc[pin] = dummy_isr; | |||||
__enable_irq(); | |||||
#endif | |||||
} | } | ||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) | |||||
static void porta_interrupt(void) | |||||
{ | |||||
uint32_t isfr = PORTA_ISFR; | |||||
PORTA_ISFR = isfr; | |||||
if ((isfr & CORE_PIN3_BITMASK) && intFunc[3]) intFunc[3](); | |||||
if ((isfr & CORE_PIN4_BITMASK) && intFunc[4]) intFunc[4](); | |||||
if ((isfr & CORE_PIN24_BITMASK) && intFunc[24]) intFunc[24](); | |||||
if ((isfr & CORE_PIN33_BITMASK) && intFunc[33]) intFunc[33](); | |||||
} | |||||
static void portb_interrupt(void) | |||||
{ | |||||
uint32_t isfr = PORTB_ISFR; | |||||
PORTB_ISFR = isfr; | |||||
if ((isfr & CORE_PIN0_BITMASK) && intFunc[0]) intFunc[0](); | |||||
if ((isfr & CORE_PIN1_BITMASK) && intFunc[1]) intFunc[1](); | |||||
if ((isfr & CORE_PIN16_BITMASK) && intFunc[16]) intFunc[16](); | |||||
if ((isfr & CORE_PIN17_BITMASK) && intFunc[17]) intFunc[17](); | |||||
if ((isfr & CORE_PIN18_BITMASK) && intFunc[18]) intFunc[18](); | |||||
if ((isfr & CORE_PIN19_BITMASK) && intFunc[19]) intFunc[19](); | |||||
if ((isfr & CORE_PIN25_BITMASK) && intFunc[25]) intFunc[25](); | |||||
if ((isfr & CORE_PIN32_BITMASK) && intFunc[32]) intFunc[32](); | |||||
} | |||||
static void portc_interrupt(void) | |||||
{ | |||||
// TODO: these are inefficent. Use CLZ somehow.... | |||||
uint32_t isfr = PORTC_ISFR; | |||||
PORTC_ISFR = isfr; | |||||
if ((isfr & CORE_PIN9_BITMASK) && intFunc[9]) intFunc[9](); | |||||
if ((isfr & CORE_PIN10_BITMASK) && intFunc[10]) intFunc[10](); | |||||
if ((isfr & CORE_PIN11_BITMASK) && intFunc[11]) intFunc[11](); | |||||
if ((isfr & CORE_PIN12_BITMASK) && intFunc[12]) intFunc[12](); | |||||
if ((isfr & CORE_PIN13_BITMASK) && intFunc[13]) intFunc[13](); | |||||
if ((isfr & CORE_PIN15_BITMASK) && intFunc[15]) intFunc[15](); | |||||
if ((isfr & CORE_PIN22_BITMASK) && intFunc[22]) intFunc[22](); | |||||
if ((isfr & CORE_PIN23_BITMASK) && intFunc[23]) intFunc[23](); | |||||
if ((isfr & CORE_PIN27_BITMASK) && intFunc[27]) intFunc[27](); | |||||
if ((isfr & CORE_PIN28_BITMASK) && intFunc[28]) intFunc[28](); | |||||
if ((isfr & CORE_PIN29_BITMASK) && intFunc[29]) intFunc[29](); | |||||
if ((isfr & CORE_PIN30_BITMASK) && intFunc[30]) intFunc[30](); | |||||
} | |||||
typedef void (*voidFuncPtr)(void); | |||||
static void portd_interrupt(void) | |||||
{ | |||||
uint32_t isfr = PORTD_ISFR; | |||||
PORTD_ISFR = isfr; | |||||
if ((isfr & CORE_PIN2_BITMASK) && intFunc[2]) intFunc[2](); | |||||
if ((isfr & CORE_PIN5_BITMASK) && intFunc[5]) intFunc[5](); | |||||
if ((isfr & CORE_PIN6_BITMASK) && intFunc[6]) intFunc[6](); | |||||
if ((isfr & CORE_PIN7_BITMASK) && intFunc[7]) intFunc[7](); | |||||
if ((isfr & CORE_PIN8_BITMASK) && intFunc[8]) intFunc[8](); | |||||
if ((isfr & CORE_PIN14_BITMASK) && intFunc[14]) intFunc[14](); | |||||
if ((isfr & CORE_PIN20_BITMASK) && intFunc[20]) intFunc[20](); | |||||
if ((isfr & CORE_PIN21_BITMASK) && intFunc[21]) intFunc[21](); | |||||
} | |||||
// Using CTZ instead of CLZ is faster, since it allows more efficient bit | |||||
// clearing and fast indexing into the pin ISR table. | |||||
#define PORT_ISR_FUNCTION_CLZ(port_name) \ | |||||
static void port_ ## port_name ## _isr(void) { \ | |||||
uint32_t isfr = PORT ## port_name ##_ISFR; \ | |||||
PORT ## port_name ##_ISFR = isfr; \ | |||||
voidFuncPtr* isr_table = isr_table_port ## port_name; \ | |||||
uint32_t bit_nr; \ | |||||
while(isfr) { \ | |||||
bit_nr = __builtin_ctz(isfr); \ | |||||
isr_table[bit_nr](); \ | |||||
isfr = isfr & (isfr-1); \ | |||||
if(!isfr) return; \ | |||||
} \ | |||||
} | |||||
// END PORT_ISR_FUNCTION_CLZ | |||||
static void porte_interrupt(void) | |||||
{ | |||||
uint32_t isfr = PORTE_ISFR; | |||||
PORTE_ISFR = isfr; | |||||
if ((isfr & CORE_PIN26_BITMASK) && intFunc[26]) intFunc[26](); | |||||
if ((isfr & CORE_PIN31_BITMASK) && intFunc[31]) intFunc[31](); | |||||
} | |||||
#if defined(KINETISK) | |||||
PORT_ISR_FUNCTION_CLZ(A) | |||||
PORT_ISR_FUNCTION_CLZ(B) | |||||
PORT_ISR_FUNCTION_CLZ(C) | |||||
PORT_ISR_FUNCTION_CLZ(D) | |||||
PORT_ISR_FUNCTION_CLZ(E) | |||||
#elif defined(KINETISL) | |||||
// Kinetis L (Teensy LC) is based on Cortex M0 and doesn't have hardware | |||||
// support for CLZ. | |||||
#elif defined(__MKL26Z64__) | |||||
#define DISPATCH_PIN_ISR(pin_nr) { voidFuncPtr pin_isr = intFunc[pin_nr]; \ | |||||
if(isfr & CORE_PIN ## pin_nr ## _BITMASK) pin_isr(); } | |||||
static void porta_interrupt(void) | static void porta_interrupt(void) | ||||
{ | { | ||||
uint32_t isfr = PORTA_ISFR; | uint32_t isfr = PORTA_ISFR; | ||||
PORTA_ISFR = isfr; | PORTA_ISFR = isfr; | ||||
if ((isfr & CORE_PIN3_BITMASK) && intFunc[3]) intFunc[3](); | |||||
if ((isfr & CORE_PIN4_BITMASK) && intFunc[4]) intFunc[4](); | |||||
DISPATCH_PIN_ISR(3); | |||||
DISPATCH_PIN_ISR(4); | |||||
} | } | ||||
static void portcd_interrupt(void) | static void portcd_interrupt(void) | ||||
{ | { | ||||
uint32_t isfr = PORTC_ISFR; | uint32_t isfr = PORTC_ISFR; | ||||
PORTC_ISFR = isfr; | PORTC_ISFR = isfr; | ||||
if ((isfr & CORE_PIN9_BITMASK) && intFunc[9]) intFunc[9](); | |||||
if ((isfr & CORE_PIN10_BITMASK) && intFunc[10]) intFunc[10](); | |||||
if ((isfr & CORE_PIN11_BITMASK) && intFunc[11]) intFunc[11](); | |||||
if ((isfr & CORE_PIN12_BITMASK) && intFunc[12]) intFunc[12](); | |||||
if ((isfr & CORE_PIN13_BITMASK) && intFunc[13]) intFunc[13](); | |||||
if ((isfr & CORE_PIN15_BITMASK) && intFunc[15]) intFunc[15](); | |||||
if ((isfr & CORE_PIN22_BITMASK) && intFunc[22]) intFunc[22](); | |||||
if ((isfr & CORE_PIN23_BITMASK) && intFunc[23]) intFunc[23](); | |||||
DISPATCH_PIN_ISR(9); | |||||
DISPATCH_PIN_ISR(10); | |||||
DISPATCH_PIN_ISR(11); | |||||
DISPATCH_PIN_ISR(12); | |||||
DISPATCH_PIN_ISR(13); | |||||
DISPATCH_PIN_ISR(15); | |||||
DISPATCH_PIN_ISR(22); | |||||
DISPATCH_PIN_ISR(23); | |||||
isfr = PORTD_ISFR; | isfr = PORTD_ISFR; | ||||
PORTD_ISFR = isfr; | PORTD_ISFR = isfr; | ||||
if ((isfr & CORE_PIN2_BITMASK) && intFunc[2]) intFunc[2](); | |||||
if ((isfr & CORE_PIN5_BITMASK) && intFunc[5]) intFunc[5](); | |||||
if ((isfr & CORE_PIN6_BITMASK) && intFunc[6]) intFunc[6](); | |||||
if ((isfr & CORE_PIN7_BITMASK) && intFunc[7]) intFunc[7](); | |||||
if ((isfr & CORE_PIN8_BITMASK) && intFunc[8]) intFunc[8](); | |||||
if ((isfr & CORE_PIN14_BITMASK) && intFunc[14]) intFunc[14](); | |||||
if ((isfr & CORE_PIN20_BITMASK) && intFunc[20]) intFunc[20](); | |||||
if ((isfr & CORE_PIN21_BITMASK) && intFunc[21]) intFunc[21](); | |||||
} | |||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
static void porta_interrupt(void) | |||||
{ | |||||
uint32_t isfr = PORTA_ISFR; | |||||
PORTA_ISFR = isfr; | |||||
if ((isfr & CORE_PIN3_BITMASK) && intFunc[3]) intFunc[3](); | |||||
if ((isfr & CORE_PIN4_BITMASK) && intFunc[4]) intFunc[4](); | |||||
if ((isfr & CORE_PIN25_BITMASK) && intFunc[25]) intFunc[25](); | |||||
if ((isfr & CORE_PIN26_BITMASK) && intFunc[26]) intFunc[26](); | |||||
if ((isfr & CORE_PIN27_BITMASK) && intFunc[27]) intFunc[27](); | |||||
if ((isfr & CORE_PIN28_BITMASK) && intFunc[28]) intFunc[28](); | |||||
if ((isfr & CORE_PIN39_BITMASK) && intFunc[39]) intFunc[39](); | |||||
} | |||||
static void portb_interrupt(void) | |||||
{ | |||||
uint32_t isfr = PORTB_ISFR; | |||||
PORTB_ISFR = isfr; | |||||
if ((isfr & CORE_PIN0_BITMASK) && intFunc[0]) intFunc[0](); | |||||
if ((isfr & CORE_PIN1_BITMASK) && intFunc[1]) intFunc[1](); | |||||
if ((isfr & CORE_PIN16_BITMASK) && intFunc[16]) intFunc[16](); | |||||
if ((isfr & CORE_PIN17_BITMASK) && intFunc[17]) intFunc[17](); | |||||
if ((isfr & CORE_PIN18_BITMASK) && intFunc[18]) intFunc[18](); | |||||
if ((isfr & CORE_PIN19_BITMASK) && intFunc[19]) intFunc[19](); | |||||
if ((isfr & CORE_PIN29_BITMASK) && intFunc[29]) intFunc[29](); | |||||
if ((isfr & CORE_PIN30_BITMASK) && intFunc[30]) intFunc[30](); | |||||
if ((isfr & CORE_PIN31_BITMASK) && intFunc[31]) intFunc[31](); | |||||
if ((isfr & CORE_PIN32_BITMASK) && intFunc[32]) intFunc[32](); | |||||
} | |||||
static void portc_interrupt(void) | |||||
{ | |||||
// TODO: these are inefficent. Use CLZ somehow.... | |||||
uint32_t isfr = PORTC_ISFR; | |||||
PORTC_ISFR = isfr; | |||||
if ((isfr & CORE_PIN9_BITMASK) && intFunc[9]) intFunc[9](); | |||||
if ((isfr & CORE_PIN10_BITMASK) && intFunc[10]) intFunc[10](); | |||||
if ((isfr & CORE_PIN11_BITMASK) && intFunc[11]) intFunc[11](); | |||||
if ((isfr & CORE_PIN12_BITMASK) && intFunc[12]) intFunc[12](); | |||||
if ((isfr & CORE_PIN13_BITMASK) && intFunc[13]) intFunc[13](); | |||||
if ((isfr & CORE_PIN15_BITMASK) && intFunc[15]) intFunc[15](); | |||||
if ((isfr & CORE_PIN22_BITMASK) && intFunc[22]) intFunc[22](); | |||||
if ((isfr & CORE_PIN23_BITMASK) && intFunc[23]) intFunc[23](); | |||||
if ((isfr & CORE_PIN35_BITMASK) && intFunc[35]) intFunc[35](); | |||||
if ((isfr & CORE_PIN36_BITMASK) && intFunc[36]) intFunc[36](); | |||||
if ((isfr & CORE_PIN37_BITMASK) && intFunc[37]) intFunc[37](); | |||||
if ((isfr & CORE_PIN38_BITMASK) && intFunc[38]) intFunc[38](); | |||||
} | |||||
static void portd_interrupt(void) | |||||
{ | |||||
uint32_t isfr = PORTD_ISFR; | |||||
PORTD_ISFR = isfr; | |||||
if ((isfr & CORE_PIN2_BITMASK) && intFunc[2]) intFunc[2](); | |||||
if ((isfr & CORE_PIN5_BITMASK) && intFunc[5]) intFunc[5](); | |||||
if ((isfr & CORE_PIN6_BITMASK) && intFunc[6]) intFunc[6](); | |||||
if ((isfr & CORE_PIN7_BITMASK) && intFunc[7]) intFunc[7](); | |||||
if ((isfr & CORE_PIN8_BITMASK) && intFunc[8]) intFunc[8](); | |||||
if ((isfr & CORE_PIN14_BITMASK) && intFunc[14]) intFunc[14](); | |||||
if ((isfr & CORE_PIN20_BITMASK) && intFunc[20]) intFunc[20](); | |||||
if ((isfr & CORE_PIN21_BITMASK) && intFunc[21]) intFunc[21](); | |||||
} | |||||
static void porte_interrupt(void) | |||||
{ | |||||
uint32_t isfr = PORTE_ISFR; | |||||
PORTE_ISFR = isfr; | |||||
if ((isfr & CORE_PIN24_BITMASK) && intFunc[24]) intFunc[24](); | |||||
if ((isfr & CORE_PIN33_BITMASK) && intFunc[33]) intFunc[33](); | |||||
if ((isfr & CORE_PIN34_BITMASK) && intFunc[34]) intFunc[34](); | |||||
DISPATCH_PIN_ISR(2); | |||||
DISPATCH_PIN_ISR(5); | |||||
DISPATCH_PIN_ISR(6); | |||||
DISPATCH_PIN_ISR(7); | |||||
DISPATCH_PIN_ISR(8); | |||||
DISPATCH_PIN_ISR(14); | |||||
DISPATCH_PIN_ISR(20); | |||||
DISPATCH_PIN_ISR(21); | |||||
} | } | ||||
#undef DISPATCH_PIN_ISR | |||||
#endif | #endif | ||||
#endif | #endif | ||||
#if F_TIMER == 60000000 | |||||
#if F_TIMER == 128000000 | |||||
#define DEFAULT_FTM_MOD (65536 - 1) | |||||
#define DEFAULT_FTM_PRESCALE 2 | |||||
#elif F_TIMER == 120000000 | |||||
#define DEFAULT_FTM_MOD (61440 - 1) | |||||
#define DEFAULT_FTM_PRESCALE 2 | |||||
#elif F_TIMER == 108000000 | |||||
#define DEFAULT_FTM_MOD (55296 - 1) | |||||
#define DEFAULT_FTM_PRESCALE 2 | |||||
#elif F_TIMER == 96000000 | |||||
#define DEFAULT_FTM_MOD (49152 - 1) | |||||
#define DEFAULT_FTM_PRESCALE 2 | |||||
#elif F_TIMER == 90000000 | |||||
#define DEFAULT_FTM_MOD (46080 - 1) | |||||
#define DEFAULT_FTM_PRESCALE 2 | |||||
#elif F_TIMER == 80000000 | |||||
#define DEFAULT_FTM_MOD (40960 - 1) | |||||
#define DEFAULT_FTM_PRESCALE 2 | |||||
#elif F_TIMER == 72000000 | |||||
#define DEFAULT_FTM_MOD (36864 - 1) | |||||
#define DEFAULT_FTM_PRESCALE 2 | |||||
#elif F_TIMER == 64000000 | |||||
#define DEFAULT_FTM_MOD (65536 - 1) | |||||
#define DEFAULT_FTM_PRESCALE 1 | |||||
#elif F_TIMER == 60000000 | |||||
#define DEFAULT_FTM_MOD (61440 - 1) | #define DEFAULT_FTM_MOD (61440 - 1) | ||||
#define DEFAULT_FTM_PRESCALE 1 | #define DEFAULT_FTM_PRESCALE 1 | ||||
#elif F_TIMER == 56000000 | #elif F_TIMER == 56000000 | ||||
#define DEFAULT_FTM_MOD (57344 - 1) | #define DEFAULT_FTM_MOD (57344 - 1) | ||||
#define DEFAULT_FTM_PRESCALE 1 | #define DEFAULT_FTM_PRESCALE 1 | ||||
#elif F_TIMER == 54000000 | |||||
#define DEFAULT_FTM_MOD (55296 - 1) | |||||
#define DEFAULT_FTM_PRESCALE 1 | |||||
#elif F_TIMER == 48000000 | #elif F_TIMER == 48000000 | ||||
#define DEFAULT_FTM_MOD (49152 - 1) | #define DEFAULT_FTM_MOD (49152 - 1) | ||||
#define DEFAULT_FTM_PRESCALE 1 | #define DEFAULT_FTM_PRESCALE 1 | ||||
#endif | #endif | ||||
//void init_pins(void) | //void init_pins(void) | ||||
__attribute__((noinline)) | |||||
void _init_Teensyduino_internal_(void) | void _init_Teensyduino_internal_(void) | ||||
{ | { | ||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | ||||
FTM3_C0SC = 0x28; | FTM3_C0SC = 0x28; | ||||
FTM3_C1SC = 0x28; | FTM3_C1SC = 0x28; | ||||
FTM3_SC = FTM_SC_CLKS(1) | FTM_SC_PS(DEFAULT_FTM_PRESCALE); | FTM3_SC = FTM_SC_CLKS(1) | FTM_SC_PS(DEFAULT_FTM_PRESCALE); | ||||
#endif | |||||
#if defined(__MK66FX1M0__) | |||||
SIM_SCGC2 |= SIM_SCGC2_TPM1; | |||||
SIM_SOPT2 |= SIM_SOPT2_TPMSRC(2); | |||||
TPM1_CNT = 0; | |||||
TPM1_MOD = 32767; | |||||
TPM1_C0SC = 0x28; | |||||
TPM1_C1SC = 0x28; | |||||
TPM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); | |||||
#endif | #endif | ||||
analog_init(); | analog_init(); | ||||
// for background about this startup delay, please see this conversation | |||||
#if !defined(TEENSY_INIT_USB_DELAY_BEFORE) | |||||
#if TEENSYDUINO >= 142 | |||||
#define TEENSY_INIT_USB_DELAY_BEFORE 25 | |||||
#else | |||||
#define TEENSY_INIT_USB_DELAY_BEFORE 50 | |||||
#endif | |||||
#endif | |||||
#if !defined(TEENSY_INIT_USB_DELAY_AFTER) | |||||
#if TEENSYDUINO >= 142 | |||||
#define TEENSY_INIT_USB_DELAY_AFTER 275 | |||||
#else | |||||
#define TEENSY_INIT_USB_DELAY_AFTER 350 | |||||
#endif | |||||
#endif | |||||
// for background about this startup delay, please see these conversations | |||||
// https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980 | |||||
// https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273 | // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273 | ||||
delay(250); | |||||
delay(TEENSY_INIT_USB_DELAY_BEFORE); | |||||
usb_init(); | usb_init(); | ||||
delay(TEENSY_INIT_USB_DELAY_AFTER); | |||||
} | } | ||||
#define FTM1_CH1_PIN 17 | #define FTM1_CH1_PIN 17 | ||||
#define FTM2_CH0_PIN 3 | #define FTM2_CH0_PIN 3 | ||||
#define FTM2_CH1_PIN 4 | #define FTM2_CH1_PIN 4 | ||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#elif defined(__MK64FX512__) | |||||
#define FTM0_CH0_PIN 22 | |||||
#define FTM0_CH1_PIN 23 | |||||
#define FTM0_CH2_PIN 9 | |||||
#define FTM0_CH3_PIN 10 | |||||
#define FTM0_CH4_PIN 6 | |||||
#define FTM0_CH5_PIN 20 | |||||
#define FTM0_CH6_PIN 21 | |||||
#define FTM0_CH7_PIN 5 | |||||
#define FTM1_CH0_PIN 3 | |||||
#define FTM1_CH1_PIN 4 | |||||
#define FTM2_CH0_PIN 29 | |||||
#define FTM2_CH1_PIN 30 | |||||
#define FTM3_CH0_PIN 2 | |||||
#define FTM3_CH1_PIN 14 | |||||
#define FTM3_CH2_PIN 7 | |||||
#define FTM3_CH3_PIN 8 | |||||
#define FTM3_CH4_PIN 35 | |||||
#define FTM3_CH5_PIN 36 | |||||
#define FTM3_CH6_PIN 37 | |||||
#define FTM3_CH7_PIN 38 | |||||
#elif defined(__MK66FX1M0__) | |||||
#define FTM0_CH0_PIN 22 | #define FTM0_CH0_PIN 22 | ||||
#define FTM0_CH1_PIN 23 | #define FTM0_CH1_PIN 23 | ||||
#define FTM0_CH2_PIN 9 | #define FTM0_CH2_PIN 9 | ||||
#define FTM3_CH5_PIN 36 | #define FTM3_CH5_PIN 36 | ||||
#define FTM3_CH6_PIN 37 | #define FTM3_CH6_PIN 37 | ||||
#define FTM3_CH7_PIN 38 | #define FTM3_CH7_PIN 38 | ||||
#define TPM1_CH0_PIN 16 | |||||
#define TPM1_CH1_PIN 17 | |||||
#endif | #endif | ||||
#define FTM_PINCFG(pin) FTM_PINCFG2(pin) | #define FTM_PINCFG(pin) FTM_PINCFG2(pin) | ||||
#define FTM_PINCFG2(pin) CORE_PIN ## pin ## _CONFIG | #define FTM_PINCFG2(pin) CORE_PIN ## pin ## _CONFIG | ||||
#if defined(FTM2_CH0_PIN) | #if defined(FTM2_CH0_PIN) | ||||
} else if (pin == FTM2_CH0_PIN || pin == FTM2_CH1_PIN) { | } else if (pin == FTM2_CH0_PIN || pin == FTM2_CH1_PIN) { | ||||
cval = ((uint32_t)val * (uint32_t)(FTM2_MOD + 1)) >> analog_write_res; | cval = ((uint32_t)val * (uint32_t)(FTM2_MOD + 1)) >> analog_write_res; | ||||
#endif | |||||
#if defined(FTM3_CH0_PIN) | |||||
} else if (pin == FTM3_CH0_PIN || pin == FTM3_CH1_PIN || pin == FTM3_CH2_PIN | |||||
|| pin == FTM3_CH3_PIN || pin == FTM3_CH4_PIN || pin == FTM3_CH5_PIN | |||||
|| pin == FTM3_CH6_PIN || pin == FTM3_CH7_PIN) { | |||||
cval = ((uint32_t)val * (uint32_t)(FTM3_MOD + 1)) >> analog_write_res; | |||||
#endif | |||||
#if defined(TPM1_CH0_PIN) | |||||
} else if (pin == TPM1_CH0_PIN || pin == TPM1_CH1_PIN) { | |||||
cval = ((uint32_t)val * (uint32_t)(TPM1_MOD + 1)) >> analog_write_res; | |||||
#endif | #endif | ||||
} else { | } else { | ||||
cval = ((uint32_t)val * (uint32_t)(FTM0_MOD + 1)) >> analog_write_res; | cval = ((uint32_t)val * (uint32_t)(FTM0_MOD + 1)) >> analog_write_res; | ||||
FTM3_C7V = cval; | FTM3_C7V = cval; | ||||
FTM_PINCFG(FTM3_CH7_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE; | FTM_PINCFG(FTM3_CH7_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE; | ||||
break; | break; | ||||
#endif | |||||
#ifdef TPM1_CH0_PIN | |||||
case TPM1_CH0_PIN: | |||||
TPM1_C0V = cval; | |||||
FTM_PINCFG(TPM1_CH0_PIN) = PORT_PCR_MUX(6) | PORT_PCR_DSE | PORT_PCR_SRE; | |||||
break; | |||||
#endif | |||||
#ifdef TPM1_CH1_PIN | |||||
case TPM1_CH1_PIN: | |||||
TPM1_C1V = cval; | |||||
FTM_PINCFG(TPM1_CH1_PIN) = PORT_PCR_MUX(6) | PORT_PCR_DSE | PORT_PCR_SRE; | |||||
break; | |||||
#endif | #endif | ||||
default: | default: | ||||
digitalWrite(pin, (val > 127) ? HIGH : LOW); | digitalWrite(pin, (val > 127) ? HIGH : LOW); | ||||
} | } | ||||
void analogWriteRes(uint32_t bits) | |||||
uint32_t analogWriteRes(uint32_t bits) | |||||
{ | { | ||||
uint32_t prior_res; | |||||
if (bits < 1) { | if (bits < 1) { | ||||
bits = 1; | bits = 1; | ||||
} else if (bits > 16) { | } else if (bits > 16) { | ||||
bits = 16; | bits = 16; | ||||
} | } | ||||
prior_res = analog_write_res; | |||||
analog_write_res = bits; | analog_write_res = bits; | ||||
return prior_res; | |||||
} | } | ||||
//serial_print(", freq = "); | //serial_print(", freq = "); | ||||
//serial_phex32((uint32_t)frequency); | //serial_phex32((uint32_t)frequency); | ||||
//serial_print("\n"); | //serial_print("\n"); | ||||
if (frequency < (float)(F_TIMER >> 7) / 65536.0f) { //If frequency is too low for working with F_TIMER: | |||||
ftmClockSource = 2; //Use alternative 31250Hz clock source | |||||
ftmClock = 31250; //Set variable for the actual timer clock frequency | |||||
} else { //Else do as before: | |||||
ftmClockSource = 1; //Use default F_Timer clock source | |||||
ftmClock = F_TIMER; //Set variable for the actual timer clock frequency | |||||
} | |||||
#ifdef TPM1_CH0_PIN | |||||
if (pin == TPM1_CH0_PIN || pin == TPM1_CH1_PIN) { | |||||
ftmClockSource = 1; | |||||
ftmClock = 16000000; | |||||
} else | |||||
#endif | |||||
#if defined(__MKL26Z64__) | |||||
// Teensy LC does not support slow clock source (ftmClockSource = 2) | |||||
ftmClockSource = 1; // Use default F_TIMER clock source | |||||
ftmClock = F_TIMER; // Set variable for the actual timer clock frequency | |||||
#else | |||||
if (frequency < (float)(F_TIMER >> 7) / 65536.0f) { | |||||
// frequency is too low for working with F_TIMER: | |||||
ftmClockSource = 2; // Use alternative 31250Hz clock source | |||||
ftmClock = 31250; // Set variable for the actual timer clock frequency | |||||
} else { | |||||
ftmClockSource = 1; // Use default F_TIMER clock source | |||||
ftmClock = F_TIMER; // Set variable for the actual timer clock frequency | |||||
} | |||||
#endif | |||||
for (prescale = 0; prescale < 7; prescale++) { | for (prescale = 0; prescale < 7; prescale++) { | ||||
FTM3_SC = FTM_SC_CLKS(ftmClockSource) | FTM_SC_PS(prescale); //Use the new ftmClockSource instead of 1 | FTM3_SC = FTM_SC_CLKS(ftmClockSource) | FTM_SC_PS(prescale); //Use the new ftmClockSource instead of 1 | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef TPM1_CH0_PIN | |||||
else if (pin == TPM1_CH0_PIN || pin == TPM1_CH1_PIN) { | |||||
TPM1_SC = 0; | |||||
TPM1_CNT = 0; | |||||
TPM1_MOD = mod; | |||||
TPM1_SC = FTM_SC_CLKS(ftmClockSource) | FTM_SC_PS(prescale); | |||||
} | |||||
#endif | |||||
} | } | ||||
#else | #else | ||||
*portModeRegister(pin) &= ~digitalPinToBitMask(pin); | *portModeRegister(pin) &= ~digitalPinToBitMask(pin); | ||||
#endif | #endif | ||||
if (mode == INPUT || mode == INPUT_PULLUP || mode == INPUT_PULLDOWN) { | |||||
if (mode == INPUT) { | |||||
*config = PORT_PCR_MUX(1); | *config = PORT_PCR_MUX(1); | ||||
if (mode == INPUT_PULLUP) { | |||||
*config |= (PORT_PCR_PE | PORT_PCR_PS); // pullup | |||||
} else if (mode == INPUT_PULLDOWN) { | |||||
*config |= (PORT_PCR_PE); // pulldown | |||||
*config &= ~(PORT_PCR_PS); | |||||
} | |||||
} else { | |||||
*config = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; // pullup | |||||
} else if (mode == INPUT_PULLUP) { | |||||
*config = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; | |||||
} else if (mode == INPUT_PULLDOWN) { | |||||
*config = PORT_PCR_MUX(1) | PORT_PCR_PE; | |||||
} else { // INPUT_DISABLE | |||||
*config = 0; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// TODO: verify these result in correct timeouts... | // TODO: verify these result in correct timeouts... | ||||
#if F_CPU == 192000000 | |||||
#if F_CPU == 256000000 | |||||
#define PULSEIN_LOOPS_PER_USEC 34 | |||||
#elif F_CPU == 240000000 | |||||
#define PULSEIN_LOOPS_PER_USEC 33 | |||||
#elif F_CPU == 216000000 | |||||
#define PULSEIN_LOOPS_PER_USEC 31 | |||||
#elif F_CPU == 192000000 | |||||
#define PULSEIN_LOOPS_PER_USEC 29 | #define PULSEIN_LOOPS_PER_USEC 29 | ||||
#elif F_CPU == 180000000 | #elif F_CPU == 180000000 | ||||
#define PULSEIN_LOOPS_PER_USEC 27 | #define PULSEIN_LOOPS_PER_USEC 27 | ||||
#define PULSEIN_LOOPS_PER_USEC 1 | #define PULSEIN_LOOPS_PER_USEC 1 | ||||
#endif | #endif | ||||
#if defined(KINETISK) | |||||
uint32_t pulseIn_high(volatile uint8_t *reg, uint32_t timeout) | uint32_t pulseIn_high(volatile uint8_t *reg, uint32_t timeout) | ||||
{ | { | ||||
uint32_t timeout_count = timeout * PULSEIN_LOOPS_PER_USEC; | uint32_t timeout_count = timeout * PULSEIN_LOOPS_PER_USEC; | ||||
uint32_t usec_start, usec_stop; | uint32_t usec_start, usec_stop; | ||||
// wait for any previous pulse to end | // wait for any previous pulse to end | ||||
while (*reg) { | while (*reg) { | ||||
if (--timeout_count == 0) return 0; | if (--timeout_count == 0) return 0; | ||||
return pulseIn_low(portInputRegister(pin), timeout);; | return pulseIn_low(portInputRegister(pin), timeout);; | ||||
} | } | ||||
#elif defined(KINETISL) | |||||
// For TeencyLC need to use mask on the input register as the register is shared by several IO pins | |||||
uint32_t pulseIn_high(volatile uint8_t *reg, uint8_t mask, uint32_t timeout) | |||||
{ | |||||
uint32_t timeout_count = timeout * PULSEIN_LOOPS_PER_USEC; | |||||
uint32_t usec_start, usec_stop; | |||||
// wait for any previous pulse to end | |||||
while (*reg & mask) { | |||||
if (--timeout_count == 0) return -1; | |||||
} | |||||
// wait for the pulse to start | |||||
while (!(*reg & mask)) { | |||||
if (--timeout_count == 0) return 0; | |||||
} | |||||
usec_start = micros(); | |||||
// wait for the pulse to stop | |||||
while (*reg & mask) { | |||||
if (--timeout_count == 0) return 0; | |||||
} | |||||
usec_stop = micros(); | |||||
return usec_stop - usec_start; | |||||
} | |||||
uint32_t pulseIn_low(volatile uint8_t *reg, uint8_t mask, uint32_t timeout) | |||||
{ | |||||
uint32_t timeout_count = timeout * PULSEIN_LOOPS_PER_USEC; | |||||
uint32_t usec_start, usec_stop; | |||||
// wait for any previous pulse to end | |||||
while (!(*reg & mask)) { | |||||
if (--timeout_count == 0) return 0; | |||||
} | |||||
// wait for the pulse to start | |||||
while (*reg & mask) { | |||||
if (--timeout_count == 0) return 0; | |||||
} | |||||
usec_start = micros(); | |||||
// wait for the pulse to stop | |||||
while (!(*reg & mask)) { | |||||
if (--timeout_count == 0) return 0; | |||||
} | |||||
usec_stop = micros(); | |||||
return usec_stop - usec_start; | |||||
} | |||||
// TODO: an inline version should handle the common case where state is const | |||||
uint32_t pulseIn(uint8_t pin, uint8_t state, uint32_t timeout) | |||||
{ | |||||
if (pin >= CORE_NUM_DIGITAL) return 0; | |||||
if (state) return pulseIn_high(portInputRegister(pin), digitalPinToBitMask(pin), timeout); | |||||
return pulseIn_low(portInputRegister(pin), digitalPinToBitMask(pin), timeout);; | |||||
} | |||||
#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 "kinetis.h" | #include "kinetis.h" | ||||
#include "ser_print.h" | #include "ser_print.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. | |||||
*/ | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
extern "C"{ | extern "C"{ |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
// Tunable parameters (relatively safe to edit these numbers) | // Tunable parameters (relatively safe to edit these numbers) | ||||
//////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////// | ||||
#define TX_BUFFER_SIZE 64 // number of outgoing bytes to buffer | |||||
#define RX_BUFFER_SIZE 64 // number of incoming bytes to buffer | |||||
#define RTS_HIGH_WATERMARK 40 // RTS requests sender to pause | |||||
#define RTS_LOW_WATERMARK 26 // RTS allows sender to resume | |||||
#ifndef SERIAL1_TX_BUFFER_SIZE | |||||
#define SERIAL1_TX_BUFFER_SIZE 64 // number of outgoing bytes to buffer | |||||
#endif | |||||
#ifndef SERIAL1_RX_BUFFER_SIZE | |||||
#define SERIAL1_RX_BUFFER_SIZE 64 // number of incoming bytes to buffer | |||||
#endif | |||||
#define RTS_HIGH_WATERMARK (SERIAL1_RX_BUFFER_SIZE-24) // RTS requests sender to pause | |||||
#define RTS_LOW_WATERMARK (SERIAL1_RX_BUFFER_SIZE-38) // RTS allows sender to resume | |||||
#define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest | #define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest | ||||
#define use9Bits 0 | #define use9Bits 0 | ||||
#endif | #endif | ||||
static volatile BUFTYPE tx_buffer[TX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE rx_buffer[RX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE tx_buffer[SERIAL1_TX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE rx_buffer[SERIAL1_RX_BUFFER_SIZE]; | |||||
static volatile uint8_t transmitting = 0; | static volatile uint8_t transmitting = 0; | ||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
static volatile uint8_t *transmit_pin=NULL; | static volatile uint8_t *transmit_pin=NULL; | ||||
#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 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 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 21: CORE_PIN21_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | case 21: CORE_PIN21_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | ||||
#if defined(KINETISL) | #if defined(KINETISL) | ||||
case 3: CORE_PIN3_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(2); break; | case 3: CORE_PIN3_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(2); break; | ||||
case 25: CORE_PIN25_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(4); break; | |||||
#endif | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
case 27: CORE_PIN27_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | |||||
#endif | #endif | ||||
} | } | ||||
switch (tx_pin_num) { | switch (tx_pin_num) { | ||||
case 5: CORE_PIN5_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); break; | case 5: CORE_PIN5_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); break; | ||||
#if defined(KINETISL) | #if defined(KINETISL) | ||||
case 4: CORE_PIN4_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(2); break; | case 4: CORE_PIN4_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(2); break; | ||||
case 24: CORE_PIN24_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(4); break; | |||||
#endif | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
case 26: CORE_PIN26_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); break; | |||||
#endif | #endif | ||||
} | } | ||||
#if defined(HAS_KINETISK_UART0) | #if defined(HAS_KINETISK_UART0) | ||||
if (divisor < 32) divisor = 32; | |||||
UART0_BDH = (divisor >> 13) & 0x1F; | UART0_BDH = (divisor >> 13) & 0x1F; | ||||
UART0_BDL = (divisor >> 5) & 0xFF; | UART0_BDL = (divisor >> 5) & 0xFF; | ||||
UART0_C4 = divisor & 0x1F; | UART0_C4 = divisor & 0x1F; | ||||
UART0_PFIFO = 0; | UART0_PFIFO = 0; | ||||
#endif | #endif | ||||
#elif defined(HAS_KINETISL_UART0) | #elif defined(HAS_KINETISL_UART0) | ||||
if (divisor < 1) divisor = 1; | |||||
UART0_BDH = (divisor >> 8) & 0x1F; | UART0_BDH = (divisor >> 8) & 0x1F; | ||||
UART0_BDL = divisor & 0xFF; | UART0_BDL = divisor & 0xFF; | ||||
UART0_C1 = 0; | UART0_C1 = 0; | ||||
UART0_C4 = c; | UART0_C4 = c; | ||||
use9Bits = format & 0x80; | use9Bits = format & 0x80; | ||||
#endif | #endif | ||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(KINETISL) | |||||
// For T3.5/T3.6/TLC See about turning on 2 stop bit mode | |||||
if ( format & 0x100) { | |||||
uint8_t bdl = UART0_BDL; | |||||
UART0_BDH |= UART_BDH_SBNS; // Turn on 2 stop bits - was turned off by set baud | |||||
UART0_BDL = bdl; // Says BDH not acted on until BDL is written | |||||
} | |||||
#endif | |||||
} | } | ||||
void serial_end(void) | void serial_end(void) | ||||
while (transmitting) yield(); // wait for buffered data to send | while (transmitting) yield(); // wait for buffered data to send | ||||
NVIC_DISABLE_IRQ(IRQ_UART0_STATUS); | NVIC_DISABLE_IRQ(IRQ_UART0_STATUS); | ||||
UART0_C2 = 0; | UART0_C2 = 0; | ||||
CORE_PIN0_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||||
CORE_PIN1_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||||
switch (rx_pin_num) { | |||||
case 0: CORE_PIN0_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||||
case 21: CORE_PIN21_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||||
#if defined(KINETISL) | |||||
case 3: CORE_PIN3_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||||
case 25: CORE_PIN25_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||||
#endif | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
case 27: CORE_PIN27_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||||
#endif | |||||
} | |||||
switch (tx_pin_num & 127) { | |||||
case 1: CORE_PIN1_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||||
case 5: CORE_PIN5_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||||
#if defined(KINETISL) | |||||
case 4: CORE_PIN4_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||||
case 24: CORE_PIN24_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||||
#endif | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
case 26: CORE_PIN26_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||||
#endif | |||||
} | |||||
UART0_S1; | |||||
UART0_D; // clear leftover error status | |||||
rx_buffer_head = 0; | rx_buffer_head = 0; | ||||
rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); | ||||
case 5: CORE_PIN5_CONFIG = 0; break; // PTD7 | case 5: CORE_PIN5_CONFIG = 0; break; // PTD7 | ||||
#if defined(KINETISL) | #if defined(KINETISL) | ||||
case 4: CORE_PIN4_CONFIG = 0; break; // PTA2 | case 4: CORE_PIN4_CONFIG = 0; break; // PTA2 | ||||
case 24: CORE_PIN24_CONFIG = 0; break; // PTE20 | |||||
#endif | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
case 26: CORE_PIN26_CONFIG = 0; break; //PTA14 | |||||
#endif | #endif | ||||
} | } | ||||
if (opendrain) { | if (opendrain) { | ||||
case 5: CORE_PIN5_CONFIG = cfg | PORT_PCR_MUX(3); break; | case 5: CORE_PIN5_CONFIG = cfg | PORT_PCR_MUX(3); break; | ||||
#if defined(KINETISL) | #if defined(KINETISL) | ||||
case 4: CORE_PIN4_CONFIG = cfg | PORT_PCR_MUX(2); break; | case 4: CORE_PIN4_CONFIG = cfg | PORT_PCR_MUX(2); break; | ||||
case 24: CORE_PIN24_CONFIG = cfg | PORT_PCR_MUX(4); break; | |||||
#endif | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
case 26: CORE_PIN26_CONFIG = cfg | PORT_PCR_MUX(3); break; | |||||
#endif | #endif | ||||
} | } | ||||
} | } | ||||
case 21: CORE_PIN21_CONFIG = 0; break; // PTD6 | case 21: CORE_PIN21_CONFIG = 0; break; // PTD6 | ||||
#if defined(KINETISL) | #if defined(KINETISL) | ||||
case 3: CORE_PIN3_CONFIG = 0; break; // PTA1 | case 3: CORE_PIN3_CONFIG = 0; break; // PTA1 | ||||
case 25: CORE_PIN25_CONFIG = 0; break; // PTE21 | |||||
#endif | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
case 27: CORE_PIN27_CONFIG = 0; break; // PTA15 | |||||
#endif | #endif | ||||
} | } | ||||
switch (pin) { | switch (pin) { | ||||
case 21: CORE_PIN21_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | case 21: CORE_PIN21_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | ||||
#if defined(KINETISL) | #if defined(KINETISL) | ||||
case 3: CORE_PIN3_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(2); break; | case 3: CORE_PIN3_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(2); break; | ||||
case 25: CORE_PIN25_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(4); break; | |||||
#endif | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
case 27: CORE_PIN27_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | |||||
#endif | #endif | ||||
} | } | ||||
} | } | ||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return; | if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return; | ||||
if (transmit_pin) transmit_assert(); | if (transmit_pin) transmit_assert(); | ||||
head = tx_buffer_head; | head = tx_buffer_head; | ||||
if (++head >= TX_BUFFER_SIZE) head = 0; | |||||
if (++head >= SERIAL1_TX_BUFFER_SIZE) head = 0; | |||||
while (tx_buffer_tail == head) { | while (tx_buffer_tail == head) { | ||||
int priority = nvic_execution_priority(); | int priority = nvic_execution_priority(); | ||||
if (priority <= IRQ_PRIORITY) { | if (priority <= IRQ_PRIORITY) { | ||||
if ((UART0_S1 & UART_S1_TDRE)) { | if ((UART0_S1 & UART_S1_TDRE)) { | ||||
uint32_t tail = tx_buffer_tail; | uint32_t tail = tx_buffer_tail; | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL1_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
UART0_D = n; | UART0_D = n; | ||||
if (transmit_pin) transmit_assert(); | if (transmit_pin) transmit_assert(); | ||||
while (p < end) { | while (p < end) { | ||||
head = tx_buffer_head; | head = tx_buffer_head; | ||||
if (++head >= TX_BUFFER_SIZE) head = 0; | |||||
if (++head >= SERIAL1_TX_BUFFER_SIZE) head = 0; | |||||
if (tx_buffer_tail == head) { | if (tx_buffer_tail == head) { | ||||
UART0_C2 = C2_TX_ACTIVE; | UART0_C2 = C2_TX_ACTIVE; | ||||
do { | do { | ||||
if (priority <= IRQ_PRIORITY) { | if (priority <= IRQ_PRIORITY) { | ||||
if ((UART0_S1 & UART_S1_TDRE)) { | if ((UART0_S1 & UART_S1_TDRE)) { | ||||
uint32_t tail = tx_buffer_tail; | uint32_t tail = tx_buffer_tail; | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL1_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
UART0_D = n; | UART0_D = n; | ||||
head = tx_buffer_head; | head = tx_buffer_head; | ||||
tail = tx_buffer_tail; | tail = tx_buffer_tail; | ||||
if (head >= tail) return TX_BUFFER_SIZE - 1 - head + tail; | |||||
if (head >= tail) return SERIAL1_TX_BUFFER_SIZE - 1 - head + tail; | |||||
return tail - head - 1; | return tail - head - 1; | ||||
} | } | ||||
head = rx_buffer_head; | head = rx_buffer_head; | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
if (head >= tail) return head - tail; | if (head >= tail) return head - tail; | ||||
return RX_BUFFER_SIZE + head - tail; | |||||
return SERIAL1_RX_BUFFER_SIZE + head - tail; | |||||
} | } | ||||
int serial_getchar(void) | int serial_getchar(void) | ||||
head = rx_buffer_head; | head = rx_buffer_head; | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
if (head == tail) return -1; | if (head == tail) return -1; | ||||
if (++tail >= RX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL1_RX_BUFFER_SIZE) tail = 0; | |||||
c = rx_buffer[tail]; | c = rx_buffer[tail]; | ||||
rx_buffer_tail = tail; | rx_buffer_tail = tail; | ||||
if (rts_pin) { | if (rts_pin) { | ||||
int avail; | int avail; | ||||
if (head >= tail) avail = head - tail; | if (head >= tail) avail = head - tail; | ||||
else avail = RX_BUFFER_SIZE + head - tail; | |||||
else avail = SERIAL1_RX_BUFFER_SIZE + head - tail; | |||||
if (avail <= RTS_LOW_WATERMARK) rts_assert(); | if (avail <= RTS_LOW_WATERMARK) rts_assert(); | ||||
} | } | ||||
return c; | return c; | ||||
head = rx_buffer_head; | head = rx_buffer_head; | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
if (head == tail) return -1; | if (head == tail) return -1; | ||||
if (++tail >= RX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL1_RX_BUFFER_SIZE) tail = 0; | |||||
return rx_buffer[tail]; | return rx_buffer[tail]; | ||||
} | } | ||||
if (rts_pin) rts_assert(); | if (rts_pin) rts_assert(); | ||||
} | } | ||||
// status interrupt combines | |||||
// status interrupt combines | |||||
// Transmit data below watermark UART_S1_TDRE | // Transmit data below watermark UART_S1_TDRE | ||||
// Transmit complete UART_S1_TC | // Transmit complete UART_S1_TC | ||||
// Idle line UART_S1_IDLE | // Idle line UART_S1_IDLE | ||||
n = UART0_D; | n = UART0_D; | ||||
} | } | ||||
newhead = head + 1; | newhead = head + 1; | ||||
if (newhead >= RX_BUFFER_SIZE) newhead = 0; | |||||
if (newhead >= SERIAL1_RX_BUFFER_SIZE) newhead = 0; | |||||
if (newhead != tail) { | if (newhead != tail) { | ||||
head = newhead; | head = newhead; | ||||
rx_buffer[head] = n; | rx_buffer[head] = n; | ||||
if (rts_pin) { | if (rts_pin) { | ||||
int avail; | int avail; | ||||
if (head >= tail) avail = head - tail; | if (head >= tail) avail = head - tail; | ||||
else avail = RX_BUFFER_SIZE + head - tail; | |||||
else avail = SERIAL1_RX_BUFFER_SIZE + head - tail; | |||||
if (avail >= RTS_HIGH_WATERMARK) rts_deassert(); | if (avail >= RTS_HIGH_WATERMARK) rts_deassert(); | ||||
} | } | ||||
} | } | ||||
tail = tx_buffer_tail; | tail = tx_buffer_tail; | ||||
do { | do { | ||||
if (tail == head) break; | if (tail == head) break; | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL1_TX_BUFFER_SIZE) tail = 0; | |||||
avail = UART0_S1; | avail = UART0_S1; | ||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
} | } | ||||
#else | #else | ||||
if (UART0_S1 & UART_S1_RDRF) { | if (UART0_S1 & UART_S1_RDRF) { | ||||
n = UART0_D; | |||||
if (use9Bits && (UART0_C3 & 0x80)) n |= 0x100; | |||||
if (use9Bits && (UART0_C3 & 0x80)) { | |||||
n = UART0_D | 0x100; | |||||
} else { | |||||
n = UART0_D; | |||||
} | |||||
head = rx_buffer_head + 1; | head = rx_buffer_head + 1; | ||||
if (head >= RX_BUFFER_SIZE) head = 0; | |||||
if (head >= SERIAL1_RX_BUFFER_SIZE) head = 0; | |||||
if (head != rx_buffer_tail) { | if (head != rx_buffer_tail) { | ||||
rx_buffer[head] = n; | rx_buffer[head] = n; | ||||
rx_buffer_head = head; | rx_buffer_head = head; | ||||
if (head == tail) { | if (head == tail) { | ||||
UART0_C2 = C2_TX_COMPLETING; | UART0_C2 = C2_TX_COMPLETING; | ||||
} else { | } else { | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL1_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
UART0_D = n; | UART0_D = n; |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
// Tunable parameters (relatively safe to edit these numbers) | // Tunable parameters (relatively safe to edit these numbers) | ||||
//////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////// | ||||
#define TX_BUFFER_SIZE 64 // number of outgoing bytes to buffer | |||||
#define RX_BUFFER_SIZE 64 // number of incoming bytes to buffer | |||||
#ifndef SERIAL1_TX_BUFFER_SIZE | |||||
#define SERIAL1_TX_BUFFER_SIZE 64 // number of outgoing bytes to buffer | |||||
#endif | |||||
#ifndef SERIAL1_RX_BUFFER_SIZE | |||||
#define SERIAL1_RX_BUFFER_SIZE 64 // number of incoming bytes to buffer | |||||
#endif | |||||
#define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest | #define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest | ||||
#define use9Bits 0 | #define use9Bits 0 | ||||
#endif | #endif | ||||
static volatile BUFTYPE tx_buffer[TX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE rx_buffer[RX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE tx_buffer[SERIAL1_TX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE rx_buffer[SERIAL1_RX_BUFFER_SIZE]; | |||||
static volatile uint8_t transmitting = 0; | static volatile uint8_t transmitting = 0; | ||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
static volatile uint8_t *transmit_pin=NULL; | static volatile uint8_t *transmit_pin=NULL; | ||||
#define transmit_assert() *(transmit_pin+4) = transmit_mask; | #define transmit_assert() *(transmit_pin+4) = transmit_mask; | ||||
#define transmit_deassert() *(transmit_pin+8) = transmit_mask; | #define transmit_deassert() *(transmit_pin+8) = transmit_mask; | ||||
#endif | #endif | ||||
#if TX_BUFFER_SIZE > 255 | |||||
#if 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 RX_BUFFER_SIZE > 255 | |||||
#if 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 | ||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return; | if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return; | ||||
if (transmit_pin) transmit_assert(); | if (transmit_pin) transmit_assert(); | ||||
head = tx_buffer_head; | head = tx_buffer_head; | ||||
if (++head >= TX_BUFFER_SIZE) head = 0; | |||||
if (++head >= SERIAL1_TX_BUFFER_SIZE) head = 0; | |||||
while (tx_buffer_tail == head) { | while (tx_buffer_tail == head) { | ||||
int priority = nvic_execution_priority(); | int priority = nvic_execution_priority(); | ||||
if (priority <= IRQ_PRIORITY) { | if (priority <= IRQ_PRIORITY) { | ||||
if ((UART0_S1 & UART_S1_TDRE)) { | if ((UART0_S1 & UART_S1_TDRE)) { | ||||
uint32_t tail = tx_buffer_tail; | uint32_t tail = tx_buffer_tail; | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL1_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
UART0_D = n; | UART0_D = n; | ||||
if (transmit_pin) transmit_assert(); | if (transmit_pin) transmit_assert(); | ||||
while (p < end) { | while (p < end) { | ||||
head = tx_buffer_head; | head = tx_buffer_head; | ||||
if (++head >= TX_BUFFER_SIZE) head = 0; | |||||
if (++head >= SERIAL1_TX_BUFFER_SIZE) head = 0; | |||||
if (tx_buffer_tail == head) { | if (tx_buffer_tail == head) { | ||||
UART0_C2 |= UART_C2_TIE; | UART0_C2 |= UART_C2_TIE; | ||||
UART0_C2 &= ~UART_C2_TCIE; | UART0_C2 &= ~UART_C2_TCIE; | ||||
if (priority <= IRQ_PRIORITY) { | if (priority <= IRQ_PRIORITY) { | ||||
if ((UART0_S1 & UART_S1_TDRE)) { | if ((UART0_S1 & UART_S1_TDRE)) { | ||||
uint32_t tail = tx_buffer_tail; | uint32_t tail = tx_buffer_tail; | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL1_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
UART0_D = n; | UART0_D = n; | ||||
head = tx_buffer_head; | head = tx_buffer_head; | ||||
tail = tx_buffer_tail; | tail = tx_buffer_tail; | ||||
if (head >= tail) return TX_BUFFER_SIZE - 1 - head + tail; | |||||
if (head >= tail) return SERIAL1_TX_BUFFER_SIZE - 1 - head + tail; | |||||
return tail - head - 1; | return tail - head - 1; | ||||
} | } | ||||
head = rx_buffer_head; | head = rx_buffer_head; | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
if (head >= tail) return head - tail; | if (head >= tail) return head - tail; | ||||
return RX_BUFFER_SIZE + head - tail; | |||||
return SERIAL1_RX_BUFFER_SIZE + head - tail; | |||||
} | } | ||||
int serial_getchar(void) | int serial_getchar(void) | ||||
head = rx_buffer_head; | head = rx_buffer_head; | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
if (head == tail) return -1; | if (head == tail) return -1; | ||||
if (++tail >= RX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL1_RX_BUFFER_SIZE) tail = 0; | |||||
c = rx_buffer[tail]; | c = rx_buffer[tail]; | ||||
rx_buffer_tail = tail; | rx_buffer_tail = tail; | ||||
#ifdef HAS_KINETISK_UART0_FIFO | #ifdef HAS_KINETISK_UART0_FIFO | ||||
if ((UART0_C2 & (UART_C2_RIE | UART_C2_ILIE))==0) {//rx interrupt currently disabled | if ((UART0_C2 & (UART_C2_RIE | UART_C2_ILIE))==0) {//rx interrupt currently disabled | ||||
int freespace; | int freespace; | ||||
if (head >= tail) //rx head and tail would be unchanged from above if interrupts were disabled | if (head >= tail) //rx head and tail would be unchanged from above if interrupts were disabled | ||||
freespace = RX_BUFFER_SIZE -1 + tail - head; | |||||
freespace = SERIAL1_RX_BUFFER_SIZE -1 + tail - head; | |||||
else | else | ||||
freespace = tail - head - 1; | freespace = tail - head - 1; | ||||
if (freespace >= UART0_RCFIFO) { | if (freespace >= UART0_RCFIFO) { | ||||
head = rx_buffer_head; | head = rx_buffer_head; | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
if (head == tail) return -1; | if (head == tail) return -1; | ||||
if (++tail >= RX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL1_RX_BUFFER_SIZE) tail = 0; | |||||
return rx_buffer[tail]; | return rx_buffer[tail]; | ||||
} | } | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
do { | do { | ||||
newhead = head + 1; | newhead = head + 1; | ||||
if (newhead >= RX_BUFFER_SIZE) newhead = 0; | |||||
if (newhead >= SERIAL1_RX_BUFFER_SIZE) newhead = 0; | |||||
if (UART0_MODEM & UART_MODEM_RXRTSE) { | if (UART0_MODEM & UART_MODEM_RXRTSE) { | ||||
if (newhead == tail) { | if (newhead == tail) { | ||||
UART0_C2 &= ~(UART_C2_RIE | UART_C2_ILIE);//disable rx interrupts | UART0_C2 &= ~(UART_C2_RIE | UART_C2_ILIE);//disable rx interrupts | ||||
tail = tx_buffer_tail; | tail = tx_buffer_tail; | ||||
do { | do { | ||||
if (tail == head) break; | if (tail == head) break; | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL1_TX_BUFFER_SIZE) tail = 0; | |||||
UART0_S1; | UART0_S1; | ||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
if (UART0_S1 & UART_S1_RDRF) { | if (UART0_S1 & UART_S1_RDRF) { | ||||
do { | do { | ||||
head = rx_buffer_head + 1; | head = rx_buffer_head + 1; | ||||
if (head >= RX_BUFFER_SIZE) head = 0; | |||||
if (head >= SERIAL1_RX_BUFFER_SIZE) head = 0; | |||||
if (UART0_MODEM & UART_MODEM_RXRTSE) { | if (UART0_MODEM & UART_MODEM_RXRTSE) { | ||||
if (head == rx_buffer_tail) { | if (head == rx_buffer_tail) { | ||||
UART0_C2 &= ~(UART_C2_RIE);//disable rx interrupts | UART0_C2 &= ~(UART_C2_RIE);//disable rx interrupts | ||||
UART0_C2 |= UART_C2_TCIE; | UART0_C2 |= UART_C2_TCIE; | ||||
UART0_C2 &= ~UART_C2_TIE; | UART0_C2 &= ~UART_C2_TIE; | ||||
} else { | } else { | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL1_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
UART0_D = n; | UART0_D = n; |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
// Tunable parameters (relatively safe to edit these numbers) | // Tunable parameters (relatively safe to edit these numbers) | ||||
//////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////// | ||||
#define TX_BUFFER_SIZE 40 // number of outgoing bytes to buffer | |||||
#define RX_BUFFER_SIZE 64 // number of incoming bytes to buffer | |||||
#define RTS_HIGH_WATERMARK 40 // RTS requests sender to pause | |||||
#define RTS_LOW_WATERMARK 26 // RTS allows sender to resume | |||||
#ifndef SERIAL2_TX_BUFFER_SIZE | |||||
#define SERIAL2_TX_BUFFER_SIZE 40 // number of outgoing bytes to buffer | |||||
#endif | |||||
#ifndef SERIAL2_RX_BUFFER_SIZE | |||||
#define SERIAL2_RX_BUFFER_SIZE 64 // number of incoming bytes to buffer | |||||
#endif | |||||
#define RTS_HIGH_WATERMARK (SERIAL2_RX_BUFFER_SIZE-24) // RTS requests sender to pause | |||||
#define RTS_LOW_WATERMARK (SERIAL2_RX_BUFFER_SIZE-38) // RTS allows sender to resume | |||||
#define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest | #define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest | ||||
//////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////// | ||||
#define use9Bits 0 | #define use9Bits 0 | ||||
#endif | #endif | ||||
static volatile BUFTYPE tx_buffer[TX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE rx_buffer[RX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE tx_buffer[SERIAL2_TX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE rx_buffer[SERIAL2_RX_BUFFER_SIZE]; | |||||
static volatile uint8_t transmitting = 0; | static volatile uint8_t transmitting = 0; | ||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
static volatile uint8_t *transmit_pin=NULL; | static volatile uint8_t *transmit_pin=NULL; | ||||
#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 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 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 | ||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
switch (rx_pin_num) { | switch (rx_pin_num) { | ||||
case 9: CORE_PIN9_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | case 9: CORE_PIN9_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | ||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) // T3.0, T3.1, T3.2 | |||||
case 26: CORE_PIN26_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | case 26: CORE_PIN26_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | ||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) // T3.5 or T3.6 | |||||
case 59: CORE_PIN59_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | |||||
#endif | |||||
} | } | ||||
switch (tx_pin_num) { | switch (tx_pin_num) { | ||||
case 10: CORE_PIN10_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); break; | case 10: CORE_PIN10_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); break; | ||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) // T3.0, T3.1, T3.2 | |||||
case 31: CORE_PIN31_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); break; | case 31: CORE_PIN31_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); break; | ||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) // T3.5 or T3.6 | |||||
case 58: CORE_PIN58_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); break; | |||||
#endif | |||||
} | } | ||||
#elif defined(KINETISL) | #elif defined(KINETISL) | ||||
CORE_PIN9_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); | CORE_PIN9_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); | ||||
CORE_PIN10_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); | CORE_PIN10_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); | ||||
#endif | #endif | ||||
#if defined(HAS_KINETISK_UART1) | #if defined(HAS_KINETISK_UART1) | ||||
if (divisor < 32) divisor = 32; | |||||
UART1_BDH = (divisor >> 13) & 0x1F; | UART1_BDH = (divisor >> 13) & 0x1F; | ||||
UART1_BDL = (divisor >> 5) & 0xFF; | UART1_BDL = (divisor >> 5) & 0xFF; | ||||
UART1_C4 = divisor & 0x1F; | UART1_C4 = divisor & 0x1F; | ||||
UART1_PFIFO = 0; | UART1_PFIFO = 0; | ||||
#endif | #endif | ||||
#elif defined(HAS_KINETISL_UART1) | #elif defined(HAS_KINETISL_UART1) | ||||
if (divisor < 1) divisor = 1; | |||||
UART1_BDH = (divisor >> 8) & 0x1F; | UART1_BDH = (divisor >> 8) & 0x1F; | ||||
UART1_BDL = divisor & 0xFF; | UART1_BDL = divisor & 0xFF; | ||||
UART1_C1 = 0; | UART1_C1 = 0; | ||||
c = UART1_C3 & ~0x10; | c = UART1_C3 & ~0x10; | ||||
if (format & 0x20) c |= 0x10; // tx invert | if (format & 0x20) c |= 0x10; // tx invert | ||||
UART1_C3 = c; | UART1_C3 = c; | ||||
#ifdef SERIAL_9BIT_SUPPORT | |||||
#if defined(SERIAL_9BIT_SUPPORT) && !defined(KINETISL) | |||||
c = UART1_C4 & 0x1F; | c = UART1_C4 & 0x1F; | ||||
if (format & 0x08) c |= 0x20; // 9 bit mode with parity (requires 10 bits) | if (format & 0x08) c |= 0x20; // 9 bit mode with parity (requires 10 bits) | ||||
UART1_C4 = c; | UART1_C4 = c; | ||||
use9Bits = format & 0x80; | use9Bits = format & 0x80; | ||||
#endif | #endif | ||||
// UART1_C1.0 = parity, 0=even, 1=odd | |||||
// UART1_C1.1 = parity, 0=disable, 1=enable | |||||
// UART1_C1.4 = mode, 1=9bit, 0=8bit | |||||
// UART1_C4.5 = mode, 1=10bit, 0=8bit | |||||
// UART1_C3.4 = txinv, 0=normal, 1=inverted | |||||
// UART1_S2.4 = rxinv, 0=normal, 1=inverted | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(KINETISL) | |||||
// For T3.5/T3.6/TLC See about turning on 2 stop bit mode | |||||
if ( format & 0x100) { | |||||
uint8_t bdl = UART1_BDL; | |||||
UART1_BDH |= UART_BDH_SBNS; // Turn on 2 stop bits - was turned off by set baud | |||||
UART1_BDL = bdl; // Says BDH not acted on until BDL is written | |||||
} | |||||
#endif | |||||
} | } | ||||
void serial2_end(void) | void serial2_end(void) | ||||
while (transmitting) yield(); // wait for buffered data to send | while (transmitting) yield(); // wait for buffered data to send | ||||
NVIC_DISABLE_IRQ(IRQ_UART1_STATUS); | NVIC_DISABLE_IRQ(IRQ_UART1_STATUS); | ||||
UART1_C2 = 0; | UART1_C2 = 0; | ||||
CORE_PIN9_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||||
CORE_PIN10_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||||
#if defined(KINETISK) | |||||
switch (rx_pin_num) { | |||||
case 9: CORE_PIN9_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; // PTC3 | |||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) // T3.0, T3.1, T3.2 | |||||
case 26: CORE_PIN26_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; // PTE1 | |||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) // T3.5, T3.6 | |||||
case 59: CORE_PIN59_CONFIG = 0; break; | |||||
#endif | |||||
} | |||||
switch (tx_pin_num & 127) { | |||||
case 10: CORE_PIN10_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; // PTC4 | |||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) // T3.0, T3.1, T3.2 | |||||
case 31: CORE_PIN31_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; // PTE0 | |||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) // T3.5, T3.6 | |||||
case 58: CORE_PIN58_CONFIG = 0; break; | |||||
#endif | |||||
} | |||||
#elif defined(KINETISL) | |||||
CORE_PIN9_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); // PTC3 | |||||
CORE_PIN10_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); // PTC4 | |||||
#endif | |||||
UART1_S1; | |||||
UART1_D; // clear leftover error status | |||||
rx_buffer_head = 0; | rx_buffer_head = 0; | ||||
rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); | ||||
if (opendrain) pin |= 128; | if (opendrain) pin |= 128; | ||||
if (pin == tx_pin_num) return; | if (pin == tx_pin_num) return; | ||||
if ((SIM_SCGC4 & SIM_SCGC4_UART2)) { | |||||
if ((SIM_SCGC4 & SIM_SCGC4_UART1)) { | |||||
switch (tx_pin_num & 127) { | switch (tx_pin_num & 127) { | ||||
case 10: CORE_PIN10_CONFIG = 0; break; // PTC4 | case 10: CORE_PIN10_CONFIG = 0; break; // PTC4 | ||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) // T3.0, T3.1, T3.2 | |||||
case 31: CORE_PIN31_CONFIG = 0; break; // PTE0 | case 31: CORE_PIN31_CONFIG = 0; break; // PTE0 | ||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) // T3.5, T3.6 | |||||
case 58: CORE_PIN58_CONFIG = 0; break; | |||||
#endif | |||||
} | } | ||||
if (opendrain) { | if (opendrain) { | ||||
cfg = PORT_PCR_DSE | PORT_PCR_ODE; | cfg = PORT_PCR_DSE | PORT_PCR_ODE; | ||||
} | } | ||||
switch (pin & 127) { | switch (pin & 127) { | ||||
case 10: CORE_PIN10_CONFIG = cfg | PORT_PCR_MUX(3); break; | case 10: CORE_PIN10_CONFIG = cfg | PORT_PCR_MUX(3); break; | ||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) // T3.0, T3.1, T3.2 | |||||
case 31: CORE_PIN31_CONFIG = cfg | PORT_PCR_MUX(3); break; | case 31: CORE_PIN31_CONFIG = cfg | PORT_PCR_MUX(3); break; | ||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) // T3.5, T3.6 | |||||
case 58: CORE_PIN58_CONFIG = cfg | PORT_PCR_MUX(3); break; | |||||
#endif | |||||
} | } | ||||
} | } | ||||
tx_pin_num = pin; | tx_pin_num = pin; | ||||
{ | { | ||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
if (pin == rx_pin_num) return; | if (pin == rx_pin_num) return; | ||||
if ((SIM_SCGC4 & SIM_SCGC4_UART2)) { | |||||
if ((SIM_SCGC4 & SIM_SCGC4_UART1)) { | |||||
switch (rx_pin_num) { | switch (rx_pin_num) { | ||||
case 9: CORE_PIN9_CONFIG = 0; break; // PTC3 | case 9: CORE_PIN9_CONFIG = 0; break; // PTC3 | ||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) // T3.0, T3.1, T3.2 | |||||
case 26: CORE_PIN26_CONFIG = 0; break; // PTE1 | case 26: CORE_PIN26_CONFIG = 0; break; // PTE1 | ||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) // T3.5, T3.6 | |||||
case 59: CORE_PIN59_CONFIG = 0; break; | |||||
#endif | |||||
} | } | ||||
switch (pin) { | switch (pin) { | ||||
case 9: CORE_PIN9_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | case 9: CORE_PIN9_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | ||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) // T3.0, T3.1, T3.2 | |||||
case 26: CORE_PIN26_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | case 26: CORE_PIN26_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | ||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) // T3.5, T3.6 | |||||
case 59: CORE_PIN59_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | |||||
#endif | |||||
} | } | ||||
} | } | ||||
rx_pin_num = pin; | rx_pin_num = pin; | ||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART1)) return 0; | if (!(SIM_SCGC4 & SIM_SCGC4_UART1)) return 0; | ||||
if (pin == 23) { | if (pin == 23) { | ||||
CORE_PIN23_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_PE; // weak pulldown | CORE_PIN23_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_PE; // weak pulldown | ||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) // on T3.5 or T3.6 | |||||
} else if (pin == 60) { | |||||
CORE_PIN60_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_PE; // weak pulldown | |||||
#endif | |||||
} else { | } else { | ||||
UART1_MODEM &= ~UART_MODEM_TXCTSE; | UART1_MODEM &= ~UART_MODEM_TXCTSE; | ||||
return 0; | return 0; | ||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART1)) return; | if (!(SIM_SCGC4 & SIM_SCGC4_UART1)) return; | ||||
if (transmit_pin) transmit_assert(); | if (transmit_pin) transmit_assert(); | ||||
head = tx_buffer_head; | head = tx_buffer_head; | ||||
if (++head >= TX_BUFFER_SIZE) head = 0; | |||||
if (++head >= SERIAL2_TX_BUFFER_SIZE) head = 0; | |||||
while (tx_buffer_tail == head) { | while (tx_buffer_tail == head) { | ||||
int priority = nvic_execution_priority(); | int priority = nvic_execution_priority(); | ||||
if (priority <= IRQ_PRIORITY) { | if (priority <= IRQ_PRIORITY) { | ||||
if ((UART1_S1 & UART_S1_TDRE)) { | if ((UART1_S1 & UART_S1_TDRE)) { | ||||
uint32_t tail = tx_buffer_tail; | uint32_t tail = tx_buffer_tail; | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL2_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART1_C3 = (UART1_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART1_C3 = (UART1_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
UART1_D = n; | UART1_D = n; | ||||
if (transmit_pin) transmit_assert(); | if (transmit_pin) transmit_assert(); | ||||
while (p < end) { | while (p < end) { | ||||
head = tx_buffer_head; | head = tx_buffer_head; | ||||
if (++head >= TX_BUFFER_SIZE) head = 0; | |||||
if (++head >= SERIAL2_TX_BUFFER_SIZE) head = 0; | |||||
if (tx_buffer_tail == head) { | if (tx_buffer_tail == head) { | ||||
UART1_C2 = C2_TX_ACTIVE; | UART1_C2 = C2_TX_ACTIVE; | ||||
do { | do { | ||||
if (priority <= IRQ_PRIORITY) { | if (priority <= IRQ_PRIORITY) { | ||||
if ((UART1_S1 & UART_S1_TDRE)) { | if ((UART1_S1 & UART_S1_TDRE)) { | ||||
uint32_t tail = tx_buffer_tail; | uint32_t tail = tx_buffer_tail; | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL2_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART1_C3 = (UART1_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART1_C3 = (UART1_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
UART1_D = n; | UART1_D = n; | ||||
head = tx_buffer_head; | head = tx_buffer_head; | ||||
tail = tx_buffer_tail; | tail = tx_buffer_tail; | ||||
if (head >= tail) return TX_BUFFER_SIZE - 1 - head + tail; | |||||
if (head >= tail) return SERIAL2_TX_BUFFER_SIZE - 1 - head + tail; | |||||
return tail - head - 1; | return tail - head - 1; | ||||
} | } | ||||
head = rx_buffer_head; | head = rx_buffer_head; | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
if (head >= tail) return head - tail; | if (head >= tail) return head - tail; | ||||
return RX_BUFFER_SIZE + head - tail; | |||||
return SERIAL2_RX_BUFFER_SIZE + head - tail; | |||||
} | } | ||||
int serial2_getchar(void) | int serial2_getchar(void) | ||||
head = rx_buffer_head; | head = rx_buffer_head; | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
if (head == tail) return -1; | if (head == tail) return -1; | ||||
if (++tail >= RX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL2_RX_BUFFER_SIZE) tail = 0; | |||||
c = rx_buffer[tail]; | c = rx_buffer[tail]; | ||||
rx_buffer_tail = tail; | rx_buffer_tail = tail; | ||||
if (rts_pin) { | if (rts_pin) { | ||||
int avail; | int avail; | ||||
if (head >= tail) avail = head - tail; | if (head >= tail) avail = head - tail; | ||||
else avail = RX_BUFFER_SIZE + head - tail; | |||||
else avail = SERIAL2_RX_BUFFER_SIZE + head - tail; | |||||
if (avail <= RTS_LOW_WATERMARK) rts_assert(); | if (avail <= RTS_LOW_WATERMARK) rts_assert(); | ||||
} | } | ||||
return c; | return c; | ||||
head = rx_buffer_head; | head = rx_buffer_head; | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
if (head == tail) return -1; | if (head == tail) return -1; | ||||
if (++tail >= RX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL2_RX_BUFFER_SIZE) tail = 0; | |||||
return rx_buffer[tail]; | return rx_buffer[tail]; | ||||
} | } | ||||
if (rts_pin) rts_assert(); | if (rts_pin) rts_assert(); | ||||
} | } | ||||
// status interrupt combines | |||||
// status interrupt combines | |||||
// Transmit data below watermark UART_S1_TDRE | // Transmit data below watermark UART_S1_TDRE | ||||
// Transmit complete UART_S1_TC | // Transmit complete UART_S1_TC | ||||
// Idle line UART_S1_IDLE | // Idle line UART_S1_IDLE | ||||
n = UART1_D; | n = UART1_D; | ||||
} | } | ||||
newhead = head + 1; | newhead = head + 1; | ||||
if (newhead >= RX_BUFFER_SIZE) newhead = 0; | |||||
if (newhead >= SERIAL2_RX_BUFFER_SIZE) newhead = 0; | |||||
if (newhead != tail) { | if (newhead != tail) { | ||||
head = newhead; | head = newhead; | ||||
rx_buffer[head] = n; | rx_buffer[head] = n; | ||||
if (rts_pin) { | if (rts_pin) { | ||||
int avail; | int avail; | ||||
if (head >= tail) avail = head - tail; | if (head >= tail) avail = head - tail; | ||||
else avail = RX_BUFFER_SIZE + head - tail; | |||||
else avail = SERIAL2_RX_BUFFER_SIZE + head - tail; | |||||
if (avail >= RTS_HIGH_WATERMARK) rts_deassert(); | if (avail >= RTS_HIGH_WATERMARK) rts_deassert(); | ||||
} | } | ||||
} | } | ||||
tail = tx_buffer_tail; | tail = tx_buffer_tail; | ||||
do { | do { | ||||
if (tail == head) break; | if (tail == head) break; | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL2_TX_BUFFER_SIZE) tail = 0; | |||||
avail = UART1_S1; | avail = UART1_S1; | ||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART1_C3 = (UART1_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART1_C3 = (UART1_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
} | } | ||||
#else | #else | ||||
if (UART1_S1 & UART_S1_RDRF) { | if (UART1_S1 & UART_S1_RDRF) { | ||||
n = UART1_D; | |||||
if (use9Bits && (UART1_C3 & 0x80)) n |= 0x100; | |||||
if (use9Bits && (UART1_C3 & 0x80)) { | |||||
n = UART1_D | 0x100; | |||||
} else { | |||||
n = UART1_D; | |||||
} | |||||
head = rx_buffer_head + 1; | head = rx_buffer_head + 1; | ||||
if (head >= RX_BUFFER_SIZE) head = 0; | |||||
if (head >= SERIAL2_RX_BUFFER_SIZE) head = 0; | |||||
if (head != rx_buffer_tail) { | if (head != rx_buffer_tail) { | ||||
rx_buffer[head] = n; | rx_buffer[head] = n; | ||||
rx_buffer_head = head; | |||||
rx_buffer_head = head; | |||||
} | } | ||||
} | } | ||||
c = UART1_C2; | c = UART1_C2; | ||||
if (head == tail) { | if (head == tail) { | ||||
UART1_C2 = C2_TX_COMPLETING; | UART1_C2 = C2_TX_COMPLETING; | ||||
} else { | } else { | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL2_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART1_C3 = (UART1_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART1_C3 = (UART1_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
UART1_D = n; | UART1_D = n; |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
// Tunable parameters (relatively safe to edit these numbers) | // Tunable parameters (relatively safe to edit these numbers) | ||||
//////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////// | ||||
#define TX_BUFFER_SIZE 40 // number of outgoing bytes to buffer | |||||
#define RX_BUFFER_SIZE 64 // number of incoming bytes to buffer | |||||
#define RTS_HIGH_WATERMARK 40 // RTS requests sender to pause | |||||
#define RTS_LOW_WATERMARK 26 // RTS allows sender to resume | |||||
#ifndef SERIAL3_TX_BUFFER_SIZE | |||||
#define SERIAL3_TX_BUFFER_SIZE 40 // number of outgoing bytes to buffer | |||||
#endif | |||||
#ifndef SERIAL3_RX_BUFFER_SIZE | |||||
#define SERIAL3_RX_BUFFER_SIZE 64 // number of incoming bytes to buffer | |||||
#endif | |||||
#define RTS_HIGH_WATERMARK (SERIAL3_RX_BUFFER_SIZE-24) // RTS requests sender to pause | |||||
#define RTS_LOW_WATERMARK (SERIAL3_RX_BUFFER_SIZE-38) // RTS allows sender to resume | |||||
#define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest | #define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest | ||||
#define use9Bits 0 | #define use9Bits 0 | ||||
#endif | #endif | ||||
static volatile BUFTYPE tx_buffer[TX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE rx_buffer[RX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE tx_buffer[SERIAL3_TX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE rx_buffer[SERIAL3_RX_BUFFER_SIZE]; | |||||
static volatile uint8_t transmitting = 0; | static volatile uint8_t transmitting = 0; | ||||
#if defined(KINETISK) | #if defined(KINETISK) | ||||
static volatile uint8_t *transmit_pin=NULL; | static volatile uint8_t *transmit_pin=NULL; | ||||
#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 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 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 | ||||
#endif | #endif | ||||
#if defined(KINETISL) | #if defined(KINETISL) | ||||
static uint8_t rx_pin_num = 7; | static uint8_t rx_pin_num = 7; | ||||
static uint8_t tx_pin_num = 8; | |||||
#endif | #endif | ||||
static uint8_t tx_pin_num = 8; | |||||
// UART0 and UART1 are clocked by F_CPU, UART2 is clocked by F_BUS | // UART0 and UART1 are clocked by F_CPU, UART2 is clocked by F_BUS | ||||
// UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer | // UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer | ||||
} | } | ||||
#endif | #endif | ||||
#if defined(HAS_KINETISK_UART2) | #if defined(HAS_KINETISK_UART2) | ||||
if (divisor < 32) divisor = 32; | |||||
UART2_BDH = (divisor >> 13) & 0x1F; | UART2_BDH = (divisor >> 13) & 0x1F; | ||||
UART2_BDL = (divisor >> 5) & 0xFF; | UART2_BDL = (divisor >> 5) & 0xFF; | ||||
UART2_C4 = divisor & 0x1F; | UART2_C4 = divisor & 0x1F; | ||||
UART2_C1 = 0; | UART2_C1 = 0; | ||||
UART2_PFIFO = 0; | UART2_PFIFO = 0; | ||||
#elif defined(HAS_KINETISL_UART2) | #elif defined(HAS_KINETISL_UART2) | ||||
if (divisor < 1) divisor = 1; | |||||
UART2_BDH = (divisor >> 8) & 0x1F; | UART2_BDH = (divisor >> 8) & 0x1F; | ||||
UART2_BDL = divisor & 0xFF; | UART2_BDL = divisor & 0xFF; | ||||
UART2_C1 = 0; | UART2_C1 = 0; | ||||
c = UART2_C3 & ~0x10; | c = UART2_C3 & ~0x10; | ||||
if (format & 0x20) c |= 0x10; // tx invert | if (format & 0x20) c |= 0x10; // tx invert | ||||
UART2_C3 = c; | UART2_C3 = c; | ||||
#ifdef SERIAL_9BIT_SUPPORT | |||||
#if defined(SERIAL_9BIT_SUPPORT) && !defined(KINETISL) | |||||
c = UART2_C4 & 0x1F; | c = UART2_C4 & 0x1F; | ||||
if (format & 0x08) c |= 0x20; // 9 bit mode with parity (requires 10 bits) | if (format & 0x08) c |= 0x20; // 9 bit mode with parity (requires 10 bits) | ||||
UART2_C4 = c; | UART2_C4 = c; | ||||
use9Bits = format & 0x80; | use9Bits = format & 0x80; | ||||
#endif | #endif | ||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(KINETISL) | |||||
// For T3.5/T3.6/TLC See about turning on 2 stop bit mode | |||||
if ( format & 0x100) { | |||||
uint8_t bdl = UART2_BDL; | |||||
UART2_BDH |= UART_BDH_SBNS; // Turn on 2 stop bits - was turned off by set baud | |||||
UART2_BDL = bdl; // Says BDH not acted on until BDL is written | |||||
} | |||||
#endif | |||||
} | } | ||||
void serial3_end(void) | void serial3_end(void) | ||||
while (transmitting) yield(); // wait for buffered data to send | while (transmitting) yield(); // wait for buffered data to send | ||||
NVIC_DISABLE_IRQ(IRQ_UART2_STATUS); | NVIC_DISABLE_IRQ(IRQ_UART2_STATUS); | ||||
UART2_C2 = 0; | UART2_C2 = 0; | ||||
#if defined(KINETISK) | |||||
CORE_PIN7_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | CORE_PIN7_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | ||||
CORE_PIN8_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | CORE_PIN8_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | ||||
#elif defined(KINETISL) | |||||
switch (rx_pin_num) { | |||||
case 7: CORE_PIN7_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||||
case 6: CORE_PIN6_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||||
} | |||||
switch (tx_pin_num & 127) { | |||||
case 8: CORE_PIN8_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 | |||||
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(); | ||||
void serial3_set_tx(uint8_t pin, uint8_t opendrain) | void serial3_set_tx(uint8_t pin, uint8_t opendrain) | ||||
{ | { | ||||
#if defined(KINETISL) | |||||
uint32_t cfg; | uint32_t cfg; | ||||
if (opendrain) pin |= 128; | if (opendrain) pin |= 128; | ||||
if ((SIM_SCGC4 & SIM_SCGC4_UART2)) { | if ((SIM_SCGC4 & SIM_SCGC4_UART2)) { | ||||
switch (tx_pin_num & 127) { | switch (tx_pin_num & 127) { | ||||
case 8: CORE_PIN8_CONFIG = 0; break; // PTD3 | case 8: CORE_PIN8_CONFIG = 0; break; // PTD3 | ||||
#if defined(KINETISL) | |||||
case 20: CORE_PIN20_CONFIG = 0; break; // PTD5 | case 20: CORE_PIN20_CONFIG = 0; break; // PTD5 | ||||
#endif | |||||
} | } | ||||
if (opendrain) { | if (opendrain) { | ||||
cfg = PORT_PCR_DSE | PORT_PCR_ODE; | cfg = PORT_PCR_DSE | PORT_PCR_ODE; | ||||
} | } | ||||
switch (pin & 127) { | switch (pin & 127) { | ||||
case 8: CORE_PIN8_CONFIG = cfg | PORT_PCR_MUX(3); break; | case 8: CORE_PIN8_CONFIG = cfg | PORT_PCR_MUX(3); break; | ||||
#if defined(KINETISL) | |||||
case 20: CORE_PIN20_CONFIG = cfg | PORT_PCR_MUX(3); break; | case 20: CORE_PIN20_CONFIG = cfg | PORT_PCR_MUX(3); break; | ||||
#endif | |||||
} | } | ||||
} | } | ||||
tx_pin_num = pin; | tx_pin_num = pin; | ||||
#endif | |||||
} | } | ||||
void serial3_set_rx(uint8_t pin) | void serial3_set_rx(uint8_t pin) | ||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART2)) return; | if (!(SIM_SCGC4 & SIM_SCGC4_UART2)) return; | ||||
if (transmit_pin) transmit_assert(); | if (transmit_pin) transmit_assert(); | ||||
head = tx_buffer_head; | head = tx_buffer_head; | ||||
if (++head >= TX_BUFFER_SIZE) head = 0; | |||||
if (++head >= SERIAL3_TX_BUFFER_SIZE) head = 0; | |||||
while (tx_buffer_tail == head) { | while (tx_buffer_tail == head) { | ||||
int priority = nvic_execution_priority(); | int priority = nvic_execution_priority(); | ||||
if (priority <= IRQ_PRIORITY) { | if (priority <= IRQ_PRIORITY) { | ||||
if ((UART2_S1 & UART_S1_TDRE)) { | if ((UART2_S1 & UART_S1_TDRE)) { | ||||
uint32_t tail = tx_buffer_tail; | uint32_t tail = tx_buffer_tail; | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL3_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART2_C3 = (UART2_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART2_C3 = (UART2_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
UART2_D = n; | UART2_D = n; | ||||
head = tx_buffer_head; | head = tx_buffer_head; | ||||
tail = tx_buffer_tail; | tail = tx_buffer_tail; | ||||
if (head >= tail) return TX_BUFFER_SIZE - 1 - head + tail; | |||||
if (head >= tail) return SERIAL3_TX_BUFFER_SIZE - 1 - head + tail; | |||||
return tail - head - 1; | return tail - head - 1; | ||||
} | } | ||||
head = rx_buffer_head; | head = rx_buffer_head; | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
if (head >= tail) return head - tail; | if (head >= tail) return head - tail; | ||||
return RX_BUFFER_SIZE + head - tail; | |||||
return SERIAL3_RX_BUFFER_SIZE + head - tail; | |||||
} | } | ||||
int serial3_getchar(void) | int serial3_getchar(void) | ||||
head = rx_buffer_head; | head = rx_buffer_head; | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
if (head == tail) return -1; | if (head == tail) return -1; | ||||
if (++tail >= RX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL3_RX_BUFFER_SIZE) tail = 0; | |||||
c = rx_buffer[tail]; | c = rx_buffer[tail]; | ||||
rx_buffer_tail = tail; | rx_buffer_tail = tail; | ||||
if (rts_pin) { | if (rts_pin) { | ||||
int avail; | int avail; | ||||
if (head >= tail) avail = head - tail; | if (head >= tail) avail = head - tail; | ||||
else avail = RX_BUFFER_SIZE + head - tail; | |||||
else avail = SERIAL3_RX_BUFFER_SIZE + head - tail; | |||||
if (avail <= RTS_LOW_WATERMARK) rts_assert(); | if (avail <= RTS_LOW_WATERMARK) rts_assert(); | ||||
} | } | ||||
return c; | return c; | ||||
head = rx_buffer_head; | head = rx_buffer_head; | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
if (head == tail) return -1; | if (head == tail) return -1; | ||||
if (++tail >= RX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL3_RX_BUFFER_SIZE) tail = 0; | |||||
return rx_buffer[tail]; | return rx_buffer[tail]; | ||||
} | } | ||||
if (rts_pin) rts_assert(); | if (rts_pin) rts_assert(); | ||||
} | } | ||||
// status interrupt combines | |||||
// status interrupt combines | |||||
// Transmit data below watermark UART_S1_TDRE | // Transmit data below watermark UART_S1_TDRE | ||||
// Transmit complete UART_S1_TC | // Transmit complete UART_S1_TC | ||||
// Idle line UART_S1_IDLE | // Idle line UART_S1_IDLE | ||||
n = UART2_D; | n = UART2_D; | ||||
} | } | ||||
head = rx_buffer_head + 1; | head = rx_buffer_head + 1; | ||||
if (head >= RX_BUFFER_SIZE) head = 0; | |||||
if (head >= SERIAL3_RX_BUFFER_SIZE) head = 0; | |||||
if (head != rx_buffer_tail) { | if (head != rx_buffer_tail) { | ||||
rx_buffer[head] = n; | rx_buffer[head] = n; | ||||
rx_buffer_head = head; | |||||
rx_buffer_head = head; | |||||
} | } | ||||
if (rts_pin) { | if (rts_pin) { | ||||
int avail; | int avail; | ||||
tail = tx_buffer_tail; | tail = tx_buffer_tail; | ||||
if (head >= tail) avail = head - tail; | if (head >= tail) avail = head - tail; | ||||
else avail = RX_BUFFER_SIZE + head - tail; | |||||
else avail = SERIAL3_RX_BUFFER_SIZE + head - tail; | |||||
if (avail >= RTS_HIGH_WATERMARK) rts_deassert(); | if (avail >= RTS_HIGH_WATERMARK) rts_deassert(); | ||||
} | } | ||||
} | } | ||||
if (head == tail) { | if (head == tail) { | ||||
UART2_C2 = C2_TX_COMPLETING; | UART2_C2 = C2_TX_COMPLETING; | ||||
} else { | } else { | ||||
if (++tail >= TX_BUFFER_SIZE) tail = 0; | |||||
if (++tail >= SERIAL3_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | n = tx_buffer[tail]; | ||||
if (use9Bits) UART2_C3 = (UART2_C3 & ~0x40) | ((n & 0x100) >> 2); | if (use9Bits) UART2_C3 = (UART2_C3 & ~0x40) | ((n & 0x100) >> 2); | ||||
UART2_D = n; | UART2_D = n; |
/* 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 "kinetis.h" | |||||
#include "core_pins.h" | |||||
#include "HardwareSerial.h" | |||||
#ifdef HAS_KINETISK_UART3 | |||||
//////////////////////////////////////////////////////////////// | |||||
// Tunable parameters (relatively safe to edit these numbers) | |||||
//////////////////////////////////////////////////////////////// | |||||
#ifndef SERIAL4_TX_BUFFER_SIZE | |||||
#define SERIAL4_TX_BUFFER_SIZE 40 // number of outgoing bytes to buffer | |||||
#endif | |||||
#ifndef SERIAL4_RX_BUFFER_SIZE | |||||
#define SERIAL4_RX_BUFFER_SIZE 64 // number of incoming bytes to buffer | |||||
#endif | |||||
#define RTS_HIGH_WATERMARK (SERIAL4_RX_BUFFER_SIZE-24) // RTS requests sender to pause | |||||
#define RTS_LOW_WATERMARK (SERIAL4_RX_BUFFER_SIZE-38) // RTS allows sender to resume | |||||
#define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest | |||||
//////////////////////////////////////////////////////////////// | |||||
// changes not recommended below this point.... | |||||
//////////////////////////////////////////////////////////////// | |||||
#ifdef SERIAL_9BIT_SUPPORT | |||||
static uint8_t use9Bits = 0; | |||||
#define BUFTYPE uint16_t | |||||
#else | |||||
#define BUFTYPE uint8_t | |||||
#define use9Bits 0 | |||||
#endif | |||||
static volatile BUFTYPE tx_buffer[SERIAL4_TX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE rx_buffer[SERIAL4_RX_BUFFER_SIZE]; | |||||
static volatile uint8_t transmitting = 0; | |||||
static volatile uint8_t *transmit_pin=NULL; | |||||
#define transmit_assert() *transmit_pin = 1 | |||||
#define transmit_deassert() *transmit_pin = 0 | |||||
static volatile uint8_t *rts_pin=NULL; | |||||
#define rts_assert() *rts_pin = 0 | |||||
#define rts_deassert() *rts_pin = 1 | |||||
#if SERIAL4_TX_BUFFER_SIZE > 65535 | |||||
static volatile uint32_t tx_buffer_head = 0; | |||||
static volatile uint32_t tx_buffer_tail = 0; | |||||
#elif SERIAL4_TX_BUFFER_SIZE > 255 | |||||
static volatile uint16_t tx_buffer_head = 0; | |||||
static volatile uint16_t tx_buffer_tail = 0; | |||||
#else | |||||
static volatile uint8_t tx_buffer_head = 0; | |||||
static volatile uint8_t tx_buffer_tail = 0; | |||||
#endif | |||||
#if SERIAL4_RX_BUFFER_SIZE > 65535 | |||||
static volatile uint32_t rx_buffer_head = 0; | |||||
static volatile uint32_t rx_buffer_tail = 0; | |||||
#elif SERIAL4_RX_BUFFER_SIZE > 255 | |||||
static volatile uint16_t rx_buffer_head = 0; | |||||
static volatile uint16_t rx_buffer_tail = 0; | |||||
#else | |||||
static volatile uint8_t rx_buffer_head = 0; | |||||
static volatile uint8_t rx_buffer_tail = 0; | |||||
#endif | |||||
static uint8_t rx_pin_num = 31; | |||||
static uint8_t tx_pin_num = 32; | |||||
// UART0 and UART1 are clocked by F_CPU, UART2 is clocked by F_BUS | |||||
// UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer | |||||
#define C2_ENABLE UART_C2_TE | UART_C2_RE | UART_C2_RIE | |||||
#define C2_TX_ACTIVE C2_ENABLE | UART_C2_TIE | |||||
#define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE | |||||
#define C2_TX_INACTIVE C2_ENABLE | |||||
void serial4_begin(uint32_t divisor) | |||||
{ | |||||
SIM_SCGC4 |= SIM_SCGC4_UART3; // turn on clock, TODO: use bitband | |||||
rx_buffer_head = 0; | |||||
rx_buffer_tail = 0; | |||||
tx_buffer_head = 0; | |||||
tx_buffer_tail = 0; | |||||
transmitting = 0; | |||||
switch (rx_pin_num) { | |||||
case 31: CORE_PIN31_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | |||||
case 63: CORE_PIN63_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | |||||
} | |||||
switch (tx_pin_num) { | |||||
case 32: CORE_PIN32_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); break; | |||||
case 62: CORE_PIN62_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); break; | |||||
} | |||||
if (divisor < 32) divisor = 32; | |||||
UART3_BDH = (divisor >> 13) & 0x1F; | |||||
UART3_BDL = (divisor >> 5) & 0xFF; | |||||
UART3_C4 = divisor & 0x1F; | |||||
UART3_C1 = 0; | |||||
UART3_PFIFO = 0; | |||||
UART3_C2 = C2_TX_INACTIVE; | |||||
NVIC_SET_PRIORITY(IRQ_UART3_STATUS, IRQ_PRIORITY); | |||||
NVIC_ENABLE_IRQ(IRQ_UART3_STATUS); | |||||
} | |||||
void serial4_format(uint32_t format) | |||||
{ | |||||
uint8_t c; | |||||
c = UART3_C1; | |||||
c = (c & ~0x13) | (format & 0x03); // configure parity | |||||
if (format & 0x04) c |= 0x10; // 9 bits (might include parity) | |||||
UART3_C1 = c; | |||||
if ((format & 0x0F) == 0x04) UART3_C3 |= 0x40; // 8N2 is 9 bit with 9th bit always 1 | |||||
c = UART3_S2 & ~0x10; | |||||
if (format & 0x10) c |= 0x10; // rx invert | |||||
UART3_S2 = c; | |||||
c = UART3_C3 & ~0x10; | |||||
if (format & 0x20) c |= 0x10; // tx invert | |||||
UART3_C3 = c; | |||||
#ifdef SERIAL_9BIT_SUPPORT | |||||
c = UART3_C4 & 0x1F; | |||||
if (format & 0x08) c |= 0x20; // 9 bit mode with parity (requires 10 bits) | |||||
UART3_C4 = c; | |||||
use9Bits = format & 0x80; | |||||
#endif | |||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(KINETISL) | |||||
// For T3.5/T3.6/TLC See about turning on 2 stop bit mode | |||||
if ( format & 0x100) { | |||||
uint8_t bdl = UART3_BDL; | |||||
UART3_BDH |= UART_BDH_SBNS; // Turn on 2 stop bits - was turned off by set baud | |||||
UART3_BDL = bdl; // Says BDH not acted on until BDL is written | |||||
} | |||||
#endif | |||||
} | |||||
void serial4_end(void) | |||||
{ | |||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART3)) return; | |||||
while (transmitting) yield(); // wait for buffered data to send | |||||
NVIC_DISABLE_IRQ(IRQ_UART3_STATUS); | |||||
UART3_C2 = 0; | |||||
switch (rx_pin_num) { | |||||
case 31: CORE_PIN31_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; // PTC3 | |||||
case 63: CORE_PIN63_CONFIG = 0; break; | |||||
} | |||||
switch (tx_pin_num & 127) { | |||||
case 32: CORE_PIN32_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; // PTC4 | |||||
case 62: CORE_PIN62_CONFIG = 0; break; | |||||
} | |||||
UART3_S1; | |||||
UART3_D; // clear leftover error status | |||||
rx_buffer_head = 0; | |||||
rx_buffer_tail = 0; | |||||
if (rts_pin) rts_deassert(); | |||||
} | |||||
void serial4_set_transmit_pin(uint8_t pin) | |||||
{ | |||||
while (transmitting) ; | |||||
pinMode(pin, OUTPUT); | |||||
digitalWrite(pin, LOW); | |||||
transmit_pin = portOutputRegister(pin); | |||||
} | |||||
void serial4_set_tx(uint8_t pin, uint8_t opendrain) | |||||
{ | |||||
uint32_t cfg; | |||||
if (opendrain) pin |= 128; | |||||
if (pin == tx_pin_num) return; | |||||
if ((SIM_SCGC4 & SIM_SCGC4_UART3)) { | |||||
switch (tx_pin_num & 127) { | |||||
case 32: CORE_PIN32_CONFIG = 0; break; // PTB11 | |||||
case 62: CORE_PIN62_CONFIG = 0; break; | |||||
} | |||||
if (opendrain) { | |||||
cfg = PORT_PCR_DSE | PORT_PCR_ODE; | |||||
} else { | |||||
cfg = PORT_PCR_DSE | PORT_PCR_SRE; | |||||
} | |||||
switch (pin & 127) { | |||||
case 32: CORE_PIN32_CONFIG = cfg | PORT_PCR_MUX(3); break; | |||||
case 62: CORE_PIN62_CONFIG = cfg | PORT_PCR_MUX(3); break; | |||||
} | |||||
} | |||||
tx_pin_num = pin; | |||||
} | |||||
void serial4_set_rx(uint8_t pin) | |||||
{ | |||||
if (pin == rx_pin_num) return; | |||||
if ((SIM_SCGC4 & SIM_SCGC4_UART3)) { | |||||
switch (rx_pin_num) { | |||||
case 31: CORE_PIN31_CONFIG = 0; break; // PTC3 | |||||
case 63: CORE_PIN63_CONFIG = 0; break; | |||||
} | |||||
switch (pin) { | |||||
case 31: CORE_PIN31_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | |||||
case 63: CORE_PIN63_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; | |||||
} | |||||
} | |||||
rx_pin_num = pin; | |||||
} | |||||
int serial4_set_rts(uint8_t pin) | |||||
{ | |||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART3)) return 0; | |||||
if (pin < CORE_NUM_DIGITAL) { | |||||
rts_pin = portOutputRegister(pin); | |||||
pinMode(pin, OUTPUT); | |||||
rts_assert(); | |||||
} else { | |||||
rts_pin = NULL; | |||||
return 0; | |||||
} | |||||
return 1; | |||||
} | |||||
int serial4_set_cts(uint8_t pin) | |||||
{ | |||||
return 0; | |||||
} | |||||
void serial4_putchar(uint32_t c) | |||||
{ | |||||
uint32_t head, n; | |||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART3)) return; | |||||
if (transmit_pin) transmit_assert(); | |||||
head = tx_buffer_head; | |||||
if (++head >= SERIAL4_TX_BUFFER_SIZE) head = 0; | |||||
while (tx_buffer_tail == head) { | |||||
int priority = nvic_execution_priority(); | |||||
if (priority <= IRQ_PRIORITY) { | |||||
if ((UART3_S1 & UART_S1_TDRE)) { | |||||
uint32_t tail = tx_buffer_tail; | |||||
if (++tail >= SERIAL4_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | |||||
if (use9Bits) UART3_C3 = (UART3_C3 & ~0x40) | ((n & 0x100) >> 2); | |||||
UART3_D = n; | |||||
tx_buffer_tail = tail; | |||||
} | |||||
} else if (priority >= 256) { | |||||
yield(); // wait | |||||
} | |||||
} | |||||
tx_buffer[head] = c; | |||||
transmitting = 1; | |||||
tx_buffer_head = head; | |||||
UART3_C2 = C2_TX_ACTIVE; | |||||
} | |||||
void serial4_write(const void *buf, unsigned int count) | |||||
{ | |||||
const uint8_t *p = (const uint8_t *)buf; | |||||
while (count-- > 0) serial4_putchar(*p++); | |||||
} | |||||
void serial4_flush(void) | |||||
{ | |||||
while (transmitting) yield(); // wait | |||||
} | |||||
int serial4_write_buffer_free(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
head = tx_buffer_head; | |||||
tail = tx_buffer_tail; | |||||
if (head >= tail) return SERIAL4_TX_BUFFER_SIZE - 1 - head + tail; | |||||
return tail - head - 1; | |||||
} | |||||
int serial4_available(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
head = rx_buffer_head; | |||||
tail = rx_buffer_tail; | |||||
if (head >= tail) return head - tail; | |||||
return SERIAL4_RX_BUFFER_SIZE + head - tail; | |||||
} | |||||
int serial4_getchar(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
int c; | |||||
head = rx_buffer_head; | |||||
tail = rx_buffer_tail; | |||||
if (head == tail) return -1; | |||||
if (++tail >= SERIAL4_RX_BUFFER_SIZE) tail = 0; | |||||
c = rx_buffer[tail]; | |||||
rx_buffer_tail = tail; | |||||
if (rts_pin) { | |||||
int avail; | |||||
if (head >= tail) avail = head - tail; | |||||
else avail = SERIAL4_RX_BUFFER_SIZE + head - tail; | |||||
if (avail <= RTS_LOW_WATERMARK) rts_assert(); | |||||
} | |||||
return c; | |||||
} | |||||
int serial4_peek(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
head = rx_buffer_head; | |||||
tail = rx_buffer_tail; | |||||
if (head == tail) return -1; | |||||
if (++tail >= SERIAL4_RX_BUFFER_SIZE) tail = 0; | |||||
return rx_buffer[tail]; | |||||
} | |||||
void serial4_clear(void) | |||||
{ | |||||
rx_buffer_head = rx_buffer_tail; | |||||
if (rts_pin) rts_assert(); | |||||
} | |||||
// status interrupt combines | |||||
// Transmit data below watermark UART_S1_TDRE | |||||
// Transmit complete UART_S1_TC | |||||
// Idle line UART_S1_IDLE | |||||
// Receive data above watermark UART_S1_RDRF | |||||
// LIN break detect UART_S2_LBKDIF | |||||
// RxD pin active edge UART_S2_RXEDGIF | |||||
void uart3_status_isr(void) | |||||
{ | |||||
uint32_t head, tail, n; | |||||
uint8_t c; | |||||
if (UART3_S1 & UART_S1_RDRF) { | |||||
if (use9Bits && (UART3_C3 & 0x80)) { | |||||
n = UART3_D | 0x100; | |||||
} else { | |||||
n = UART3_D; | |||||
} | |||||
head = rx_buffer_head + 1; | |||||
if (head >= SERIAL4_RX_BUFFER_SIZE) head = 0; | |||||
if (head != rx_buffer_tail) { | |||||
rx_buffer[head] = n; | |||||
rx_buffer_head = head; | |||||
} | |||||
if (rts_pin) { | |||||
int avail; | |||||
tail = tx_buffer_tail; | |||||
if (head >= tail) avail = head - tail; | |||||
else avail = SERIAL4_RX_BUFFER_SIZE + head - tail; | |||||
if (avail >= RTS_HIGH_WATERMARK) rts_deassert(); | |||||
} | |||||
} | |||||
c = UART3_C2; | |||||
if ((c & UART_C2_TIE) && (UART3_S1 & UART_S1_TDRE)) { | |||||
head = tx_buffer_head; | |||||
tail = tx_buffer_tail; | |||||
if (head == tail) { | |||||
UART3_C2 = C2_TX_COMPLETING; | |||||
} else { | |||||
if (++tail >= SERIAL4_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | |||||
if (use9Bits) UART3_C3 = (UART3_C3 & ~0x40) | ((n & 0x100) >> 2); | |||||
UART3_D = n; | |||||
tx_buffer_tail = tail; | |||||
} | |||||
} | |||||
if ((c & UART_C2_TCIE) && (UART3_S1 & UART_S1_TC)) { | |||||
transmitting = 0; | |||||
if (transmit_pin) transmit_deassert(); | |||||
UART3_C2 = C2_TX_INACTIVE; | |||||
} | |||||
} | |||||
#endif // HAS_KINETISK_UART3 |
/* 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 "kinetis.h" | |||||
#include "core_pins.h" | |||||
#include "HardwareSerial.h" | |||||
#ifdef HAS_KINETISK_UART4 | |||||
//////////////////////////////////////////////////////////////// | |||||
// Tunable parameters (relatively safe to edit these numbers) | |||||
//////////////////////////////////////////////////////////////// | |||||
#ifndef SERIAL5_TX_BUFFER_SIZE | |||||
#define SERIAL5_TX_BUFFER_SIZE 40 // number of outgoing bytes to buffer | |||||
#endif | |||||
#ifndef SERIAL5_RX_BUFFER_SIZE | |||||
#define SERIAL5_RX_BUFFER_SIZE 64 // number of incoming bytes to buffer | |||||
#endif | |||||
#define RTS_HIGH_WATERMARK (SERIAL5_RX_BUFFER_SIZE-24) // RTS requests sender to pause | |||||
#define RTS_LOW_WATERMARK (SERIAL5_RX_BUFFER_SIZE-38) // RTS allows sender to resume | |||||
#define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest | |||||
//////////////////////////////////////////////////////////////// | |||||
// changes not recommended below this point.... | |||||
//////////////////////////////////////////////////////////////// | |||||
#ifdef SERIAL_9BIT_SUPPORT | |||||
static uint8_t use9Bits = 0; | |||||
#define BUFTYPE uint16_t | |||||
#else | |||||
#define BUFTYPE uint8_t | |||||
#define use9Bits 0 | |||||
#endif | |||||
static volatile BUFTYPE tx_buffer[SERIAL5_TX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE rx_buffer[SERIAL5_RX_BUFFER_SIZE]; | |||||
static volatile uint8_t transmitting = 0; | |||||
static volatile uint8_t *transmit_pin=NULL; | |||||
#define transmit_assert() *transmit_pin = 1 | |||||
#define transmit_deassert() *transmit_pin = 0 | |||||
static volatile uint8_t *rts_pin=NULL; | |||||
#define rts_assert() *rts_pin = 0 | |||||
#define rts_deassert() *rts_pin = 1 | |||||
#if SERIAL5_TX_BUFFER_SIZE > 65535 | |||||
static volatile uint32_t tx_buffer_head = 0; | |||||
static volatile uint32_t tx_buffer_tail = 0; | |||||
#elif SERIAL5_TX_BUFFER_SIZE > 255 | |||||
static volatile uint16_t tx_buffer_head = 0; | |||||
static volatile uint16_t tx_buffer_tail = 0; | |||||
#else | |||||
static volatile uint8_t tx_buffer_head = 0; | |||||
static volatile uint8_t tx_buffer_tail = 0; | |||||
#endif | |||||
#if SERIAL5_RX_BUFFER_SIZE > 65535 | |||||
static volatile uint32_t rx_buffer_head = 0; | |||||
static volatile uint32_t rx_buffer_tail = 0; | |||||
#elif SERIAL5_RX_BUFFER_SIZE > 255 | |||||
static volatile uint16_t rx_buffer_head = 0; | |||||
static volatile uint16_t rx_buffer_tail = 0; | |||||
#else | |||||
static volatile uint8_t rx_buffer_head = 0; | |||||
static volatile uint8_t rx_buffer_tail = 0; | |||||
#endif | |||||
static uint8_t tx_pin_num = 33; | |||||
// UART0 and UART1 are clocked by F_CPU, UART2 is clocked by F_BUS | |||||
// UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer | |||||
#define C2_ENABLE UART_C2_TE | UART_C2_RE | UART_C2_RIE | |||||
#define C2_TX_ACTIVE C2_ENABLE | UART_C2_TIE | |||||
#define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE | |||||
#define C2_TX_INACTIVE C2_ENABLE | |||||
void serial5_begin(uint32_t divisor) | |||||
{ | |||||
SIM_SCGC1 |= SIM_SCGC1_UART4; // turn on clock, TODO: use bitband | |||||
rx_buffer_head = 0; | |||||
rx_buffer_tail = 0; | |||||
tx_buffer_head = 0; | |||||
tx_buffer_tail = 0; | |||||
transmitting = 0; | |||||
CORE_PIN34_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); | |||||
CORE_PIN33_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); | |||||
if (divisor < 32) divisor = 32; | |||||
UART4_BDH = (divisor >> 13) & 0x1F; | |||||
UART4_BDL = (divisor >> 5) & 0xFF; | |||||
UART4_C4 = divisor & 0x1F; | |||||
UART4_C1 = 0; | |||||
UART4_PFIFO = 0; | |||||
UART4_C2 = C2_TX_INACTIVE; | |||||
NVIC_SET_PRIORITY(IRQ_UART4_STATUS, IRQ_PRIORITY); | |||||
NVIC_ENABLE_IRQ(IRQ_UART4_STATUS); | |||||
} | |||||
void serial5_format(uint32_t format) | |||||
{ | |||||
uint8_t c; | |||||
c = UART4_C1; | |||||
c = (c & ~0x13) | (format & 0x03); // configure parity | |||||
if (format & 0x04) c |= 0x10; // 9 bits (might include parity) | |||||
UART4_C1 = c; | |||||
if ((format & 0x0F) == 0x04) UART4_C3 |= 0x40; // 8N2 is 9 bit with 9th bit always 1 | |||||
c = UART4_S2 & ~0x10; | |||||
if (format & 0x10) c |= 0x10; // rx invert | |||||
UART4_S2 = c; | |||||
c = UART4_C3 & ~0x10; | |||||
if (format & 0x20) c |= 0x10; // tx invert | |||||
UART4_C3 = c; | |||||
#ifdef SERIAL_9BIT_SUPPORT | |||||
c = UART4_C4 & 0x1F; | |||||
if (format & 0x08) c |= 0x20; // 9 bit mode with parity (requires 10 bits) | |||||
UART4_C4 = c; | |||||
use9Bits = format & 0x80; | |||||
#endif | |||||
// For T3.5/T3.6 See about turning on 2 stop bit mode | |||||
if ( format & 0x100) { | |||||
uint8_t bdl = UART4_BDL; | |||||
UART4_BDH |= UART_BDH_SBNS; // Turn on 2 stop bits - was turned off by set baud | |||||
UART4_BDL = bdl; // Says BDH not acted on until BDL is written | |||||
} | |||||
} | |||||
void serial5_end(void) | |||||
{ | |||||
if (!(SIM_SCGC1 & SIM_SCGC1_UART4)) return; | |||||
while (transmitting) yield(); // wait for buffered data to send | |||||
NVIC_DISABLE_IRQ(IRQ_UART4_STATUS); | |||||
UART4_C2 = 0; | |||||
CORE_PIN34_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||||
CORE_PIN33_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||||
UART4_S1; | |||||
UART4_D; // clear leftover error status | |||||
rx_buffer_head = 0; | |||||
rx_buffer_tail = 0; | |||||
if (rts_pin) rts_deassert(); | |||||
} | |||||
void serial5_set_transmit_pin(uint8_t pin) | |||||
{ | |||||
while (transmitting) ; | |||||
pinMode(pin, OUTPUT); | |||||
digitalWrite(pin, LOW); | |||||
transmit_pin = portOutputRegister(pin); | |||||
} | |||||
void serial5_set_tx(uint8_t pin, uint8_t opendrain) | |||||
{ | |||||
uint32_t cfg; | |||||
if (opendrain) pin |= 128; | |||||
if (pin == tx_pin_num) return; | |||||
if ((SIM_SCGC1 & SIM_SCGC1_UART4)) { | |||||
switch (tx_pin_num & 127) { | |||||
case 33: CORE_PIN33_CONFIG = 0; break; // PTE24 | |||||
} | |||||
if (opendrain) { | |||||
cfg = PORT_PCR_DSE | PORT_PCR_ODE; | |||||
} else { | |||||
cfg = PORT_PCR_DSE | PORT_PCR_SRE; | |||||
} | |||||
switch (pin & 127) { | |||||
case 33: CORE_PIN33_CONFIG = cfg | PORT_PCR_MUX(3); break; | |||||
} | |||||
} | |||||
tx_pin_num = pin; | |||||
} | |||||
void serial5_set_rx(uint8_t pin) | |||||
{ | |||||
} | |||||
int serial5_set_rts(uint8_t pin) | |||||
{ | |||||
if (!(SIM_SCGC1 & SIM_SCGC1_UART4)) return 0; | |||||
if (pin < CORE_NUM_DIGITAL) { | |||||
rts_pin = portOutputRegister(pin); | |||||
pinMode(pin, OUTPUT); | |||||
rts_assert(); | |||||
} else { | |||||
rts_pin = NULL; | |||||
return 0; | |||||
} | |||||
return 1; | |||||
} | |||||
int serial5_set_cts(uint8_t pin) | |||||
{ | |||||
if (!(SIM_SCGC1 & SIM_SCGC1_UART4)) return 0; | |||||
if (pin == 24) { | |||||
CORE_PIN24_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_PE; // weak pulldown | |||||
} else { | |||||
UART4_MODEM &= ~UART_MODEM_TXCTSE; | |||||
return 0; | |||||
} | |||||
UART4_MODEM |= UART_MODEM_TXCTSE; | |||||
return 1; | |||||
} | |||||
void serial5_putchar(uint32_t c) | |||||
{ | |||||
uint32_t head, n; | |||||
if (!(SIM_SCGC1 & SIM_SCGC1_UART4)) return; | |||||
if (transmit_pin) transmit_assert(); | |||||
head = tx_buffer_head; | |||||
if (++head >= SERIAL5_TX_BUFFER_SIZE) head = 0; | |||||
while (tx_buffer_tail == head) { | |||||
int priority = nvic_execution_priority(); | |||||
if (priority <= IRQ_PRIORITY) { | |||||
if ((UART4_S1 & UART_S1_TDRE)) { | |||||
uint32_t tail = tx_buffer_tail; | |||||
if (++tail >= SERIAL5_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | |||||
if (use9Bits) UART4_C3 = (UART4_C3 & ~0x40) | ((n & 0x100) >> 2); | |||||
UART4_D = n; | |||||
tx_buffer_tail = tail; | |||||
} | |||||
} else if (priority >= 256) { | |||||
yield(); // wait | |||||
} | |||||
} | |||||
tx_buffer[head] = c; | |||||
transmitting = 1; | |||||
tx_buffer_head = head; | |||||
UART4_C2 = C2_TX_ACTIVE; | |||||
} | |||||
void serial5_write(const void *buf, unsigned int count) | |||||
{ | |||||
const uint8_t *p = (const uint8_t *)buf; | |||||
while (count-- > 0) serial5_putchar(*p++); | |||||
} | |||||
void serial5_flush(void) | |||||
{ | |||||
while (transmitting) yield(); // wait | |||||
} | |||||
int serial5_write_buffer_free(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
head = tx_buffer_head; | |||||
tail = tx_buffer_tail; | |||||
if (head >= tail) return SERIAL5_TX_BUFFER_SIZE - 1 - head + tail; | |||||
return tail - head - 1; | |||||
} | |||||
int serial5_available(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
head = rx_buffer_head; | |||||
tail = rx_buffer_tail; | |||||
if (head >= tail) return head - tail; | |||||
return SERIAL5_RX_BUFFER_SIZE + head - tail; | |||||
} | |||||
int serial5_getchar(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
int c; | |||||
head = rx_buffer_head; | |||||
tail = rx_buffer_tail; | |||||
if (head == tail) return -1; | |||||
if (++tail >= SERIAL5_RX_BUFFER_SIZE) tail = 0; | |||||
c = rx_buffer[tail]; | |||||
rx_buffer_tail = tail; | |||||
if (rts_pin) { | |||||
int avail; | |||||
if (head >= tail) avail = head - tail; | |||||
else avail = SERIAL5_RX_BUFFER_SIZE + head - tail; | |||||
if (avail <= RTS_LOW_WATERMARK) rts_assert(); | |||||
} | |||||
return c; | |||||
} | |||||
int serial5_peek(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
head = rx_buffer_head; | |||||
tail = rx_buffer_tail; | |||||
if (head == tail) return -1; | |||||
if (++tail >= SERIAL5_RX_BUFFER_SIZE) tail = 0; | |||||
return rx_buffer[tail]; | |||||
} | |||||
void serial5_clear(void) | |||||
{ | |||||
rx_buffer_head = rx_buffer_tail; | |||||
if (rts_pin) rts_assert(); | |||||
} | |||||
// status interrupt combines | |||||
// Transmit data below watermark UART_S1_TDRE | |||||
// Transmit complete UART_S1_TC | |||||
// Idle line UART_S1_IDLE | |||||
// Receive data above watermark UART_S1_RDRF | |||||
// LIN break detect UART_S2_LBKDIF | |||||
// RxD pin active edge UART_S2_RXEDGIF | |||||
void uart4_status_isr(void) | |||||
{ | |||||
uint32_t head, tail, n; | |||||
uint8_t c; | |||||
if (UART4_S1 & UART_S1_RDRF) { | |||||
if (use9Bits && (UART4_C3 & 0x80)) { | |||||
n = UART4_D | 0x100; | |||||
} else { | |||||
n = UART4_D; | |||||
} | |||||
head = rx_buffer_head + 1; | |||||
if (head >= SERIAL5_RX_BUFFER_SIZE) head = 0; | |||||
if (head != rx_buffer_tail) { | |||||
rx_buffer[head] = n; | |||||
rx_buffer_head = head; | |||||
} | |||||
if (rts_pin) { | |||||
int avail; | |||||
tail = tx_buffer_tail; | |||||
if (head >= tail) avail = head - tail; | |||||
else avail = SERIAL5_RX_BUFFER_SIZE + head - tail; | |||||
if (avail >= RTS_HIGH_WATERMARK) rts_deassert(); | |||||
} | |||||
} | |||||
c = UART4_C2; | |||||
if ((c & UART_C2_TIE) && (UART4_S1 & UART_S1_TDRE)) { | |||||
head = tx_buffer_head; | |||||
tail = tx_buffer_tail; | |||||
if (head == tail) { | |||||
UART4_C2 = C2_TX_COMPLETING; | |||||
} else { | |||||
if (++tail >= SERIAL5_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | |||||
if (use9Bits) UART4_C3 = (UART4_C3 & ~0x40) | ((n & 0x100) >> 2); | |||||
UART4_D = n; | |||||
tx_buffer_tail = tail; | |||||
} | |||||
} | |||||
if ((c & UART_C2_TCIE) && (UART4_S1 & UART_S1_TC)) { | |||||
transmitting = 0; | |||||
if (transmit_pin) transmit_deassert(); | |||||
UART4_C2 = C2_TX_INACTIVE; | |||||
} | |||||
} | |||||
#endif // HAS_KINETISK_UART4 |
/* 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 "kinetis.h" | |||||
#include "core_pins.h" | |||||
#include "HardwareSerial.h" | |||||
#ifdef HAS_KINETISK_UART5 | |||||
//////////////////////////////////////////////////////////////// | |||||
// Tunable parameters (relatively safe to edit these numbers) | |||||
//////////////////////////////////////////////////////////////// | |||||
#ifndef SERIAL6_TX_BUFFER_SIZE | |||||
#define SERIAL6_TX_BUFFER_SIZE 40 // number of outgoing bytes to buffer | |||||
#endif | |||||
#ifndef SERIAL6_RX_BUFFER_SIZE | |||||
#define SERIAL6_RX_BUFFER_SIZE 64 // number of incoming bytes to buffer | |||||
#endif | |||||
#define RTS_HIGH_WATERMARK (SERIAL6_RX_BUFFER_SIZE-24) // RTS requests sender to pause | |||||
#define RTS_LOW_WATERMARK (SERIAL6_RX_BUFFER_SIZE-38) // RTS allows sender to resume | |||||
#define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest | |||||
//////////////////////////////////////////////////////////////// | |||||
// changes not recommended below this point.... | |||||
//////////////////////////////////////////////////////////////// | |||||
#ifdef SERIAL_9BIT_SUPPORT | |||||
static uint8_t use9Bits = 0; | |||||
#define BUFTYPE uint16_t | |||||
#else | |||||
#define BUFTYPE uint8_t | |||||
#define use9Bits 0 | |||||
#endif | |||||
static volatile BUFTYPE tx_buffer[SERIAL6_TX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE rx_buffer[SERIAL6_RX_BUFFER_SIZE]; | |||||
static volatile uint8_t transmitting = 0; | |||||
static volatile uint8_t *transmit_pin=NULL; | |||||
#define transmit_assert() *transmit_pin = 1 | |||||
#define transmit_deassert() *transmit_pin = 0 | |||||
static volatile uint8_t *rts_pin=NULL; | |||||
#define rts_assert() *rts_pin = 0 | |||||
#define rts_deassert() *rts_pin = 1 | |||||
#if SERIAL6_TX_BUFFER_SIZE > 65535 | |||||
static volatile uint32_t tx_buffer_head = 0; | |||||
static volatile uint32_t tx_buffer_tail = 0; | |||||
#elif SERIAL6_TX_BUFFER_SIZE > 255 | |||||
static volatile uint16_t tx_buffer_head = 0; | |||||
static volatile uint16_t tx_buffer_tail = 0; | |||||
#else | |||||
static volatile uint8_t tx_buffer_head = 0; | |||||
static volatile uint8_t tx_buffer_tail = 0; | |||||
#endif | |||||
#if SERIAL6_RX_BUFFER_SIZE > 65535 | |||||
static volatile uint32_t rx_buffer_head = 0; | |||||
static volatile uint32_t rx_buffer_tail = 0; | |||||
#elif SERIAL6_RX_BUFFER_SIZE > 255 | |||||
static volatile uint16_t rx_buffer_head = 0; | |||||
static volatile uint16_t rx_buffer_tail = 0; | |||||
#else | |||||
static volatile uint8_t rx_buffer_head = 0; | |||||
static volatile uint8_t rx_buffer_tail = 0; | |||||
#endif | |||||
static uint8_t tx_pin_num = 48; | |||||
// UART0 and UART1 are clocked by F_CPU, UART2 is clocked by F_BUS | |||||
// UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer | |||||
#define C2_ENABLE UART_C2_TE | UART_C2_RE | UART_C2_RIE | |||||
#define C2_TX_ACTIVE C2_ENABLE | UART_C2_TIE | |||||
#define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE | |||||
#define C2_TX_INACTIVE C2_ENABLE | |||||
void serial6_begin(uint32_t divisor) | |||||
{ | |||||
SIM_SCGC1 |= SIM_SCGC1_UART5; // turn on clock, TODO: use bitband | |||||
rx_buffer_head = 0; | |||||
rx_buffer_tail = 0; | |||||
tx_buffer_head = 0; | |||||
tx_buffer_tail = 0; | |||||
transmitting = 0; | |||||
CORE_PIN47_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); | |||||
CORE_PIN48_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); | |||||
if (divisor < 32) divisor = 32; | |||||
UART5_BDH = (divisor >> 13) & 0x1F; | |||||
UART5_BDL = (divisor >> 5) & 0xFF; | |||||
UART5_C4 = divisor & 0x1F; | |||||
UART5_C1 = 0; | |||||
UART5_PFIFO = 0; | |||||
UART5_C2 = C2_TX_INACTIVE; | |||||
NVIC_SET_PRIORITY(IRQ_UART5_STATUS, IRQ_PRIORITY); | |||||
NVIC_ENABLE_IRQ(IRQ_UART5_STATUS); | |||||
} | |||||
void serial6_format(uint32_t format) | |||||
{ | |||||
uint8_t c; | |||||
c = UART5_C1; | |||||
c = (c & ~0x13) | (format & 0x03); // configure parity | |||||
if (format & 0x04) c |= 0x10; // 9 bits (might include parity) | |||||
UART5_C1 = c; | |||||
if ((format & 0x0F) == 0x04) UART5_C3 |= 0x40; // 8N2 is 9 bit with 9th bit always 1 | |||||
c = UART5_S2 & ~0x10; | |||||
if (format & 0x10) c |= 0x10; // rx invert | |||||
UART5_S2 = c; | |||||
c = UART5_C3 & ~0x10; | |||||
if (format & 0x20) c |= 0x10; // tx invert | |||||
UART5_C3 = c; | |||||
#ifdef SERIAL_9BIT_SUPPORT | |||||
c = UART5_C4 & 0x1F; | |||||
if (format & 0x08) c |= 0x20; // 9 bit mode with parity (requires 10 bits) | |||||
UART5_C4 = c; | |||||
use9Bits = format & 0x80; | |||||
#endif | |||||
// For T3.5 See about turning on 2 stop bit mode | |||||
if ( format & 0x100) { | |||||
uint8_t bdl = UART5_BDL; | |||||
UART5_BDH |= UART_BDH_SBNS; // Turn on 2 stop bits - was turned off by set baud | |||||
UART5_BDL = bdl; // Says BDH not acted on until BDL is written | |||||
} | |||||
} | |||||
void serial6_end(void) | |||||
{ | |||||
if (!(SIM_SCGC1 & SIM_SCGC1_UART5)) return; | |||||
while (transmitting) yield(); // wait for buffered data to send | |||||
NVIC_DISABLE_IRQ(IRQ_UART5_STATUS); | |||||
UART5_C2 = 0; | |||||
CORE_PIN47_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||||
CORE_PIN48_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||||
UART5_S1; | |||||
UART5_D; // clear leftover error status | |||||
rx_buffer_head = 0; | |||||
rx_buffer_tail = 0; | |||||
if (rts_pin) rts_deassert(); | |||||
} | |||||
void serial6_set_transmit_pin(uint8_t pin) | |||||
{ | |||||
while (transmitting) ; | |||||
pinMode(pin, OUTPUT); | |||||
digitalWrite(pin, LOW); | |||||
transmit_pin = portOutputRegister(pin); | |||||
} | |||||
void serial6_set_tx(uint8_t pin, uint8_t opendrain) | |||||
{ | |||||
uint32_t cfg; | |||||
if (opendrain) pin |= 128; | |||||
if (pin == tx_pin_num) return; | |||||
if ((SIM_SCGC1 & SIM_SCGC1_UART5)) { | |||||
switch (tx_pin_num & 127) { | |||||
case 48: CORE_PIN48_CONFIG = 0; break; // PTE24 | |||||
} | |||||
if (opendrain) { | |||||
cfg = PORT_PCR_DSE | PORT_PCR_ODE; | |||||
} else { | |||||
cfg = PORT_PCR_DSE | PORT_PCR_SRE; | |||||
} | |||||
switch (pin & 127) { | |||||
case 48: CORE_PIN48_CONFIG = cfg | PORT_PCR_MUX(3); break; | |||||
} | |||||
} | |||||
tx_pin_num = pin; | |||||
} | |||||
void serial6_set_rx(uint8_t pin) | |||||
{ | |||||
} | |||||
int serial6_set_rts(uint8_t pin) | |||||
{ | |||||
if (!(SIM_SCGC1 & SIM_SCGC1_UART5)) return 0; | |||||
if (pin < CORE_NUM_DIGITAL) { | |||||
rts_pin = portOutputRegister(pin); | |||||
pinMode(pin, OUTPUT); | |||||
rts_assert(); | |||||
} else { | |||||
rts_pin = NULL; | |||||
return 0; | |||||
} | |||||
return 1; | |||||
} | |||||
int serial6_set_cts(uint8_t pin) | |||||
{ | |||||
if (!(SIM_SCGC1 & SIM_SCGC1_UART5)) return 0; | |||||
if (pin == 56) { | |||||
CORE_PIN56_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_PE; // weak pulldown | |||||
} else { | |||||
UART5_MODEM &= ~UART_MODEM_TXCTSE; | |||||
return 0; | |||||
} | |||||
UART5_MODEM |= UART_MODEM_TXCTSE; | |||||
return 1; | |||||
} | |||||
void serial6_putchar(uint32_t c) | |||||
{ | |||||
uint32_t head, n; | |||||
if (!(SIM_SCGC1 & SIM_SCGC1_UART5)) return; | |||||
if (transmit_pin) transmit_assert(); | |||||
head = tx_buffer_head; | |||||
if (++head >= SERIAL6_TX_BUFFER_SIZE) head = 0; | |||||
while (tx_buffer_tail == head) { | |||||
int priority = nvic_execution_priority(); | |||||
if (priority <= IRQ_PRIORITY) { | |||||
if ((UART5_S1 & UART_S1_TDRE)) { | |||||
uint32_t tail = tx_buffer_tail; | |||||
if (++tail >= SERIAL6_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | |||||
if (use9Bits) UART5_C3 = (UART5_C3 & ~0x40) | ((n & 0x100) >> 2); | |||||
UART5_D = n; | |||||
tx_buffer_tail = tail; | |||||
} | |||||
} else if (priority >= 256) { | |||||
yield(); // wait | |||||
} | |||||
} | |||||
tx_buffer[head] = c; | |||||
transmitting = 1; | |||||
tx_buffer_head = head; | |||||
UART5_C2 = C2_TX_ACTIVE; | |||||
} | |||||
void serial6_write(const void *buf, unsigned int count) | |||||
{ | |||||
const uint8_t *p = (const uint8_t *)buf; | |||||
while (count-- > 0) serial6_putchar(*p++); | |||||
} | |||||
void serial6_flush(void) | |||||
{ | |||||
while (transmitting) yield(); // wait | |||||
} | |||||
int serial6_write_buffer_free(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
head = tx_buffer_head; | |||||
tail = tx_buffer_tail; | |||||
if (head >= tail) return SERIAL6_TX_BUFFER_SIZE - 1 - head + tail; | |||||
return tail - head - 1; | |||||
} | |||||
int serial6_available(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
head = rx_buffer_head; | |||||
tail = rx_buffer_tail; | |||||
if (head >= tail) return head - tail; | |||||
return SERIAL6_RX_BUFFER_SIZE + head - tail; | |||||
} | |||||
int serial6_getchar(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
int c; | |||||
head = rx_buffer_head; | |||||
tail = rx_buffer_tail; | |||||
if (head == tail) return -1; | |||||
if (++tail >= SERIAL6_RX_BUFFER_SIZE) tail = 0; | |||||
c = rx_buffer[tail]; | |||||
rx_buffer_tail = tail; | |||||
if (rts_pin) { | |||||
int avail; | |||||
if (head >= tail) avail = head - tail; | |||||
else avail = SERIAL6_RX_BUFFER_SIZE + head - tail; | |||||
if (avail <= RTS_LOW_WATERMARK) rts_assert(); | |||||
} | |||||
return c; | |||||
} | |||||
int serial6_peek(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
head = rx_buffer_head; | |||||
tail = rx_buffer_tail; | |||||
if (head == tail) return -1; | |||||
if (++tail >= SERIAL6_RX_BUFFER_SIZE) tail = 0; | |||||
return rx_buffer[tail]; | |||||
} | |||||
void serial6_clear(void) | |||||
{ | |||||
rx_buffer_head = rx_buffer_tail; | |||||
if (rts_pin) rts_assert(); | |||||
} | |||||
// status interrupt combines | |||||
// Transmit data below watermark UART_S1_TDRE | |||||
// Transmit complete UART_S1_TC | |||||
// Idle line UART_S1_IDLE | |||||
// Receive data above watermark UART_S1_RDRF | |||||
// LIN break detect UART_S2_LBKDIF | |||||
// RxD pin active edge UART_S2_RXEDGIF | |||||
void uart5_status_isr(void) | |||||
{ | |||||
uint32_t head, tail, n; | |||||
uint8_t c; | |||||
if (UART5_S1 & UART_S1_RDRF) { | |||||
if (use9Bits && (UART5_C3 & 0x80)) { | |||||
n = UART5_D | 0x100; | |||||
} else { | |||||
n = UART5_D; | |||||
} | |||||
head = rx_buffer_head + 1; | |||||
if (head >= SERIAL6_RX_BUFFER_SIZE) head = 0; | |||||
if (head != rx_buffer_tail) { | |||||
rx_buffer[head] = n; | |||||
rx_buffer_head = head; | |||||
} | |||||
if (rts_pin) { | |||||
int avail; | |||||
tail = tx_buffer_tail; | |||||
if (head >= tail) avail = head - tail; | |||||
else avail = SERIAL6_RX_BUFFER_SIZE + head - tail; | |||||
if (avail >= RTS_HIGH_WATERMARK) rts_deassert(); | |||||
} | |||||
} | |||||
c = UART5_C2; | |||||
if ((c & UART_C2_TIE) && (UART5_S1 & UART_S1_TDRE)) { | |||||
head = tx_buffer_head; | |||||
tail = tx_buffer_tail; | |||||
if (head == tail) { | |||||
UART5_C2 = C2_TX_COMPLETING; | |||||
} else { | |||||
if (++tail >= SERIAL6_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | |||||
if (use9Bits) UART5_C3 = (UART5_C3 & ~0x40) | ((n & 0x100) >> 2); | |||||
UART5_D = n; | |||||
tx_buffer_tail = tail; | |||||
} | |||||
} | |||||
if ((c & UART_C2_TCIE) && (UART5_S1 & UART_S1_TC)) { | |||||
transmitting = 0; | |||||
if (transmit_pin) transmit_deassert(); | |||||
UART5_C2 = C2_TX_INACTIVE; | |||||
} | |||||
} | |||||
#endif // HAS_KINETISK_UART5 |
/* 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 "kinetis.h" | |||||
#include "core_pins.h" | |||||
#include "HardwareSerial.h" | |||||
#ifdef HAS_KINETISK_LPUART0 | |||||
#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) | |||||
#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) | |||||
#define BITBAND_SET_BIT(reg, bit) (*GPIO_BITBAND_PTR((reg), (bit)) = 1) | |||||
#define BITBAND_CLR_BIT(reg, bit) (*GPIO_BITBAND_PTR((reg), (bit)) = 0) | |||||
#define TCIE_BIT 22 | |||||
#define TIE_BIT 23 | |||||
//////////////////////////////////////////////////////////////// | |||||
// Tunable parameters (relatively safe to edit these numbers) | |||||
//////////////////////////////////////////////////////////////// | |||||
#ifndef SERIAL6_TX_BUFFER_SIZE | |||||
#define SERIAL6_TX_BUFFER_SIZE 40 // number of outgoing bytes to buffer | |||||
#endif | |||||
#ifndef SERIAL6_RX_BUFFER_SIZE | |||||
#define SERIAL6_RX_BUFFER_SIZE 64 // number of incoming bytes to buffer | |||||
#endif | |||||
#define RTS_HIGH_WATERMARK (SERIAL6_RX_BUFFER_SIZE-24) // RTS requests sender to pause | |||||
#define RTS_LOW_WATERMARK (SERIAL6_RX_BUFFER_SIZE-38) // RTS allows sender to resume | |||||
#define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest | |||||
//////////////////////////////////////////////////////////////// | |||||
// changes not recommended below this point.... | |||||
//////////////////////////////////////////////////////////////// | |||||
#ifdef SERIAL_9BIT_SUPPORT | |||||
static uint8_t use9Bits = 0; | |||||
#define BUFTYPE uint16_t | |||||
#else | |||||
#define BUFTYPE uint8_t | |||||
#define use9Bits 0 | |||||
#endif | |||||
static volatile BUFTYPE tx_buffer[SERIAL6_TX_BUFFER_SIZE]; | |||||
static volatile BUFTYPE rx_buffer[SERIAL6_RX_BUFFER_SIZE]; | |||||
static volatile uint8_t transmitting = 0; | |||||
static volatile uint8_t *transmit_pin=NULL; | |||||
#define transmit_assert() *transmit_pin = 1 | |||||
#define transmit_deassert() *transmit_pin = 0 | |||||
static volatile uint8_t *rts_pin=NULL; | |||||
#define rts_assert() *rts_pin = 0 | |||||
#define rts_deassert() *rts_pin = 1 | |||||
#if SERIAL6_TX_BUFFER_SIZE > 255 | |||||
static volatile uint16_t tx_buffer_head = 0; | |||||
static volatile uint16_t tx_buffer_tail = 0; | |||||
#else | |||||
static volatile uint8_t tx_buffer_head = 0; | |||||
static volatile uint8_t tx_buffer_tail = 0; | |||||
#endif | |||||
#if SERIAL6_RX_BUFFER_SIZE > 255 | |||||
static volatile uint16_t rx_buffer_head = 0; | |||||
static volatile uint16_t rx_buffer_tail = 0; | |||||
#else | |||||
static volatile uint8_t rx_buffer_head = 0; | |||||
static volatile uint8_t rx_buffer_tail = 0; | |||||
#endif | |||||
static uint8_t tx_pin_num = 48; | |||||
// UART0 and UART1 are clocked by F_CPU, UART2 is clocked by F_BUS | |||||
// UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer | |||||
void serial6_begin(uint32_t desiredBaudRate) | |||||
{ | |||||
#define F_LPUART_CLOCK_SPEED 48000000 //F_BUS | |||||
// Make sure the clock for this uart is enabled, else the registers are not | |||||
// vailable. | |||||
SIM_SCGC2 |= SIM_SCGC2_LPUART0; // Turn on the clock | |||||
// Convert the baud rate to best divisor and OSR, based off of code I found in posting | |||||
// try to find an OSR > 4 with the minimum difference from the actual disired baud rate. | |||||
uint16_t sbr, sbrTemp, osrCheck; | |||||
uint32_t osr, baudDiffCheck, calculatedBaud, baudDiff; | |||||
uint32_t clockSpeed; | |||||
// First lets figure out what the LPUART Clock speed is. | |||||
uint32_t PLLFLLSEL = SIM_SOPT2 & SIM_SOPT2_IRC48SEL; // Note: Bot bits on here | |||||
if (PLLFLLSEL == SIM_SOPT2_IRC48SEL) | |||||
clockSpeed = 48000000; // Fixed to 48mhz | |||||
else if (PLLFLLSEL == SIM_SOPT2_PLLFLLSEL) | |||||
clockSpeed = F_PLL; // Using PLL clock | |||||
else | |||||
clockSpeed = F_CPU/4; // FLL clock, guessing | |||||
osr = 4; | |||||
sbr = (clockSpeed/(desiredBaudRate * osr)); | |||||
/*set sbr to 1 if the clockSpeed can not satisfy the desired baud rate*/ | |||||
if(sbr == 0) { | |||||
// Maybe print something. | |||||
return; // can not initialize | |||||
} | |||||
// With integer math the divide*muliply implies the calculated baud will be >= desired baud | |||||
calculatedBaud = (clockSpeed / (osr * sbr)); | |||||
baudDiff = calculatedBaud - desiredBaudRate; | |||||
// Check if better off with sbr+1 | |||||
if (baudDiff != 0) { | |||||
calculatedBaud = (clockSpeed / (osr * (sbr + 1))); | |||||
baudDiffCheck = desiredBaudRate - calculatedBaud ; | |||||
if (baudDiffCheck < baudDiff) { | |||||
sbr++; // use the higher sbr | |||||
baudDiff = baudDiffCheck; | |||||
} | |||||
} | |||||
// loop to find the best osr value possible, one that generates minimum baudDiff | |||||
for (osrCheck = 5; osrCheck <= 32; osrCheck++) { | |||||
sbrTemp = (clockSpeed/(desiredBaudRate * osrCheck)); | |||||
if(sbrTemp == 0) | |||||
break; // higher divisor returns 0 so can not use... | |||||
// Remember integer math so (X/Y)*Y will always be <=X | |||||
calculatedBaud = (clockSpeed / (osrCheck * sbrTemp)); | |||||
baudDiffCheck = calculatedBaud - desiredBaudRate; | |||||
if (baudDiffCheck <= baudDiff) { | |||||
baudDiff = baudDiffCheck; | |||||
osr = osrCheck; | |||||
sbr = sbrTemp; | |||||
} | |||||
// Lets try the rounded up one as well | |||||
if (baudDiffCheck) { | |||||
calculatedBaud = (clockSpeed / (osrCheck * ++sbrTemp)); | |||||
baudDiffCheck = desiredBaudRate - calculatedBaud; | |||||
if (baudDiffCheck <= baudDiff) { | |||||
baudDiff = baudDiffCheck; | |||||
osr = osrCheck; | |||||
sbr = sbrTemp; | |||||
} | |||||
} | |||||
} | |||||
// for lower OSR <= 7x turn on both edge sampling | |||||
uint32_t lpb = LPUART_BAUD_OSR(osr-1) | LPUART_BAUD_SBR(sbr); | |||||
if (osr < 8) { | |||||
lpb |= LPUART_BAUD_BOTHEDGE; | |||||
} | |||||
LPUART0_BAUD = lpb; | |||||
SIM_SOPT2 |= SIM_SOPT2_LPUARTSRC(1); // Lets use PLL? | |||||
rx_buffer_head = 0; | |||||
rx_buffer_tail = 0; | |||||
tx_buffer_head = 0; | |||||
tx_buffer_tail = 0; | |||||
transmitting = 0; | |||||
CORE_PIN47_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(5); | |||||
CORE_PIN48_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(5); | |||||
LPUART0_CTRL = 0; | |||||
LPUART0_MATCH = 0; | |||||
LPUART0_STAT = 0; | |||||
// Enable the transmitter, receiver and enable receiver interrupt | |||||
LPUART0_CTRL |= LPUART_CTRL_RIE | LPUART_CTRL_TE | LPUART_CTRL_RE; | |||||
NVIC_SET_PRIORITY(IRQ_LPUART0, IRQ_PRIORITY); | |||||
NVIC_ENABLE_IRQ(IRQ_LPUART0); | |||||
} | |||||
void serial6_format(uint32_t format) | |||||
{ | |||||
uint32_t c; | |||||
// Bits 0-2 - Parity plus 9 bit. | |||||
c = LPUART0_CTRL; | |||||
//c = (c & ~(LPUART_CTRL_M | LPUART_CTRL_PE | LPUART_CTRL_PT)) | (format & (LPUART_CTRL_PE | LPUART_CTRL_PT)); // configure parity | |||||
//if (format & 0x04) c |= LPUART_CTRL_M; // 9 bits (might include parity) | |||||
c = (c & ~0x13) | (format & 0x03); // configure parity | |||||
if (format & 0x04) c |= 0x10; // 9 bits (might include parity) | |||||
LPUART0_CTRL = c; | |||||
if ((format & 0x0F) == 0x04) LPUART0_CTRL |= LPUART_CTRL_T8; // 8N2 is 9 bit with 9th bit always 1 | |||||
// Bit 3 10 bit - Will assume that begin already cleared it. | |||||
if (format & 0x08) | |||||
LPUART0_BAUD |= LPUART_BAUD_M10; | |||||
// Bit 4 RXINVERT | |||||
c = LPUART0_STAT & ~LPUART_STAT_RXINV; | |||||
if (format & 0x10) c |= LPUART_STAT_RXINV; // rx invert | |||||
LPUART0_STAT = c; | |||||
// Bit 5 TXINVERT | |||||
c = LPUART0_CTRL & ~LPUART_CTRL_TXINV; | |||||
if (format & 0x20) c |= LPUART_CTRL_TXINV; // tx invert | |||||
LPUART0_CTRL = c; | |||||
// For T3.6 See about turning on 2 stop bit mode | |||||
if ( format & 0x100) LPUART0_BAUD |= LPUART_BAUD_SBNS; | |||||
} | |||||
void serial6_end(void) | |||||
{ | |||||
if (!(SIM_SCGC2 & SIM_SCGC2_LPUART0)) return; | |||||
while (transmitting) yield(); // wait for buffered data to send | |||||
NVIC_DISABLE_IRQ(IRQ_LPUART0); | |||||
LPUART0_CTRL = 0; | |||||
CORE_PIN47_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||||
CORE_PIN48_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||||
rx_buffer_head = 0; | |||||
rx_buffer_tail = 0; | |||||
if (rts_pin) rts_deassert(); | |||||
} | |||||
void serial6_set_transmit_pin(uint8_t pin) | |||||
{ | |||||
while (transmitting) ; | |||||
pinMode(pin, OUTPUT); | |||||
digitalWrite(pin, LOW); | |||||
transmit_pin = portOutputRegister(pin); | |||||
} | |||||
void serial6_set_tx(uint8_t pin, uint8_t opendrain) | |||||
{ | |||||
uint32_t cfg; | |||||
if (opendrain) pin |= 128; | |||||
if (pin == tx_pin_num) return; | |||||
if ((SIM_SCGC2 & SIM_SCGC2_LPUART0)) { | |||||
switch (tx_pin_num & 127) { | |||||
case 48: CORE_PIN48_CONFIG = 0; break; // PTE24 | |||||
} | |||||
if (opendrain) { | |||||
cfg = PORT_PCR_DSE | PORT_PCR_ODE; | |||||
} else { | |||||
cfg = PORT_PCR_DSE | PORT_PCR_SRE; | |||||
} | |||||
switch (pin & 127) { | |||||
case 48: CORE_PIN48_CONFIG = cfg | PORT_PCR_MUX(5); break; | |||||
} | |||||
} | |||||
tx_pin_num = pin; | |||||
} | |||||
void serial6_set_rx(uint8_t pin) | |||||
{ | |||||
} | |||||
int serial6_set_rts(uint8_t pin) | |||||
{ | |||||
if (!(SIM_SCGC2 & SIM_SCGC2_LPUART0)) return 0; | |||||
if (pin < CORE_NUM_DIGITAL) { | |||||
rts_pin = portOutputRegister(pin); | |||||
pinMode(pin, OUTPUT); | |||||
rts_assert(); | |||||
} else { | |||||
rts_pin = NULL; | |||||
return 0; | |||||
} | |||||
return 1; | |||||
} | |||||
int serial6_set_cts(uint8_t pin) | |||||
{ | |||||
if (!(SIM_SCGC2 & SIM_SCGC2_LPUART0)) return 0; | |||||
if (pin == 56) { | |||||
CORE_PIN56_CONFIG = PORT_PCR_MUX(5) | PORT_PCR_PE; // weak pulldown | |||||
} else { | |||||
UART5_MODEM &= ~UART_MODEM_TXCTSE; | |||||
return 0; | |||||
} | |||||
UART5_MODEM |= UART_MODEM_TXCTSE; | |||||
return 1; | |||||
} | |||||
void serial6_putchar(uint32_t c) | |||||
{ | |||||
uint32_t head, n; | |||||
if (!(SIM_SCGC2 & SIM_SCGC2_LPUART0)) return; | |||||
if (transmit_pin) transmit_assert(); | |||||
head = tx_buffer_head; | |||||
if (++head >= SERIAL6_TX_BUFFER_SIZE) head = 0; | |||||
while (tx_buffer_tail == head) { | |||||
int priority = nvic_execution_priority(); | |||||
if (priority <= IRQ_PRIORITY) { | |||||
if ((LPUART0_STAT & LPUART_STAT_TDRE)) { | |||||
uint32_t tail = tx_buffer_tail; | |||||
if (++tail >= SERIAL6_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | |||||
//if (use9Bits) UART5_C3 = (UART5_C3 & ~0x40) | ((n & 0x100) >> 2); | |||||
LPUART0_DATA = n; | |||||
tx_buffer_tail = tail; | |||||
} | |||||
} else if (priority >= 256) { | |||||
yield(); // wait | |||||
} | |||||
} | |||||
tx_buffer[head] = c; | |||||
transmitting = 1; | |||||
tx_buffer_head = head; | |||||
//LPUART0_CTRL |= LPUART_CTRL_TIE; // enable the transmit interrupt | |||||
BITBAND_SET_BIT(LPUART0_CTRL, TIE_BIT); | |||||
} | |||||
void serial6_write(const void *buf, unsigned int count) | |||||
{ | |||||
const uint8_t *p = (const uint8_t *)buf; | |||||
while (count-- > 0) serial6_putchar(*p++); | |||||
} | |||||
void serial6_flush(void) | |||||
{ | |||||
while (transmitting) yield(); // wait | |||||
} | |||||
int serial6_write_buffer_free(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
head = tx_buffer_head; | |||||
tail = tx_buffer_tail; | |||||
if (head >= tail) return SERIAL6_TX_BUFFER_SIZE - 1 - head + tail; | |||||
return tail - head - 1; | |||||
} | |||||
int serial6_available(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
head = rx_buffer_head; | |||||
tail = rx_buffer_tail; | |||||
if (head >= tail) return head - tail; | |||||
return SERIAL6_RX_BUFFER_SIZE + head - tail; | |||||
} | |||||
int serial6_getchar(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
int c; | |||||
head = rx_buffer_head; | |||||
tail = rx_buffer_tail; | |||||
if (head == tail) return -1; | |||||
if (++tail >= SERIAL6_RX_BUFFER_SIZE) tail = 0; | |||||
c = rx_buffer[tail]; | |||||
rx_buffer_tail = tail; | |||||
if (rts_pin) { | |||||
int avail; | |||||
if (head >= tail) avail = head - tail; | |||||
else avail = SERIAL6_RX_BUFFER_SIZE + head - tail; | |||||
if (avail <= RTS_LOW_WATERMARK) rts_assert(); | |||||
} | |||||
return c; | |||||
} | |||||
int serial6_peek(void) | |||||
{ | |||||
uint32_t head, tail; | |||||
head = rx_buffer_head; | |||||
tail = rx_buffer_tail; | |||||
if (head == tail) return -1; | |||||
if (++tail >= SERIAL6_RX_BUFFER_SIZE) tail = 0; | |||||
return rx_buffer[tail]; | |||||
} | |||||
void serial6_clear(void) | |||||
{ | |||||
rx_buffer_head = rx_buffer_tail; | |||||
if (rts_pin) rts_assert(); | |||||
} | |||||
// status interrupt combines | |||||
// Transmit data below watermark LPUART_STAT_TDRE | |||||
// Transmit complete LPUART_STAT_TC | |||||
// Idle line LPUART_STAT_IDLE | |||||
// Receive data above watermark LPUART_STAT_RDRF | |||||
// LIN break detect UART_S2_LBKDIF | |||||
// RxD pin active edge UART_S2_RXEDGIF | |||||
void lpuart0_status_isr(void) | |||||
{ | |||||
uint32_t head, tail, n; | |||||
uint32_t c; | |||||
if (LPUART0_STAT & LPUART_STAT_RDRF) { | |||||
// if (use9Bits && (UART5_C3 & 0x80)) { | |||||
// n = UART5_D | 0x100; | |||||
// } else { | |||||
// n = UART5_D; | |||||
// } | |||||
n = LPUART0_DATA & 0x3ff; // use only the 10 data bits | |||||
head = rx_buffer_head + 1; | |||||
if (head >= SERIAL6_RX_BUFFER_SIZE) head = 0; | |||||
if (head != rx_buffer_tail) { | |||||
rx_buffer[head] = n; | |||||
rx_buffer_head = head; | |||||
} | |||||
if (rts_pin) { | |||||
int avail; | |||||
tail = tx_buffer_tail; | |||||
if (head >= tail) avail = head - tail; | |||||
else avail = SERIAL6_RX_BUFFER_SIZE + head - tail; | |||||
if (avail >= RTS_HIGH_WATERMARK) rts_deassert(); | |||||
} | |||||
} | |||||
c = LPUART0_CTRL; | |||||
if ((c & LPUART_CTRL_TIE) && (LPUART0_STAT & LPUART_STAT_TDRE)) { | |||||
head = tx_buffer_head; | |||||
tail = tx_buffer_tail; | |||||
if (head == tail) { | |||||
BITBAND_CLR_BIT(LPUART0_CTRL, TIE_BIT); | |||||
BITBAND_SET_BIT(LPUART0_CTRL, TCIE_BIT); | |||||
//LPUART0_CTRL &= ~LPUART_CTRL_TIE; | |||||
//LPUART0_CTRL |= LPUART_CTRL_TCIE; // Actually wondering if we can just leave this one on... | |||||
} else { | |||||
if (++tail >= SERIAL6_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | |||||
//if (use9Bits) UART5_C3 = (UART5_C3 & ~0x40) | ((n & 0x100) >> 2); | |||||
LPUART0_DATA = n; | |||||
tx_buffer_tail = tail; | |||||
} | |||||
} | |||||
if ((c & LPUART_CTRL_TCIE) && (LPUART0_STAT & LPUART_STAT_TC)) { | |||||
transmitting = 0; | |||||
if (transmit_pin) transmit_deassert(); | |||||
BITBAND_CLR_BIT(LPUART0_CTRL, TCIE_BIT); | |||||
// LPUART0_CTRL &= ~LPUART_CTRL_TCIE; // Actually wondering if we can just leave this one on... | |||||
} | |||||
} | |||||
#endif // HAS_KINETISK_LPUART0 |
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
* | * | ||||
* 1. The above copyright notice and this permission notice shall be | |||||
* 1. The above copyright notice and this permission notice shall be | |||||
* included in all copies or substantial portions of the Software. | * included in all copies or substantial portions of the Software. | ||||
* | * | ||||
* 2. If the Software is incorporated into a build system that allows | |||||
* 2. If the Software is incorporated into a build system that allows | |||||
* selection among a list of target devices, then similar target | * selection among a list of target devices, then similar target | ||||
* devices manufactured by PJRC.COM must be included in the list of | * devices manufactured by PJRC.COM must be included in the list of | ||||
* target devices and selectable in the same manner. | * target devices and selectable in the same manner. | ||||
#include "core_pins.h" | #include "core_pins.h" | ||||
//#include "HardwareSerial.h" | //#include "HardwareSerial.h" | ||||
#if defined(HAS_KINETIS_TSI) || defined(HAS_KINETIS_TSI_LITE) | |||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) | #if defined(__MK20DX128__) || defined(__MK20DX256__) | ||||
// These settings give approx 0.02 pF sensitivity and 1200 pF range | // These settings give approx 0.02 pF sensitivity and 1200 pF range | ||||
// Lower current, higher number of scans, and higher prescaler | // Lower current, higher number of scans, and higher prescaler | ||||
}; | }; | ||||
#elif defined(__MK66FX1M0__) | #elif defined(__MK66FX1M0__) | ||||
#define CURRENT 2 | |||||
#define NSCAN 9 | #define NSCAN 9 | ||||
#define PRESCALE 2 | #define PRESCALE 2 | ||||
static const uint8_t pin2tsi[] = { | static const uint8_t pin2tsi[] = { | ||||
int touchRead(uint8_t pin) | int touchRead(uint8_t pin) | ||||
{ | { | ||||
#if defined(__MK64FX512__) | |||||
return 0; // no Touch sensing :( | |||||
#else | |||||
uint32_t ch; | uint32_t ch; | ||||
if (pin >= NUM_DIGITAL_PINS) return 0; | if (pin >= NUM_DIGITAL_PINS) return 0; | ||||
*portConfigRegister(pin) = PORT_PCR_MUX(0); | *portConfigRegister(pin) = PORT_PCR_MUX(0); | ||||
SIM_SCGC5 |= SIM_SCGC5_TSI; | SIM_SCGC5 |= SIM_SCGC5_TSI; | ||||
#if defined(KINETISK) | |||||
#if defined(HAS_KINETIS_TSI) | |||||
TSI0_GENCS = 0; | TSI0_GENCS = 0; | ||||
TSI0_PEN = (1 << ch); | TSI0_PEN = (1 << ch); | ||||
TSI0_SCANC = TSI_SCANC_REFCHRG(3) | TSI_SCANC_EXTCHRG(CURRENT); | TSI0_SCANC = TSI_SCANC_REFCHRG(3) | TSI_SCANC_EXTCHRG(CURRENT); | ||||
while (TSI0_GENCS & TSI_GENCS_SCNIP) ; // wait | while (TSI0_GENCS & TSI_GENCS_SCNIP) ; // wait | ||||
delayMicroseconds(1); | delayMicroseconds(1); | ||||
return *((volatile uint16_t *)(&TSI0_CNTR1) + ch); | return *((volatile uint16_t *)(&TSI0_CNTR1) + ch); | ||||
#elif defined(KINETISL) | |||||
#elif defined(HAS_KINETIS_TSI_LITE) | |||||
TSI0_GENCS = TSI_GENCS_REFCHRG(4) | TSI_GENCS_EXTCHRG(3) | TSI_GENCS_PS(PRESCALE) | TSI0_GENCS = TSI_GENCS_REFCHRG(4) | TSI_GENCS_EXTCHRG(3) | TSI_GENCS_PS(PRESCALE) | ||||
| TSI_GENCS_NSCN(NSCAN) | TSI_GENCS_TSIEN | TSI_GENCS_EOSF; | | TSI_GENCS_NSCN(NSCAN) | TSI_GENCS_TSIEN | TSI_GENCS_EOSF; | ||||
TSI0_DATA = TSI_DATA_TSICH(ch) | TSI_DATA_SWTS; | TSI0_DATA = TSI_DATA_TSICH(ch) | TSI_DATA_SWTS; | ||||
delayMicroseconds(1); | delayMicroseconds(1); | ||||
return TSI0_DATA & 0xFFFF; | return TSI0_DATA & 0xFFFF; | ||||
#endif | #endif | ||||
#endif | |||||
} | } | ||||
#else | |||||
int touchRead(uint8_t pin) | |||||
{ | |||||
return 0; // no Touch sensing :( | |||||
} | |||||
#endif | |||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2016 PJRC.COM, LLC. | |||||
* Copyright (c) 2017 PJRC.COM, LLC. | |||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* 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 | ||||
// Uncomment this to work around a limitation in Macintosh adaptive rates | |||||
// This is not a perfect solution. Details here: | |||||
// https://forum.pjrc.com/threads/34855-Distorted-audio-when-using-USB-input-on-Teensy-3-1 | |||||
//#define MACOSX_ADAPTIVE_LIMIT | |||||
bool AudioInputUSB::update_responsibility; | bool AudioInputUSB::update_responsibility; | ||||
audio_block_t * AudioInputUSB::incoming_left; | audio_block_t * AudioInputUSB::incoming_left; | ||||
audio_block_t * AudioInputUSB::incoming_right; | audio_block_t * AudioInputUSB::incoming_right; | ||||
uint16_t AudioInputUSB::incoming_count; | uint16_t AudioInputUSB::incoming_count; | ||||
uint8_t AudioInputUSB::receive_flag; | uint8_t AudioInputUSB::receive_flag; | ||||
struct usb_audio_features_struct AudioInputUSB::features = {0,0,FEATURE_MAX_VOLUME}; | |||||
struct usb_audio_features_struct AudioInputUSB::features = {0,0,FEATURE_MAX_VOLUME/2}; | |||||
#define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4))) | #define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4))) | ||||
uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR; | uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR; | ||||
// but also because the PC may stop transmitting data, which | // but also because the PC may stop transmitting data, which | ||||
// means we no longer get receive callbacks from usb_dev. | // means we no longer get receive callbacks from usb_dev. | ||||
update_responsibility = false; | update_responsibility = false; | ||||
//usb_audio_sync_feedback = 722824; | |||||
//usb_audio_sync_feedback = 723700; // too fast? | |||||
usb_audio_sync_feedback = 722534; // too slow | |||||
usb_audio_sync_feedback = feedback_accumulator >> 8; | |||||
} | } | ||||
static void copy_to_buffers(const uint32_t *src, int16_t *left, int16_t *right, unsigned int len) | static void copy_to_buffers(const uint32_t *src, int16_t *left, int16_t *right, unsigned int len) | ||||
while ((src < target - 2)) { | while ((src < target - 2)) { | ||||
uint32_t n1 = *src++; | uint32_t n1 = *src++; | ||||
uint32_t n = *src++; | uint32_t n = *src++; | ||||
*(uint32_t *)left = n1 & 0xFFFF | ((n & 0xFFFF) << 16); | |||||
*(uint32_t *)left = (n1 & 0xFFFF) | ((n & 0xFFFF) << 16); | |||||
left+=2; | left+=2; | ||||
*(uint32_t *)right = (n1 >> 16) | ((n & 0xFFFF0000)) ; | *(uint32_t *)right = (n1 >> 16) | ((n & 0xFFFF0000)) ; | ||||
right+=2; | right+=2; | ||||
__enable_irq(); | __enable_irq(); | ||||
if (f) { | if (f) { | ||||
int diff = AUDIO_BLOCK_SAMPLES/2 - (int)c; | int diff = AUDIO_BLOCK_SAMPLES/2 - (int)c; | ||||
feedback_accumulator += diff; | |||||
// TODO: min/max sanity check for feedback_accumulator?? | |||||
usb_audio_sync_feedback = (feedback_accumulator >> 8) + diff * 3; | |||||
feedback_accumulator += diff / 3; | |||||
uint32_t feedback = (feedback_accumulator >> 8) + diff * 100; | |||||
#ifdef MACOSX_ADAPTIVE_LIMIT | |||||
if (feedback > 722698) feedback = 722698; | |||||
#endif | |||||
usb_audio_sync_feedback = feedback; | |||||
//if (diff > 0) { | //if (diff > 0) { | ||||
//serial_print("."); | //serial_print("."); | ||||
//} else if (diff < 0) { | //} else if (diff < 0) { | ||||
//serial_print("."); | //serial_print("."); | ||||
if (!left || !right) { | if (!left || !right) { | ||||
//serial_print("#"); // buffer underrun - PC sending too slow | //serial_print("#"); // buffer underrun - PC sending too slow | ||||
if (f) feedback_accumulator += 10 << 8; | |||||
//if (f) feedback_accumulator += 10 << 8; | |||||
} | } | ||||
if (left) { | if (left) { | ||||
transmit(left, 0); | transmit(left, 0); | ||||
{ | { | ||||
audio_block_t *left, *right; | audio_block_t *left, *right; | ||||
left = receiveReadOnly(0); // input 0 = left channel | |||||
right = receiveReadOnly(1); // input 1 = right channel | |||||
// TODO: we shouldn't be writing to these...... | |||||
//left = receiveReadOnly(0); // input 0 = left channel | |||||
//right = receiveReadOnly(1); // input 1 = right channel | |||||
left = receiveWritable(0); // input 0 = left channel | |||||
right = receiveWritable(1); // input 1 = right channel | |||||
if (usb_audio_transmit_setting == 0) { | if (usb_audio_transmit_setting == 0) { | ||||
if (left) release(left); | if (left) release(left); | ||||
if (right) release(right); | if (right) release(right); | ||||
return; | return; | ||||
} | } | ||||
if (left == NULL) { | if (left == NULL) { | ||||
if (right == NULL) return; | |||||
right->ref_count++; | |||||
left = right; | |||||
} else if (right == NULL) { | |||||
left->ref_count++; | |||||
right = left; | |||||
left = allocate(); | |||||
if (left == NULL) { | |||||
if (right) release(right); | |||||
return; | |||||
} | |||||
memset(left->data, 0, sizeof(left->data)); | |||||
} | |||||
if (right == NULL) { | |||||
right = allocate(); | |||||
if (right == NULL) { | |||||
release(left); | |||||
return; | |||||
} | |||||
memset(right->data, 0, sizeof(right->data)); | |||||
} | } | ||||
__disable_irq(); | __disable_irq(); | ||||
if (left_1st == NULL) { | if (left_1st == NULL) { | ||||
return target * 4; | return target * 4; | ||||
} | } | ||||
struct setup_struct { | |||||
union { | |||||
struct { | |||||
uint8_t bmRequestType; | |||||
uint8_t bRequest; | |||||
union { | |||||
struct { | |||||
uint8_t bChannel; // 0=main, 1=left, 2=right | |||||
uint8_t bCS; // Control Selector | |||||
}; | |||||
uint16_t wValue; | |||||
}; | |||||
union { | |||||
struct { | |||||
uint8_t bIfEp; // type of entity | |||||
uint8_t bEntityId; // UnitID, TerminalID, etc. | |||||
}; | |||||
uint16_t wIndex; | |||||
}; | |||||
uint16_t wLength; | |||||
}; | |||||
}; | |||||
}; | |||||
int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen) | int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen) | ||||
{ | { | ||||
struct setup_struct setup = *((struct setup_struct *)stp); | struct setup_struct setup = *((struct setup_struct *)stp); |
/* 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 USBaudio_h_ | #ifndef USBaudio_h_ | ||||
#define USBaudio_h_ | #define USBaudio_h_ | ||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
} | } | ||||
// setup struct definition could be moved from usb_dev.c to usb_dev.h so we can reuse | |||||
// it instead of redefining it here | |||||
struct setup_struct { | |||||
union { | |||||
struct { | |||||
uint8_t bmRequestType; | |||||
uint8_t bRequest; | |||||
union { | |||||
struct { | |||||
uint8_t bChannel; // 0=main, 1=left, 2=right | |||||
uint8_t bCS; // Control Selector | |||||
}; | |||||
uint16_t wValue; | |||||
}; | |||||
union { | |||||
struct { | |||||
uint8_t bIfEp; // type of entity | |||||
uint8_t bEntityId; // UnitID, TerminalID, etc. | |||||
}; | |||||
uint16_t wIndex; | |||||
}; | |||||
uint16_t wLength; | |||||
}; | |||||
}; | |||||
}; | |||||
// audio features supported | // audio features supported | ||||
struct usb_audio_features_struct { | struct usb_audio_features_struct { | ||||
int change; // set to 1 when any value is changed | int change; // set to 1 when any value is changed | ||||
friend void usb_audio_receive_callback(unsigned int len); | friend void usb_audio_receive_callback(unsigned int len); | ||||
friend int usb_audio_set_feature(void *stp, uint8_t *buf); | friend int usb_audio_set_feature(void *stp, uint8_t *buf); | ||||
friend int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen); | friend int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen); | ||||
static struct usb_audio_features_struct features; | static struct usb_audio_features_struct features; | ||||
float volume(void) { | |||||
if (features.mute) return 0.0; | |||||
return (float)(features.volume) * (1.0 / (float)FEATURE_MAX_VOLUME); | |||||
} | |||||
private: | private: | ||||
static bool update_responsibility; | static bool update_responsibility; | ||||
static audio_block_t *incoming_left; | static audio_block_t *incoming_left; |