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 and 3.0 core libraries for Arduino. | |||||
Teensy 2.0, 3.x, LC 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: | ||||
http://www.pjrc.com/teensy/td_download.html | http://www.pjrc.com/teensy/td_download.html | ||||
This version implements overclock to 120MHz, 144MHz and 168MHz. | |||||
Howto: | |||||
1. Overwrite Arduino\hardware\teensy\boards.txt with this version | |||||
2. Overwrite all in core/teensy3 with this version | |||||
# language keywords - Arduino doesn't define these, but probably should | |||||
volatile LITERAL1 | |||||
constexpr LITERAL1 | |||||
alignas LITERAL1 | |||||
alignof LITERAL1 | |||||
nullptr LITERAL1 | |||||
noexcept LITERAL1 | |||||
static_assert LITERAL1 | |||||
thread_local LITERAL1 | |||||
# teensy specific functions | |||||
elapsedMillis LITERAL1 | |||||
elapsedMicros LITERAL1 | |||||
readString KEYWORD2 | |||||
readStringUntil KEYWORD2 | |||||
analogReadRes KEYWORD2 | |||||
analogReadResolution KEYWORD2 | |||||
analogReadAveraging KEYWORD2 | |||||
analogWriteRes KEYWORD2 | |||||
analogWriteResolution KEYWORD2 | |||||
analogWriteFrequency KEYWORD2 | |||||
touchRead KEYWORD2 | |||||
Teensy3Clock KEYWORD2 | |||||
IntervalTimer KEYWORD2 | |||||
printf KEYWORD2 | |||||
digitalWriteFast KEYWORD2 | |||||
digitalReadFast KEYWORD2 | |||||
transmitterEnable KEYWORD2 | |||||
attachRts KEYWORD2 | |||||
attachCts KEYWORD2 | |||||
PROGMEM LITERAL1 | |||||
DMAMEM LITERAL1 | |||||
FASTRUN LITERAL1 | |||||
Serial4 KEYWORD1 | |||||
Serial5 KEYWORD1 | |||||
Serial6 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, now also removed from Teensyduino | |||||
#BYTE LITERAL1 | |||||
# Arduino constants | |||||
A0 LITERAL1 | |||||
A1 LITERAL1 | |||||
A2 LITERAL1 | |||||
A3 LITERAL1 | |||||
A4 LITERAL1 | |||||
A5 LITERAL1 | |||||
A6 LITERAL1 | |||||
A7 LITERAL1 | |||||
A8 LITERAL1 | |||||
A9 LITERAL1 | |||||
A10 LITERAL1 | |||||
A11 LITERAL1 | |||||
A12 LITERAL1 | |||||
A13 LITERAL1 | |||||
A14 LITERAL1 | |||||
A15 LITERAL1 | |||||
A16 LITERAL1 | |||||
A17 LITERAL1 | |||||
A18 LITERAL1 | |||||
A19 LITERAL1 | |||||
A20 LITERAL1 | |||||
A21 LITERAL1 | |||||
A22 LITERAL1 | |||||
A23 LITERAL1 | |||||
A24 LITERAL1 | |||||
A25 LITERAL1 | |||||
A26 LITERAL1 | |||||
SS LITERAL1 | |||||
MOSI LITERAL1 | |||||
MISO LITERAL1 | |||||
SCK LITERAL1 | |||||
SDA LITERAL1 | |||||
SCL LITERAL1 | |||||
NUM_DIGITAL_PINS LITERAL1 | |||||
NUM_ANALOG_INPUTS LITERAL1 | |||||
analogInputToDigitalPin KEYWORD2 | |||||
digitalPinHasPWM KEYWORD2 | |||||
NOT_AN_INTERRUPT LITERAL1 | |||||
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 | |||||
OUTPUT_OPENDRAIN LITERAL1 | |||||
INPUT_PULLUP LITERAL1 | |||||
INPUT_PULLDOWN LITERAL1 | |||||
INPUT_DISABLE LITERAL1 | |||||
# String functions | |||||
copy KEYWORD2 | |||||
append KEYWORD2 | |||||
# Teensy 2.0 pin names | |||||
PIN_A0 LITERAL1 | |||||
PIN_A1 LITERAL1 | |||||
PIN_A2 LITERAL1 | |||||
PIN_A3 LITERAL1 | |||||
PIN_A4 LITERAL1 | |||||
PIN_A5 LITERAL1 | |||||
PIN_A6 LITERAL1 | |||||
PIN_A7 LITERAL1 | |||||
PIN_B0 LITERAL1 | |||||
PIN_B1 LITERAL1 | |||||
PIN_B2 LITERAL1 | |||||
PIN_B3 LITERAL1 | |||||
PIN_B4 LITERAL1 | |||||
PIN_B5 LITERAL1 | |||||
PIN_B6 LITERAL1 | |||||
PIN_B7 LITERAL1 | |||||
PIN_C0 LITERAL1 | |||||
PIN_C1 LITERAL1 | |||||
PIN_C2 LITERAL1 | |||||
PIN_C3 LITERAL1 | |||||
PIN_C4 LITERAL1 | |||||
PIN_C5 LITERAL1 | |||||
PIN_C6 LITERAL1 | |||||
PIN_C7 LITERAL1 | |||||
PIN_D0 LITERAL1 | |||||
PIN_D1 LITERAL1 | |||||
PIN_D2 LITERAL1 | |||||
PIN_D3 LITERAL1 | |||||
PIN_D4 LITERAL1 | |||||
PIN_D5 LITERAL1 | |||||
PIN_D6 LITERAL1 | |||||
PIN_D7 LITERAL1 | |||||
PIN_E0 LITERAL1 | |||||
PIN_E1 LITERAL1 | |||||
PIN_E2 LITERAL1 | |||||
PIN_E3 LITERAL1 | |||||
PIN_E4 LITERAL1 | |||||
PIN_E5 LITERAL1 | |||||
PIN_E6 LITERAL1 | |||||
PIN_E7 LITERAL1 | |||||
PIN_F0 LITERAL1 | |||||
PIN_F1 LITERAL1 | |||||
PIN_F2 LITERAL1 | |||||
PIN_F3 LITERAL1 | |||||
PIN_F4 LITERAL1 | |||||
PIN_F5 LITERAL1 | |||||
PIN_F6 LITERAL1 | |||||
PIN_F7 LITERAL1 | |||||
PIN_SS LITERAL1 | |||||
PIN_SCLK LITERAL1 | |||||
PIN_MOSI LITERAL1 | |||||
PIN_MISO LITERAL1 | |||||
PIN_LED LITERAL1 | |||||
ANALOG_0 LITERAL1 AnalogRead | |||||
ANALOG_1 LITERAL1 AnalogRead | |||||
ANALOG_2 LITERAL1 AnalogRead | |||||
ANALOG_3 LITERAL1 AnalogRead | |||||
ANALOG_4 LITERAL1 AnalogRead | |||||
ANALOG_5 LITERAL1 AnalogRead | |||||
ANALOG_6 LITERAL1 AnalogRead | |||||
ANALOG_7 LITERAL1 AnalogRead | |||||
ANALOG_1_TO_0_X10 LITERAL1 AnalogRead | |||||
ANALOG_1_TO_0_X200 LITERAL1 AnalogRead | |||||
ANALOG_3_TO_2_X10 LITERAL1 AnalogRead | |||||
ANALOG_3_TO_2_X200 LITERAL1 AnalogRead | |||||
ANALOG_0_TO_1 LITERAL1 AnalogRead | |||||
ANALOG_2_TO_1 LITERAL1 AnalogRead | |||||
ANALOG_3_TO_1 LITERAL1 AnalogRead | |||||
ANALOG_4_TO_1 LITERAL1 AnalogRead | |||||
ANALOG_5_TO_1 LITERAL1 AnalogRead | |||||
ANALOG_6_TO_1 LITERAL1 AnalogRead | |||||
ANALOG_7_TO_1 LITERAL1 AnalogRead | |||||
ANALOG_0_TO_2 LITERAL1 AnalogRead | |||||
ANALOG_1_TO_2 LITERAL1 AnalogRead | |||||
ANALOG_3_TO_2 LITERAL1 AnalogRead | |||||
ANALOG_4_TO_2 LITERAL1 AnalogRead | |||||
ANALOG_5_TO_2 LITERAL1 AnalogRead | |||||
ANALOG_1_1V LITERAL1 AnalogRead | |||||
ANALOG_0V LITERAL1 AnalogRead | |||||
# USB Serial | |||||
send_now KEYWORD2 | |||||
baud KEYWORD2 | |||||
stopbits KEYWORD2 | |||||
paritytype KEYWORD2 | |||||
numbits KEYWORD2 | |||||
dtr KEYWORD2 | |||||
rts KEYWORD2 | |||||
# USB Keyboard | |||||
write_unicode KEYWORD2 | |||||
set_modifier KEYWORD2 | |||||
set_key1 KEYWORD2 | |||||
set_key2 KEYWORD2 | |||||
set_key3 KEYWORD2 | |||||
set_key4 KEYWORD2 | |||||
set_key5 KEYWORD2 | |||||
set_key6 KEYWORD2 | |||||
set_media KEYWORD2 | |||||
MODIFIERKEY_CTRL LITERAL1 | |||||
MODIFIERKEY_SHIFT LITERAL1 | |||||
MODIFIERKEY_ALT LITERAL1 | |||||
MODIFIERKEY_GUI LITERAL1 | |||||
MODIFIERKEY_LEFT_CTRL LITERAL1 | |||||
MODIFIERKEY_LEFT_SHIFT LITERAL1 | |||||
MODIFIERKEY_LEFT_ALT LITERAL1 | |||||
MODIFIERKEY_LEFT_GUI LITERAL1 | |||||
MODIFIERKEY_RIGHT_CTRL LITERAL1 | |||||
MODIFIERKEY_RIGHT_SHIFT LITERAL1 | |||||
MODIFIERKEY_RIGHT_ALT LITERAL1 | |||||
MODIFIERKEY_RIGHT_GUI LITERAL1 | |||||
KEY_MEDIA_VOLUME_INC LITERAL1 | |||||
KEY_MEDIA_VOLUME_DEC LITERAL1 | |||||
KEY_MEDIA_MUTE LITERAL1 | |||||
KEY_MEDIA_PLAY_PAUSE LITERAL1 | |||||
KEY_MEDIA_NEXT_TRACK LITERAL1 | |||||
KEY_MEDIA_PREV_TRACK LITERAL1 | |||||
KEY_MEDIA_STOP 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_B LITERAL1 | |||||
KEY_C LITERAL1 | |||||
KEY_D LITERAL1 | |||||
KEY_E LITERAL1 | |||||
KEY_F LITERAL1 | |||||
KEY_G LITERAL1 | |||||
KEY_H LITERAL1 | |||||
KEY_I LITERAL1 | |||||
KEY_J LITERAL1 | |||||
KEY_K LITERAL1 | |||||
KEY_L LITERAL1 | |||||
KEY_M LITERAL1 | |||||
KEY_N LITERAL1 | |||||
KEY_O LITERAL1 | |||||
KEY_P LITERAL1 | |||||
KEY_Q LITERAL1 | |||||
KEY_R LITERAL1 | |||||
KEY_S LITERAL1 | |||||
KEY_T LITERAL1 | |||||
KEY_U LITERAL1 | |||||
KEY_V LITERAL1 | |||||
KEY_W LITERAL1 | |||||
KEY_X LITERAL1 | |||||
KEY_Y LITERAL1 | |||||
KEY_Z LITERAL1 | |||||
KEY_1 LITERAL1 | |||||
KEY_2 LITERAL1 | |||||
KEY_3 LITERAL1 | |||||
KEY_4 LITERAL1 | |||||
KEY_5 LITERAL1 | |||||
KEY_6 LITERAL1 | |||||
KEY_7 LITERAL1 | |||||
KEY_8 LITERAL1 | |||||
KEY_9 LITERAL1 | |||||
KEY_0 LITERAL1 | |||||
KEY_ENTER LITERAL1 | |||||
KEY_ESC LITERAL1 | |||||
KEY_BACKSPACE LITERAL1 | |||||
KEY_TAB LITERAL1 | |||||
KEY_SPACE LITERAL1 | |||||
KEY_MINUS LITERAL1 | |||||
KEY_EQUAL LITERAL1 | |||||
KEY_LEFT_BRACE LITERAL1 | |||||
KEY_RIGHT_BRACE LITERAL1 | |||||
KEY_BACKSLASH LITERAL1 | |||||
KEY_NON_US_NUM LITERAL1 | |||||
KEY_SEMICOLON LITERAL1 | |||||
KEY_QUOTE LITERAL1 | |||||
KEY_TILDE LITERAL1 | |||||
KEY_COMMA LITERAL1 | |||||
KEY_PERIOD LITERAL1 | |||||
KEY_SLASH LITERAL1 | |||||
KEY_CAPS_LOCK LITERAL1 | |||||
KEY_F1 LITERAL1 | |||||
KEY_F2 LITERAL1 | |||||
KEY_F3 LITERAL1 | |||||
KEY_F4 LITERAL1 | |||||
KEY_F5 LITERAL1 | |||||
KEY_F6 LITERAL1 | |||||
KEY_F7 LITERAL1 | |||||
KEY_F8 LITERAL1 | |||||
KEY_F9 LITERAL1 | |||||
KEY_F10 LITERAL1 | |||||
KEY_F11 LITERAL1 | |||||
KEY_F12 LITERAL1 | |||||
KEY_PRINTSCREEN LITERAL1 | |||||
KEY_SCROLL_LOCK LITERAL1 | |||||
KEY_PAUSE LITERAL1 | |||||
KEY_INSERT LITERAL1 | |||||
KEY_HOME LITERAL1 | |||||
KEY_PAGE_UP LITERAL1 | |||||
KEY_DELETE LITERAL1 | |||||
KEY_END LITERAL1 | |||||
KEY_PAGE_DOWN LITERAL1 | |||||
KEY_RIGHT LITERAL1 | |||||
KEY_LEFT LITERAL1 | |||||
KEY_DOWN LITERAL1 | |||||
KEY_UP LITERAL1 | |||||
KEY_NUM_LOCK LITERAL1 | |||||
KEYPAD_SLASH LITERAL1 | |||||
KEYPAD_ASTERIX LITERAL1 | |||||
KEYPAD_MINUS LITERAL1 | |||||
KEYPAD_PLUS LITERAL1 | |||||
KEYPAD_ENTER LITERAL1 | |||||
KEYPAD_1 LITERAL1 | |||||
KEYPAD_2 LITERAL1 | |||||
KEYPAD_3 LITERAL1 | |||||
KEYPAD_4 LITERAL1 | |||||
KEYPAD_5 LITERAL1 | |||||
KEYPAD_6 LITERAL1 | |||||
KEYPAD_7 LITERAL1 | |||||
KEYPAD_8 LITERAL1 | |||||
KEYPAD_9 LITERAL1 | |||||
KEYPAD_0 LITERAL1 | |||||
KEYPAD_PERIOD LITERAL1 | |||||
KEY_UP_ARROW LITERAL1 | |||||
KEY_DOWN_ARROW LITERAL1 | |||||
KEY_LEFT_ARROW LITERAL1 | |||||
KEY_RIGHT_ARROW LITERAL1 | |||||
KEY_RETURN LITERAL1 | |||||
KEY_LEFT_CTRL LITERAL1 | |||||
KEY_LEFT_SHIFT LITERAL1 | |||||
KEY_LEFT_ALT LITERAL1 | |||||
KEY_LEFT_GUI LITERAL1 | |||||
KEY_RIGHT_CTRL LITERAL1 | |||||
KEY_RIGHT_SHIFT LITERAL1 | |||||
KEY_RIGHT_ALT LITERAL1 | |||||
KEY_RIGHT_GUI LITERAL1 | |||||
# USB Mouse | |||||
moveTo KEYWORD2 | |||||
screenSize KEYWORD2 | |||||
scroll KEYWORD2 | |||||
set_buttons KEYWORD2 | |||||
isPressed KEYWORD2 | |||||
MOUSE_LEFT LITERAL1 | |||||
MOUSE_MIDDLE LITERAL1 | |||||
MOUSE_RIGHT LITERAL1 | |||||
MOUSE_ALL LITERAL1 | |||||
MOUSE_BACK LITERAL1 | |||||
MOUSE_FORWARD LITERAL1 | |||||
# USB Joystick | |||||
Joystick KEYWORD1 | |||||
button KEYWORD2 | |||||
X KEYWORD2 | |||||
Y KEYWORD2 | |||||
position KEYWORD2 | |||||
Z KEYWORD2 | |||||
Xrotate KEYWORD2 | |||||
Yrotate KEYWORD2 | |||||
Zrotate KEYWORD2 | |||||
sliderLeft KEYWORD2 | |||||
sliderRight KEYWORD2 | |||||
slider KEYWORD2 | |||||
hat KEYWORD2 | |||||
useManualSend KEYWORD2 | |||||
# USB Disk | |||||
Disk KEYWORD1 | |||||
claim KEYWORD2 | |||||
readSector KEYWORD2 | |||||
writeSector KEYWORD2 | |||||
releaseReadOnly KEYWORD2 | |||||
# USB MIDI | |||||
usbMIDI KEYWORD1 | |||||
sendNoteOff KEYWORD2 | |||||
sendNoteOn KEYWORD2 | |||||
sendAfterTouchPoly KEYWORD2 | |||||
sendPolyPressure KEYWORD2 | |||||
sendControlChange KEYWORD2 | |||||
sendProgramChange KEYWORD2 | |||||
sendAfterTouch KEYWORD2 | |||||
sendPitchBend 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 | |||||
getType KEYWORD2 | |||||
getCable KEYWORD2 | |||||
getChannel KEYWORD2 | |||||
getData1 KEYWORD2 | |||||
getData2 KEYWORD2 | |||||
getSysExArray KEYWORD2 | |||||
setHandleNoteOff KEYWORD2 | |||||
setHandleNoteOn KEYWORD2 | |||||
setHandleVelocityChange KEYWORD2 | |||||
setHandleControlChange KEYWORD2 | |||||
setHandleProgramChange KEYWORD2 | |||||
setHandleAfterTouch KEYWORD2 | |||||
setHandlePitchChange KEYWORD2 | |||||
NoteOff LITERAL1 | |||||
NoteOn LITERAL1 | |||||
AfterTouchPoly LITERAL1 | |||||
ControlChange LITERAL1 | |||||
ProgramChange LITERAL1 | |||||
AfterTouchChannel LITERAL1 | |||||
PitchBend 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 | |||||
RawHID KEYWORD1 | |||||
recv KEYWORD2 | |||||
send KEYWORD2 | |||||
# USB Flight Sim Controls | |||||
FlightSim KEYWORD1 | |||||
FlightSimCommand KEYWORD2 | |||||
FlightSimInteger KEYWORD2 | |||||
FlightSimFloat KEYWORD2 | |||||
FlightSimElapsedFrames KEYWORD2 | |||||
onChange KEYWORD2 | |||||
update KEYWORD2 | |||||
isEnabled KEYWORD2 | |||||
getFrameCount KEYWORD2 | |||||
XPlaneRef KEYWORD2 | |||||
# USB Touchscreen | |||||
TouchscreenUSB KEYWORD1 |
#include <avr/interrupt.h> | #include <avr/interrupt.h> | ||||
#include "core_pins.h" | #include "core_pins.h" | ||||
#include "HardwareSerial.h" | #include "HardwareSerial.h" | ||||
#include "wiring_private.h" | |||||
#define RX_BUFFER_SIZE 64 | #define RX_BUFFER_SIZE 64 | ||||
static volatile uint8_t rx_buffer[RX_BUFFER_SIZE]; | static volatile uint8_t rx_buffer[RX_BUFFER_SIZE]; | ||||
return RX_BUFFER_SIZE + head - tail; | return RX_BUFFER_SIZE + head - tail; | ||||
} | } | ||||
int HardwareSerial::availableForWrite(void) | |||||
{ | |||||
uint8_t head, tail; | |||||
head = rx_buffer_head; | |||||
tail = rx_buffer_tail; | |||||
if (head >= tail) return TX_BUFFER_SIZE - 1 - head + tail; | |||||
return tail - head - 1; | |||||
} | |||||
int HardwareSerial::peek(void) | int HardwareSerial::peek(void) | ||||
{ | { | ||||
uint8_t head, tail; | uint8_t head, tail; | ||||
#endif | #endif | ||||
{ | { | ||||
uint8_t i; | uint8_t i; | ||||
uint8_t status; | |||||
if (!(UCSR1B & (1<<TXEN1))) { | if (!(UCSR1B & (1<<TXEN1))) { | ||||
#if ARDUINO >= 100 | #if ARDUINO >= 100 | ||||
if (tx_enable_pin < 255 && !transmitting) { | if (tx_enable_pin < 255 && !transmitting) { | ||||
digitalWrite(tx_enable_pin, HIGH); | digitalWrite(tx_enable_pin, HIGH); | ||||
} | } | ||||
// If the buffer and the data register is empty, just write the byte | |||||
// to the data register and be done. This shortcut helps | |||||
// significantly improve the effective datarate at high (> | |||||
// 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. | |||||
if ((tx_buffer_head == tx_buffer_tail) && (UCSR1A & (1<<UDRE1))) { | |||||
status = SREG; | |||||
cli(); | |||||
UDR1 = c; | |||||
transmitting = 1; | |||||
SREG = status; | |||||
return 1; | |||||
} | |||||
i = tx_buffer_head + 1; | i = tx_buffer_head + 1; | ||||
if (i >= TX_BUFFER_SIZE) i = 0; | if (i >= TX_BUFFER_SIZE) i = 0; | ||||
while (tx_buffer_tail == i) ; // wait until space in buffer | while (tx_buffer_tail == i) ; // wait until space in buffer | ||||
tx_buffer[i] = c; | tx_buffer[i] = c; | ||||
transmitting = 1; | transmitting = 1; | ||||
tx_buffer_head = i; | tx_buffer_head = i; | ||||
UCSR1B = (1<<RXEN1) | (1<<TXCIE1) | (1<<TXEN1) | (1<<RXCIE1) | (1<<UDRIE1); | |||||
//UCSR1B = (1<<RXEN1) | (1<<TXCIE1) | (1<<TXEN1) | (1<<RXCIE1) | (1<<UDRIE1); | |||||
sbi(UCSR1B, UDRIE1); | |||||
#if ARDUINO >= 100 | #if ARDUINO >= 100 | ||||
return 1; | return 1; | ||||
#endif | #endif | ||||
if (tx_buffer_head == tx_buffer_tail) { | if (tx_buffer_head == tx_buffer_tail) { | ||||
// buffer is empty, disable transmit interrupt | // buffer is empty, disable transmit interrupt | ||||
UCSR1B = (1<<RXEN1) | (1<<TXCIE1) | (1<<TXEN1) | (1<<RXCIE1); | |||||
//UCSR1B = (1<<RXEN1) | (1<<TXCIE1) | (1<<TXEN1) | (1<<RXCIE1); | |||||
cbi(UCSR1B, UDRIE1); | |||||
} else { | } else { | ||||
i = tx_buffer_tail + 1; | i = tx_buffer_tail + 1; | ||||
if (i >= TX_BUFFER_SIZE) i = 0; | if (i >= TX_BUFFER_SIZE) i = 0; |
virtual int peek(void); | virtual int peek(void); | ||||
virtual int read(void); | virtual int read(void); | ||||
virtual void flush(void); | virtual void flush(void); | ||||
int availableForWrite(void); | |||||
void clear(void); | void clear(void); | ||||
#if ARDUINO >= 100 | #if ARDUINO >= 100 | ||||
virtual size_t write(uint8_t); | virtual size_t write(uint8_t); |
IPAddress::IPAddress() | IPAddress::IPAddress() | ||||
{ | { | ||||
memset(_address, 0, sizeof(_address)); | |||||
_address.dword = 0; | |||||
} | } | ||||
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) | IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) | ||||
{ | { | ||||
_address[0] = first_octet; | |||||
_address[1] = second_octet; | |||||
_address[2] = third_octet; | |||||
_address[3] = fourth_octet; | |||||
_address.bytes[0] = first_octet; | |||||
_address.bytes[1] = second_octet; | |||||
_address.bytes[2] = third_octet; | |||||
_address.bytes[3] = fourth_octet; | |||||
} | } | ||||
IPAddress::IPAddress(uint32_t address) | IPAddress::IPAddress(uint32_t address) | ||||
{ | { | ||||
memcpy(_address, &address, sizeof(_address)); | |||||
_address.dword = address; | |||||
} | } | ||||
IPAddress::IPAddress(const uint8_t *address) | IPAddress::IPAddress(const uint8_t *address) | ||||
{ | { | ||||
memcpy(_address, address, sizeof(_address)); | |||||
memcpy(_address.bytes, address, sizeof(_address)); | |||||
} | } | ||||
IPAddress& IPAddress::operator=(const uint8_t *address) | IPAddress& IPAddress::operator=(const uint8_t *address) | ||||
{ | { | ||||
memcpy(_address, address, sizeof(_address)); | |||||
memcpy(_address.bytes, address, sizeof(_address.bytes)); | |||||
return *this; | return *this; | ||||
} | } | ||||
IPAddress& IPAddress::operator=(uint32_t address) | IPAddress& IPAddress::operator=(uint32_t address) | ||||
{ | { | ||||
memcpy(_address, (const uint8_t *)&address, sizeof(_address)); | |||||
_address.dword = address; | |||||
return *this; | return *this; | ||||
} | } | ||||
bool IPAddress::operator==(const uint8_t* addr) | bool IPAddress::operator==(const uint8_t* addr) | ||||
{ | { | ||||
return memcmp(addr, _address, sizeof(_address)) == 0; | |||||
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; | |||||
} | } | ||||
size_t IPAddress::printTo(Print& p) const | size_t IPAddress::printTo(Print& p) const | ||||
{ | { | ||||
size_t n = 0; | |||||
for (int i =0; i < 3; i++) | |||||
{ | |||||
n += p.print(_address[i], DEC); | |||||
n += p.print('.'); | |||||
for (int i= 0; i < 3; i++) { | |||||
p.print(_address.bytes[i], DEC); | |||||
p.print('.'); | |||||
} | } | ||||
n += p.print(_address[3], DEC); | |||||
return n; | |||||
p.print(_address.bytes[3], DEC); | |||||
return 4; | |||||
} | |||||
bool IPAddress::fromString(const char *address) | |||||
{ | |||||
uint16_t acc = 0; // Accumulator | |||||
uint8_t dots = 0; | |||||
while (*address) { | |||||
char c = *address++; | |||||
if (c >= '0' && c <= '9') { | |||||
acc = acc * 10 + (c - '0'); | |||||
if (acc > 255) { | |||||
// Value out of [0..255] range | |||||
return false; | |||||
} | |||||
} else if (c == '.') { | |||||
if (dots == 3) { | |||||
// Too much dots (there must be 3 dots) | |||||
return false; | |||||
} | |||||
_address.bytes[dots++] = acc; | |||||
acc = 0; | |||||
} else { | |||||
// Invalid char | |||||
return false; | |||||
} | |||||
} | |||||
if (dots != 3) { | |||||
// Too few dots (there must be 3 dots) | |||||
return false; | |||||
} | |||||
_address.bytes[3] = acc; | |||||
return true; | |||||
} | } | ||||
#endif | #endif |
// A class to make it easier to handle and pass around IP addresses | // A class to make it easier to handle and pass around IP addresses | ||||
class IPAddress : public Printable { | class IPAddress : public Printable { | ||||
private: | |||||
uint8_t _address[4]; // IPv4 address | |||||
private: | |||||
union { | |||||
uint8_t bytes[4]; // IPv4 address | |||||
uint32_t dword; | |||||
} _address; | |||||
// Access the raw byte array containing the address. Because this returns a pointer | // Access the raw byte array containing the address. Because this returns a pointer | ||||
// to the internal structure rather than a copy of the address this function should only | // to the internal structure rather than a copy of the address this function should only | ||||
// be used when you know that the usage of the returned uint8_t* will be transient and not | // be used when you know that the usage of the returned uint8_t* will be transient and not | ||||
// stored. | // stored. | ||||
uint8_t* raw_address() { return _address; }; | |||||
uint8_t* raw_address() { return _address.bytes; }; | |||||
public: | public: | ||||
// Constructors | // Constructors | ||||
IPAddress(uint32_t address); | IPAddress(uint32_t address); | ||||
IPAddress(const uint8_t *address); | IPAddress(const uint8_t *address); | ||||
bool fromString(const char *address); | |||||
bool fromString(const String &address) { | |||||
return fromString(address.c_str()); | |||||
} | |||||
// Overloaded cast operator to allow IPAddress objects to be used where a pointer | // Overloaded cast operator to allow IPAddress objects to be used where a pointer | ||||
// to a four-byte uint8_t array is expected | // to a four-byte uint8_t array is expected | ||||
operator uint32_t() { return *((uint32_t*)_address); }; | |||||
bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); }; | |||||
operator uint32_t() { return _address.dword; }; | |||||
bool operator==(const IPAddress& addr) { return _address.dword == addr._address.dword; }; | |||||
bool operator==(const uint8_t* addr); | bool operator==(const uint8_t* addr); | ||||
// Overloaded index operator to allow getting and setting individual octets of the address | // Overloaded index operator to allow getting and setting individual octets of the address | ||||
uint8_t operator[](int index) const { return _address[index]; }; | |||||
uint8_t& operator[](int index) { return _address[index]; }; | |||||
uint8_t operator[](int index) const { return _address.bytes[index]; }; | |||||
uint8_t& operator[](int index) { return _address.bytes[index]; }; | |||||
// Overloaded copy operators to allow initialisation of IPAddress objects from other types | // Overloaded copy operators to allow initialisation of IPAddress objects from other types | ||||
IPAddress& operator=(const uint8_t *address); | IPAddress& operator=(const uint8_t *address); |
// 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 |
#include "Print.h" | #include "Print.h" | ||||
#if ARDUINO >= 100 | |||||
#else | |||||
void Print::write(const char *str) | |||||
{ | |||||
write((const uint8_t *)str, strlen(str)); | |||||
} | |||||
#endif | |||||
#if ARDUINO >= 100 | |||||
size_t Print::write(const uint8_t *buffer, size_t size) | size_t Print::write(const uint8_t *buffer, size_t size) | ||||
{ | { | ||||
size_t count = 0; | size_t count = 0; | ||||
while (size--) count += write(*buffer++); | while (size--) count += write(*buffer++); | ||||
return count; | return count; | ||||
} | } | ||||
#else | |||||
void Print::write(const uint8_t *buffer, size_t size) | |||||
{ | |||||
while (size--) write(*buffer++); | |||||
} | |||||
#endif | |||||
#if ARDUINO >= 100 | |||||
size_t Print::print(const String &s) | size_t Print::print(const String &s) | ||||
{ | { | ||||
uint8_t buffer[33]; | uint8_t buffer[33]; | ||||
} | } | ||||
return count; | return count; | ||||
} | } | ||||
#else | |||||
void Print::print(const String &s) | |||||
{ | |||||
unsigned int len = s.length(); | |||||
for (unsigned int i=0; i < len; i++) { | |||||
write(s[i]); | |||||
} | |||||
} | |||||
#endif | |||||
#if ARDUINO >= 100 | |||||
size_t Print::print(const __FlashStringHelper *ifsh) | size_t Print::print(const __FlashStringHelper *ifsh) | ||||
{ | { | ||||
uint8_t buffer[32]; | uint8_t buffer[32]; | ||||
size_t count = 0; | size_t count = 0; | ||||
const char PROGMEM *p = (const char PROGMEM *)ifsh; | |||||
const char *p = (const char *)ifsh; | |||||
unsigned int len = strlen_P(p); | unsigned int len = strlen_P(p); | ||||
while (len > 0) { | while (len > 0) { | ||||
unsigned int nbytes = len; | unsigned int nbytes = len; | ||||
} | } | ||||
return count; | return count; | ||||
} | } | ||||
#else | |||||
void Print::print(const __FlashStringHelper *ifsh) | |||||
{ | |||||
const char PROGMEM *p = (const char PROGMEM *)ifsh; | |||||
while (1) { | |||||
unsigned char c = pgm_read_byte(p++); | |||||
if (c == 0) return; | |||||
write(c); | |||||
} | |||||
} | |||||
#endif | |||||
#if ARDUINO >= 100 | |||||
size_t Print::print(long n) | size_t Print::print(long n) | ||||
{ | { | ||||
uint8_t sign=0; | uint8_t sign=0; | ||||
} | } | ||||
return printNumber(n, sign, 10); | return printNumber(n, sign, 10); | ||||
} | } | ||||
#else | |||||
void Print::print(long n) | |||||
{ | |||||
uint8_t sign=0; | |||||
if (n < 0) { | |||||
sign = 1; | |||||
n = -n; | |||||
} | |||||
printNumber(n, sign, 10); | |||||
} | |||||
#endif | |||||
#if ARDUINO >= 100 | |||||
size_t Print::println(void) | size_t Print::println(void) | ||||
{ | { | ||||
uint8_t buf[2]={'\r', '\n'}; | uint8_t buf[2]={'\r', '\n'}; | ||||
return write(buf, 2); | return write(buf, 2); | ||||
} | } | ||||
#else | |||||
void Print::println(void) | |||||
{ | |||||
uint8_t buf[2]={'\r', '\n'}; | |||||
write(buf, 2); | |||||
} | |||||
#endif | |||||
#if ARDUINO >= 100 | |||||
static int printf_putchar(char c, FILE *fp) | static int printf_putchar(char c, FILE *fp) | ||||
{ | { | ||||
((class Print *)(fdev_get_udata(fp)))->write((uint8_t)c); | ((class Print *)(fdev_get_udata(fp)))->write((uint8_t)c); | ||||
va_start(ap, format); | va_start(ap, format); | ||||
return vfprintf_P(&f, (const char *)format, ap); | return vfprintf_P(&f, (const char *)format, ap); | ||||
} | } | ||||
#endif | |||||
//#define USE_HACKER_DELIGHT_OPTIMIZATION | //#define USE_HACKER_DELIGHT_OPTIMIZATION | ||||
#endif | #endif | ||||
#if ARDUINO >= 100 | |||||
size_t Print::printNumberDec(unsigned long n, uint8_t sign) | size_t Print::printNumberDec(unsigned long n, uint8_t sign) | ||||
#else | |||||
void Print::printNumberDec(unsigned long n, uint8_t sign) | |||||
#endif | |||||
{ | { | ||||
uint8_t digit, buf[11], *p; | uint8_t digit, buf[11], *p; | ||||
#if defined(USE_HACKER_DELIGHT_OPTIMIZATION) | #if defined(USE_HACKER_DELIGHT_OPTIMIZATION) | ||||
#ifdef USE_BENCHMARK_CODE | #ifdef USE_BENCHMARK_CODE | ||||
uint32_t usec = micros(); | uint32_t usec = micros(); | ||||
#endif | #endif | ||||
p = buf + (sizeof(buf)-1); | |||||
p = buf + (sizeof(buf)); | |||||
do { | do { | ||||
#if defined(USE_HACKER_DELIGHT_OPTIMIZATION) | #if defined(USE_HACKER_DELIGHT_OPTIMIZATION) | ||||
divmod10_asm(n, tmp32, digit); | divmod10_asm(n, tmp32, digit); | ||||
#ifdef USE_BENCHMARK_CODE | #ifdef USE_BENCHMARK_CODE | ||||
usec_print += micros() - usec; | usec_print += micros() - usec; | ||||
#endif | #endif | ||||
#if ARDUINO >= 100 | |||||
return write(p, sizeof(buf)-1 - (p - buf)); | |||||
#else | |||||
write(p, sizeof(buf)-1 - (p - buf)); | |||||
#endif | |||||
return write(p, sizeof(buf) - (p - buf)); | |||||
} | } | ||||
#if ARDUINO >= 100 | |||||
size_t Print::printNumberHex(unsigned long n) | size_t Print::printNumberHex(unsigned long n) | ||||
#else | |||||
void Print::printNumberHex(unsigned long n) | |||||
#endif | |||||
{ | { | ||||
uint8_t digit, buf[8], *p; | uint8_t digit, buf[8], *p; | ||||
p = buf + (sizeof(buf)-1); | |||||
p = buf + (sizeof(buf)); | |||||
do { | do { | ||||
digit = n & 15; | digit = n & 15; | ||||
*--p = (digit < 10) ? '0' + digit : 'A' + digit - 10; | *--p = (digit < 10) ? '0' + digit : 'A' + digit - 10; | ||||
n >>= 4; | n >>= 4; | ||||
} while (n); | } while (n); | ||||
#if ARDUINO >= 100 | |||||
return write(p, sizeof(buf)-1 - (p - buf)); | |||||
#else | |||||
write(p, sizeof(buf)-1 - (p - buf)); | |||||
#endif | |||||
return write(p, sizeof(buf) - (p - buf)); | |||||
} | } | ||||
#if ARDUINO >= 100 | |||||
size_t Print::printNumberBin(unsigned long n) | size_t Print::printNumberBin(unsigned long n) | ||||
#else | |||||
void Print::printNumberBin(unsigned long n) | |||||
#endif | |||||
{ | { | ||||
uint8_t buf[32], *p; | uint8_t buf[32], *p; | ||||
p = buf + (sizeof(buf)-1); | |||||
p = buf + (sizeof(buf)); | |||||
do { | do { | ||||
*--p = '0' + ((uint8_t)n & 1); | *--p = '0' + ((uint8_t)n & 1); | ||||
n >>= 1; | n >>= 1; | ||||
} while (n); | } while (n); | ||||
#if ARDUINO >= 100 | |||||
return write(p, sizeof(buf)-1 - (p - buf)); | |||||
#else | |||||
write(p, sizeof(buf)-1 - (p - buf)); | |||||
#endif | |||||
return write(p, sizeof(buf) - (p - buf)); | |||||
} | } | ||||
#if ARDUINO >= 100 | |||||
size_t Print::printNumberAny(unsigned long n, uint8_t base) | size_t Print::printNumberAny(unsigned long n, uint8_t base) | ||||
#else | |||||
void Print::printNumberAny(unsigned long n, uint8_t base) | |||||
#endif | |||||
{ | { | ||||
uint8_t digit, buf[21], *p; | uint8_t digit, buf[21], *p; | ||||
uint32_t tmp; | uint32_t tmp; | ||||
//uint32_t usec; | //uint32_t usec; | ||||
//usec = micros(); | //usec = micros(); | ||||
p = buf + (sizeof(buf)-1); | |||||
p = buf + sizeof(buf); | |||||
do { | do { | ||||
tmp = n; | tmp = n; | ||||
n = n / base; | n = n / base; | ||||
*--p = (digit < 10) ? '0' + digit : 'A' + digit - 10; | *--p = (digit < 10) ? '0' + digit : 'A' + digit - 10; | ||||
} while (n); | } while (n); | ||||
//usec_print += micros() - usec; | //usec_print += micros() - usec; | ||||
#if ARDUINO >= 100 | |||||
return write(p, sizeof(buf)-1 - (p - buf)); | |||||
#else | |||||
write(p, sizeof(buf)-1 - (p - buf)); | |||||
#endif | |||||
return write(p, sizeof(buf) - (p - buf)); | |||||
} | } | ||||
#if ARDUINO >= 100 | |||||
size_t Print::printFloat(double number, uint8_t digits) | size_t Print::printFloat(double number, uint8_t digits) | ||||
#else | |||||
void Print::printFloat(double number, uint8_t digits) | |||||
#endif | |||||
{ | { | ||||
uint8_t sign=0; | uint8_t sign=0; | ||||
#if ARDUINO >= 100 | |||||
size_t count=0; | size_t count=0; | ||||
#endif | |||||
// Handle negative numbers | // Handle negative numbers | ||||
if (number < 0.0) { | if (number < 0.0) { | ||||
// Extract the integer part of the number and print it | // Extract the integer part of the number and print it | ||||
unsigned long int_part = (unsigned long)number; | unsigned long int_part = (unsigned long)number; | ||||
double remainder = number - (double)int_part; | double remainder = number - (double)int_part; | ||||
#if ARDUINO >= 100 | |||||
count += printNumber(int_part, sign, 10); | count += printNumber(int_part, sign, 10); | ||||
#else | |||||
printNumber(int_part, sign, 10); | |||||
#endif | |||||
// Print the decimal point, but only if there are digits beyond | // Print the decimal point, but only if there are digits beyond | ||||
if (digits > 0) { | if (digits > 0) { | ||||
buf[count++] = '0' + n; | buf[count++] = '0' + n; | ||||
remainder -= n; | remainder -= n; | ||||
} | } | ||||
#if ARDUINO >= 100 | |||||
count += write(buf, count); | count += write(buf, count); | ||||
#else | |||||
write(buf, count); | |||||
#endif | |||||
} | } | ||||
#if ARDUINO >= 100 | |||||
return count; | return count; | ||||
#endif | |||||
} | } | ||||
#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 |
String::String(unsigned char c) | String::String(unsigned char c) | ||||
{ | { | ||||
init(); | init(); | ||||
*this = (char)c; | |||||
char buf[4]; | |||||
utoa(c, buf, 10); | |||||
*this = buf; | |||||
} | } | ||||
String::String(const int value, unsigned char base) | String::String(const int value, unsigned char base) |
} | } | ||||
} | } | ||||
static inline void digitalWriteFast(uint8_t, uint8_t) __attribute__((always_inline, unused)); | |||||
static inline void digitalWriteFast(uint8_t pin, uint8_t val) | |||||
{ | |||||
if (__builtin_constant_p(pin)) { | |||||
if (val) { | |||||
if (pin == 0) { | |||||
CORE_PIN0_PORTREG |= CORE_PIN0_BITMASK; | |||||
} else if (pin == 1) { | |||||
CORE_PIN1_PORTREG |= CORE_PIN1_BITMASK; | |||||
} else if (pin == 2) { | |||||
CORE_PIN2_PORTREG |= CORE_PIN2_BITMASK; | |||||
} else if (pin == 3) { | |||||
CORE_PIN3_PORTREG |= CORE_PIN3_BITMASK; | |||||
} else if (pin == 4) { | |||||
CORE_PIN4_PORTREG |= CORE_PIN4_BITMASK; | |||||
} else if (pin == 5) { | |||||
CORE_PIN5_PORTREG |= CORE_PIN5_BITMASK; | |||||
} else if (pin == 6) { | |||||
CORE_PIN6_PORTREG |= CORE_PIN6_BITMASK; | |||||
} else if (pin == 7) { | |||||
CORE_PIN7_PORTREG |= CORE_PIN7_BITMASK; | |||||
} else if (pin == 8) { | |||||
CORE_PIN8_PORTREG |= CORE_PIN8_BITMASK; | |||||
} else if (pin == 9) { | |||||
CORE_PIN9_PORTREG |= CORE_PIN9_BITMASK; | |||||
} else if (pin == 10) { | |||||
CORE_PIN10_PORTREG |= CORE_PIN10_BITMASK; | |||||
} else if (pin == 11) { | |||||
CORE_PIN11_PORTREG |= CORE_PIN11_BITMASK; | |||||
} else if (pin == 12) { | |||||
CORE_PIN12_PORTREG |= CORE_PIN12_BITMASK; | |||||
} else if (pin == 13) { | |||||
CORE_PIN13_PORTREG |= CORE_PIN13_BITMASK; | |||||
} else if (pin == 14) { | |||||
CORE_PIN14_PORTREG |= CORE_PIN14_BITMASK; | |||||
} else if (pin == 15) { | |||||
CORE_PIN15_PORTREG |= CORE_PIN15_BITMASK; | |||||
} else if (pin == 16) { | |||||
CORE_PIN16_PORTREG |= CORE_PIN16_BITMASK; | |||||
} else if (pin == 17) { | |||||
CORE_PIN17_PORTREG |= CORE_PIN17_BITMASK; | |||||
} else if (pin == 18) { | |||||
CORE_PIN18_PORTREG |= CORE_PIN18_BITMASK; | |||||
} else if (pin == 19) { | |||||
CORE_PIN19_PORTREG |= CORE_PIN19_BITMASK; | |||||
} else if (pin == 20) { | |||||
CORE_PIN20_PORTREG |= CORE_PIN20_BITMASK; | |||||
} | |||||
#if CORE_NUM_TOTAL_PINS > 21 | |||||
else if (pin == 21) { | |||||
CORE_PIN21_PORTREG |= CORE_PIN21_BITMASK; | |||||
} else if (pin == 22) { | |||||
CORE_PIN22_PORTREG |= CORE_PIN22_BITMASK; | |||||
} else if (pin == 23) { | |||||
CORE_PIN23_PORTREG |= CORE_PIN23_BITMASK; | |||||
} else if (pin == 24) { | |||||
CORE_PIN24_PORTREG |= CORE_PIN24_BITMASK; | |||||
} | |||||
#endif | |||||
#if CORE_NUM_TOTAL_PINS > 25 | |||||
else if (pin == 25) { | |||||
CORE_PIN25_PORTREG |= CORE_PIN25_BITMASK; | |||||
} else if (pin == 26) { | |||||
CORE_PIN26_PORTREG |= CORE_PIN26_BITMASK; | |||||
} else if (pin == 27) { | |||||
CORE_PIN27_PORTREG |= CORE_PIN27_BITMASK; | |||||
} else if (pin == 28) { | |||||
CORE_PIN28_PORTREG |= CORE_PIN28_BITMASK; | |||||
} else if (pin == 29) { | |||||
CORE_PIN29_PORTREG |= CORE_PIN29_BITMASK; | |||||
} else if (pin == 30) { | |||||
CORE_PIN30_PORTREG |= CORE_PIN30_BITMASK; | |||||
} else if (pin == 31) { | |||||
CORE_PIN31_PORTREG |= CORE_PIN31_BITMASK; | |||||
} else if (pin == 32) { | |||||
CORE_PIN32_PORTREG |= CORE_PIN32_BITMASK; | |||||
} else if (pin == 33) { | |||||
CORE_PIN33_PORTREG |= CORE_PIN33_BITMASK; | |||||
} else if (pin == 34) { | |||||
CORE_PIN34_PORTREG |= CORE_PIN34_BITMASK; | |||||
} else if (pin == 35) { | |||||
CORE_PIN35_PORTREG |= CORE_PIN35_BITMASK; | |||||
} else if (pin == 36) { | |||||
CORE_PIN36_PORTREG |= CORE_PIN36_BITMASK; | |||||
} else if (pin == 37) { | |||||
CORE_PIN37_PORTREG |= CORE_PIN37_BITMASK; | |||||
} else if (pin == 38) { | |||||
CORE_PIN38_PORTREG |= CORE_PIN38_BITMASK; | |||||
} else if (pin == 39) { | |||||
CORE_PIN39_PORTREG |= CORE_PIN39_BITMASK; | |||||
} else if (pin == 40) { | |||||
CORE_PIN40_PORTREG |= CORE_PIN40_BITMASK; | |||||
} else if (pin == 41) { | |||||
CORE_PIN41_PORTREG |= CORE_PIN41_BITMASK; | |||||
} else if (pin == 42) { | |||||
CORE_PIN42_PORTREG |= CORE_PIN42_BITMASK; | |||||
} else if (pin == 43) { | |||||
CORE_PIN43_PORTREG |= CORE_PIN43_BITMASK; | |||||
} else if (pin == 44) { | |||||
CORE_PIN44_PORTREG |= CORE_PIN44_BITMASK; | |||||
} else if (pin == 45) { | |||||
CORE_PIN45_PORTREG |= CORE_PIN45_BITMASK; | |||||
} | |||||
#endif | |||||
} else { | |||||
if (pin == 0) { | |||||
CORE_PIN0_PORTREG &= ~CORE_PIN0_BITMASK; | |||||
} else if (pin == 1) { | |||||
CORE_PIN1_PORTREG &= ~CORE_PIN1_BITMASK; | |||||
} else if (pin == 2) { | |||||
CORE_PIN2_PORTREG &= ~CORE_PIN2_BITMASK; | |||||
} else if (pin == 3) { | |||||
CORE_PIN3_PORTREG &= ~CORE_PIN3_BITMASK; | |||||
} else if (pin == 4) { | |||||
CORE_PIN4_PORTREG &= ~CORE_PIN4_BITMASK; | |||||
} else if (pin == 5) { | |||||
CORE_PIN5_PORTREG &= ~CORE_PIN5_BITMASK; | |||||
} else if (pin == 6) { | |||||
CORE_PIN6_PORTREG &= ~CORE_PIN6_BITMASK; | |||||
} else if (pin == 7) { | |||||
CORE_PIN7_PORTREG &= ~CORE_PIN7_BITMASK; | |||||
} else if (pin == 8) { | |||||
CORE_PIN8_PORTREG &= ~CORE_PIN8_BITMASK; | |||||
} else if (pin == 9) { | |||||
CORE_PIN9_PORTREG &= ~CORE_PIN9_BITMASK; | |||||
} else if (pin == 10) { | |||||
CORE_PIN10_PORTREG &= ~CORE_PIN10_BITMASK; | |||||
} else if (pin == 11) { | |||||
CORE_PIN11_PORTREG &= ~CORE_PIN11_BITMASK; | |||||
} else if (pin == 12) { | |||||
CORE_PIN12_PORTREG &= ~CORE_PIN12_BITMASK; | |||||
} else if (pin == 13) { | |||||
CORE_PIN13_PORTREG &= ~CORE_PIN13_BITMASK; | |||||
} else if (pin == 14) { | |||||
CORE_PIN14_PORTREG &= ~CORE_PIN14_BITMASK; | |||||
} else if (pin == 15) { | |||||
CORE_PIN15_PORTREG &= ~CORE_PIN15_BITMASK; | |||||
} else if (pin == 16) { | |||||
CORE_PIN16_PORTREG &= ~CORE_PIN16_BITMASK; | |||||
} else if (pin == 17) { | |||||
CORE_PIN17_PORTREG &= ~CORE_PIN17_BITMASK; | |||||
} else if (pin == 18) { | |||||
CORE_PIN18_PORTREG &= ~CORE_PIN18_BITMASK; | |||||
} else if (pin == 19) { | |||||
CORE_PIN19_PORTREG &= ~CORE_PIN19_BITMASK; | |||||
} else if (pin == 20) { | |||||
CORE_PIN20_PORTREG &= ~CORE_PIN20_BITMASK; | |||||
} | |||||
#if CORE_NUM_TOTAL_PINS > 21 | |||||
else if (pin == 21) { | |||||
CORE_PIN21_PORTREG &= ~CORE_PIN21_BITMASK; | |||||
} else if (pin == 22) { | |||||
CORE_PIN22_PORTREG &= ~CORE_PIN22_BITMASK; | |||||
} else if (pin == 23) { | |||||
CORE_PIN23_PORTREG &= ~CORE_PIN23_BITMASK; | |||||
} else if (pin == 24) { | |||||
CORE_PIN24_PORTREG &= ~CORE_PIN24_BITMASK; | |||||
} | |||||
#endif | |||||
#if CORE_NUM_TOTAL_PINS > 25 | |||||
else if (pin == 25) { | |||||
CORE_PIN25_PORTREG &= ~CORE_PIN25_BITMASK; | |||||
} else if (pin == 26) { | |||||
CORE_PIN26_PORTREG &= ~CORE_PIN26_BITMASK; | |||||
} else if (pin == 27) { | |||||
CORE_PIN27_PORTREG &= ~CORE_PIN27_BITMASK; | |||||
} else if (pin == 28) { | |||||
CORE_PIN28_PORTREG &= ~CORE_PIN28_BITMASK; | |||||
} else if (pin == 29) { | |||||
CORE_PIN29_PORTREG &= ~CORE_PIN29_BITMASK; | |||||
} else if (pin == 30) { | |||||
CORE_PIN30_PORTREG &= ~CORE_PIN30_BITMASK; | |||||
} else if (pin == 31) { | |||||
CORE_PIN31_PORTREG &= ~CORE_PIN31_BITMASK; | |||||
} else if (pin == 32) { | |||||
CORE_PIN32_PORTREG &= ~CORE_PIN32_BITMASK; | |||||
} else if (pin == 33) { | |||||
CORE_PIN33_PORTREG &= ~CORE_PIN33_BITMASK; | |||||
} else if (pin == 34) { | |||||
CORE_PIN34_PORTREG &= ~CORE_PIN34_BITMASK; | |||||
} else if (pin == 35) { | |||||
CORE_PIN35_PORTREG &= ~CORE_PIN35_BITMASK; | |||||
} else if (pin == 36) { | |||||
CORE_PIN36_PORTREG &= ~CORE_PIN36_BITMASK; | |||||
} else if (pin == 37) { | |||||
CORE_PIN37_PORTREG &= ~CORE_PIN37_BITMASK; | |||||
} else if (pin == 38) { | |||||
CORE_PIN38_PORTREG &= ~CORE_PIN38_BITMASK; | |||||
} else if (pin == 39) { | |||||
CORE_PIN39_PORTREG &= ~CORE_PIN39_BITMASK; | |||||
} else if (pin == 40) { | |||||
CORE_PIN40_PORTREG &= ~CORE_PIN40_BITMASK; | |||||
} else if (pin == 41) { | |||||
CORE_PIN41_PORTREG &= ~CORE_PIN41_BITMASK; | |||||
} else if (pin == 42) { | |||||
CORE_PIN42_PORTREG &= ~CORE_PIN42_BITMASK; | |||||
} else if (pin == 43) { | |||||
CORE_PIN43_PORTREG &= ~CORE_PIN43_BITMASK; | |||||
} else if (pin == 44) { | |||||
CORE_PIN44_PORTREG &= ~CORE_PIN44_BITMASK; | |||||
} else if (pin == 45) { | |||||
CORE_PIN45_PORTREG &= ~CORE_PIN45_BITMASK; | |||||
} | |||||
#endif | |||||
} | |||||
} else { | |||||
digitalWrite(pin, val); | |||||
} | |||||
} | |||||
extern void _digitalRead(void) __attribute__((noinline)); | extern void _digitalRead(void) __attribute__((noinline)); | ||||
static inline uint8_t digitalRead(uint8_t) __attribute__((always_inline, unused)); | static inline uint8_t digitalRead(uint8_t) __attribute__((always_inline, unused)); | ||||
} | } | ||||
} | } | ||||
static inline uint8_t digitalReadFast(uint8_t) __attribute__((always_inline, unused)); | |||||
static inline uint8_t digitalReadFast(uint8_t pin) | |||||
{ | |||||
return digitalRead(pin); | |||||
} | |||||
extern void _pinMode(uint8_t pin, uint8_t mode) __attribute__((noinline)); | extern void _pinMode(uint8_t pin, uint8_t mode) __attribute__((noinline)); | ||||
extern void _pinMode_output(uint8_t pin) __attribute__((noinline)); | extern void _pinMode_output(uint8_t pin) __attribute__((noinline)); | ||||
extern void _pinMode_input(uint8_t pin) __attribute__((noinline)); | extern void _pinMode_input(uint8_t pin) __attribute__((noinline)); | ||||
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) |
#ifdef M | #ifdef M | ||||
#undef M | #undef M | ||||
#endif | #endif | ||||
#define M(n) ((n) & 0x3FFF) | |||||
#define M(n) ((n) & KEYCODE_MASK) | |||||
const KEYCODE_TYPE PROGMEM keycodes_ascii[] = { | const KEYCODE_TYPE PROGMEM keycodes_ascii[] = { | ||||
M(ASCII_20), M(ASCII_21), M(ASCII_22), M(ASCII_23), | M(ASCII_20), M(ASCII_21), M(ASCII_22), M(ASCII_23), |
// 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? | ||||
} | } | ||||
} | } | ||||
#define SERIAL_PORT_MONITOR Serial | |||||
#define SERIAL_PORT_USBVIRTUAL Serial | |||||
#define SERIAL_PORT_HARDWARE Serial1 | |||||
#define SERIAL_PORT_HARDWARE_OPEN Serial1 | |||||
#define SerialUSB Serial | |||||
#endif | #endif |
#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; | ||||
// 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 <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(); | ||||
// Transmit an audio data block | // Transmit an audio data block | ||||
// to all streams that connect to an output. The block | // to all streams that connect to an output. The block | ||||
// becomes owned by all the recepients, but also is still | // becomes owned by all the recepients, but also is still | ||||
// owned by this object. Normally, a block is released | |||||
// after it's transmitted. | |||||
// owned by this object. Normally, a block must be released | |||||
// by the caller after it's transmitted. This allows the | |||||
// caller to transmit to same block to more than 1 output, | |||||
// and then release it once after all transmit calls. | |||||
void AudioStream::transmit(audio_block_t *block, unsigned char index) | void AudioStream::transmit(audio_block_t *block, unsigned char index) | ||||
{ | { | ||||
for (AudioConnection *c = destination_list; c != NULL; c = c->next_dest) { | for (AudioConnection *c = destination_list; c != NULL; c = c->next_dest) { | ||||
{ | { | ||||
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() | ||||
bool AudioStream::update_setup(void) | bool AudioStream::update_setup(void) | ||||
{ | { | ||||
if (update_scheduled) return false; | if (update_scheduled) return false; | ||||
NVIC_SET_PRIORITY(IRQ_SOFTWARE, 0xFF); // 0xFF = lowest priority | |||||
NVIC_SET_PRIORITY(IRQ_SOFTWARE, 208); // 255 = lowest priority | |||||
NVIC_ENABLE_IRQ(IRQ_SOFTWARE); | NVIC_ENABLE_IRQ(IRQ_SOFTWARE); | ||||
update_scheduled = true; | update_scheduled = true; | ||||
return true; | return true; |
/* 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 | ||||
#include "Arduino.h" | |||||
#ifndef __ASSEMBLER__ | |||||
#include <stdio.h> // for NULL | |||||
#include <string.h> // for memcpy | |||||
#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. | |||||
#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 | |||||
#elif defined(__MKL26Z64__) | |||||
#define AUDIO_BLOCK_SAMPLES 64 | |||||
#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 | #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 | |||||
#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; | |||||
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 | |||||
#define DMA_MAX_CHANNELS DMA_NUM_CHANNELS | |||||
#else | |||||
#define DMA_MAX_CHANNELS 16 | |||||
#endif | |||||
// The channel allocation bitmask is accessible from "C" namespace, | // The channel allocation bitmask is accessible from "C" namespace, | ||||
// so C-only code can reserve DMA channels | // so C-only code can reserve DMA channels | ||||
uint16_t dma_channel_allocated_mask = 0; | uint16_t dma_channel_allocated_mask = 0; | ||||
/****************************************************************/ | |||||
/** Teensy 3.0 & 3.1 **/ | |||||
/****************************************************************/ | |||||
#if defined(KINETISK) | |||||
void DMAChannel::begin(bool force_initialization) | void DMAChannel::begin(bool force_initialization) | ||||
{ | { | ||||
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 = 16; | |||||
channel = DMA_MAX_CHANNELS; | |||||
TCD = (TCD_t *)0; | TCD = (TCD_t *)0; | ||||
} | } | ||||
c2.TCD = t; | c2.TCD = t; | ||||
} | } | ||||
/****************************************************************/ | |||||
/** Teensy-LC **/ | |||||
/****************************************************************/ | |||||
#elif defined(KINETISL) | |||||
void DMAChannel::begin(bool force_initialization) | |||||
{ | |||||
uint32_t ch = 0; | |||||
__disable_irq(); | |||||
if (!force_initialization && CFG && channel < DMA_MAX_CHANNELS | |||||
&& (dma_channel_allocated_mask & (1 << channel)) | |||||
&& (uint32_t)CFG == (uint32_t)(0x40008100 + channel * 16)) { | |||||
// DMA channel already allocated | |||||
__enable_irq(); | |||||
return; | |||||
} | |||||
while (1) { | |||||
if (!(dma_channel_allocated_mask & (1 << ch))) { | |||||
dma_channel_allocated_mask |= (1 << ch); | |||||
__enable_irq(); | |||||
break; | |||||
} | |||||
if (++ch >= DMA_MAX_CHANNELS) { | |||||
__enable_irq(); | |||||
CFG = (CFG_t *)0; | |||||
channel = DMA_MAX_CHANNELS; | |||||
return; // no more channels available | |||||
// attempts to use this object will hardfault | |||||
} | |||||
} | |||||
channel = ch; | |||||
SIM_SCGC7 |= SIM_SCGC7_DMA; | |||||
SIM_SCGC6 |= SIM_SCGC6_DMAMUX; | |||||
CFG = (CFG_t *)(0x40008100 + ch * 16); | |||||
CFG->DSR_BCR = DMA_DSR_BCR_DONE; | |||||
CFG->DCR = DMA_DCR_CS; | |||||
CFG->SAR = NULL; | |||||
CFG->DAR = NULL; | |||||
} | |||||
void DMAChannel::release(void) | |||||
{ | |||||
if (channel >= DMA_MAX_CHANNELS) return; | |||||
CFG->DSR_BCR = DMA_DSR_BCR_DONE; | |||||
__disable_irq(); | |||||
dma_channel_allocated_mask &= ~(1 << channel); | |||||
__enable_irq(); | |||||
channel = 16; | |||||
CFG = (CFG_t *)0; | |||||
} | |||||
static uint32_t priority(const DMAChannel &c) | |||||
{ | |||||
return 3 - c.channel; | |||||
} | |||||
static void swap(DMAChannel &c1, DMAChannel &c2) | |||||
{ | |||||
uint8_t c; | |||||
DMABaseClass::CFG_t *t; | |||||
c = c1.channel; | |||||
c1.channel = c2.channel; | |||||
c2.channel = c; | |||||
t = c1.CFG; | |||||
c1.CFG = c2.CFG; | |||||
c2.CFG = t; | |||||
} | |||||
#endif | |||||
void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2) | void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2) | ||||
{ | { | ||||
if (priority(ch1) < priority(ch2)) swap(ch1, ch2); | if (priority(ch1) < priority(ch2)) swap(ch1, ch2); |
/* 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_ | ||||
#include "kinetis.h" | #include "kinetis.h" | ||||
// This code is a work-in-progress. It's incomplete and not usable yet... | |||||
// | |||||
// Discussion about DMAChannel is here: | |||||
// http://forum.pjrc.com/threads/25778-Could-there-be-something-like-an-ISR-template-function/page3 | // http://forum.pjrc.com/threads/25778-Could-there-be-something-like-an-ISR-template-function/page3 | ||||
#define DMACHANNEL_HAS_BEGIN | |||||
#define DMACHANNEL_HAS_BOOLEAN_CTOR | |||||
// The channel allocation bitmask is accessible from "C" namespace, | |||||
// so C-only code can reserve DMA channels | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
extern uint16_t dma_channel_allocated_mask; | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#ifdef __cplusplus | |||||
// known libraries with DMA usage (in need of porting to this new scheme): | // known libraries with DMA usage (in need of porting to this new scheme): | ||||
// | // | ||||
// https://github.com/pixelmatix/SmartMatrix | // https://github.com/pixelmatix/SmartMatrix | ||||
// https://github.com/crteensy/DmaSpi <-- DmaSpi has adopted this scheme | // https://github.com/crteensy/DmaSpi <-- DmaSpi has adopted this scheme | ||||
#ifdef __cplusplus | |||||
#define DMACHANNEL_HAS_BEGIN | |||||
#define DMACHANNEL_HAS_BOOLEAN_CTOR | |||||
/****************************************************************/ | |||||
/** Teensy 3.0 & 3.1 **/ | |||||
/****************************************************************/ | |||||
#if defined(KINETISK) | |||||
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 data size used for each triggered transfer | // Set the data size used for each triggered transfer | ||||
void transferSize(unsigned int len) { | void transferSize(unsigned int len) { | ||||
if (len == 4) { | |||||
if (len == 16) { | |||||
TCD->NBYTES = 16; | |||||
if (TCD->SOFF != 0) TCD->SOFF = 16; | |||||
if (TCD->DOFF != 0) TCD->DOFF = 16; | |||||
TCD->ATTR = (TCD->ATTR & 0xF8F8) | 0x0404; | |||||
} else if (len == 4) { | |||||
TCD->NBYTES = 4; | TCD->NBYTES = 4; | ||||
if (TCD->SOFF != 0) TCD->SOFF = 4; | if (TCD->SOFF != 0) TCD->SOFF = 4; | ||||
if (TCD->DOFF != 0) TCD->DOFF = 4; | if (TCD->DOFF != 0) TCD->DOFF = 4; | ||||
// 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; | ||||
} | } | ||||
// code, but direct control of all parameters is possible. | // code, but direct control of all parameters is possible. | ||||
uint8_t channel; | uint8_t channel; | ||||
// TCD is accessible due to inheritance from DMABaseClass | // TCD is accessible due to inheritance from DMABaseClass | ||||
}; | |||||
// arrange the relative priority of 2 or more DMA channels | |||||
void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2); | |||||
void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3); | |||||
void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3, DMAChannel &ch4); | |||||
/****************************************************************/ | |||||
/** Teensy-LC **/ | |||||
/****************************************************************/ | |||||
#elif defined(KINETISL) | |||||
class DMABaseClass { | |||||
public: | |||||
typedef struct __attribute__((packed, aligned(4))) { | |||||
volatile const void * volatile SAR; | |||||
volatile void * volatile DAR; | |||||
volatile uint32_t DSR_BCR; | |||||
volatile uint32_t DCR; | |||||
} CFG_t; | |||||
CFG_t *CFG; | |||||
/***************************************/ | |||||
/** Data Transfer **/ | |||||
/***************************************/ | |||||
// Use a single variable as the data source. Typically a register | |||||
// for receiving data from one of the hardware peripherals is used. | |||||
void source(volatile const signed char &p) { source(*(volatile const uint8_t *)&p); } | |||||
void source(volatile const unsigned char &p) { | |||||
CFG->SAR = &p; | |||||
CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(1); | |||||
} | |||||
void source(volatile const signed short &p) { source(*(volatile const uint16_t *)&p); } | |||||
void source(volatile const unsigned short &p) { | |||||
CFG->SAR = &p; | |||||
CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(2); | |||||
} | |||||
void source(volatile const signed int &p) { source(*(volatile const uint32_t *)&p); } | |||||
void source(volatile const unsigned int &p) { source(*(volatile const uint32_t *)&p); } | |||||
void source(volatile const signed long &p) { source(*(volatile const uint32_t *)&p); } | |||||
void source(volatile const unsigned long &p) { | |||||
CFG->SAR = &p; | |||||
CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(0); | |||||
} | |||||
// Use a buffer (array of data) as the data source. Typically a | |||||
// buffer for transmitting data is used. | |||||
void sourceBuffer(volatile const signed char p[], unsigned int len) { | |||||
sourceBuffer((volatile const uint8_t *)p, len); } | |||||
void sourceBuffer(volatile const unsigned char p[], unsigned int len) { | |||||
if (len > 0xFFFFF) return; | |||||
CFG->SAR = p; | |||||
CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(1) | DMA_DCR_SINC; | |||||
CFG->DSR_BCR = len; | |||||
} | |||||
void sourceBuffer(volatile const signed short p[], unsigned int len) { | |||||
sourceBuffer((volatile const uint16_t *)p, len); } | |||||
void sourceBuffer(volatile const unsigned short p[], unsigned int len) { | |||||
if (len > 0xFFFFF) return; | |||||
CFG->SAR = p; | |||||
CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(2) | DMA_DCR_SINC; | |||||
CFG->DSR_BCR = len; | |||||
} | |||||
void sourceBuffer(volatile const signed int p[], unsigned int len) { | |||||
sourceBuffer((volatile const uint32_t *)p, len); } | |||||
void sourceBuffer(volatile const unsigned int p[], unsigned int len) { | |||||
sourceBuffer((volatile const uint32_t *)p, len); } | |||||
void sourceBuffer(volatile const signed long p[], unsigned int len) { | |||||
sourceBuffer((volatile const uint32_t *)p, len); } | |||||
void sourceBuffer(volatile const unsigned long p[], unsigned int len) { | |||||
if (len > 0xFFFFF) return; | |||||
CFG->SAR = p; | |||||
CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(0) | DMA_DCR_SINC; | |||||
CFG->DSR_BCR = len; | |||||
} | |||||
// Use a circular buffer as the data source | |||||
void sourceCircular(volatile const signed char p[], unsigned int len) { | |||||
sourceCircular((volatile const uint8_t *)p, len); } | |||||
void sourceCircular(volatile const unsigned char p[], unsigned int len) { | |||||
uint32_t mod = len2mod(len); | |||||
if (mod == 0) return; | |||||
CFG->SAR = p; | |||||
CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(1) | DMA_DCR_SINC | |||||
| DMA_DCR_SMOD(mod); | |||||
CFG->DSR_BCR = len; | |||||
} | |||||
void sourceCircular(volatile const signed short p[], unsigned int len) { | |||||
sourceCircular((volatile const uint16_t *)p, len); } | |||||
void sourceCircular(volatile const unsigned short p[], unsigned int len) { | |||||
uint32_t mod = len2mod(len); | |||||
if (mod == 0) return; | |||||
CFG->SAR = p; | |||||
CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(2) | DMA_DCR_SINC | |||||
| DMA_DCR_SMOD(mod); | |||||
CFG->DSR_BCR = len; | |||||
} | |||||
void sourceCircular(volatile const signed int p[], unsigned int len) { | |||||
sourceCircular((volatile const uint32_t *)p, len); } | |||||
void sourceCircular(volatile const unsigned int p[], unsigned int len) { | |||||
sourceCircular((volatile const uint32_t *)p, len); } | |||||
void sourceCircular(volatile const signed long p[], unsigned int len) { | |||||
sourceCircular((volatile const uint32_t *)p, len); } | |||||
void sourceCircular(volatile const unsigned long p[], unsigned int len) { | |||||
uint32_t mod = len2mod(len); | |||||
if (mod == 0) return; | |||||
CFG->SAR = p; | |||||
CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(0) | DMA_DCR_SINC | |||||
| DMA_DCR_SMOD(mod); | |||||
CFG->DSR_BCR = len; | |||||
} | |||||
// Use a single variable as the data destination. Typically a register | |||||
// for transmitting data to one of the hardware peripherals is used. | |||||
void destination(volatile signed char &p) { destination(*(volatile uint8_t *)&p); } | |||||
void destination(volatile unsigned char &p) { | |||||
CFG->DAR = &p; | |||||
CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1); | |||||
} | |||||
void destination(volatile signed short &p) { destination(*(volatile uint16_t *)&p); } | |||||
void destination(volatile unsigned short &p) { | |||||
CFG->DAR = &p; | |||||
CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(2); | |||||
} | |||||
void destination(volatile signed int &p) { destination(*(volatile uint32_t *)&p); } | |||||
void destination(volatile unsigned int &p) { destination(*(volatile uint32_t *)&p); } | |||||
void destination(volatile signed long &p) { destination(*(volatile uint32_t *)&p); } | |||||
void destination(volatile unsigned long &p) { | |||||
CFG->DAR = &p; | |||||
CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(0); | |||||
} | |||||
// Use a buffer (array of data) as the data destination. Typically a | |||||
// buffer for receiving data is used. | |||||
void destinationBuffer(volatile signed char p[], unsigned int len) { | |||||
destinationBuffer((volatile uint8_t *)p, len); } | |||||
void destinationBuffer(volatile unsigned char p[], unsigned int len) { | |||||
CFG->DAR = p; | |||||
CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC; | |||||
CFG->DSR_BCR = len; | |||||
} | |||||
void destinationBuffer(volatile signed short p[], unsigned int len) { | |||||
destinationBuffer((volatile uint16_t *)p, len); } | |||||
void destinationBuffer(volatile unsigned short p[], unsigned int len) { | |||||
CFG->DAR = p; | |||||
CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(2) | DMA_DCR_DINC; | |||||
CFG->DSR_BCR = len; | |||||
} | |||||
void destinationBuffer(volatile signed int p[], unsigned int len) { | |||||
destinationBuffer((volatile uint32_t *)p, len); } | |||||
void destinationBuffer(volatile unsigned int p[], unsigned int len) { | |||||
destinationBuffer((volatile uint32_t *)p, len); } | |||||
void destinationBuffer(volatile signed long p[], unsigned int len) { | |||||
destinationBuffer((volatile uint32_t *)p, len); } | |||||
void destinationBuffer(volatile unsigned long p[], unsigned int len) { | |||||
CFG->DAR = p; | |||||
CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(0) | DMA_DCR_DINC; | |||||
CFG->DSR_BCR = len; | |||||
} | |||||
// Use a circular buffer as the data destination | |||||
void destinationCircular(volatile signed char p[], unsigned int len) { | |||||
destinationCircular((volatile uint8_t *)p, len); } | |||||
void destinationCircular(volatile unsigned char p[], unsigned int len) { | |||||
uint32_t mod = len2mod(len); | |||||
if (mod == 0) return; | |||||
CFG->DAR = p; | |||||
CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC | |||||
| DMA_DCR_DMOD(mod); | |||||
CFG->DSR_BCR = len; | |||||
} | |||||
void destinationCircular(volatile signed short p[], unsigned int len) { | |||||
destinationCircular((volatile uint16_t *)p, len); } | |||||
void destinationCircular(volatile unsigned short p[], unsigned int len) { | |||||
uint32_t mod = len2mod(len); | |||||
if (mod == 0) return; | |||||
CFG->DAR = p; | |||||
CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(2) | DMA_DCR_DINC | |||||
| DMA_DCR_DMOD(mod); | |||||
CFG->DSR_BCR = len; | |||||
} | |||||
void destinationCircular(volatile signed int p[], unsigned int len) { | |||||
destinationCircular((volatile uint32_t *)p, len); } | |||||
void destinationCircular(volatile unsigned int p[], unsigned int len) { | |||||
destinationCircular((volatile uint32_t *)p, len); } | |||||
void destinationCircular(volatile signed long p[], unsigned int len) { | |||||
destinationCircular((volatile uint32_t *)p, len); } | |||||
void destinationCircular(volatile unsigned long p[], unsigned int len) { | |||||
uint32_t mod = len2mod(len); | |||||
if (mod == 0) return; | |||||
CFG->DAR = p; | |||||
CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(0) | DMA_DCR_DINC | |||||
| DMA_DCR_DMOD(mod); | |||||
CFG->DSR_BCR = len; | |||||
} | |||||
/* usage cases: | |||||
************************ | |||||
OctoWS2811: | |||||
************************ | |||||
// enable clocks to the DMA controller and DMAMUX | |||||
SIM_SCGC7 |= SIM_SCGC7_DMA; | |||||
SIM_SCGC6 |= SIM_SCGC6_DMAMUX; | |||||
DMA_CR = 0; | |||||
DMA_CERQ = 1; | |||||
DMA_CERQ = 2; | |||||
DMA_CERQ = 3; | |||||
// DMA channel #1 sets WS2811 high at the beginning of each cycle | |||||
DMA_TCD1_SADDR = &ones; | |||||
DMA_TCD1_SOFF = 0; | |||||
DMA_TCD1_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0); | |||||
DMA_TCD1_NBYTES_MLNO = 1; | |||||
DMA_TCD1_SLAST = 0; | |||||
DMA_TCD1_DADDR = &GPIOD_PSOR; | |||||
DMA_TCD1_DOFF = 0; | |||||
DMA_TCD1_CITER_ELINKNO = bufsize; | |||||
DMA_TCD1_DLASTSGA = 0; | |||||
DMA_TCD1_CSR = DMA_TCD_CSR_DREQ; | |||||
DMA_TCD1_BITER_ELINKNO = bufsize; | |||||
dma1.source(ones); | |||||
dma1.destination(GPIOD_PSOR); | |||||
dma1.size(1); | |||||
dma1.count(bufsize); | |||||
dma1.disableOnCompletion(); | |||||
// DMA channel #2 writes the pixel data at 20% of the cycle | |||||
DMA_TCD2_SADDR = frameBuffer; | |||||
DMA_TCD2_SOFF = 1; | |||||
DMA_TCD2_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0); | |||||
DMA_TCD2_NBYTES_MLNO = 1; | |||||
DMA_TCD2_SLAST = -bufsize; | |||||
DMA_TCD2_DADDR = &GPIOD_PDOR; | |||||
DMA_TCD2_DOFF = 0; | |||||
DMA_TCD2_CITER_ELINKNO = bufsize; | |||||
DMA_TCD2_DLASTSGA = 0; | |||||
DMA_TCD2_CSR = DMA_TCD_CSR_DREQ; | |||||
DMA_TCD2_BITER_ELINKNO = bufsize; | |||||
dma2.source(frameBuffer, sizeof(frameBuffer)); | |||||
dma2.destination(GPIOD_PDOR); | |||||
dma2.size(1); | |||||
dma2.count(bufsize); | |||||
dma2.disableOnCompletion(); | |||||
// DMA channel #3 clear all the pins low at 48% of the cycle | |||||
DMA_TCD3_SADDR = &ones; | |||||
DMA_TCD3_SOFF = 0; | |||||
DMA_TCD3_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0); | |||||
DMA_TCD3_NBYTES_MLNO = 1; | |||||
DMA_TCD3_SLAST = 0; | |||||
DMA_TCD3_DADDR = &GPIOD_PCOR; | |||||
DMA_TCD3_DOFF = 0; | |||||
DMA_TCD3_CITER_ELINKNO = bufsize; | |||||
DMA_TCD3_DLASTSGA = 0; | |||||
DMA_TCD3_CSR = DMA_TCD_CSR_DREQ | DMA_TCD_CSR_INTMAJOR; | |||||
DMA_TCD3_BITER_ELINKNO = bufsize; | |||||
dma3.source(ones); | |||||
dma3.destination(GPIOD_PCOR); | |||||
dma3.size(1); | |||||
dma3.count(bufsize); | |||||
dma3.disableOnCompletion(); | |||||
************************ | |||||
Audio, DAC | |||||
************************ | |||||
DMA_CR = 0; | |||||
DMA_TCD4_SADDR = dac_buffer; | |||||
DMA_TCD4_SOFF = 2; | |||||
DMA_TCD4_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||||
DMA_TCD4_NBYTES_MLNO = 2; | |||||
DMA_TCD4_SLAST = -sizeof(dac_buffer); | |||||
DMA_TCD4_DADDR = &DAC0_DAT0L; | |||||
DMA_TCD4_DOFF = 0; | |||||
DMA_TCD4_CITER_ELINKNO = sizeof(dac_buffer) / 2; | |||||
DMA_TCD4_DLASTSGA = 0; | |||||
DMA_TCD4_BITER_ELINKNO = sizeof(dac_buffer) / 2; | |||||
DMA_TCD4_CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||||
DMAMUX0_CHCFG4 = DMAMUX_DISABLE; | |||||
DMAMUX0_CHCFG4 = DMAMUX_SOURCE_PDB | DMAMUX_ENABLE; | |||||
************************ | |||||
Audio, I2S | |||||
************************ | |||||
DMA_CR = 0; | |||||
DMA_TCD0_SADDR = i2s_tx_buffer; | |||||
DMA_TCD0_SOFF = 2; | |||||
DMA_TCD0_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||||
DMA_TCD0_NBYTES_MLNO = 2; | |||||
DMA_TCD0_SLAST = -sizeof(i2s_tx_buffer); | |||||
DMA_TCD0_DADDR = &I2S0_TDR0; | |||||
DMA_TCD0_DOFF = 0; | |||||
DMA_TCD0_CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | |||||
DMA_TCD0_DLASTSGA = 0; | |||||
DMA_TCD0_BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | |||||
DMA_TCD0_CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||||
DMAMUX0_CHCFG0 = DMAMUX_DISABLE; | |||||
DMAMUX0_CHCFG0 = DMAMUX_SOURCE_I2S0_TX | DMAMUX_ENABLE; | |||||
************************ | |||||
ADC lib, Pedro Villanueva | |||||
************************ | |||||
DMA_CR = 0; // normal mode of operation | |||||
*DMAMUX0_CHCFG = DMAMUX_DISABLE; // disable before changing | |||||
*DMA_TCD_ATTR = DMA_TCD_ATTR_SSIZE(DMA_TCD_ATTR_SIZE_16BIT) | | |||||
DMA_TCD_ATTR_DSIZE(DMA_TCD_ATTR_SIZE_16BIT) | | |||||
DMA_TCD_ATTR_DMOD(4); // src and dst data is 16 bit (2 bytes), buffer size 2^^4 bytes = 8 values | |||||
*DMA_TCD_NBYTES_MLNO = 2; // Minor Byte Transfer Count 2 bytes = 16 bits (we transfer 2 bytes each minor loop) | |||||
*DMA_TCD_SADDR = ADC_RA; // source address | |||||
*DMA_TCD_SOFF = 0; // don't change the address when minor loop finishes | |||||
*DMA_TCD_SLAST = 0; // don't change src address after major loop completes | |||||
*DMA_TCD_DADDR = elems; // destination address | |||||
*DMA_TCD_DOFF = 2; // increment 2 bytes each minor loop | |||||
*DMA_TCD_DLASTSGA = 0; // modulus feature takes care of going back to first element | |||||
*DMA_TCD_CITER_ELINKNO = 1; // Current Major Iteration Count with channel linking disabled | |||||
*DMA_TCD_BITER_ELINKNO = 1; // Starting Major Iteration Count with channel linking disabled | |||||
*DMA_TCD_CSR = DMA_TCD_CSR_INTMAJOR; // Control and status: interrupt when major counter is complete | |||||
DMA_CERQ = DMA_CERQ_CERQ(DMA_channel); // clear all past request | |||||
DMA_CINT = DMA_channel; // clear interrupts | |||||
uint8_t DMAMUX_SOURCE_ADC = DMAMUX_SOURCE_ADC0; | |||||
if(ADC_number==1){ | |||||
DMAMUX_SOURCE_ADC = DMAMUX_SOURCE_ADC1; | |||||
} | |||||
*DMAMUX0_CHCFG = DMAMUX_SOURCE_ADC | DMAMUX_ENABLE; // enable mux and set channel DMA_channel to ADC0 | |||||
DMA_SERQ = DMA_SERQ_SERQ(DMA_channel); // enable DMA request | |||||
NVIC_ENABLE_IRQ(IRQ_DMA_CH); // enable interrupts | |||||
************************ | |||||
SmartMatrix | |||||
************************ | |||||
// enable minor loop mapping so addresses can get reset after minor loops | |||||
DMA_CR = 1 << 7; | |||||
// DMA channel #0 - on latch rising edge, read address from fixed address temporary buffer, and output address on GPIO | |||||
// using combo of writes to set+clear registers, to only modify the address pins and not other GPIO pins | |||||
// address temporary buffer is refreshed before each DMA trigger (by DMA channel #2) | |||||
// only use single major loop, never disable channel | |||||
#define ADDRESS_ARRAY_REGISTERS_TO_UPDATE 2 | |||||
DMA_TCD0_SADDR = &gpiosync.gpio_pcor; | |||||
DMA_TCD0_SOFF = (int)&gpiosync.gpio_psor - (int)&gpiosync.gpio_pcor; | |||||
DMA_TCD0_SLAST = (ADDRESS_ARRAY_REGISTERS_TO_UPDATE * ((int)&ADDX_GPIO_CLEAR_REGISTER - (int)&ADDX_GPIO_SET_REGISTER)); | |||||
DMA_TCD0_ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); | |||||
// Destination Minor Loop Offset Enabled - transfer appropriate number of bytes per minor loop, and put DADDR back to original value when minor loop is complete | |||||
// Source Minor Loop Offset Enabled - source buffer is same size and offset as destination so values reset after each minor loop | |||||
DMA_TCD0_NBYTES_MLOFFYES = DMA_TCD_NBYTES_SMLOE | DMA_TCD_NBYTES_DMLOE | | |||||
((ADDRESS_ARRAY_REGISTERS_TO_UPDATE * ((int)&ADDX_GPIO_CLEAR_REGISTER - (int)&ADDX_GPIO_SET_REGISTER)) << 10) | | |||||
(ADDRESS_ARRAY_REGISTERS_TO_UPDATE * sizeof(gpiosync.gpio_psor)); | |||||
// start on higher value of two registers, and make offset decrement to avoid negative number in NBYTES_MLOFFYES (TODO: can switch order by masking negative offset) | |||||
DMA_TCD0_DADDR = &ADDX_GPIO_CLEAR_REGISTER; | |||||
// update destination address so the second update per minor loop is ADDX_GPIO_SET_REGISTER | |||||
DMA_TCD0_DOFF = (int)&ADDX_GPIO_SET_REGISTER - (int)&ADDX_GPIO_CLEAR_REGISTER; | |||||
DMA_TCD0_DLASTSGA = (ADDRESS_ARRAY_REGISTERS_TO_UPDATE * ((int)&ADDX_GPIO_CLEAR_REGISTER - (int)&ADDX_GPIO_SET_REGISTER)); | |||||
// single major loop | |||||
DMA_TCD0_CITER_ELINKNO = 1; | |||||
DMA_TCD0_BITER_ELINKNO = 1; | |||||
// link channel 1, enable major channel-to-channel linking, don't clear enable on major loop complete | |||||
DMA_TCD0_CSR = (1 << 8) | (1 << 5); | |||||
DMAMUX0_CHCFG0 = DMAMUX_SOURCE_LATCH_RISING_EDGE | DMAMUX_ENABLE; | |||||
// DMA channel #1 - copy address values from current position in array to buffer to temporarily hold row values for the next timer cycle | |||||
// only use single major loop, never disable channel | |||||
DMA_TCD1_SADDR = &matrixUpdateBlocks[0][0].addressValues; | |||||
DMA_TCD1_SOFF = sizeof(uint16_t); | |||||
DMA_TCD1_SLAST = sizeof(matrixUpdateBlock) - (ADDRESS_ARRAY_REGISTERS_TO_UPDATE * sizeof(uint16_t)); | |||||
DMA_TCD1_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||||
// 16-bit = 2 bytes transferred | |||||
// transfer two 16-bit values, reset destination address back after each minor loop | |||||
DMA_TCD1_NBYTES_MLOFFNO = (ADDRESS_ARRAY_REGISTERS_TO_UPDATE * sizeof(uint16_t)); | |||||
// start with the register that's the highest location in memory and make offset decrement to avoid negative number in NBYTES_MLOFFYES register (TODO: can switch order by masking negative offset) | |||||
DMA_TCD1_DADDR = &gpiosync.gpio_pcor; | |||||
DMA_TCD1_DOFF = (int)&gpiosync.gpio_psor - (int)&gpiosync.gpio_pcor; | |||||
DMA_TCD1_DLASTSGA = (ADDRESS_ARRAY_REGISTERS_TO_UPDATE * ((int)&gpiosync.gpio_pcor - (int)&gpiosync.gpio_psor)); | |||||
// no minor loop linking, single major loop, single minor loop, don't clear enable after major loop complete | |||||
DMA_TCD1_CITER_ELINKNO = 1; | |||||
DMA_TCD1_BITER_ELINKNO = 1; | |||||
DMA_TCD1_CSR = 0; | |||||
// DMA channel #2 - on latch falling edge, load FTM1_CV1 and FTM1_MOD with with next values from current block | |||||
// only use single major loop, never disable channel | |||||
// link to channel 3 when complete | |||||
#define TIMER_REGISTERS_TO_UPDATE 2 | |||||
DMA_TCD2_SADDR = &matrixUpdateBlocks[0][0].timerValues.timer_oe; | |||||
DMA_TCD2_SOFF = sizeof(uint16_t); | |||||
DMA_TCD2_SLAST = sizeof(matrixUpdateBlock) - (TIMER_REGISTERS_TO_UPDATE * sizeof(uint16_t)); | |||||
DMA_TCD2_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||||
// 16-bit = 2 bytes transferred | |||||
DMA_TCD2_NBYTES_MLOFFNO = TIMER_REGISTERS_TO_UPDATE * sizeof(uint16_t); | |||||
DMA_TCD2_DADDR = &FTM1_C1V; | |||||
DMA_TCD2_DOFF = (int)&FTM1_MOD - (int)&FTM1_C1V; | |||||
DMA_TCD2_DLASTSGA = TIMER_REGISTERS_TO_UPDATE * ((int)&FTM1_C1V - (int)&FTM1_MOD); | |||||
// no minor loop linking, single major loop | |||||
DMA_TCD2_CITER_ELINKNO = 1; | |||||
DMA_TCD2_BITER_ELINKNO = 1; | |||||
// link channel 3, enable major channel-to-channel linking, don't clear enable after major loop complete | |||||
DMA_TCD2_CSR = (3 << 8) | (1 << 5); | |||||
DMAMUX0_CHCFG2 = DMAMUX_SOURCE_LATCH_FALLING_EDGE | DMAMUX_ENABLE; | |||||
#define DMA_TCD_MLOFF_MASK (0x3FFFFC00) | |||||
// DMA channel #3 - repeatedly load gpio_array into GPIOD_PDOR, stop and int on major loop complete | |||||
DMA_TCD3_SADDR = matrixUpdateData[0][0]; | |||||
DMA_TCD3_SOFF = sizeof(matrixUpdateData[0][0]) / 2; | |||||
// SADDR will get updated by ISR, no need to set SLAST | |||||
DMA_TCD3_SLAST = 0; | |||||
DMA_TCD3_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0); | |||||
// after each minor loop, set source to point back to the beginning of this set of data, | |||||
// but advance by 1 byte to get the next significant bits data | |||||
DMA_TCD3_NBYTES_MLOFFYES = DMA_TCD_NBYTES_SMLOE | | |||||
(((1 - sizeof(matrixUpdateData[0])) << 10) & DMA_TCD_MLOFF_MASK) | | |||||
(MATRIX_WIDTH * DMA_UPDATES_PER_CLOCK); | |||||
DMA_TCD3_DADDR = &GPIOD_PDOR; | |||||
DMA_TCD3_DOFF = 0; | |||||
DMA_TCD3_DLASTSGA = 0; | |||||
DMA_TCD3_CITER_ELINKNO = LATCHES_PER_ROW; | |||||
DMA_TCD3_BITER_ELINKNO = LATCHES_PER_ROW; | |||||
// int after major loop is complete | |||||
DMA_TCD3_CSR = DMA_TCD_CSR_INTMAJOR; | |||||
// for debugging - enable bandwidth control (space out GPIO updates so they can be seen easier on a low-bandwidth logic analyzer) | |||||
//DMA_TCD3_CSR |= (0x02 << 14); | |||||
// enable a done interrupt when all DMA operations are complete | |||||
NVIC_ENABLE_IRQ(IRQ_DMA_CH3); | |||||
// enable additional dma interrupt used as software interrupt | |||||
NVIC_SET_PRIORITY(IRQ_DMA_CH1, 0xFF); // 0xFF = lowest priority | |||||
NVIC_ENABLE_IRQ(IRQ_DMA_CH1); | |||||
// enable channels 0, 1, 2, 3 | |||||
DMA_ERQ = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3); | |||||
// at the end after everything is set up: enable timer from system clock, with appropriate prescale | |||||
FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(LATCH_TIMER_PRESCALE); | |||||
*/ | |||||
/*************************************************/ | |||||
/** Quantity of Data to Transfer **/ | |||||
/*************************************************/ | |||||
// Set the data size used for each triggered transfer | |||||
void transferSize(unsigned int len) { | |||||
uint32_t dcr = CFG->DCR & 0xF0C8FFFF; | |||||
if (len == 4) { | |||||
CFG->DCR = dcr | DMA_DCR_SSIZE(0) | DMA_DCR_DSIZE(0); | |||||
} else if (len == 2) { | |||||
CFG->DCR = dcr | DMA_DCR_SSIZE(2) | DMA_DCR_DSIZE(2); | |||||
} else { | |||||
CFG->DCR = dcr | DMA_DCR_SSIZE(1) | DMA_DCR_DSIZE(1); | |||||
} | |||||
} | |||||
// Set the number of transfers (number of triggers until complete) | |||||
void transferCount(unsigned int len) { | |||||
uint32_t s, d, n = 0; // 0 = 8 bit, 1 = 16 bit, 2 = 32 bit | |||||
uint32_t dcr = CFG->DCR; | |||||
s = (dcr >> 20) & 3; | |||||
d = (dcr >> 17) & 3; | |||||
if (s == 0 || d == 0) n = 2; | |||||
else if (s == 2 || d == 2) n = 1; | |||||
CFG->DSR_BCR = len << n; | |||||
} | |||||
/*************************************************/ | |||||
/** Special Options / Features **/ | |||||
/*************************************************/ | |||||
void interruptAtCompletion(void) { | |||||
CFG->DCR |= DMA_DCR_EINT; | |||||
} | |||||
void disableOnCompletion(void) { | |||||
CFG->DCR |= DMA_DCR_D_REQ; | |||||
} | |||||
// Kinetis-L DMA does not have these features :-( | |||||
// | |||||
// void interruptAtHalf(void) {} | |||||
// void replaceSettingsOnCompletion(const DMABaseClass &settings) {}; | |||||
// TODO: can a 2nd linked channel be used to emulate this? | |||||
protected: | |||||
// users should not be able to create instances of DMABaseClass, which | |||||
// require the inheriting class to initialize the TCD pointer. | |||||
DMABaseClass() {} | |||||
static inline void copy_cfg(CFG_t *dst, const CFG_t *src) { | |||||
dst->SAR = src->SAR; | |||||
dst->DAR = src->DAR; | |||||
dst->DSR_BCR = src->DSR_BCR; | |||||
dst->DCR = src->DCR; | |||||
} | |||||
private: | |||||
static inline uint32_t len2mod(uint32_t len) { | |||||
if (len < 16) return 0; | |||||
if (len < 32) return 1; | |||||
if (len < 64) return 2; | |||||
if (len < 128) return 3; | |||||
if (len < 256) return 4; | |||||
if (len < 512) return 5; | |||||
if (len < 1024) return 6; | |||||
if (len < 2048) return 7; | |||||
if (len < 4096) return 8; | |||||
if (len < 8192) return 9; | |||||
if (len < 16384) return 10; | |||||
if (len < 32768) return 11; | |||||
if (len < 65536) return 12; | |||||
if (len < 131072) return 13; | |||||
if (len < 262144) return 14; | |||||
return 15; | |||||
} | |||||
}; | |||||
// DMASetting represents settings stored only in memory, which can be | |||||
// applied to any DMA channel. | |||||
class DMASetting : public DMABaseClass { | |||||
public: | |||||
DMASetting() { | |||||
cfgdata.SAR = NULL; | |||||
cfgdata.DAR = NULL; | |||||
cfgdata.DSR_BCR = 0; | |||||
cfgdata.DCR = DMA_DCR_CS; | |||||
CFG = &cfgdata; | |||||
} | |||||
DMASetting(const DMASetting &c) { | |||||
CFG = &cfgdata; | |||||
*this = c; | |||||
} | |||||
DMASetting(const DMABaseClass &c) { | |||||
CFG = &cfgdata; | |||||
*this = c; | |||||
} | |||||
DMASetting & operator = (const DMABaseClass &rhs) { | |||||
copy_cfg(CFG, rhs.CFG); | |||||
return *this; | |||||
} | |||||
private: | |||||
CFG_t cfgdata __attribute__((aligned(4))); | |||||
}; | |||||
// DMAChannel reprents an actual DMA channel and its current settings | |||||
class DMAChannel : public DMABaseClass { | |||||
public: | |||||
/*************************************************/ | |||||
/** Channel Allocation **/ | |||||
/*************************************************/ | |||||
DMAChannel() { | |||||
begin(); | |||||
} | |||||
DMAChannel(const DMAChannel &c) { | |||||
CFG = c.CFG; | |||||
channel = c.channel; | |||||
} | |||||
DMAChannel(const DMASetting &c) { | |||||
begin(); | |||||
copy_cfg(CFG, c.CFG); | |||||
} | |||||
DMAChannel(bool allocate) { | |||||
if (allocate) begin(); | |||||
} | |||||
DMAChannel & operator = (const DMAChannel &rhs) { | |||||
if (channel != rhs.channel) { | |||||
release(); | |||||
CFG = rhs.CFG; | |||||
channel = rhs.channel; | |||||
} | |||||
return *this; | |||||
} | |||||
DMAChannel & operator = (const DMASetting &rhs) { | |||||
copy_cfg(CFG, rhs.CFG); | |||||
return *this; | |||||
} | |||||
~DMAChannel() { | |||||
release(); | |||||
} | |||||
void begin(bool force_initialization = false); | |||||
private: | |||||
void release(void); | |||||
public: | |||||
/***************************************/ | |||||
/** Triggering **/ | |||||
/***************************************/ | |||||
// Triggers cause the DMA channel to actually move data. Each | |||||
// trigger moves a single data unit, which is typically 8, 16 or | |||||
// 32 bits. If a channel is configured for 200 transfers | |||||
// Use a hardware trigger to make the DMA channel run | |||||
void triggerAtHardwareEvent(uint8_t source) { | |||||
volatile uint8_t *mux; | |||||
CFG->DCR |= DMA_DCR_CS; | |||||
mux = (volatile uint8_t *)&(DMAMUX0_CHCFG0) + channel; | |||||
*mux = 0; | |||||
*mux = (source & 63) | DMAMUX_ENABLE; | |||||
} | |||||
// Use another DMA channel as the trigger, causing this | |||||
// channel to trigger after each transfer is makes, including | |||||
// the its last transfer. This effectively makes the 2 | |||||
// channels run in parallel. Note, on Teensy 3.0 & 3.1, | |||||
// this feature triggers on every transfer except the last. | |||||
// On Teensy-LC, it triggers on every one, including the last. | |||||
void triggerAtTransfersOf(DMABaseClass &ch) { | |||||
uint32_t dcr = ch.CFG->DCR; | |||||
uint32_t linkcc = (dcr >> 4) & 3; | |||||
if (linkcc == 0 || linkcc == 2) { | |||||
ch.CFG->DCR = (dcr & ~DMA_DCR_LCH1(3)) | | |||||
DMA_DCR_LINKCC(2) | DMA_DCR_LCH1(channel); | |||||
} else if (linkcc == 1) { | |||||
ch.CFG->DCR = (dcr & ~DMA_DCR_LCH1(3)) | | |||||
DMA_DCR_LCH1(channel); | |||||
} else { | |||||
uint32_t lch1 = (dcr >> 2) & 3; | |||||
ch.CFG->DCR = (dcr | |||||
& ~(DMA_DCR_LINKCC(3) | DMA_DCR_LCH2(3) | DMA_DCR_LCH1(3))) | |||||
| DMA_DCR_LINKCC(1) | DMA_DCR_LCH2(lch1) | DMA_DCR_LCH1(channel); | |||||
} | |||||
} | |||||
// Use another DMA channel as the trigger, causing this | |||||
// channel to trigger when the other channel completes. | |||||
void triggerAtCompletionOf(DMABaseClass &ch) { | |||||
uint32_t dcr = ch.CFG->DCR; | |||||
uint32_t linkcc = (dcr >> 4) & 3; | |||||
if (linkcc == 0 || linkcc == 3) { | |||||
ch.CFG->DCR = (dcr & ~DMA_DCR_LCH1(3)) | | |||||
DMA_DCR_LINKCC(3) | DMA_DCR_LCH1(channel); | |||||
} else { | |||||
ch.CFG->DCR = (dcr | |||||
& ~(DMA_DCR_LINKCC(3) | DMA_DCR_LCH2(3))) | |||||
| DMA_DCR_LINKCC(1) | DMA_DCR_LCH2(channel); | |||||
} | |||||
} | |||||
// Cause this DMA channel to be continuously triggered, so | |||||
// it will move data as rapidly as possible, without waiting. | |||||
// Normally this would be used with disableOnCompletion(). | |||||
void triggerContinuously(void) { | |||||
uint32_t dcr = CFG->DCR; | |||||
dcr &= ~(DMA_DCR_ERQ | DMA_DCR_CS); | |||||
CFG->DCR = dcr; | |||||
CFG->DCR = dcr | DMA_DCR_START; | |||||
} | |||||
// Manually trigger the DMA channel. | |||||
void triggerManual(void) { | |||||
CFG->DCR = (CFG->DCR & ~DMA_DCR_ERQ) | (DMA_DCR_CS | DMA_DCR_START); | |||||
} | |||||
/***************************************/ | |||||
/** Interrupts **/ | |||||
/***************************************/ | |||||
// An interrupt routine can be run when the DMA channel completes | |||||
// the entire transfer, and also optionally when half of the | |||||
// transfer is completed. | |||||
void attachInterrupt(void (*isr)(void)) { | |||||
_VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr; | |||||
NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); | |||||
} | |||||
void detachInterrupt(void) { | |||||
NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel); | |||||
} | |||||
void clearInterrupt(void) { | |||||
CFG->DSR_BCR = DMA_DSR_BCR_DONE; | |||||
} | |||||
/***************************************/ | |||||
/** Enable / Disable **/ | |||||
/***************************************/ | |||||
void enable(void) { | |||||
CFG->DCR |= DMA_DCR_ERQ; | |||||
} | |||||
void disable(void) { | |||||
CFG->DCR &= ~DMA_DCR_ERQ; | |||||
} | |||||
/***************************************/ | |||||
/** Status **/ | |||||
/***************************************/ | |||||
bool complete(void) { | |||||
if (CFG->DSR_BCR & DMA_DSR_BCR_DONE) return true; | |||||
return false; | |||||
} | |||||
void clearComplete(void) { | |||||
CFG->DSR_BCR |= DMA_DSR_BCR_DONE; | |||||
} | |||||
bool error(void) { | |||||
if (CFG->DSR_BCR & | |||||
(DMA_DSR_BCR_CE | DMA_DSR_BCR_BES | DMA_DSR_BCR_BED)) return true; | |||||
return false; | |||||
} | |||||
void clearError(void) { | |||||
CFG->DSR_BCR |= DMA_DSR_BCR_DONE; | |||||
} | |||||
void * sourceAddress(void) { | |||||
return (void *)(CFG->SAR); | |||||
} | |||||
void * destinationAddress(void) { | |||||
return (void *)(CFG->DAR); | |||||
} | |||||
/***************************************/ | |||||
/** Direct Hardware Access **/ | |||||
/***************************************/ | |||||
uint8_t channel; | |||||
// CFG is accessible due to inheritance from DMABaseClass | |||||
}; | }; | ||||
// arrange the relative priority of 2 or more DMA channels | // arrange the relative priority of 2 or more DMA channels | ||||
extern "C" { | |||||
#endif | |||||
extern uint16_t dma_channel_allocated_mask; | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif // KINETISL | |||||
#endif | |||||
#endif // __cplusplus | |||||
#endif // DMAChannel_h_ |
/* 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 | ||||
// bit7: actual data goes into 9th bit | // bit7: actual data goes into 9th bit | ||||
#if defined(KINETISK) | |||||
#define BAUD2DIV(baud) (((F_CPU * 2) + ((baud) >> 1)) / (baud)) | #define BAUD2DIV(baud) (((F_CPU * 2) + ((baud) >> 1)) / (baud)) | ||||
#define BAUD2DIV2(baud) (((F_CPU * 2) + ((baud) >> 1)) / (baud)) | |||||
#define BAUD2DIV3(baud) (((F_BUS * 2) + ((baud) >> 1)) / (baud)) | #define BAUD2DIV3(baud) (((F_BUS * 2) + ((baud) >> 1)) / (baud)) | ||||
#elif defined(KINETISL) | |||||
#if F_CPU <= 2000000 | |||||
#define BAUD2DIV(baud) (((F_PLL / 16 ) + ((baud) >> 1)) / (baud)) | |||||
#elif F_CPU <= 16000000 | |||||
#define BAUD2DIV(baud) (((F_PLL / (F_PLL / 1000000)) + ((baud) >> 1)) / (baud)) | |||||
#else | |||||
#define BAUD2DIV(baud) (((F_PLL / 2 / 16) + ((baud) >> 1)) / (baud)) | |||||
#endif | |||||
#define BAUD2DIV2(baud) (((F_BUS / 16) + ((baud) >> 1)) / (baud)) | |||||
#define BAUD2DIV3(baud) (((F_BUS / 16) + ((baud) >> 1)) / (baud)) | |||||
#endif | |||||
// C language implementation | // C language implementation | ||||
// | // | ||||
void serial_format(uint32_t format); | void serial_format(uint32_t format); | ||||
void serial_end(void); | void serial_end(void); | ||||
void serial_set_transmit_pin(uint8_t pin); | void serial_set_transmit_pin(uint8_t pin); | ||||
void serial_set_rx(uint8_t pin); | |||||
void serial_set_tx(uint8_t pin, uint8_t opendrain); | |||||
int serial_set_rts(uint8_t pin); | |||||
int serial_set_cts(uint8_t pin); | |||||
void serial_putchar(uint32_t c); | void serial_putchar(uint32_t c); | ||||
void serial_write(const void *buf, unsigned int count); | void serial_write(const void *buf, unsigned int count); | ||||
void serial_flush(void); | void serial_flush(void); | ||||
void serial2_format(uint32_t format); | void serial2_format(uint32_t format); | ||||
void serial2_end(void); | void serial2_end(void); | ||||
void serial2_set_transmit_pin(uint8_t pin); | void serial2_set_transmit_pin(uint8_t pin); | ||||
void serial2_set_rx(uint8_t pin); | |||||
void serial2_set_tx(uint8_t pin, uint8_t opendrain); | |||||
int serial2_set_rts(uint8_t pin); | |||||
int serial2_set_cts(uint8_t pin); | |||||
void serial2_putchar(uint32_t c); | void serial2_putchar(uint32_t c); | ||||
void serial2_write(const void *buf, unsigned int count); | void serial2_write(const void *buf, unsigned int count); | ||||
void serial2_flush(void); | void serial2_flush(void); | ||||
void serial3_format(uint32_t format); | void serial3_format(uint32_t format); | ||||
void serial3_end(void); | void serial3_end(void); | ||||
void serial3_set_transmit_pin(uint8_t pin); | void serial3_set_transmit_pin(uint8_t pin); | ||||
void serial3_set_rx(uint8_t pin); | |||||
void serial3_set_tx(uint8_t pin, uint8_t opendrain); | |||||
int serial3_set_rts(uint8_t pin); | |||||
int serial3_set_cts(uint8_t pin); | |||||
void serial3_putchar(uint32_t c); | void serial3_putchar(uint32_t c); | ||||
void serial3_write(const void *buf, unsigned int count); | void serial3_write(const void *buf, unsigned int count); | ||||
void serial3_flush(void); | void serial3_flush(void); | ||||
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)); | ||||
serial_format(format); } | serial_format(format); } | ||||
virtual void end(void) { serial_end(); } | virtual void end(void) { serial_end(); } | ||||
virtual void transmitterEnable(uint8_t pin) { serial_set_transmit_pin(pin); } | virtual void transmitterEnable(uint8_t pin) { serial_set_transmit_pin(pin); } | ||||
virtual void setRX(uint8_t pin) { serial_set_rx(pin); } | |||||
virtual void setTX(uint8_t pin, bool opendrain=false) { serial_set_tx(pin, opendrain); } | |||||
virtual bool attachRts(uint8_t pin) { return serial_set_rts(pin); } | |||||
virtual bool attachCts(uint8_t pin) { return serial_set_cts(pin); } | |||||
virtual int available(void) { return serial_available(); } | virtual int available(void) { return serial_available(); } | ||||
virtual int peek(void) { return serial_peek(); } | virtual int peek(void) { return serial_peek(); } | ||||
virtual int read(void) { return serial_getchar(); } | virtual int read(void) { return serial_getchar(); } | ||||
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); } | ||||
serial_write((const uint8_t *)str, len); | serial_write((const uint8_t *)str, len); | ||||
return len; } | return len; } | ||||
virtual size_t write9bit(uint32_t c) { serial_putchar(c); return 1; } | virtual size_t write9bit(uint32_t c) { serial_putchar(c); return 1; } | ||||
operator bool() { return true; } | |||||
}; | }; | ||||
extern HardwareSerial Serial1; | extern HardwareSerial Serial1; | ||||
extern void serialEvent1(void); | extern void serialEvent1(void); | ||||
class HardwareSerial2 : public HardwareSerial | class HardwareSerial2 : public HardwareSerial | ||||
{ | { | ||||
public: | public: | ||||
virtual void begin(uint32_t baud) { serial2_begin(BAUD2DIV(baud)); } | |||||
constexpr HardwareSerial2() {} | |||||
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(BAUD2DIV(baud)); | |||||
serial2_begin(BAUD2DIV2(baud)); | |||||
serial2_format(format); } | serial2_format(format); } | ||||
virtual void end(void) { serial2_end(); } | virtual void end(void) { serial2_end(); } | ||||
virtual void transmitterEnable(uint8_t pin) { serial2_set_transmit_pin(pin); } | virtual void transmitterEnable(uint8_t pin) { serial2_set_transmit_pin(pin); } | ||||
virtual void setRX(uint8_t pin) { serial2_set_rx(pin); } | |||||
virtual void setTX(uint8_t pin, bool opendrain=false) { serial2_set_tx(pin, opendrain); } | |||||
virtual bool attachRts(uint8_t pin) { return serial2_set_rts(pin); } | |||||
virtual bool attachCts(uint8_t pin) { return serial2_set_cts(pin); } | |||||
virtual int available(void) { return serial2_available(); } | virtual int available(void) { return serial2_available(); } | ||||
virtual int peek(void) { return serial2_peek(); } | virtual int peek(void) { return serial2_peek(); } | ||||
virtual int read(void) { return serial2_getchar(); } | virtual int read(void) { return serial2_getchar(); } | ||||
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); } | ||||
serial2_write((const uint8_t *)str, len); | serial2_write((const uint8_t *)str, len); | ||||
return len; } | return len; } | ||||
virtual size_t write9bit(uint32_t c) { serial2_putchar(c); return 1; } | virtual size_t write9bit(uint32_t c) { serial2_putchar(c); return 1; } | ||||
operator bool() { return true; } | |||||
}; | }; | ||||
extern HardwareSerial2 Serial2; | extern HardwareSerial2 Serial2; | ||||
extern void serialEvent2(void); | extern void serialEvent2(void); | ||||
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)); | ||||
serial3_format(format); } | serial3_format(format); } | ||||
virtual void end(void) { serial3_end(); } | virtual void end(void) { serial3_end(); } | ||||
virtual void transmitterEnable(uint8_t pin) { serial3_set_transmit_pin(pin); } | virtual void transmitterEnable(uint8_t pin) { serial3_set_transmit_pin(pin); } | ||||
virtual void setRX(uint8_t pin) { serial3_set_rx(pin); } | |||||
virtual void setTX(uint8_t pin, bool opendrain=false) { serial3_set_tx(pin, opendrain); } | |||||
virtual bool attachRts(uint8_t pin) { return serial3_set_rts(pin); } | |||||
virtual bool attachCts(uint8_t pin) { return serial3_set_cts(pin); } | |||||
virtual int available(void) { return serial3_available(); } | virtual int available(void) { return serial3_available(); } | ||||
virtual int peek(void) { return serial3_peek(); } | virtual int peek(void) { return serial3_peek(); } | ||||
virtual int read(void) { return serial3_getchar(); } | virtual int read(void) { return serial3_getchar(); } | ||||
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); } | ||||
serial3_write((const uint8_t *)str, len); | serial3_write((const uint8_t *)str, len); | ||||
return len; } | return len; } | ||||
virtual size_t write9bit(uint32_t c) { serial3_putchar(c); return 1; } | virtual size_t write9bit(uint32_t c) { serial3_putchar(c); return 1; } | ||||
operator bool() { return true; } | |||||
}; | }; | ||||
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 |
#if ARDUINO >= 100 | |||||
#include "Arduino.h" | |||||
#include "IPAddress.h" | |||||
/* | |||||
IPAddress.cpp - Base class that provides IPAddress | |||||
Copyright (c) 2011 Adrian McEwen. All right reserved. | |||||
IPAddress::IPAddress() | |||||
{ | |||||
memset(_address, 0, sizeof(_address)); | |||||
} | |||||
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. | |||||
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) | |||||
{ | |||||
_address[0] = first_octet; | |||||
_address[1] = second_octet; | |||||
_address[2] = third_octet; | |||||
_address[3] = fourth_octet; | |||||
} | |||||
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. | |||||
IPAddress::IPAddress(uint32_t address) | |||||
{ | |||||
memcpy(_address, &address, sizeof(_address)); | |||||
} | |||||
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 | |||||
*/ | |||||
IPAddress::IPAddress(const uint8_t *address) | |||||
{ | |||||
memcpy(_address, address, sizeof(_address)); | |||||
} | |||||
IPAddress& IPAddress::operator=(const uint8_t *address) | |||||
{ | |||||
memcpy(_address, address, sizeof(_address)); | |||||
return *this; | |||||
} | |||||
#include <Arduino.h> | |||||
#include "IPAddress.h" | |||||
IPAddress& IPAddress::operator=(uint32_t address) | |||||
size_t IPAddress::printTo(Print& p) const | |||||
{ | { | ||||
memcpy(_address, (const uint8_t *)&address, sizeof(_address)); | |||||
return *this; | |||||
int i=0; | |||||
while (1) { | |||||
p.print(_address.bytes[i], DEC); | |||||
if (++i >= 4) return 4; | |||||
p.write('.'); | |||||
} | |||||
} | } | ||||
bool IPAddress::operator==(const uint8_t* addr) | |||||
bool IPAddress::fromString(const char *address) | |||||
{ | { | ||||
return memcmp(addr, _address, sizeof(_address)) == 0; | |||||
} | |||||
unsigned int acc = 0; // Accumulator | |||||
unsigned int dots = 0; | |||||
size_t IPAddress::printTo(Print& p) const | |||||
{ | |||||
size_t n = 0; | |||||
for (int i =0; i < 3; i++) | |||||
{ | |||||
n += p.print(_address[i], DEC); | |||||
n += p.print('.'); | |||||
} | |||||
n += p.print(_address[3], DEC); | |||||
return n; | |||||
while (*address) { | |||||
char c = *address++; | |||||
if (c >= '0' && c <= '9') { | |||||
acc = acc * 10 + (c - '0'); | |||||
if (acc > 255) { | |||||
// Value out of [0..255] range | |||||
return false; | |||||
} | |||||
} else if (c == '.') { | |||||
if (dots == 3) { | |||||
// Too much dots (there must be 3 dots) | |||||
return false; | |||||
} | |||||
_address.bytes[dots++] = acc; | |||||
acc = 0; | |||||
} else { | |||||
// Invalid char | |||||
return false; | |||||
} | |||||
} | |||||
if (dots != 3) { | |||||
// Too few dots (there must be 3 dots) | |||||
return false; | |||||
} | |||||
_address.bytes[3] = acc; | |||||
return true; | |||||
} | } | ||||
#endif |
* adrianm@mcqn.com 1/1/2011 | * adrianm@mcqn.com 1/1/2011 | ||||
*/ | */ | ||||
#if ARDUINO >= 100 | |||||
#ifndef IPAddress_h | #ifndef IPAddress_h | ||||
#define IPAddress_h | #define IPAddress_h | ||||
#include <Printable.h> | #include <Printable.h> | ||||
#include <WString.h> | |||||
// A class to make it easier to handle and pass around IP addresses | // A class to make it easier to handle and pass around IP addresses | ||||
class IPAddress : public Printable { | class IPAddress : public Printable { | ||||
private: | private: | ||||
uint8_t _address[4]; // IPv4 address | |||||
// Access the raw byte array containing the address. Because this returns a pointer | |||||
// to the internal structure rather than a copy of the address this function should only | |||||
// be used when you know that the usage of the returned uint8_t* will be transient and not | |||||
// stored. | |||||
uint8_t* raw_address() { return _address; }; | |||||
union { | |||||
uint8_t bytes[4]; // IPv4 address | |||||
uint32_t dword; | |||||
} _address; | |||||
// Access the raw byte array containing the address. Because this returns a pointer | |||||
// to the internal structure rather than a copy of the address this function should only | |||||
// be used when you know that the usage of the returned uint8_t* will be transient and not | |||||
// stored. | |||||
uint8_t * raw_address() { return _address.bytes; }; | |||||
public: | public: | ||||
// Constructors | |||||
IPAddress(); | |||||
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); | |||||
IPAddress(uint32_t address); | |||||
IPAddress(const uint8_t *address); | |||||
// Constructors | |||||
IPAddress() { | |||||
_address.dword = 0; | |||||
} | |||||
IPAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) { | |||||
_address.bytes[0] = b1; | |||||
_address.bytes[1] = b2; | |||||
_address.bytes[2] = b3; | |||||
_address.bytes[3] = b4; | |||||
} | |||||
IPAddress(uint32_t address) { | |||||
_address.dword = address; | |||||
} | |||||
IPAddress(const uint8_t *address) { | |||||
// TODO: use unaligned read on Cortex-M4 | |||||
_address.bytes[0] = *address++; | |||||
_address.bytes[1] = *address++; | |||||
_address.bytes[2] = *address++; | |||||
_address.bytes[3] = *address++; | |||||
} | |||||
bool fromString(const char *address); | |||||
bool fromString(const String &address) { | |||||
return fromString(address.c_str()); | |||||
} | |||||
// Overloaded cast operator to allow IPAddress objects to be used where a pointer | |||||
// to a four-byte uint8_t array is expected | |||||
operator uint32_t () { return _address[0] | (_address[1] << 8) | |||||
| (_address[2] << 16) | (_address[3] << 24); } | |||||
bool operator==(const IPAddress& addr) { return _address[0] == addr._address[0] | |||||
&& _address[1] == addr._address[1] | |||||
&& _address[2] == addr._address[2] | |||||
&& _address[3] == addr._address[3]; } | |||||
bool operator==(const uint8_t* addr); | |||||
// Overloaded cast operator to allow IPAddress objects to be used where a pointer | |||||
// to a four-byte uint8_t array is expected | |||||
operator uint32_t () { | |||||
return _address.dword; | |||||
} | |||||
bool operator==(const IPAddress& addr) { | |||||
return _address.dword == addr._address.dword; | |||||
} | |||||
bool operator==(const uint8_t* addr) { | |||||
// TODO: use unaligned read on Cortex-M4 | |||||
return (_address.bytes[0] == addr[0] | |||||
&& _address.bytes[1] == addr[1] | |||||
&& _address.bytes[2] == addr[2] | |||||
&& _address.bytes[3] == addr[3]); | |||||
} | |||||
// Overloaded index operator to allow getting and setting individual octets of the address | |||||
uint8_t operator[](int index) const { return _address[index]; }; | |||||
uint8_t& operator[](int index) { return _address[index]; }; | |||||
// Overloaded index operator to allow getting and setting individual octets of the address | |||||
uint8_t operator[](int index) const { | |||||
return _address.bytes[index]; | |||||
}; | |||||
uint8_t& operator[](int index) { | |||||
return _address.bytes[index]; | |||||
}; | |||||
// Overloaded copy operators to allow initialisation of IPAddress objects from other types | |||||
IPAddress& operator=(const uint8_t *address); | |||||
IPAddress& operator=(uint32_t address); | |||||
// Overloaded copy operators to allow initialisation of IPAddress objects from other types | |||||
IPAddress& operator=(const uint8_t *address) { | |||||
// TODO: use unaligned read on Cortex-M4 | |||||
_address.bytes[0] = *address++; | |||||
_address.bytes[1] = *address++; | |||||
_address.bytes[2] = *address++; | |||||
_address.bytes[3] = *address++; | |||||
return *this; | |||||
} | |||||
IPAddress& operator=(uint32_t address) { | |||||
_address.dword = address; | |||||
return *this; | |||||
} | |||||
virtual size_t printTo(Print& p) const; | |||||
virtual size_t printTo(Print& p) const; | |||||
friend class EthernetClass; | |||||
friend class UDP; | |||||
friend class Client; | |||||
friend class Server; | |||||
friend class DhcpClass; | |||||
friend class DNSClient; | |||||
friend class EthernetClass; | |||||
friend class UDP; | |||||
friend class Client; | |||||
friend class Server; | |||||
friend class DhcpClass; | |||||
friend class DNSClient; | |||||
}; | }; | ||||
const IPAddress INADDR_NONE(0,0,0,0); | |||||
const IPAddress INADDR_NONE((uint32_t)0); | |||||
#endif | #endif | ||||
#endif |
/* 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 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 | |||||
// ------------------------------------------------------------ | |||||
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](); } | |||||
// ------------------------------------------------------------ | |||||
// 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; | |||||
static void dummy_funct(void); | |||||
#if defined(KINETISK) | |||||
#define NUM_CHANNELS 4 | |||||
static void (*funct_table[4])(void) = {dummy_funct, dummy_funct, dummy_funct, dummy_funct}; | |||||
#elif defined(KINETISL) | |||||
#define NUM_CHANNELS 2 | |||||
static void (*funct_table[2])(void) = {dummy_funct, dummy_funct}; | |||||
uint8_t IntervalTimer::nvic_priorites[2] = {255, 255}; | |||||
#endif | |||||
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; | |||||
IRQ_PIT_CH = IRQ_PIT_CH0 + PIT_id; | |||||
// 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; | |||||
NVIC_SET_PRIORITY(IRQ_PIT_CH, nvic_priority); | |||||
NVIC_ENABLE_IRQ(IRQ_PIT_CH); | |||||
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 | |||||
NVIC_DISABLE_IRQ(IRQ_PIT_CH); | |||||
*PIT_TCTRL = 0; | |||||
// 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(); | |||||
#elif defined(KINETISL) | |||||
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}; | |||||
static const uint8_t NUM_PIT = 4; | |||||
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]; | |||||
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); | |||||
} | |||||
static ISR PIT_ISR[NUM_PIT]; | |||||
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` | |||||
MCU=MK20DX256 | |||||
#MCU=MKL26Z64 | |||||
#MCU=MK64FX512 | |||||
#MCU=MK66FX1M0 | |||||
# 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))))))))))))))))))))))))))) | |||||
MCU_LD = $(LOWER_MCU).ld | |||||
# The name of your project (used to name the compiled .hex file) | # The name of your project (used to name the compiled .hex file) | ||||
TARGET = main | TARGET = main | ||||
# Those that specify a NO_ARDUINO environment variable will | |||||
# be able to use this Makefile with no Arduino dependency. | |||||
# Please note that if ARDUINOPATH was set, it will override | |||||
# the NO_ARDUINO behaviour. | |||||
ifndef NO_ARDUINO | |||||
# Path to your arduino installation | # Path to your arduino installation | ||||
ARDUINOPATH ?= ../../../.. | |||||
ARDUINOPATH ?= ../../../../.. | |||||
endif | |||||
# configurable options | # configurable options | ||||
OPTIONS = -DF_CPU=48000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH | |||||
OPTIONS = -DF_CPU=48000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH -DUSING_MAKEFILE | |||||
# options needed by many Arduino libraries to configure for Teensy 3.x | |||||
OPTIONS += -D__$(MCU)__ -DARDUINO=10805 -DTEENSYDUINO=144 | |||||
# options needed by many Arduino libraries to configure for Teensy 3.0 | |||||
OPTIONS += -D__MK20DX128__ -DARDUIO=105 -DTEENSYDUINO=118 | |||||
# 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: | ||||
# locations and edit the pathnames. The rest of Arduino is not needed. | # locations and edit the pathnames. The rest of Arduino is not needed. | ||||
#************************************************************************ | #************************************************************************ | ||||
# path location for Teensy Loader, teensy_post_compile and teensy_reboot | |||||
TOOLSPATH = $(ARDUINOPATH)/hardware/tools # on Linux | |||||
#TOOLSPATH = $(ARDUINOPATH)/hardware/tools/tools/avr/bin # on Mac or Windows | |||||
ifdef ARDUINOPATH | |||||
# 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 = $(ARDUINOPATH)/libraries | |||||
LIBRARYPATH = $(abspath $(ARDUINOPATH)/libraries) | |||||
# path location for the arm-none-eabi compiler | # path location for the arm-none-eabi compiler | ||||
COMPILERPATH = $(ARDUINOPATH)/hardware/tools/arm-none-eabi/bin | |||||
COMPILERPATH = $(abspath $(ARDUINOPATH)/hardware/tools/arm/bin) | |||||
else | |||||
# Default to the normal GNU/Linux compiler path if NO_ARDUINO | |||||
# and ARDUINOPATH was not set. | |||||
COMPILERPATH ?= /usr/bin | |||||
endif | |||||
#************************************************************************ | #************************************************************************ | ||||
# Settings below this point usually do not need to be edited | # Settings below this point usually do not need to be edited | ||||
#************************************************************************ | #************************************************************************ | ||||
# CPPFLAGS = compiler options for C and C++ | # CPPFLAGS = compiler options for C and C++ | ||||
CPPFLAGS = -Wall -g -Os -mcpu=cortex-m4 -mthumb -nostdlib -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 -mcpu=cortex-m4 -mthumb -Tmk20dx128.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 | ||||
# names for the compiler programs | # names for the compiler programs | ||||
CC = $(abspath $(COMPILERPATH))/arm-none-eabi-gcc | |||||
CXX = $(abspath $(COMPILERPATH))/arm-none-eabi-g++ | |||||
OBJCOPY = $(abspath $(COMPILERPATH))/arm-none-eabi-objcopy | |||||
SIZE = $(abspath $(COMPILERPATH))/arm-none-eabi-size | |||||
CC = $(COMPILERPATH)/arm-none-eabi-gcc | |||||
CXX = $(COMPILERPATH)/arm-none-eabi-g++ | |||||
OBJCOPY = $(COMPILERPATH)/arm-none-eabi-objcopy | |||||
SIZE = $(COMPILERPATH)/arm-none-eabi-size | |||||
# automatically create lists of the sources and objects | # automatically create lists of the sources and objects | ||||
# TODO: this does not handle Arduino libraries yet... | # TODO: this does not handle Arduino libraries yet... | ||||
all: $(TARGET).hex | all: $(TARGET).hex | ||||
$(TARGET).elf: $(OBJS) mk20dx128.ld | |||||
$(TARGET).elf: $(OBJS) $(MCU_LD) | |||||
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) | $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) | ||||
%.hex: %.elf | %.hex: %.elf | ||||
$(SIZE) $< | $(SIZE) $< | ||||
$(OBJCOPY) -O ihex -R .eeprom $< $@ | $(OBJCOPY) -O ihex -R .eeprom $< $@ | ||||
$(abspath $(TOOLSPATH))/teensy_post_compile -file=$(basename $@) -path=$(shell pwd) -tools=$(abspath $(TOOLSPATH)) | |||||
-$(abspath $(TOOLSPATH))/teensy_reboot | |||||
ifneq (,$(wildcard $(TOOLSPATH))) | |||||
$(TOOLSPATH)/teensy_post_compile -file=$(basename $@) -path=$(shell pwd) -tools=$(TOOLSPATH) | |||||
-$(TOOLSPATH)/teensy_reboot | |||||
endif | |||||
# compiler generated dependency info | # compiler generated dependency info | ||||
-include $(OBJS:.o=.d) | -include $(OBJS:.o=.d) | ||||
clean: | clean: | ||||
rm -f *.o *.d $(TARGET).elf $(TARGET).hex | rm -f *.o *.d $(TARGET).elf $(TARGET).hex | ||||
// 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) | ||||
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; | |||||
} | } | ||||
} | } | ||||
{ | { | ||||
va_list ap; | va_list ap; | ||||
va_start(ap, format); | va_start(ap, format); | ||||
#ifdef __STRICT_ANSI__ | |||||
return 0; // TODO: make this work with -std=c++0x | |||||
#else | |||||
return vdprintf((int)this, format, ap); | return vdprintf((int)this, format, ap); | ||||
#endif | |||||
} | } | ||||
int Print::printf(const __FlashStringHelper *format, ...) | int Print::printf(const __FlashStringHelper *format, ...) | ||||
{ | { | ||||
va_list ap; | va_list ap; | ||||
va_start(ap, format); | va_start(ap, format); | ||||
#ifdef __STRICT_ANSI__ | |||||
return 0; | |||||
#else | |||||
return vdprintf((int)this, (const char *)format, ap); | return vdprintf((int)this, (const char *)format, ap); | ||||
#endif | |||||
} | |||||
#ifdef __MKL26Z64__ | |||||
// optimized code inspired by Stimmer's optimization | |||||
// obviously a dit different, adapted to 32 bit Cortex-M0+ | |||||
// http://forum.arduino.cc/index.php?topic=167414.msg1293679#msg1293679 | |||||
// http://forum.arduino.cc/index.php?topic=167414.msg1309482#msg1309482 | |||||
// equivelant code: | |||||
// mod = div % 10; | |||||
// div = div / 10; | |||||
// tmp1 = {random}; | |||||
// tmp2 = 10; | |||||
#if 1 | |||||
// https://forum.pjrc.com/threads/28932-LC-is-10-9-times-slower-than-T3-1?p=76072&viewfull=1#post76072 | |||||
void inline divmod10_v2(uint32_t n,uint32_t *div,uint32_t *mod) { | |||||
uint32_t p,q; | |||||
/* Using 32.16 fixed point representation p.q */ | |||||
/* p.q = (n+1)/512 */ | |||||
q = (n&0xFFFF) + 1; | |||||
p = (n>>16); | |||||
/* p.q = 51*(n+1)/512 */ | |||||
q = 13107*q; | |||||
p = 13107*p; | |||||
/* p.q = (1+1/2^8+1/2^16+1/2^24)*51*(n+1)/512 */ | |||||
q = q + (q>>16) + (p&0xFFFF); | |||||
p = p + (p>>16) + (q>>16); | |||||
/* divide by 2 */ | |||||
p = p>>1; | |||||
*div = p; | |||||
*mod = n-10*p; | |||||
} | |||||
#define divmod10_asm(div, mod, tmp1, tmp2, const3333) \ | |||||
divmod10_v2(div, &div, &mod); | |||||
/* | |||||
#define divmod10_asm(div, mod, tmp1, tmp2, const3333) \ | |||||
asm ( \ | |||||
" lsr %2, %0, #16" "\n\t" \ | |||||
" mul %2, %4" "\n\t" \ | |||||
" uxth %1, %0" "\n\t" \ | |||||
" mul %1, %4" "\n\t" \ | |||||
" add %1, #1" "\n\t" \ | |||||
" lsr %0, %2, #16" "\n\t" \ | |||||
" lsl %2, %2, #16" "\n\t" \ | |||||
" add %1, %2" "\n\t" \ | |||||
" mov %3, #0" "\n\t" \ | |||||
" adc %0, %3" "\n\t" \ | |||||
" lsl %0, %0, #15" "\n\t" \ | |||||
" lsr %2, %1, #17" "\n\t" \ | |||||
" orr %0, %2" "\n\t" \ | |||||
" lsl %1, %1, #15" "\n\t" \ | |||||
" lsr %2, %1, #16" "\n\t" \ | |||||
" lsl %3, %0, #16" "\n\t" \ | |||||
" orr %2, %3" "\n\t" \ | |||||
" lsr %3, %0, #16" "\n\t" \ | |||||
" add %1, %0" "\n\t" \ | |||||
" adc %0, %1" "\n\t" \ | |||||
" sub %0, %1" "\n\t" \ | |||||
" add %1, %2" "\n\t" \ | |||||
" adc %0, %3" "\n\t" \ | |||||
" lsr %1, %1, #4" "\n\t" \ | |||||
" mov %3, #10" "\n\t" \ | |||||
" mul %1, %3" "\n\t" \ | |||||
" lsr %1, %1, #28" "\n\t" \ | |||||
: "+l" (div), \ | |||||
"=&l" (mod), \ | |||||
"=&l" (tmp1), \ | |||||
"=&l" (tmp2) \ | |||||
: "l" (const3333) \ | |||||
: \ | |||||
) | |||||
*/ | |||||
#else | |||||
#define divmod10_asm(_div, _mod, _tmp1, _tmp2, _const3333) \ | |||||
({ _tmp1 = _div; _div = _div / 10; _mod = _tmp1 - _div * 10; }) | |||||
// ({_mod = _div % 10, _div = _div / 10; }) | |||||
#endif | |||||
size_t Print::printNumberDec(unsigned long n, uint8_t sign) | |||||
{ | |||||
uint8_t buf[11], *p; | |||||
uint32_t digit; | |||||
//uint32_t t1, t2, c3333=0x3333; | |||||
p = buf + (sizeof(buf)); | |||||
do { | |||||
uint32_t div; | |||||
divmod10_v2(n, &div, &digit); | |||||
n = div; | |||||
//divmod10_asm(n, digit, t1, t2, c3333); | |||||
*--p = digit + '0'; | |||||
} while (n); | |||||
if (sign) *--p = '-'; | |||||
return write(p, sizeof(buf) - (p - buf)); | |||||
} | |||||
size_t Print::printNumberHex(unsigned long n) | |||||
{ | |||||
uint8_t digit, buf[8], *p; | |||||
p = buf + (sizeof(buf)); | |||||
do { | |||||
digit = n & 15; | |||||
*--p = (digit < 10) ? '0' + digit : 'A' + digit - 10; | |||||
n >>= 4; | |||||
} while (n); | |||||
return write(p, sizeof(buf) - (p - buf)); | |||||
} | |||||
size_t Print::printNumberBin(unsigned long n) | |||||
{ | |||||
uint8_t buf[32], *p; | |||||
p = buf + (sizeof(buf)); | |||||
do { | |||||
*--p = '0' + ((uint8_t)n & 1); | |||||
n >>= 1; | |||||
} while (n); | |||||
return write(p, sizeof(buf) - (p - buf)); | |||||
} | |||||
size_t Print::printNumberAny(unsigned long n, uint8_t base) | |||||
{ | |||||
uint8_t digit, buf[21], *p; | |||||
uint32_t tmp; | |||||
p = buf + sizeof(buf); | |||||
do { | |||||
tmp = n; | |||||
n = n / base; | |||||
digit = tmp - n * base; | |||||
*--p = (digit < 10) ? '0' + digit : 'A' + digit - 10; | |||||
} while (n); | |||||
return write(p, sizeof(buf) - (p - buf)); | |||||
} | } | ||||
#else | |||||
size_t Print::printNumber(unsigned long n, uint8_t base, uint8_t sign) | size_t Print::printNumber(unsigned long n, uint8_t base, uint8_t sign) | ||||
{ | { | ||||
return write(buf + i, sizeof(buf) - i); | return write(buf + i, sizeof(buf) - i); | ||||
} | } | ||||
#endif | |||||
size_t Print::printFloat(double number, uint8_t digits) | size_t Print::printFloat(double number, uint8_t digits) | ||||
{ | { | ||||
uint8_t sign=0; | uint8_t sign=0; | ||||
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; | ||||
// Print the decimal point, but only if there are digits beyond | // Print the decimal point, but only if there are digits beyond | ||||
if (digits > 0) { | if (digits > 0) { | ||||
uint8_t n, buf[8], count=1; | |||||
uint8_t n, buf[16], count=1; | |||||
buf[0] = '.'; | buf[0] = '.'; | ||||
// Extract digits from the remainder one at a time | // Extract digits from the remainder one at a time |
/* 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); } | ||||
private: | private: | ||||
char write_error; | char write_error; | ||||
size_t printFloat(double n, uint8_t digits); | size_t printFloat(double n, uint8_t digits); | ||||
#ifdef __MKL26Z64__ | |||||
size_t printNumberDec(unsigned long n, uint8_t sign); | |||||
size_t printNumberHex(unsigned long n); | |||||
size_t printNumberBin(unsigned long n); | |||||
size_t printNumberAny(unsigned long n, uint8_t base); | |||||
inline size_t printNumber(unsigned long n, uint8_t base, uint8_t sign) __attribute__((always_inline)) { | |||||
// when "base" is a constant (pretty much always), the | |||||
// compiler optimizes this to a single function call. | |||||
if (base == 0) return write((uint8_t)n); | |||||
if (base == 10 || base < 2) return printNumberDec(n, sign); | |||||
if (base == 16) return printNumberHex(n); | |||||
if (base == 2) return printNumberBin(n); | |||||
return printNumberAny(n, base); | |||||
} | |||||
#else | |||||
size_t printNumber(unsigned long n, uint8_t base, uint8_t sign); | size_t printNumber(unsigned long n, uint8_t base, uint8_t sign); | ||||
#endif | |||||
}; | }; | ||||
/* 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_ | ||||
#include "avr_emulation.h" | #include "avr_emulation.h" | ||||
#if F_BUS == 60000000 | |||||
#ifdef KINETISK | |||||
// 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 | ||||
#define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 1 MHz | #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 1 MHz | ||||
#define SPI_CLOCK_4MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 1 MHz | #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 1 MHz | ||||
#endif | |||||
#endif // F_BUS | |||||
#endif // KINETISK | |||||
/* | /* | ||||
#! /usr/bin/perl | #! /usr/bin/perl | ||||
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; | ||||
SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F); | |||||
KINETISK_SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F); | |||||
if (mode & 0x08) ctar |= SPI_CTAR_CPOL; | if (mode & 0x08) ctar |= SPI_CTAR_CPOL; | ||||
if (mode & 0x04) { | if (mode & 0x04) { | ||||
ctar |= SPI_CTAR_CPHA; | ctar |= SPI_CTAR_CPHA; | ||||
} else { | } else { | ||||
ctar |= (ctar & 0x0F) << 12; | ctar |= (ctar & 0x0F) << 12; | ||||
} | } | ||||
SPI0.CTAR0 = ctar | SPI_CTAR_FMSZ(7); | |||||
SPI0.CTAR1 = ctar | SPI_CTAR_FMSZ(15); | |||||
KINETISK_SPI0.CTAR0 = ctar | SPI_CTAR_FMSZ(7); | |||||
KINETISK_SPI0.CTAR1 = ctar | SPI_CTAR_FMSZ(15); | |||||
if (pin == 10) { // PTC4 | if (pin == 10) { // PTC4 | ||||
CORE_PIN10_CONFIG = PORT_PCR_MUX(2); | CORE_PIN10_CONFIG = PORT_PCR_MUX(2); | ||||
p = 0x01; | p = 0x01; | ||||
} 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); | ||||
*reg = 1; | |||||
pinMode(pin, OUTPUT); | pinMode(pin, OUTPUT); | ||||
*reg = 1; | |||||
p = 0; | p = 0; | ||||
} | } | ||||
pcs = p; | pcs = p; | ||||
inline void write(uint32_t b, uint32_t cont=0) __attribute__((always_inline)) { | inline void write(uint32_t b, uint32_t cont=0) __attribute__((always_inline)) { | ||||
uint32_t pcsbits = pcs << 16; | uint32_t pcsbits = pcs << 16; | ||||
if (pcsbits) { | if (pcsbits) { | ||||
SPI0.PUSHR = (b & 0xFF) | pcsbits | (cont ? SPI_PUSHR_CONT : 0); | |||||
while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full | |||||
KINETISK_SPI0.PUSHR = (b & 0xFF) | pcsbits | (cont ? SPI_PUSHR_CONT : 0); | |||||
while (((KINETISK_SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full | |||||
} else { | } else { | ||||
*reg = 0; | *reg = 0; | ||||
SPI0.SR = SPI_SR_EOQF; | |||||
SPI0.PUSHR = (b & 0xFF) | (cont ? 0 : SPI_PUSHR_EOQ); | |||||
KINETISK_SPI0.SR = SPI_SR_EOQF; | |||||
KINETISK_SPI0.PUSHR = (b & 0xFF) | (cont ? 0 : SPI_PUSHR_EOQ); | |||||
if (cont) { | if (cont) { | ||||
while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; | |||||
while (((KINETISK_SPI0.SR) & (15 << 12)) > (3 << 12)) ; | |||||
} else { | } else { | ||||
while (!(SPI0.SR & SPI_SR_EOQF)) ; | |||||
while (!(KINETISK_SPI0.SR & SPI_SR_EOQF)) ; | |||||
*reg = 1; | *reg = 1; | ||||
} | } | ||||
} | } | ||||
inline void write16(uint32_t b, uint32_t cont=0) __attribute__((always_inline)) { | inline void write16(uint32_t b, uint32_t cont=0) __attribute__((always_inline)) { | ||||
uint32_t pcsbits = pcs << 16; | uint32_t pcsbits = pcs << 16; | ||||
if (pcsbits) { | if (pcsbits) { | ||||
SPI0.PUSHR = (b & 0xFFFF) | (pcs << 16) | | |||||
KINETISK_SPI0.PUSHR = (b & 0xFFFF) | (pcs << 16) | | |||||
(cont ? SPI_PUSHR_CONT : 0) | SPI_PUSHR_CTAS(1); | (cont ? SPI_PUSHR_CONT : 0) | SPI_PUSHR_CTAS(1); | ||||
while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; | |||||
while (((KINETISK_SPI0.SR) & (15 << 12)) > (3 << 12)) ; | |||||
} else { | } else { | ||||
*reg = 0; | *reg = 0; | ||||
SPI0.SR = SPI_SR_EOQF; | |||||
SPI0.PUSHR = (b & 0xFFFF) | (cont ? 0 : SPI_PUSHR_EOQ) | SPI_PUSHR_CTAS(1); | |||||
KINETISK_SPI0.SR = SPI_SR_EOQF; | |||||
KINETISK_SPI0.PUSHR = (b & 0xFFFF) | (cont ? 0 : SPI_PUSHR_EOQ) | SPI_PUSHR_CTAS(1); | |||||
if (cont) { | if (cont) { | ||||
while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; | |||||
while (((KINETISK_SPI0.SR) & (15 << 12)) > (3 << 12)) ; | |||||
} else { | } else { | ||||
while (!(SPI0.SR & SPI_SR_EOQF)) ; | |||||
while (!(KINETISK_SPI0.SR & SPI_SR_EOQF)) ; | |||||
*reg = 1; | *reg = 1; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
inline uint32_t read(void) __attribute__((always_inline)) { | inline uint32_t read(void) __attribute__((always_inline)) { | ||||
while ((SPI0.SR & (15 << 4)) == 0) ; // TODO, could wait forever | |||||
return SPI0.POPR; | |||||
while ((KINETISK_SPI0.SR & (15 << 4)) == 0) ; // TODO, could wait forever | |||||
return KINETISK_SPI0.POPR; | |||||
} | } | ||||
inline void clear(void) __attribute__((always_inline)) { | inline void clear(void) __attribute__((always_inline)) { | ||||
SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F) | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF; | |||||
KINETISK_SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F) | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF; | |||||
} | } | ||||
private: | private: | ||||
static uint8_t pcs; | static uint8_t pcs; | ||||
}; | }; | ||||
extern SPIFIFOclass SPIFIFO; | extern SPIFIFOclass SPIFIFO; | ||||
#endif | |||||
#endif // HAS_SPIFIFO | |||||
#endif | #endif |
/* | |||||
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)); | 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, 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; | ||||
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(); | ||||
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> | |||||
#if 1 | |||||
// 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 | ||||
// which never use tone(). Someday this single-tone implementation might be | // which never use tone(). Someday this single-tone implementation might be | ||||
static uint32_t tone_toggle_count; | static uint32_t tone_toggle_count; | ||||
static volatile uint8_t *tone_reg; | static volatile uint8_t *tone_reg; | ||||
static uint8_t tone_pin=255; | static uint8_t tone_pin=255; | ||||
static uint16_t tone_frequency=0; | |||||
static float tone_usec=0.0; | |||||
static uint32_t tone_new_count=0; | |||||
IntervalTimer tone_timer; | IntervalTimer tone_timer; | ||||
void tone_interrupt(void); | void tone_interrupt(void); | ||||
#if defined(KINETISK) | |||||
#define TONE_CLEAR_PIN tone_reg[0] = 1 | |||||
#define TONE_TOGGLE_PIN tone_reg[128] = 1 | |||||
#define TONE_OUTPUT_PIN tone_reg[384] = 1 | |||||
#elif defined(KINETISL) | |||||
static uint8_t tone_mask; | |||||
#define TONE_CLEAR_PIN tone_reg[0] = tone_mask | |||||
#define TONE_TOGGLE_PIN tone_reg[4] = tone_mask | |||||
#define TONE_OUTPUT_PIN __disable_irq(); tone_reg[12] |= tone_mask; __enable_irq() | |||||
#endif | |||||
void tone(uint8_t pin, uint16_t frequency, uint32_t duration) | void tone(uint8_t pin, uint16_t frequency, uint32_t duration) | ||||
{ | { | ||||
uint32_t count; | uint32_t count; | ||||
if (pin >= CORE_NUM_DIGITAL) return; | if (pin >= CORE_NUM_DIGITAL) return; | ||||
if (duration) { | if (duration) { | ||||
count = (frequency * duration / 1000) * 2; | count = (frequency * duration / 1000) * 2; | ||||
if (!(count & 1)) count++; // always full waveform cycles | |||||
} else { | } else { | ||||
count = 0xFFFFFFFF; | |||||
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); | ||||
// the interrupt on a single timer. | // the interrupt on a single timer. | ||||
__disable_irq(); | __disable_irq(); | ||||
if (pin == tone_pin) { | if (pin == tone_pin) { | ||||
if (frequency == tone_frequency) { | |||||
// same pin, same frequency, so just update the | |||||
// duration. Users will call repetitively call | |||||
// tone() with the same setting, expecting a | |||||
// continuous output with no glitches or phase | |||||
// changes or jitter at each call. | |||||
tone_toggle_count = count; | |||||
// changing a pin which is already playing a tone | |||||
if (usec == tone_usec) { | |||||
// same frequency, so just change the duration | |||||
tone_toggle_count = (tone_toggle_count & 1) + count - 1; | |||||
} else { | } else { | ||||
// same pin, but a new frequency. | |||||
tone_reg[0] = 1; // clear pin | |||||
tone_timer.begin(tone_interrupt, usec); | |||||
// different frequency, reduce duration to only the | |||||
// remainder of its current cycle, and configure for | |||||
// the transition to the new frequency when the | |||||
// current cycle completes | |||||
tone_usec = usec; | |||||
tone_new_count = count; | |||||
tone_toggle_count = (tone_toggle_count & 1); | |||||
} | } | ||||
} else { | } else { | ||||
// if playing on a different pin, immediately stop, even mid-cycle :-( | |||||
if (tone_pin < CORE_NUM_DIGITAL) { | if (tone_pin < CORE_NUM_DIGITAL) { | ||||
tone_reg[0] = 1; // clear pin | |||||
TONE_CLEAR_PIN; // clear pin | |||||
} | } | ||||
// configure the new tone to play | |||||
tone_pin = pin; | tone_pin = pin; | ||||
tone_reg = portClearRegister(pin); | tone_reg = portClearRegister(pin); | ||||
tone_reg[0] = 1; // clear pin | |||||
tone_reg[384] = 1; // output mode; | |||||
#if defined(KINETISL) | |||||
tone_mask = digitalPinToBitMask(pin); | |||||
#endif | |||||
TONE_CLEAR_PIN; // clear pin | |||||
TONE_OUTPUT_PIN; // output mode; | |||||
*config = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | *config = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | ||||
tone_toggle_count = count; | tone_toggle_count = count; | ||||
tone_usec = usec; | |||||
tone_timer.begin(tone_interrupt, usec); | tone_timer.begin(tone_interrupt, usec); | ||||
} | } | ||||
__enable_irq(); | __enable_irq(); | ||||
void tone_interrupt(void) | void tone_interrupt(void) | ||||
{ | { | ||||
if (tone_toggle_count) { | |||||
tone_reg[128] = 1; // toggle | |||||
if (tone_toggle_count < 0xFFFFFFFF) tone_toggle_count--; | |||||
if (tone_toggle_count) { // odd = rising edge, even = falling edge | |||||
// not the end | |||||
TONE_TOGGLE_PIN; // toggle | |||||
tone_toggle_count--; | |||||
if (tone_toggle_count == 0xFFFFFFFB) tone_toggle_count = 0xFFFFFFFD; | |||||
} else { | } else { | ||||
tone_timer.end(); | |||||
tone_reg[0] = 0; // clear | |||||
tone_pin = 255; | |||||
tone_frequency = 0; | |||||
} | |||||
} | |||||
void noTone(uint8_t pin) | |||||
{ | |||||
if (pin >= CORE_NUM_DIGITAL) return; | |||||
__disable_irq(); | |||||
if (pin == tone_pin) { | |||||
tone_timer.end(); | |||||
tone_reg[0] = 0; // clear | |||||
tone_pin = 255; | |||||
tone_frequency = 0; | |||||
} | |||||
__enable_irq(); | |||||
} | |||||
#endif | |||||
#if 0 | |||||
// Old PIT timer based tone(). This implementation is slightly more efficient, | |||||
// but it consumes one of the PIT timers, even for projects which never use tone(). | |||||
static uint32_t tone_toggle_count; | |||||
static volatile uint8_t *tone_reg; | |||||
static uint8_t tone_pin; | |||||
void init_tone(void) | |||||
{ | |||||
if (SIM_SCGC6 & SIM_SCGC6_PIT) return; | |||||
SIM_SCGC6 |= SIM_SCGC6_PIT; // TODO: use bitband for atomic read-mod-write | |||||
PIT_MCR = 0; | |||||
PIT_TCTRL3 = 0; // disabled | |||||
tone_pin = 255; | |||||
NVIC_ENABLE_IRQ(IRQ_PIT_CH3); | |||||
} | |||||
void tone(uint8_t pin, uint16_t frequency, uint32_t duration) | |||||
{ | |||||
uint32_t count, load; | |||||
volatile uint32_t *config; | |||||
init_tone(); | |||||
if (pin >= CORE_NUM_DIGITAL) return; | |||||
if (duration) { | |||||
count = (frequency * duration / 1000) * 2; | |||||
} else { | |||||
count = 0xFFFFFFFF; | |||||
} | |||||
load = (F_BUS / 2) / frequency; | |||||
config = portConfigRegister(pin); | |||||
__disable_irq(); | |||||
if (pin != tone_pin) { | |||||
if (tone_pin < CORE_NUM_DIGITAL) { | |||||
tone_reg[0] = 1; // clear pin | |||||
// this transition completes the tone | |||||
TONE_CLEAR_PIN; // clear | |||||
if (tone_new_count > 0) { | |||||
// begin playing a new tone | |||||
tone_timer.begin(tone_interrupt, tone_usec); | |||||
tone_toggle_count = tone_new_count; | |||||
tone_new_count = 0; | |||||
} else { | |||||
// finished playing | |||||
tone_timer.end(); | |||||
tone_pin = 255; | |||||
} | } | ||||
tone_pin = pin; | |||||
tone_reg = portClearRegister(pin); | |||||
tone_reg[0] = 1; // clear pin | |||||
tone_reg[384] = 1; // output mode; | |||||
*config = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||||
} | |||||
tone_toggle_count = count; | |||||
if (PIT_LDVAL3 != load) { | |||||
PIT_TCTRL3 = 0; | |||||
PIT_LDVAL3 = load; | |||||
PIT_TCTRL3 = 3; | |||||
} | |||||
__enable_irq(); | |||||
} | |||||
void pit3_isr(void) | |||||
{ | |||||
PIT_TFLG3 = 1; | |||||
if (tone_toggle_count) { | |||||
tone_reg[128] = 1; // toggle | |||||
if (tone_toggle_count < 0xFFFFFFFF) tone_toggle_count--; | |||||
} else { | |||||
PIT_TCTRL3 = 0; | |||||
PIT_LDVAL3 = 0; | |||||
tone_reg[0] = 0; // clear | |||||
tone_pin = 255; | |||||
} | } | ||||
} | } | ||||
if (pin >= CORE_NUM_DIGITAL) return; | if (pin >= CORE_NUM_DIGITAL) return; | ||||
__disable_irq(); | __disable_irq(); | ||||
if (pin == tone_pin) { | if (pin == tone_pin) { | ||||
PIT_TCTRL3 = 0; | |||||
PIT_LDVAL3 = 0; | |||||
tone_reg[0] = 0; // clear | |||||
tone_timer.end(); | |||||
TONE_CLEAR_PIN; // clear | |||||
tone_pin = 255; | tone_pin = 255; | ||||
} | } | ||||
__enable_irq(); | __enable_irq(); | ||||
} | } | ||||
#endif | |||||
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 "HardwareSerial.h" | #include "HardwareSerial.h" | ||||
#define DMAMEM __attribute__ ((section(".dmabuffers"), used)) | #define DMAMEM __attribute__ ((section(".dmabuffers"), used)) | ||||
#define FASTRUN __attribute__ ((section(".fastrun"))) | |||||
#define FASTRUN __attribute__ ((section(".fastrun"), noinline, noclone )) | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
#include "usb_midi.h" | #include "usb_midi.h" | ||||
#include "usb_rawhid.h" | #include "usb_rawhid.h" | ||||
#include "usb_flightsim.h" | #include "usb_flightsim.h" | ||||
#include "usb_mtp.h" | |||||
#include "usb_audio.h" | |||||
#include "usb_touch.h" | |||||
#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" | ||||
#endif // __cplusplus | #endif // __cplusplus | ||||
// Fast memcpy | |||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
extern void *memcpy (void *dst, const void *src, size_t count); | |||||
} | |||||
#else | |||||
extern void *memcpy (void *dst, const void *src, size_t count); | |||||
#endif | |||||
#endif | |||||
#endif // WProgram_h | #endif // WProgram_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> | |||||
/*********************************************/ | /*********************************************/ | ||||
*this = value; | *this = value; | ||||
} | } | ||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__ | |||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) | |||||
String::String(String &&rval) | String::String(String &&rval) | ||||
{ | { | ||||
init(); | init(); | ||||
return copy(rhs.buffer, rhs.len); | return copy(rhs.buffer, rhs.len); | ||||
} | } | ||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__ | |||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) | |||||
String & String::operator = (String &&rval) | String & String::operator = (String &&rval) | ||||
{ | { | ||||
if (this != &rval) move(rval); | if (this != &rval) move(rval); | ||||
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. | ||||
String(const char *cstr = (const char *)NULL); | String(const char *cstr = (const char *)NULL); | ||||
String(const __FlashStringHelper *pgmstr); | String(const __FlashStringHelper *pgmstr); | ||||
String(const String &str); | String(const String &str); | ||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__ | |||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) | |||||
String(String &&rval); | String(String &&rval); | ||||
String(StringSumHelper &&rval); | String(StringSumHelper &&rval); | ||||
#endif | #endif | ||||
String & operator = (const String &rhs); | String & operator = (const String &rhs); | ||||
String & operator = (const char *cstr); | String & operator = (const char *cstr); | ||||
String & operator = (const __FlashStringHelper *pgmstr); | String & operator = (const __FlashStringHelper *pgmstr); | ||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__ | |||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) | |||||
String & operator = (String &&rval); | String & operator = (String &&rval); | ||||
String & operator = (StringSumHelper &&rval); | String & operator = (StringSumHelper &&rval); | ||||
#endif | #endif | ||||
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. | ||||
// 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__) || 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 | |||||
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 | ||||
} | } | ||||
#if defined(__MK20DX128__) | |||||
if (analog_reference_internal) { | |||||
ADC0_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref | |||||
} else { | |||||
ADC0_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref | |||||
} | |||||
#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 | ||||
#if defined(__MK20DX256__) | |||||
ADC1_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref | ADC1_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref | ||||
#endif | |||||
} else { | } else { | ||||
ADC0_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref | ADC0_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref | ||||
#if defined(__MK20DX256__) | |||||
ADC1_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref | ADC1_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref | ||||
#endif | |||||
} | } | ||||
#elif defined(__MKL26Z64__) | |||||
if (analog_reference_internal) { | |||||
ADC0_SC2 = ADC_SC2_REFSEL(0); // external AREF | |||||
} else { | |||||
ADC0_SC2 = ADC_SC2_REFSEL(1); // vcc | |||||
} | |||||
#endif | |||||
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__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#define DEFAULT 0 | #define DEFAULT 0 | ||||
#define INTERNAL 2 | #define INTERNAL 2 | ||||
#define INTERNAL1V2 2 | #define INTERNAL1V2 2 | ||||
#define INTERNAL1V1 2 | #define INTERNAL1V1 2 | ||||
#define EXTERNAL 0 | #define EXTERNAL 0 | ||||
#elif defined(__MKL26Z64__) | |||||
#define DEFAULT 0 | |||||
#define INTERNAL 0 | |||||
#define EXTERNAL 1 | |||||
#endif | |||||
void analogReference(uint8_t type) | void analogReference(uint8_t type) | ||||
{ | { | ||||
if (type) { | if (type) { | ||||
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__) | |||||
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 (pin <= 13) { | |||||
index = pin; // 0-13 refer to A0-A13 | |||||
} else if (pin <= 23) { | |||||
index = pin - 14; // 14-23 are A0-A9 | |||||
#if defined(__MK20DX256__) | |||||
} else if (pin >= 26 && pin <= 31) { | |||||
index = pin - 9; // 26-31 are A15-A20 | |||||
#endif | |||||
} else if (pin >= 34 && pin <= 40) { | |||||
index = pin - 24; // 34-37 are A10-A13, 38 is temp sensor, | |||||
// 39 is vref, 40 is unused (A14 on Teensy 3.1) | |||||
} else { | |||||
return 0; // all others are invalid | |||||
} | |||||
//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 | ||||
__disable_irq(); | __disable_irq(); | ||||
startADC0: | startADC0: | ||||
//serial_print("startADC0\n"); | //serial_print("startADC0\n"); | ||||
#if defined(__MKL26Z64__) | |||||
if (channel & 0x40) { | |||||
ADC0_CFG2 &= ~ADC_CFG2_MUXSEL; | |||||
channel &= 0x3F; | |||||
} else { | |||||
ADC0_CFG2 |= ADC_CFG2_MUXSEL; | |||||
} | |||||
#endif | |||||
ADC0_SC1A = channel; | ADC0_SC1A = channel; | ||||
analogReadBusyADC0 = 1; | analogReadBusyADC0 = 1; | ||||
__enable_irq(); | __enable_irq(); | ||||
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? | |||||
__asm__ ("usat %[value], #12, %[value]\n\t" : [value] "+r" (val)); // 0 <= val <= 4095 | |||||
*(volatile aliased_int16_t *)&(DAC0_DAT0L) = val; | |||||
#elif defined(__MKL26Z64__) | |||||
SIM_SCGC6 |= SIM_SCGC6_DAC0; | |||||
if (analog_reference_internal == 0) { | |||||
// use 3.3V VDDA power as the reference (this is the default) | |||||
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS | DAC_C0_DACSWTRG; // 3.3V VDDA | |||||
} else { | |||||
// use whatever voltage is on the AREF pin | |||||
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACSWTRG; // 3.3V VDDA | |||||
} | |||||
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 | ||||
} | } | ||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
void analogWriteDAC1(int val) | |||||
{ | |||||
SIM_SCGC2 |= SIM_SCGC2_DAC1; | |||||
if (analog_reference_internal) { | |||||
DAC1_C0 = DAC_C0_DACEN; // 1.2V ref is DACREF_1 | |||||
} else { | |||||
DAC1_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2 | |||||
} | |||||
__asm__ ("usat %[value], #12, %[value]\n\t" : [value] "+r" (val)); // 0 <= val <= 4095 | |||||
*(volatile aliased_int16_t *)&(DAC1_DAT0L) = val; | |||||
} | |||||
#endif | |||||
/* Simple compatibility headers for AVR code used with ARM chips | |||||
* Copyright (c) 2015 Paul Stoffregen <paul@pjrc.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. | |||||
*/ | |||||
// Guidelines for editing this file: | |||||
// https://forum.pjrc.com/threads/34537-Teensy-LC-Increase-EEPROM-Size/page2 | |||||
#ifndef _AVR_EEPROM_H_ | #ifndef _AVR_EEPROM_H_ | ||||
#define _AVR_EEPROM_H_ 1 | #define _AVR_EEPROM_H_ 1 | ||||
#include <stddef.h> | #include <stddef.h> | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#define E2END 0x80 | |||||
#include "avr_functions.h" | |||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) | |||||
#define E2END 0x7FF | |||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#define E2END 0xFFF | |||||
#elif defined(__MKL26Z64__) | |||||
#define E2END 0x7F | |||||
#else | |||||
#define E2END 0 | |||||
#endif | |||||
#endif | #endif |
// This header file is in the public domain. |
/* Simple compatibility headers for AVR code used with ARM chips | |||||
* Copyright (c) 2015 Paul Stoffregen <paul@pjrc.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. | |||||
*/ | |||||
#include "../avr_emulation.h" | #include "../avr_emulation.h" |
/* Simple compatibility headers for AVR code used with ARM chips | |||||
* Copyright (c) 2015 Paul Stoffregen <paul@pjrc.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. | |||||
*/ | |||||
#ifndef __PGMSPACE_H_ | #ifndef __PGMSPACE_H_ | ||||
#define __PGMSPACE_H_ 1 | #define __PGMSPACE_H_ 1 | ||||
typedef uint16_t prog_uint16_t; | typedef uint16_t prog_uint16_t; | ||||
typedef int32_t prog_int32_t; | typedef int32_t prog_int32_t; | ||||
typedef uint32_t prog_uint32_t; | typedef uint32_t prog_uint32_t; | ||||
typedef int64_t prog_int64_t; | |||||
typedef uint64_t prog_uint64_t; | |||||
#define memchr_P(str, c, len) memchr((str), (c), (len)) | #define memchr_P(str, c, len) memchr((str), (c), (len)) | ||||
#define memcmp_P(a, b, n) memcmp((a), (b), (n)) | #define memcmp_P(a, b, n) memcmp((a), (b), (n)) | ||||
#define strspn_P(str, chrs) strspn((str), (chrs)) | #define strspn_P(str, chrs) strspn((str), (chrs)) | ||||
#define strstr_P(a, b) strstr((a), (b)) | #define strstr_P(a, b) strstr((a), (b)) | ||||
#define sprintf_P(s, ...) sprintf((s), __VA_ARGS__) | #define sprintf_P(s, ...) sprintf((s), __VA_ARGS__) | ||||
#define vfprintf_P(s, ...) vfprintf((s), __VA_ARGS__) | |||||
#define vfprintf_P(fp, s, ...) vfprintf((fp), (s), __VA_ARGS__) | |||||
#define printf_P(...) printf(__VA_ARGS__) | #define printf_P(...) printf(__VA_ARGS__) | ||||
#define snprintf_P(s, n, ...) ((s), (n), __VA_ARGS__) | |||||
#define vsprintf_P(s, ...) ((s),__VA_ARGS__) | |||||
#define vsnprintf_P(s, n, ...) ((s), (n),__VA_ARGS__) | |||||
#define fprintf_P(s, ...) ((s), __VA_ARGS__) | |||||
#define snprintf_P(s, n, ...) snprintf((s), (n), __VA_ARGS__) | |||||
#define vsprintf_P(s, ...) vsprintf((s), __VA_ARGS__) | |||||
#define vsnprintf_P(s, n, ...) vsnprintf((s), (n), __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 |
/* Simple compatibility headers for AVR code used with ARM chips | |||||
* Copyright (c) 2015 Paul Stoffregen <paul@pjrc.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. | |||||
*/ | |||||
#ifndef _AVR_POWER_H_ | |||||
#define _AVR_POWER_H_ 1 | |||||
#endif |
/* Simple compatibility headers for AVR code used with ARM chips | |||||
* Copyright (c) 2015 Paul Stoffregen <paul@pjrc.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. | |||||
*/ | |||||
#ifndef _AVR_SLEEP_H_ | #ifndef _AVR_SLEEP_H_ | ||||
#define _AVR_SLEEP_H_ 1 | #define _AVR_SLEEP_H_ 1 | ||||
#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_ | |||||
#define _AVR_WDT_H_ | |||||
#define WDTO_15MS 0 | |||||
#define WDTO_30MS 1 | |||||
#define WDTO_60MS 2 | |||||
#define WDTO_120MS 3 | |||||
#define WDTO_250MS 4 | |||||
#define WDTO_500MS 5 | |||||
#define WDTO_1S 6 | |||||
#define WDTO_2S 7 | |||||
#define WDTO_4S 8 | |||||
#define WDTO_8S 9 | |||||
#define wdt_reset() | |||||
#define wdt_enable(timeout) | |||||
#define wdt_disable() | |||||
#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 "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) | |||||
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 | |||||
#ifdef HAS_SPIFIFO | #ifdef HAS_SPIFIFO | ||||
uint8_t SPIFIFOclass::pcs = 0; | uint8_t SPIFIFOclass::pcs = 0; | ||||
#endif | #endif | ||||
uint8_t EIMSK = 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 | ||||
char * ultoa(unsigned long val, char *buf, int radix); | char * ultoa(unsigned long val, char *buf, int radix); | ||||
char * ltoa(long val, char *buf, int radix); | char * ltoa(long val, char *buf, int radix); | ||||
#if defined(_NEWLIB_VERSION) && (__NEWLIB__ < 2 || __NEWLIB__ == 2 && __NEWLIB_MINOR__ < 2) | |||||
static inline char * utoa(unsigned int val, char *buf, int radix) __attribute__((always_inline, unused)); | static inline char * utoa(unsigned int val, char *buf, int radix) __attribute__((always_inline, unused)); | ||||
static inline char * utoa(unsigned int val, char *buf, int radix) { return ultoa(val, buf, radix); } | static inline char * utoa(unsigned int val, char *buf, int radix) { return ultoa(val, buf, radix); } | ||||
static inline char * itoa(int val, char *buf, int radix) __attribute__((always_inline, unused)); | static inline char * itoa(int val, char *buf, int radix) __attribute__((always_inline, unused)); | ||||
static inline char * itoa(int val, char *buf, int radix) { return ltoa(val, buf, radix); } | static inline char * itoa(int val, char *buf, int radix) { return ltoa(val, buf, radix); } | ||||
#endif | |||||
char * dtostrf(float val, int width, unsigned int precision, char *buf); | char * dtostrf(float val, int width, unsigned int precision, char *buf); | ||||
// 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 | ||||
* 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 <stdint.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__) | |||||
#define EEPROM_MAX 2048 | |||||
#define EEPARTITION 0x03 // all 32K dataflash for EEPROM, none for Data | |||||
#define EEESPLIT 0x30 // must be 0x30 on these chips | |||||
#elif defined(__MK64FX512__) | |||||
#define EEPROM_MAX 4096 | |||||
#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__) | |||||
#define EEPROM_MAX 4096 | |||||
#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__) | |||||
#define EEPROM_MAX 255 | |||||
#endif | |||||
#if E2END > (EEPROM_MAX-1) | |||||
#error "E2END is set larger than the maximum possible EEPROM size" | |||||
#endif | |||||
#if defined(KINETISK) | |||||
// The EEPROM is really RAM with a hardware-based backup system to | // The EEPROM is really RAM with a hardware-based backup system to | ||||
// flash memory. Selecting a smaller size EEPROM allows more wear | // flash memory. Selecting a smaller size EEPROM allows more wear | ||||
// (aligned to 2 or 4 byte boundaries) has twice the endurance | // (aligned to 2 or 4 byte boundaries) has twice the endurance | ||||
// compared to writing 8 bit bytes. | // compared to writing 8 bit bytes. | ||||
// | // | ||||
#define EEPROM_SIZE 2048 | |||||
#if E2END < 32 | |||||
#define EEPROM_SIZE 32 | |||||
#define EEESIZE 0x09 | |||||
#elif E2END < 64 | |||||
#define EEPROM_SIZE 64 | |||||
#define EEESIZE 0x08 | |||||
#elif E2END < 128 | |||||
#define EEPROM_SIZE 128 | |||||
#define EEESIZE 0x07 | |||||
#elif E2END < 256 | |||||
#define EEPROM_SIZE 256 | |||||
#define EEESIZE 0x06 | |||||
#elif E2END < 512 | |||||
#define EEPROM_SIZE 512 | |||||
#define EEESIZE 0x05 | |||||
#elif E2END < 1024 | |||||
#define EEPROM_SIZE 1024 | |||||
#define EEESIZE 0x04 | |||||
#elif E2END < 2048 | |||||
#define EEPROM_SIZE 2048 | |||||
#define EEESIZE 0x03 | |||||
#elif E2END < 4096 | |||||
#define EEPROM_SIZE 4096 | |||||
#define EEESIZE 0x02 | |||||
#endif | |||||
// Writing unaligned 16 or 32 bit data is handled automatically when | // Writing unaligned 16 or 32 bit data is handled automatically when | ||||
// this is defined, but at a cost of extra code size. Without this, | // this is defined, but at a cost of extra code size. Without this, | ||||
// | // | ||||
#define HANDLE_UNALIGNED_WRITES | #define HANDLE_UNALIGNED_WRITES | ||||
// Minimum EEPROM Endurance | |||||
// ------------------------ | |||||
#if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word | |||||
#define EEESIZE 0x33 | |||||
#elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word | |||||
#define EEESIZE 0x34 | |||||
#elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word | |||||
#define EEESIZE 0x35 | |||||
#elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word | |||||
#define EEESIZE 0x36 | |||||
#elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word | |||||
#define EEESIZE 0x37 | |||||
#elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word | |||||
#define EEESIZE 0x38 | |||||
#elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word | |||||
#define EEESIZE 0x39 | |||||
#endif | |||||
void eeprom_initialize(void) | void eeprom_initialize(void) | ||||
{ | { | ||||
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_FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup | |||||
FTFL_FCCOB3 = 0; | |||||
FTFL_FCCOB4 = EEESPLIT | EEESIZE; | |||||
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--; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
void do_flash_cmd(volatile uint8_t *fstat) | void do_flash_cmd(volatile uint8_t *fstat) | ||||
{ | { | ||||
e: 4770 bx lr | e: 4770 bx lr | ||||
*/ | */ | ||||
#elif defined(KINETISL) | |||||
#define EEPROM_SIZE (E2END+1) | |||||
#define FLASH_BEGIN (uint16_t *)63488 | |||||
#define FLASH_END (uint16_t *)65536 | |||||
static uint16_t flashend = 0; | |||||
void eeprom_initialize(void) | |||||
{ | |||||
const uint16_t *p = FLASH_BEGIN; | |||||
do { | |||||
if (*p++ == 0xFFFF) { | |||||
flashend = (uint32_t)(p - 2); | |||||
return; | |||||
} | |||||
} while (p < FLASH_END); | |||||
flashend = (uint32_t)(FLASH_END - 1); | |||||
} | |||||
uint8_t eeprom_read_byte(const uint8_t *addr) | |||||
{ | |||||
uint32_t offset = (uint32_t)addr; | |||||
const uint16_t *p = FLASH_BEGIN; | |||||
const uint16_t *end = (const uint16_t *)((uint32_t)flashend); | |||||
uint16_t val; | |||||
uint8_t data=0xFF; | |||||
if (!end) { | |||||
eeprom_initialize(); | |||||
end = (const uint16_t *)((uint32_t)flashend); | |||||
} | |||||
if (offset < EEPROM_SIZE) { | |||||
while (p <= end) { | |||||
val = *p++; | |||||
if ((val & 255) == offset) data = val >> 8; | |||||
} | |||||
} | |||||
return data; | |||||
} | |||||
static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data) | |||||
{ | |||||
// with great power comes great responsibility.... | |||||
uint32_t stat; | |||||
*(uint32_t *)&FTFL_FCCOB3 = 0x06000000 | (addr & 0x00FFFFFC); | |||||
*(uint32_t *)&FTFL_FCCOB7 = data; | |||||
__disable_irq(); | |||||
(*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&FTFL_FSTAT); | |||||
__enable_irq(); | |||||
stat = FTFL_FSTAT & 0x70; | |||||
if (stat) { | |||||
FTFL_FSTAT = stat; | |||||
} | |||||
MCM_PLACR |= MCM_PLACR_CFCC; | |||||
} | |||||
void eeprom_write_byte(uint8_t *addr, uint8_t data) | |||||
{ | |||||
uint32_t offset = (uint32_t)addr; | |||||
const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend); | |||||
uint32_t i, val, flashaddr; | |||||
uint16_t do_flash_cmd[] = { | |||||
0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770}; | |||||
uint8_t buf[EEPROM_SIZE]; | |||||
if (offset >= EEPROM_SIZE) return; | |||||
if (!end) { | |||||
eeprom_initialize(); | |||||
end = (const uint16_t *)((uint32_t)flashend); | |||||
} | |||||
if (++end < FLASH_END) { | |||||
val = (data << 8) | offset; | |||||
flashaddr = (uint32_t)end; | |||||
flashend = flashaddr; | |||||
if ((flashaddr & 2) == 0) { | |||||
val |= 0xFFFF0000; | |||||
} else { | |||||
val <<= 16; | |||||
val |= 0x0000FFFF; | |||||
} | |||||
flash_write(do_flash_cmd, flashaddr, val); | |||||
} else { | |||||
for (i=0; i < EEPROM_SIZE; i++) { | |||||
buf[i] = 0xFF; | |||||
} | |||||
for (p = FLASH_BEGIN; p < FLASH_END; p++) { | |||||
val = *p; | |||||
if ((val & 255) < EEPROM_SIZE) { | |||||
buf[val & 255] = val >> 8; | |||||
} | |||||
} | |||||
buf[offset] = data; | |||||
for (flashaddr=(uint32_t)FLASH_BEGIN; flashaddr < (uint32_t)FLASH_END; flashaddr += 1024) { | |||||
*(uint32_t *)&FTFL_FCCOB3 = 0x09000000 | flashaddr; | |||||
__disable_irq(); | |||||
(*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&FTFL_FSTAT); | |||||
__enable_irq(); | |||||
val = FTFL_FSTAT & 0x70; | |||||
if (val) FTFL_FSTAT = val; | |||||
MCM_PLACR |= MCM_PLACR_CFCC; | |||||
} | |||||
flashaddr=(uint32_t)FLASH_BEGIN; | |||||
for (i=0; i < EEPROM_SIZE; i++) { | |||||
if (buf[i] == 0xFF) continue; | |||||
if ((flashaddr & 2) == 0) { | |||||
val = (buf[i] << 8) | i; | |||||
} else { | |||||
val = val | (buf[i] << 24) | (i << 16); | |||||
flash_write(do_flash_cmd, flashaddr, val); | |||||
} | |||||
flashaddr += 2; | |||||
} | |||||
flashend = flashaddr; | |||||
if ((flashaddr & 2)) { | |||||
val |= 0xFFFF0000; | |||||
flash_write(do_flash_cmd, flashaddr, val); | |||||
} | |||||
} | |||||
} | |||||
/* | |||||
void do_flash_cmd(volatile uint8_t *fstat) | |||||
{ | |||||
*fstat = 0x80; | |||||
while ((*fstat & 0x80) == 0) ; // wait | |||||
} | |||||
00000000 <do_flash_cmd>: | |||||
0: 2380 movs r3, #128 ; 0x80 | |||||
2: 7003 strb r3, [r0, #0] | |||||
4: 7803 ldrb r3, [r0, #0] | |||||
6: b25b sxtb r3, r3 | |||||
8: 2b00 cmp r3, #0 | |||||
a: dafb bge.n 4 <do_flash_cmd+0x4> | |||||
c: 4770 bx lr | |||||
*/ | |||||
uint16_t eeprom_read_word(const uint16_t *addr) | |||||
{ | |||||
const uint8_t *p = (const uint8_t *)addr; | |||||
return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8); | |||||
} | |||||
uint32_t eeprom_read_dword(const uint32_t *addr) | |||||
{ | |||||
const uint8_t *p = (const uint8_t *)addr; | |||||
return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8) | |||||
| (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24); | |||||
} | |||||
void eeprom_read_block(void *buf, const void *addr, uint32_t len) | |||||
{ | |||||
const uint8_t *p = (const uint8_t *)addr; | |||||
uint8_t *dest = (uint8_t *)buf; | |||||
while (len--) { | |||||
*dest++ = eeprom_read_byte(p++); | |||||
} | |||||
} | |||||
int eeprom_is_ready(void) | |||||
{ | |||||
return 1; | |||||
} | |||||
void eeprom_write_word(uint16_t *addr, uint16_t value) | |||||
{ | |||||
uint8_t *p = (uint8_t *)addr; | |||||
eeprom_write_byte(p++, value); | |||||
eeprom_write_byte(p, value >> 8); | |||||
} | |||||
void eeprom_write_dword(uint32_t *addr, uint32_t value) | |||||
{ | |||||
uint8_t *p = (uint8_t *)addr; | |||||
eeprom_write_byte(p++, value); | |||||
eeprom_write_byte(p++, value >> 8); | |||||
eeprom_write_byte(p++, value >> 16); | |||||
eeprom_write_byte(p, value >> 24); | |||||
} | |||||
void eeprom_write_block(const void *buf, void *addr, uint32_t len) | |||||
{ | |||||
uint8_t *p = (uint8_t *)addr; | |||||
const uint8_t *src = (const uint8_t *)buf; | |||||
while (len--) { | |||||
eeprom_write_byte(p++, *src++); | |||||
} | |||||
} | |||||
#endif // KINETISL |
/* 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 | ||||
#ifdef M | #ifdef M | ||||
#undef M | #undef M | ||||
#endif | #endif | ||||
#define M(n) ((n) & 0x3FFF) | |||||
#define M(n) ((n) & KEYCODE_MASK) | |||||
const KEYCODE_TYPE keycodes_ascii[] = { | const KEYCODE_TYPE keycodes_ascii[] = { | ||||
M(ASCII_20), M(ASCII_21), M(ASCII_22), M(ASCII_23), | M(ASCII_20), M(ASCII_21), M(ASCII_22), M(ASCII_23), |
/* 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 | ||||
// http://en.wikipedia.org/wiki/Keyboard_layout | // http://en.wikipedia.org/wiki/Keyboard_layout | ||||
#define MODIFIERKEY_CTRL ( 0x01 | 0x8000 ) | |||||
#define MODIFIERKEY_SHIFT ( 0x02 | 0x8000 ) | |||||
#define MODIFIERKEY_ALT ( 0x04 | 0x8000 ) | |||||
#define MODIFIERKEY_GUI ( 0x08 | 0x8000 ) | |||||
#define MODIFIERKEY_LEFT_CTRL ( 0x01 | 0x8000 ) | |||||
#define MODIFIERKEY_LEFT_SHIFT ( 0x02 | 0x8000 ) | |||||
#define MODIFIERKEY_LEFT_ALT ( 0x04 | 0x8000 ) | |||||
#define MODIFIERKEY_LEFT_GUI ( 0x08 | 0x8000 ) | |||||
#define MODIFIERKEY_RIGHT_CTRL ( 0x10 | 0x8000 ) | |||||
#define MODIFIERKEY_RIGHT_SHIFT ( 0x20 | 0x8000 ) | |||||
#define MODIFIERKEY_RIGHT_ALT ( 0x40 | 0x8000 ) | |||||
#define MODIFIERKEY_RIGHT_GUI ( 0x80 | 0x8000 ) | |||||
#define KEY_MEDIA_VOLUME_INC 0x01 | |||||
#define KEY_MEDIA_VOLUME_DEC 0x02 | |||||
#define KEY_MEDIA_MUTE 0x04 | |||||
#define KEY_MEDIA_PLAY_PAUSE 0x08 | |||||
#define KEY_MEDIA_NEXT_TRACK 0x10 | |||||
#define KEY_MEDIA_PREV_TRACK 0x20 | |||||
#define KEY_MEDIA_STOP 0x40 | |||||
#define KEY_MEDIA_EJECT 0x80 | |||||
#define KEY_A ( 4 | 0x4000 ) | |||||
#define KEY_B ( 5 | 0x4000 ) | |||||
#define KEY_C ( 6 | 0x4000 ) | |||||
#define KEY_D ( 7 | 0x4000 ) | |||||
#define KEY_E ( 8 | 0x4000 ) | |||||
#define KEY_F ( 9 | 0x4000 ) | |||||
#define KEY_G ( 10 | 0x4000 ) | |||||
#define KEY_H ( 11 | 0x4000 ) | |||||
#define KEY_I ( 12 | 0x4000 ) | |||||
#define KEY_J ( 13 | 0x4000 ) | |||||
#define KEY_K ( 14 | 0x4000 ) | |||||
#define KEY_L ( 15 | 0x4000 ) | |||||
#define KEY_M ( 16 | 0x4000 ) | |||||
#define KEY_N ( 17 | 0x4000 ) | |||||
#define KEY_O ( 18 | 0x4000 ) | |||||
#define KEY_P ( 19 | 0x4000 ) | |||||
#define KEY_Q ( 20 | 0x4000 ) | |||||
#define KEY_R ( 21 | 0x4000 ) | |||||
#define KEY_S ( 22 | 0x4000 ) | |||||
#define KEY_T ( 23 | 0x4000 ) | |||||
#define KEY_U ( 24 | 0x4000 ) | |||||
#define KEY_V ( 25 | 0x4000 ) | |||||
#define KEY_W ( 26 | 0x4000 ) | |||||
#define KEY_X ( 27 | 0x4000 ) | |||||
#define KEY_Y ( 28 | 0x4000 ) | |||||
#define KEY_Z ( 29 | 0x4000 ) | |||||
#define KEY_1 ( 30 | 0x4000 ) | |||||
#define KEY_2 ( 31 | 0x4000 ) | |||||
#define KEY_3 ( 32 | 0x4000 ) | |||||
#define KEY_4 ( 33 | 0x4000 ) | |||||
#define KEY_5 ( 34 | 0x4000 ) | |||||
#define KEY_6 ( 35 | 0x4000 ) | |||||
#define KEY_7 ( 36 | 0x4000 ) | |||||
#define KEY_8 ( 37 | 0x4000 ) | |||||
#define KEY_9 ( 38 | 0x4000 ) | |||||
#define KEY_0 ( 39 | 0x4000 ) | |||||
#define KEY_ENTER ( 40 | 0x4000 ) | |||||
#define KEY_ESC ( 41 | 0x4000 ) | |||||
#define KEY_BACKSPACE ( 42 | 0x4000 ) | |||||
#define KEY_TAB ( 43 | 0x4000 ) | |||||
#define KEY_SPACE ( 44 | 0x4000 ) | |||||
#define KEY_MINUS ( 45 | 0x4000 ) | |||||
#define KEY_EQUAL ( 46 | 0x4000 ) | |||||
#define KEY_LEFT_BRACE ( 47 | 0x4000 ) | |||||
#define KEY_RIGHT_BRACE ( 48 | 0x4000 ) | |||||
#define KEY_BACKSLASH ( 49 | 0x4000 ) | |||||
#define KEY_NON_US_NUM ( 50 | 0x4000 ) | |||||
#define KEY_SEMICOLON ( 51 | 0x4000 ) | |||||
#define KEY_QUOTE ( 52 | 0x4000 ) | |||||
#define KEY_TILDE ( 53 | 0x4000 ) | |||||
#define KEY_COMMA ( 54 | 0x4000 ) | |||||
#define KEY_PERIOD ( 55 | 0x4000 ) | |||||
#define KEY_SLASH ( 56 | 0x4000 ) | |||||
#define KEY_CAPS_LOCK ( 57 | 0x4000 ) | |||||
#define KEY_F1 ( 58 | 0x4000 ) | |||||
#define KEY_F2 ( 59 | 0x4000 ) | |||||
#define KEY_F3 ( 60 | 0x4000 ) | |||||
#define KEY_F4 ( 61 | 0x4000 ) | |||||
#define KEY_F5 ( 62 | 0x4000 ) | |||||
#define KEY_F6 ( 63 | 0x4000 ) | |||||
#define KEY_F7 ( 64 | 0x4000 ) | |||||
#define KEY_F8 ( 65 | 0x4000 ) | |||||
#define KEY_F9 ( 66 | 0x4000 ) | |||||
#define KEY_F10 ( 67 | 0x4000 ) | |||||
#define KEY_F11 ( 68 | 0x4000 ) | |||||
#define KEY_F12 ( 69 | 0x4000 ) | |||||
#define KEY_PRINTSCREEN ( 70 | 0x4000 ) | |||||
#define KEY_SCROLL_LOCK ( 71 | 0x4000 ) | |||||
#define KEY_PAUSE ( 72 | 0x4000 ) | |||||
#define KEY_INSERT ( 73 | 0x4000 ) | |||||
#define KEY_HOME ( 74 | 0x4000 ) | |||||
#define KEY_PAGE_UP ( 75 | 0x4000 ) | |||||
#define KEY_DELETE ( 76 | 0x4000 ) | |||||
#define KEY_END ( 77 | 0x4000 ) | |||||
#define KEY_PAGE_DOWN ( 78 | 0x4000 ) | |||||
#define KEY_RIGHT ( 79 | 0x4000 ) | |||||
#define KEY_LEFT ( 80 | 0x4000 ) | |||||
#define KEY_DOWN ( 81 | 0x4000 ) | |||||
#define KEY_UP ( 82 | 0x4000 ) | |||||
#define KEY_NUM_LOCK ( 83 | 0x4000 ) | |||||
#define KEYPAD_SLASH ( 84 | 0x4000 ) | |||||
#define KEYPAD_ASTERIX ( 85 | 0x4000 ) | |||||
#define KEYPAD_MINUS ( 86 | 0x4000 ) | |||||
#define KEYPAD_PLUS ( 87 | 0x4000 ) | |||||
#define KEYPAD_ENTER ( 88 | 0x4000 ) | |||||
#define KEYPAD_1 ( 89 | 0x4000 ) | |||||
#define KEYPAD_2 ( 90 | 0x4000 ) | |||||
#define KEYPAD_3 ( 91 | 0x4000 ) | |||||
#define KEYPAD_4 ( 92 | 0x4000 ) | |||||
#define KEYPAD_5 ( 93 | 0x4000 ) | |||||
#define KEYPAD_6 ( 94 | 0x4000 ) | |||||
#define KEYPAD_7 ( 95 | 0x4000 ) | |||||
#define KEYPAD_8 ( 96 | 0x4000 ) | |||||
#define KEYPAD_9 ( 97 | 0x4000 ) | |||||
#define KEYPAD_0 ( 98 | 0x4000 ) | |||||
#define KEYPAD_PERIOD ( 99 | 0x4000 ) | |||||
#define KEY_MENU ( 101 | 0x4000 ) | |||||
#define KEY_F13 ( 104 | 0x4000 ) | |||||
#define KEY_F14 ( 105 | 0x4000 ) | |||||
#define KEY_F15 ( 106 | 0x4000 ) | |||||
#define KEY_F16 ( 107 | 0x4000 ) | |||||
#define KEY_F17 ( 108 | 0x4000 ) | |||||
#define KEY_F18 ( 109 | 0x4000 ) | |||||
#define KEY_F19 ( 110 | 0x4000 ) | |||||
#define KEY_F20 ( 111 | 0x4000 ) | |||||
#define KEY_F21 ( 112 | 0x4000 ) | |||||
#define KEY_F22 ( 113 | 0x4000 ) | |||||
#define KEY_F23 ( 114 | 0x4000 ) | |||||
#define KEY_F24 ( 115 | 0x4000 ) | |||||
#define MODIFIERKEY_CTRL ( 0x01 | 0xE000 ) | |||||
#define MODIFIERKEY_SHIFT ( 0x02 | 0xE000 ) | |||||
#define MODIFIERKEY_ALT ( 0x04 | 0xE000 ) | |||||
#define MODIFIERKEY_GUI ( 0x08 | 0xE000 ) | |||||
#define MODIFIERKEY_LEFT_CTRL ( 0x01 | 0xE000 ) | |||||
#define MODIFIERKEY_LEFT_SHIFT ( 0x02 | 0xE000 ) | |||||
#define MODIFIERKEY_LEFT_ALT ( 0x04 | 0xE000 ) | |||||
#define MODIFIERKEY_LEFT_GUI ( 0x08 | 0xE000 ) | |||||
#define MODIFIERKEY_RIGHT_CTRL ( 0x10 | 0xE000 ) | |||||
#define MODIFIERKEY_RIGHT_SHIFT ( 0x20 | 0xE000 ) | |||||
#define MODIFIERKEY_RIGHT_ALT ( 0x40 | 0xE000 ) | |||||
#define MODIFIERKEY_RIGHT_GUI ( 0x80 | 0xE000 ) | |||||
#define KEY_SYSTEM_POWER_DOWN ( 0x81 | 0xE200 ) | |||||
#define KEY_SYSTEM_SLEEP ( 0x82 | 0xE200 ) | |||||
#define KEY_SYSTEM_WAKE_UP ( 0x83 | 0xE200 ) | |||||
#define KEY_MEDIA_PLAY ( 0xB0 | 0xE400 ) | |||||
#define KEY_MEDIA_PAUSE ( 0xB1 | 0xE400 ) | |||||
#define KEY_MEDIA_RECORD ( 0xB2 | 0xE400 ) | |||||
#define KEY_MEDIA_FAST_FORWARD ( 0xB3 | 0xE400 ) | |||||
#define KEY_MEDIA_REWIND ( 0xB4 | 0xE400 ) | |||||
#define KEY_MEDIA_NEXT_TRACK ( 0xB5 | 0xE400 ) | |||||
#define KEY_MEDIA_PREV_TRACK ( 0xB6 | 0xE400 ) | |||||
#define KEY_MEDIA_STOP ( 0xB7 | 0xE400 ) | |||||
#define KEY_MEDIA_EJECT ( 0xB8 | 0xE400 ) | |||||
#define KEY_MEDIA_RANDOM_PLAY ( 0xB9 | 0xE400 ) | |||||
#define KEY_MEDIA_PLAY_PAUSE ( 0xCD | 0xE400 ) | |||||
#define KEY_MEDIA_PLAY_SKIP ( 0xCE | 0xE400 ) | |||||
#define KEY_MEDIA_MUTE ( 0xE2 | 0xE400 ) | |||||
#define KEY_MEDIA_VOLUME_INC ( 0xE9 | 0xE400 ) | |||||
#define KEY_MEDIA_VOLUME_DEC ( 0xEA | 0xE400 ) | |||||
#define KEY_A ( 4 | 0xF000 ) | |||||
#define KEY_B ( 5 | 0xF000 ) | |||||
#define KEY_C ( 6 | 0xF000 ) | |||||
#define KEY_D ( 7 | 0xF000 ) | |||||
#define KEY_E ( 8 | 0xF000 ) | |||||
#define KEY_F ( 9 | 0xF000 ) | |||||
#define KEY_G ( 10 | 0xF000 ) | |||||
#define KEY_H ( 11 | 0xF000 ) | |||||
#define KEY_I ( 12 | 0xF000 ) | |||||
#define KEY_J ( 13 | 0xF000 ) | |||||
#define KEY_K ( 14 | 0xF000 ) | |||||
#define KEY_L ( 15 | 0xF000 ) | |||||
#define KEY_M ( 16 | 0xF000 ) | |||||
#define KEY_N ( 17 | 0xF000 ) | |||||
#define KEY_O ( 18 | 0xF000 ) | |||||
#define KEY_P ( 19 | 0xF000 ) | |||||
#define KEY_Q ( 20 | 0xF000 ) | |||||
#define KEY_R ( 21 | 0xF000 ) | |||||
#define KEY_S ( 22 | 0xF000 ) | |||||
#define KEY_T ( 23 | 0xF000 ) | |||||
#define KEY_U ( 24 | 0xF000 ) | |||||
#define KEY_V ( 25 | 0xF000 ) | |||||
#define KEY_W ( 26 | 0xF000 ) | |||||
#define KEY_X ( 27 | 0xF000 ) | |||||
#define KEY_Y ( 28 | 0xF000 ) | |||||
#define KEY_Z ( 29 | 0xF000 ) | |||||
#define KEY_1 ( 30 | 0xF000 ) | |||||
#define KEY_2 ( 31 | 0xF000 ) | |||||
#define KEY_3 ( 32 | 0xF000 ) | |||||
#define KEY_4 ( 33 | 0xF000 ) | |||||
#define KEY_5 ( 34 | 0xF000 ) | |||||
#define KEY_6 ( 35 | 0xF000 ) | |||||
#define KEY_7 ( 36 | 0xF000 ) | |||||
#define KEY_8 ( 37 | 0xF000 ) | |||||
#define KEY_9 ( 38 | 0xF000 ) | |||||
#define KEY_0 ( 39 | 0xF000 ) | |||||
#define KEY_ENTER ( 40 | 0xF000 ) | |||||
#define KEY_ESC ( 41 | 0xF000 ) | |||||
#define KEY_BACKSPACE ( 42 | 0xF000 ) | |||||
#define KEY_TAB ( 43 | 0xF000 ) | |||||
#define KEY_SPACE ( 44 | 0xF000 ) | |||||
#define KEY_MINUS ( 45 | 0xF000 ) | |||||
#define KEY_EQUAL ( 46 | 0xF000 ) | |||||
#define KEY_LEFT_BRACE ( 47 | 0xF000 ) | |||||
#define KEY_RIGHT_BRACE ( 48 | 0xF000 ) | |||||
#define KEY_BACKSLASH ( 49 | 0xF000 ) | |||||
#define KEY_NON_US_NUM ( 50 | 0xF000 ) | |||||
#define KEY_SEMICOLON ( 51 | 0xF000 ) | |||||
#define KEY_QUOTE ( 52 | 0xF000 ) | |||||
#define KEY_TILDE ( 53 | 0xF000 ) | |||||
#define KEY_COMMA ( 54 | 0xF000 ) | |||||
#define KEY_PERIOD ( 55 | 0xF000 ) | |||||
#define KEY_SLASH ( 56 | 0xF000 ) | |||||
#define KEY_CAPS_LOCK ( 57 | 0xF000 ) | |||||
#define KEY_F1 ( 58 | 0xF000 ) | |||||
#define KEY_F2 ( 59 | 0xF000 ) | |||||
#define KEY_F3 ( 60 | 0xF000 ) | |||||
#define KEY_F4 ( 61 | 0xF000 ) | |||||
#define KEY_F5 ( 62 | 0xF000 ) | |||||
#define KEY_F6 ( 63 | 0xF000 ) | |||||
#define KEY_F7 ( 64 | 0xF000 ) | |||||
#define KEY_F8 ( 65 | 0xF000 ) | |||||
#define KEY_F9 ( 66 | 0xF000 ) | |||||
#define KEY_F10 ( 67 | 0xF000 ) | |||||
#define KEY_F11 ( 68 | 0xF000 ) | |||||
#define KEY_F12 ( 69 | 0xF000 ) | |||||
#define KEY_PRINTSCREEN ( 70 | 0xF000 ) | |||||
#define KEY_SCROLL_LOCK ( 71 | 0xF000 ) | |||||
#define KEY_PAUSE ( 72 | 0xF000 ) | |||||
#define KEY_INSERT ( 73 | 0xF000 ) | |||||
#define KEY_HOME ( 74 | 0xF000 ) | |||||
#define KEY_PAGE_UP ( 75 | 0xF000 ) | |||||
#define KEY_DELETE ( 76 | 0xF000 ) | |||||
#define KEY_END ( 77 | 0xF000 ) | |||||
#define KEY_PAGE_DOWN ( 78 | 0xF000 ) | |||||
#define KEY_RIGHT ( 79 | 0xF000 ) | |||||
#define KEY_LEFT ( 80 | 0xF000 ) | |||||
#define KEY_DOWN ( 81 | 0xF000 ) | |||||
#define KEY_UP ( 82 | 0xF000 ) | |||||
#define KEY_NUM_LOCK ( 83 | 0xF000 ) | |||||
#define KEYPAD_SLASH ( 84 | 0xF000 ) | |||||
#define KEYPAD_ASTERIX ( 85 | 0xF000 ) | |||||
#define KEYPAD_MINUS ( 86 | 0xF000 ) | |||||
#define KEYPAD_PLUS ( 87 | 0xF000 ) | |||||
#define KEYPAD_ENTER ( 88 | 0xF000 ) | |||||
#define KEYPAD_1 ( 89 | 0xF000 ) | |||||
#define KEYPAD_2 ( 90 | 0xF000 ) | |||||
#define KEYPAD_3 ( 91 | 0xF000 ) | |||||
#define KEYPAD_4 ( 92 | 0xF000 ) | |||||
#define KEYPAD_5 ( 93 | 0xF000 ) | |||||
#define KEYPAD_6 ( 94 | 0xF000 ) | |||||
#define KEYPAD_7 ( 95 | 0xF000 ) | |||||
#define KEYPAD_8 ( 96 | 0xF000 ) | |||||
#define KEYPAD_9 ( 97 | 0xF000 ) | |||||
#define KEYPAD_0 ( 98 | 0xF000 ) | |||||
#define KEYPAD_PERIOD ( 99 | 0xF000 ) | |||||
#define KEY_NON_US_BS ( 100 | 0xF000 ) | |||||
#define KEY_MENU ( 101 | 0xF000 ) | |||||
#define KEY_F13 ( 104 | 0xF000 ) | |||||
#define KEY_F14 ( 105 | 0xF000 ) | |||||
#define KEY_F15 ( 106 | 0xF000 ) | |||||
#define KEY_F16 ( 107 | 0xF000 ) | |||||
#define KEY_F17 ( 108 | 0xF000 ) | |||||
#define KEY_F18 ( 109 | 0xF000 ) | |||||
#define KEY_F19 ( 110 | 0xF000 ) | |||||
#define KEY_F20 ( 111 | 0xF000 ) | |||||
#define KEY_F21 ( 112 | 0xF000 ) | |||||
#define KEY_F22 ( 113 | 0xF000 ) | |||||
#define KEY_F23 ( 114 | 0xF000 ) | |||||
#define KEY_F24 ( 115 | 0xF000 ) | |||||
// for compatibility with Leonardo's slightly different names | // for compatibility with Leonardo's slightly different names | ||||
#define KEY_UP_ARROW KEY_UP | #define KEY_UP_ARROW KEY_UP | ||||
#define SHIFT_MASK 0x40 | #define SHIFT_MASK 0x40 | ||||
#define KEYCODE_TYPE uint8_t | #define KEYCODE_TYPE uint8_t | ||||
#define KEYCODE_MASK 0x007F | |||||
#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 TILDE_BITS 0x0400 | #define TILDE_BITS 0x0400 | ||||
#define DIAERESIS_BITS 0x0500 | #define DIAERESIS_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_6 + SHIFT_MASK | #define DEADKEY_CIRCUMFLEX KEY_6 + SHIFT_MASK | ||||
#define DEADKEY_ACUTE_ACCENT KEY_QUOTE | #define DEADKEY_ACUTE_ACCENT KEY_QUOTE | ||||
#define DEADKEY_GRAVE_ACCENT KEY_TILDE | #define DEADKEY_GRAVE_ACCENT KEY_TILDE | ||||
#define ACUTE_ACCENT_BITS 0x0400 | #define ACUTE_ACCENT_BITS 0x0400 | ||||
#define GRAVE_ACCENT_BITS 0x0500 | #define GRAVE_ACCENT_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_TILDE | #define DEADKEY_CIRCUMFLEX KEY_TILDE | ||||
#define DEADKEY_ACUTE_ACCENT KEY_EQUAL | #define DEADKEY_ACUTE_ACCENT KEY_EQUAL | ||||
#define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | #define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | ||||
#define DIAERESIS_BITS 0x0400 | #define DIAERESIS_BITS 0x0400 | ||||
#define TILDE_BITS 0x0500 | #define TILDE_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_ACUTE_ACCENT KEY_EQUAL | #define DEADKEY_ACUTE_ACCENT KEY_EQUAL | ||||
#define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | #define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | ||||
#define DEADKEY_CIRCUMFLEX KEY_6 + SHIFT_MASK + ALTGR_MASK | #define DEADKEY_CIRCUMFLEX KEY_6 + SHIFT_MASK + ALTGR_MASK | ||||
#define CEDILLA_BITS 0x0500 | #define CEDILLA_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_LEFT_BRACE | #define DEADKEY_CIRCUMFLEX KEY_LEFT_BRACE | ||||
#define DEADKEY_ACUTE_ACCENT KEY_SLASH + ALTGR_MASK | #define DEADKEY_ACUTE_ACCENT KEY_SLASH + ALTGR_MASK | ||||
#define DEADKEY_GRAVE_ACCENT KEY_QUOTE | #define DEADKEY_GRAVE_ACCENT KEY_QUOTE | ||||
#define TILDE_BITS 0x0600 | #define TILDE_BITS 0x0600 | ||||
#define RING_ABOVE_BITS 0x0700 | #define RING_ABOVE_BITS 0x0700 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x0FFF | |||||
#define DEADKEY_CIRCUMFLEX KEY_LEFT_BRACE | #define DEADKEY_CIRCUMFLEX KEY_LEFT_BRACE | ||||
#define DEADKEY_DIAERESIS KEY_LEFT_BRACE + SHIFT_MASK | #define DEADKEY_DIAERESIS KEY_LEFT_BRACE + SHIFT_MASK | ||||
#define DEADKEY_ACUTE_ACCENT KEY_SEMICOLON + RCTRL_MASK | #define DEADKEY_ACUTE_ACCENT KEY_SEMICOLON + RCTRL_MASK | ||||
#define SHIFT_MASK 0x0040 | #define SHIFT_MASK 0x0040 | ||||
#define ALTGR_MASK 0x0080 | #define ALTGR_MASK 0x0080 | ||||
#define KEYCODE_TYPE uint8_t | #define KEYCODE_TYPE uint8_t | ||||
#define KEYCODE_MASK 0x00FF | |||||
#define KEY_NON_US_100 63 | #define KEY_NON_US_100 63 | ||||
#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 TILDE_BITS 0x0400 | #define TILDE_BITS 0x0400 | ||||
#define DIAERESIS_BITS 0x0500 | #define DIAERESIS_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_RIGHT_BRACE + SHIFT_MASK | #define DEADKEY_CIRCUMFLEX KEY_RIGHT_BRACE + SHIFT_MASK | ||||
#define DEADKEY_ACUTE_ACCENT KEY_EQUAL | #define DEADKEY_ACUTE_ACCENT KEY_EQUAL | ||||
#define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | #define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | ||||
#define DIAERESIS_BITS 0x0300 | #define DIAERESIS_BITS 0x0300 | ||||
#define TILDE_BITS 0x0400 | #define TILDE_BITS 0x0400 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_LEFT_BRACE | #define DEADKEY_CIRCUMFLEX KEY_LEFT_BRACE | ||||
#define DEADKEY_GRAVE_ACCENT KEY_7 + ALTGR_MASK | #define DEADKEY_GRAVE_ACCENT KEY_7 + ALTGR_MASK | ||||
#define DEADKEY_DIAERESIS KEY_LEFT_BRACE + SHIFT_MASK | #define DEADKEY_DIAERESIS KEY_LEFT_BRACE + SHIFT_MASK | ||||
#define TILDE_BITS 0x0400 | #define TILDE_BITS 0x0400 | ||||
#define DIAERESIS_BITS 0x0500 | #define DIAERESIS_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_RIGHT_BRACE + SHIFT_MASK | #define DEADKEY_CIRCUMFLEX KEY_RIGHT_BRACE + SHIFT_MASK | ||||
#define DEADKEY_ACUTE_ACCENT KEY_EQUAL | #define DEADKEY_ACUTE_ACCENT KEY_EQUAL | ||||
#define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | #define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | ||||
#define TILDE_BITS 0x0400 | #define TILDE_BITS 0x0400 | ||||
#define DIAERESIS_BITS 0x0500 | #define DIAERESIS_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_RIGHT_BRACE + SHIFT_MASK | #define DEADKEY_CIRCUMFLEX KEY_RIGHT_BRACE + SHIFT_MASK | ||||
#define DEADKEY_ACUTE_ACCENT KEY_EQUAL + ALTGR_MASK | #define DEADKEY_ACUTE_ACCENT KEY_EQUAL + ALTGR_MASK | ||||
#define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | #define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | ||||
#define TILDE_BITS 0x0400 | #define TILDE_BITS 0x0400 | ||||
#define DIAERESIS_BITS 0x0500 | #define DIAERESIS_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_RIGHT_BRACE + SHIFT_MASK | #define DEADKEY_CIRCUMFLEX KEY_RIGHT_BRACE + SHIFT_MASK | ||||
#define DEADKEY_ACUTE_ACCENT KEY_EQUAL | #define DEADKEY_ACUTE_ACCENT KEY_EQUAL | ||||
#define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | #define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | ||||
#define TILDE_BITS 0x0400 | #define TILDE_BITS 0x0400 | ||||
#define DIAERESIS_BITS 0x0500 | #define DIAERESIS_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_LEFT_BRACE + SHIFT_MASK | #define DEADKEY_CIRCUMFLEX KEY_LEFT_BRACE + SHIFT_MASK | ||||
#define DEADKEY_ACUTE_ACCENT KEY_QUOTE | #define DEADKEY_ACUTE_ACCENT KEY_QUOTE | ||||
#define DEADKEY_GRAVE_ACCENT KEY_LEFT_BRACE | #define DEADKEY_GRAVE_ACCENT KEY_LEFT_BRACE | ||||
#define TILDE_BITS 0x0400 | #define TILDE_BITS 0x0400 | ||||
#define DIAERESIS_BITS 0x0500 | #define DIAERESIS_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_BACKSLASH | #define DEADKEY_CIRCUMFLEX KEY_BACKSLASH | ||||
#define DEADKEY_ACUTE_ACCENT KEY_RIGHT_BRACE + SHIFT_MASK | #define DEADKEY_ACUTE_ACCENT KEY_RIGHT_BRACE + SHIFT_MASK | ||||
#define DEADKEY_GRAVE_ACCENT KEY_RIGHT_BRACE + SHIFT_MASK | #define DEADKEY_GRAVE_ACCENT KEY_RIGHT_BRACE + SHIFT_MASK | ||||
#define SHIFT_MASK 0x40 | #define SHIFT_MASK 0x40 | ||||
#define ALTGR_MASK 0x80 | #define ALTGR_MASK 0x80 | ||||
#define KEYCODE_TYPE uint8_t | #define KEYCODE_TYPE uint8_t | ||||
#define KEYCODE_MASK 0x00FF | |||||
#define KEY_NON_US_100 63 | #define KEY_NON_US_100 63 | ||||
#define ASCII_20 KEY_SPACE // 32 | #define ASCII_20 KEY_SPACE // 32 | ||||
#define TILDE_BITS 0x0400 | #define TILDE_BITS 0x0400 | ||||
#define DIAERESIS_BITS 0x0500 | #define DIAERESIS_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_QUOTE + SHIFT_MASK | #define DEADKEY_CIRCUMFLEX KEY_QUOTE + SHIFT_MASK | ||||
#define DEADKEY_ACUTE_ACCENT KEY_LEFT_BRACE | #define DEADKEY_ACUTE_ACCENT KEY_LEFT_BRACE | ||||
#define DEADKEY_GRAVE_ACCENT KEY_LEFT_BRACE + SHIFT_MASK | #define DEADKEY_GRAVE_ACCENT KEY_LEFT_BRACE + SHIFT_MASK | ||||
#define TILDE_BITS 0x0400 | #define TILDE_BITS 0x0400 | ||||
#define ACUTE_ACCENT_BITS 0x0500 | #define ACUTE_ACCENT_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_LEFT_BRACE | #define DEADKEY_CIRCUMFLEX KEY_LEFT_BRACE | ||||
#define DEADKEY_ACUTE_ACCENT KEY_QUOTE + ALTGR_MASK | #define DEADKEY_ACUTE_ACCENT KEY_QUOTE + ALTGR_MASK | ||||
#define DEADKEY_GRAVE_ACCENT KEY_BACKSLASH + ALTGR_MASK | #define DEADKEY_GRAVE_ACCENT KEY_BACKSLASH + ALTGR_MASK | ||||
#define TILDE_BITS 0x0400 | #define TILDE_BITS 0x0400 | ||||
#define ACUTE_ACCENT_BITS 0x0500 | #define ACUTE_ACCENT_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_EQUAL | #define DEADKEY_CIRCUMFLEX KEY_EQUAL | ||||
#define DEADKEY_ACUTE_ACCENT KEY_MINUS + ALTGR_MASK | #define DEADKEY_ACUTE_ACCENT KEY_MINUS + ALTGR_MASK | ||||
#define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | #define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | ||||
#define TILDE_BITS 0x0400 | #define TILDE_BITS 0x0400 | ||||
#define ACUTE_ACCENT_BITS 0x0500 | #define ACUTE_ACCENT_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_EQUAL | #define DEADKEY_CIRCUMFLEX KEY_EQUAL | ||||
#define DEADKEY_ACUTE_ACCENT KEY_MINUS + ALTGR_MASK | #define DEADKEY_ACUTE_ACCENT KEY_MINUS + ALTGR_MASK | ||||
#define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | #define DEADKEY_GRAVE_ACCENT KEY_EQUAL + SHIFT_MASK | ||||
#define GRAVE_ACCENT_BITS 0x0300 | #define GRAVE_ACCENT_BITS 0x0300 | ||||
#define DIAERESIS_BITS 0x0400 | #define DIAERESIS_BITS 0x0400 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_QUOTE + ALTGR_MASK | #define DEADKEY_CIRCUMFLEX KEY_QUOTE + ALTGR_MASK | ||||
#define DEADKEY_ACUTE_ACCENT KEY_LEFT_BRACE | #define DEADKEY_ACUTE_ACCENT KEY_LEFT_BRACE | ||||
#define DEADKEY_GRAVE_ACCENT KEY_BACKSLASH + ALTGR_MASK | #define DEADKEY_GRAVE_ACCENT KEY_BACKSLASH + ALTGR_MASK | ||||
#define GRAVE_ACCENT_BITS 0x0100 | #define GRAVE_ACCENT_BITS 0x0100 | ||||
#define ACUTE_ACCENT_BITS 0x0200 | #define ACUTE_ACCENT_BITS 0x0200 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x03FF | |||||
#define DEADKEY_ACUTE_ACCENT KEY_QUOTE + ALTGR_MASK | #define DEADKEY_ACUTE_ACCENT KEY_QUOTE + ALTGR_MASK | ||||
#define DEADKEY_GRAVE_ACCENT KEY_TILDE | #define DEADKEY_GRAVE_ACCENT KEY_TILDE | ||||
#define KEY_NON_US_100 63 | #define KEY_NON_US_100 63 | ||||
#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 DIAERESIS_BITS 0x0400 | #define DIAERESIS_BITS 0x0400 | ||||
#define RING_ABOVE_BITS 0x0500 | #define RING_ABOVE_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_QUOTE + ALTGR_MASK | #define DEADKEY_CIRCUMFLEX KEY_QUOTE + ALTGR_MASK | ||||
#define DEADKEY_ACUTE_ACCENT KEY_QUOTE | #define DEADKEY_ACUTE_ACCENT KEY_QUOTE | ||||
#define DEADKEY_GRAVE_ACCENT KEY_BACKSLASH + ALTGR_MASK | #define DEADKEY_GRAVE_ACCENT KEY_BACKSLASH + ALTGR_MASK | ||||
#define TILDE_BITS 0x0400 | #define TILDE_BITS 0x0400 | ||||
#define DIAERESIS_BITS 0x0500 | #define DIAERESIS_BITS 0x0500 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x07FF | |||||
#define DEADKEY_CIRCUMFLEX KEY_3 + SHIFT_MASK | #define DEADKEY_CIRCUMFLEX KEY_3 + SHIFT_MASK | ||||
#define DEADKEY_ACUTE_ACCENT KEY_SEMICOLON + ALTGR_MASK | #define DEADKEY_ACUTE_ACCENT KEY_SEMICOLON + ALTGR_MASK | ||||
#define DEADKEY_GRAVE_ACCENT KEY_BACKSLASH + ALTGR_MASK | #define DEADKEY_GRAVE_ACCENT KEY_BACKSLASH + ALTGR_MASK | ||||
//#define DIAERESIS_BITS 0x0A00 | //#define DIAERESIS_BITS 0x0A00 | ||||
#define CEDILLA_BITS 0x0B00 | #define CEDILLA_BITS 0x0B00 | ||||
#define KEYCODE_TYPE uint16_t | #define KEYCODE_TYPE uint16_t | ||||
#define KEYCODE_MASK 0x0FFF | |||||
#define DEADKEY_ACUTE_ACCENT KEY_EQUAL // TODO: is it KEY_9 + ALTGR_MASK | #define DEADKEY_ACUTE_ACCENT KEY_EQUAL // TODO: is it KEY_9 + ALTGR_MASK | ||||
#define DEADKEY_DEGREE_SIGN KEY_TILDE + SHIFT_MASK // TODO: is it KEY_5 + ALTGR_MASK | #define DEADKEY_DEGREE_SIGN KEY_TILDE + SHIFT_MASK // TODO: is it KEY_5 + ALTGR_MASK | ||||
#define DEADKEY_CARON KEY_EQUAL + SHIFT_MASK // TODO: is it KEY_2 + ALTGR_MASK | #define DEADKEY_CARON KEY_EQUAL + SHIFT_MASK // TODO: is it KEY_2 + ALTGR_MASK | ||||
#endif // LAYOUT_CZECH | #endif // LAYOUT_CZECH | ||||
#ifdef LAYOUT_SERBIAN_LATIN_ONLY | |||||
// http://forum.pjrc.com/threads/27032-Serbian-Keyboard-Layout | |||||
#define SHIFT_MASK 0x0040 | |||||
#define ALTGR_MASK 0x0080 | |||||
#define DEADKEYS_MASK 0x0F00 | |||||
#define CEDILLA_BITS 0x0100 | |||||
#define CARON_BITS 0x0200 | |||||
#define CIRCUMFLEX_BITS 0x0300 | |||||
#define BREVE_BITS 0x0400 | |||||
#define DEGREE_SIGN_BITS 0x0500 | |||||
#define OGONEK_BITS 0x0600 | |||||
#define DOT_ABOVE_BITS 0x0700 | |||||
#define ACUTE_ACCENT_BITS 0x0800 | |||||
#define DOUBLE_ACUTE_BITS 0x0900 | |||||
#define DIAERESIS_BITS 0x0A00 | |||||
#define KEYCODE_TYPE uint16_t | |||||
#define KEYCODE_MASK 0x0FFF | |||||
#define DEADKEY_CEDILLA KEY_TILDE | |||||
#define DEADKEY_CARON KEY_2 + ALTGR_MASK | |||||
#define DEADKEY_CIRCUMFLEX KEY_3 + ALTGR_MASK | |||||
#define DEADKEY_BREVE KEY_4 + ALTGR_MASK | |||||
#define DEADKEY_DEGREE_SIGN KEY_5 + ALTGR_MASK | |||||
#define DEADKEY_OGONEK KEY_6 + ALTGR_MASK | |||||
#define DEADKEY_DOT_ABOVE KEY_8 + ALTGR_MASK | |||||
#define DEADKEY_ACUTE_ACCENT KEY_9 + ALTGR_MASK | |||||
#define DEADKEY_DOUBLE_ACUTE KEY_0 + ALTGR_MASK | |||||
#define DEADKEY_DIAERESIS KEY_MINUS + ALTGR_MASK | |||||
//#define DEADKEY_CEDILLA KEY_EQUAL + ALTGR_MASK <-- TODO: why are there 2 Cedilla deadkeys? | |||||
#define KEY_NON_US_100 63 | |||||
#define ASCII_20 KEY_SPACE // 32 | |||||
#define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | |||||
#define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | |||||
#define ASCII_23 KEY_3 + SHIFT_MASK // 35 # | |||||
#define ASCII_24 KEY_4 + SHIFT_MASK // 36 $ | |||||
#define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | |||||
#define ASCII_26 KEY_6 + SHIFT_MASK // 38 & | |||||
#define ASCII_27 KEY_MINUS // 39 ' | |||||
#define ASCII_28 KEY_8 + SHIFT_MASK // 40 ( | |||||
#define ASCII_29 KEY_9 + SHIFT_MASK // 41 ) | |||||
#define ASCII_2A KEY_EQUAL + SHIFT_MASK // 42 * | |||||
#define ASCII_2B KEY_EQUAL // 43 + | |||||
#define ASCII_2C KEY_COMMA // 44 , | |||||
#define ASCII_2D KEY_SLASH // 45 - TODO: verify | |||||
#define ASCII_2E KEY_PERIOD // 46 . | |||||
#define ASCII_2F KEY_7 + SHIFT_MASK // 47 / | |||||
#define ASCII_30 KEY_0 // 48 0 | |||||
#define ASCII_31 KEY_1 // 49 1 | |||||
#define ASCII_32 KEY_2 // 50 2 | |||||
#define ASCII_33 KEY_3 // 51 3 | |||||
#define ASCII_34 KEY_4 // 52 4 | |||||
#define ASCII_35 KEY_5 // 53 5 | |||||
#define ASCII_36 KEY_6 // 54 6 | |||||
#define ASCII_37 KEY_7 // 55 7 | |||||
#define ASCII_38 KEY_8 // 55 8 | |||||
#define ASCII_39 KEY_9 // 57 9 | |||||
#define ASCII_3A KEY_PERIOD + SHIFT_MASK // 58 : | |||||
#define ASCII_3B KEY_COMMA + SHIFT_MASK // 59 ; | |||||
#define ASCII_3C KEY_NON_US_100 // 60 < | |||||
#define ASCII_3D KEY_0 + SHIFT_MASK // 61 = | |||||
#define ASCII_3E KEY_NON_US_100 + SHIFT_MASK // 62 > | |||||
#define ASCII_3F KEY_MINUS + SHIFT_MASK // 63 ? | |||||
#define ASCII_40 KEY_V + ALTGR_MASK // 64 @ | |||||
#define ASCII_41 KEY_A + SHIFT_MASK // 65 A | |||||
#define ASCII_42 KEY_B + SHIFT_MASK // 66 B | |||||
#define ASCII_43 KEY_C + SHIFT_MASK // 67 C | |||||
#define ASCII_44 KEY_D + SHIFT_MASK // 68 D | |||||
#define ASCII_45 KEY_E + SHIFT_MASK // 69 E | |||||
#define ASCII_46 KEY_F + SHIFT_MASK // 70 F | |||||
#define ASCII_47 KEY_G + SHIFT_MASK // 71 G | |||||
#define ASCII_48 KEY_H + SHIFT_MASK // 72 H | |||||
#define ASCII_49 KEY_I + SHIFT_MASK // 73 I | |||||
#define ASCII_4A KEY_J + SHIFT_MASK // 74 J | |||||
#define ASCII_4B KEY_K + SHIFT_MASK // 75 K | |||||
#define ASCII_4C KEY_L + SHIFT_MASK // 76 L | |||||
#define ASCII_4D KEY_M + SHIFT_MASK // 77 M | |||||
#define ASCII_4E KEY_N + SHIFT_MASK // 78 N | |||||
#define ASCII_4F KEY_O + SHIFT_MASK // 79 O | |||||
#define ASCII_50 KEY_P + SHIFT_MASK // 80 P | |||||
#define ASCII_51 KEY_Q + SHIFT_MASK // 81 Q | |||||
#define ASCII_52 KEY_R + SHIFT_MASK // 82 R | |||||
#define ASCII_53 KEY_S + SHIFT_MASK // 83 S | |||||
#define ASCII_54 KEY_T + SHIFT_MASK // 84 T | |||||
#define ASCII_55 KEY_U + SHIFT_MASK // 85 U | |||||
#define ASCII_56 KEY_V + SHIFT_MASK // 86 V | |||||
#define ASCII_57 KEY_W + SHIFT_MASK // 87 W | |||||
#define ASCII_58 KEY_X + SHIFT_MASK // 88 X | |||||
#define ASCII_59 KEY_Z + SHIFT_MASK // 89 Y | |||||
#define ASCII_5A KEY_Y + SHIFT_MASK // 90 Z | |||||
#define ASCII_5B KEY_F + ALTGR_MASK // 91 [ | |||||
#define ASCII_5C KEY_Q + ALTGR_MASK // 92 | |||||
#define ASCII_5D KEY_G + ALTGR_MASK // 93 ] | |||||
#define ASCII_5E CIRCUMFLEX_BITS + KEY_SPACE // 94 ^ | |||||
#define ASCII_5F KEY_SLASH + SHIFT_MASK // 95 _ TODO: verify | |||||
#define ASCII_60 KEY_7 + ALTGR_MASK // 96 ` | |||||
#define ASCII_61 KEY_A // 97 a | |||||
#define ASCII_62 KEY_B // 98 b | |||||
#define ASCII_63 KEY_C // 99 c | |||||
#define ASCII_64 KEY_D // 100 d | |||||
#define ASCII_65 KEY_E // 101 e | |||||
#define ASCII_66 KEY_F // 102 f | |||||
#define ASCII_67 KEY_G // 103 g | |||||
#define ASCII_68 KEY_H // 104 h | |||||
#define ASCII_69 KEY_I // 105 i | |||||
#define ASCII_6A KEY_J // 106 j | |||||
#define ASCII_6B KEY_K // 107 k | |||||
#define ASCII_6C KEY_L // 108 l | |||||
#define ASCII_6D KEY_M // 109 m | |||||
#define ASCII_6E KEY_N // 110 n | |||||
#define ASCII_6F KEY_O // 111 o | |||||
#define ASCII_70 KEY_P // 112 p | |||||
#define ASCII_71 KEY_Q // 113 q | |||||
#define ASCII_72 KEY_R // 114 r | |||||
#define ASCII_73 KEY_S // 115 s | |||||
#define ASCII_74 KEY_T // 116 t | |||||
#define ASCII_75 KEY_U // 117 u | |||||
#define ASCII_76 KEY_V // 118 v | |||||
#define ASCII_77 KEY_W // 119 w | |||||
#define ASCII_78 KEY_X // 120 x | |||||
#define ASCII_79 KEY_Z // 121 y | |||||
#define ASCII_7A KEY_Y // 122 z | |||||
#define ASCII_7B KEY_B + ALTGR_MASK // 123 { | |||||
#define ASCII_7C KEY_W + ALTGR_MASK // 124 | | |||||
#define ASCII_7D KEY_N + ALTGR_MASK // 125 } | |||||
#define ASCII_7E KEY_1 + ALTGR_MASK // 126 ~ | |||||
#define ASCII_7F KEY_BACKSPACE // 127 | |||||
#define ISO_8859_1_A0 KEY_SPACE // 160 Nonbreakng Space | |||||
#define ISO_8859_1_A1 0 // 161 ¡ Inverted Exclamation | |||||
#define ISO_8859_1_A2 0 // 162 ¢ Cent Sign | |||||
#define ISO_8859_1_A3 0 // 163 £ Pound Sign | |||||
#define ISO_8859_1_A4 KEY_BACKSLASH + ALTGR_MASK // 164 ¤ Currency Sign | |||||
#define ISO_8859_1_A5 0 // 165 ¥ YEN SIGN | |||||
#define ISO_8859_1_A6 0 // 166 ¦ BROKEN BAR | |||||
#define ISO_8859_1_A7 KEY_M + ALTGR_MASK // 167 § SECTION SIGN | |||||
#define ISO_8859_1_A8 DIAERESIS_BITS + KEY_SPACE // 168 ¨ DIAERESIS | |||||
#define ISO_8859_1_A9 0 // 169 © COPYRIGHT SIGN | |||||
#define ISO_8859_1_AA 0 // 170 ª FEMININE ORDINAL | |||||
#define ISO_8859_1_AB 0 // 171 « LEFT DOUBLE ANGLE QUOTE | |||||
#define ISO_8859_1_AC 0 // 172 ¬ NOT SIGN | |||||
#define ISO_8859_1_AD 0 // 173 SOFT HYPHEN | |||||
#define ISO_8859_1_AE 0 // 174 ® REGISTERED SIGN | |||||
#define ISO_8859_1_AF 0 // 175 ¯ MACRON | |||||
#define ISO_8859_1_B0 DEGREE_SIGN_BITS + KEY_SPACE // 176 ° DEGREE SIGN | |||||
#define ISO_8859_1_B1 0 // 177 ± PLUS-MINUS SIGN | |||||
#define ISO_8859_1_B2 0 // 178 ² SUPERSCRIPT TWO | |||||
#define ISO_8859_1_B3 0 // 179 ³ SUPERSCRIPT THREE | |||||
#define ISO_8859_1_B4 ACUTE_ACCENT_BITS + KEY_SPACE // 180 ´ ACUTE ACCENT | |||||
#define ISO_8859_1_B5 0 // 181 µ MICRO SIGN | |||||
#define ISO_8859_1_B6 0 // 182 ¶ PILCROW SIGN | |||||
#define ISO_8859_1_B7 0 // 183 · MIDDLE DOT | |||||
#define ISO_8859_1_B8 CEDILLA_BITS + KEY_SPACE // 184 ¸ CEDILLA | |||||
#define ISO_8859_1_B9 0 // 185 ¹ SUPERSCRIPT ONE | |||||
#define ISO_8859_1_BA 0 // 186 º MASCULINE ORDINAL | |||||
#define ISO_8859_1_BB 0 // 187 » RIGHT DOUBLE ANGLE QUOTE | |||||
#define ISO_8859_1_BC 0 // 188 ¼ FRACTION ONE QUARTER | |||||
#define ISO_8859_1_BD 0 // 189 ½ FRACTION ONE HALF | |||||
#define ISO_8859_1_BE 0 // 190 ¾ FRACTION THREE QUARTERS | |||||
#define ISO_8859_1_BF 0 // 191 ¿ INVERTED QUESTION MARK | |||||
#define ISO_8859_1_C0 0 // 192 À A GRAVE | |||||
#define ISO_8859_1_C1 ACUTE_ACCENT_BITS + KEY_A + SHIFT_MASK // 193 Á A ACUTE | |||||
#define ISO_8859_1_C2 CIRCUMFLEX_BITS + KEY_A + SHIFT_MASK // 194 Â A CIRCUMFLEX | |||||
#define ISO_8859_1_C3 0 // 195 Ã A TILDE | |||||
#define ISO_8859_1_C4 DIAERESIS_BITS + KEY_A + SHIFT_MASK // 196 Ä A DIAERESIS | |||||
#define ISO_8859_1_C5 0 // 197 Å A RING ABOVE | |||||
#define ISO_8859_1_C6 0 // 198 Æ AE | |||||
#define ISO_8859_1_C7 CEDILLA_BITS + KEY_C + SHIFT_MASK // 199 Ç C CEDILLA | |||||
#define ISO_8859_1_C8 0 // 200 È E GRAVE | |||||
#define ISO_8859_1_C9 ACUTE_ACCENT_BITS + KEY_E + SHIFT_MASK // 201 É E ACUTE | |||||
#define ISO_8859_1_CA CIRCUMFLEX_BITS + KEY_E + SHIFT_MASK // 202 Ê E CIRCUMFLEX | |||||
#define ISO_8859_1_CB DIAERESIS_BITS + KEY_E + SHIFT_MASK // 203 Ë E DIAERESIS | |||||
#define ISO_8859_1_CC 0 // 204 Ì I GRAVE | |||||
#define ISO_8859_1_CD ACUTE_ACCENT_BITS + KEY_I + SHIFT_MASK // 205 Í I ACUTE | |||||
#define ISO_8859_1_CE CIRCUMFLEX_BITS + KEY_I + SHIFT_MASK // 206 Î I CIRCUMFLEX | |||||
#define ISO_8859_1_CF DIAERESIS_BITS + KEY_I + SHIFT_MASK // 207 Ï I DIAERESIS | |||||
#define ISO_8859_1_D0 0 // 208 Ð ETH | |||||
#define ISO_8859_1_D1 0 // 209 Ñ N TILDE | |||||
#define ISO_8859_1_D2 0 // 210 Ò O GRAVE | |||||
#define ISO_8859_1_D3 ACUTE_ACCENT_BITS + KEY_O + SHIFT_MASK // 211 Ó O ACUTE | |||||
#define ISO_8859_1_D4 CIRCUMFLEX_BITS + KEY_O + SHIFT_MASK // 212 Ô O CIRCUMFLEX | |||||
#define ISO_8859_1_D5 0 // 213 Õ O TILDE | |||||
#define ISO_8859_1_D6 DIAERESIS_BITS + KEY_O + SHIFT_MASK // 214 Ö O DIAERESIS | |||||
#define ISO_8859_1_D7 KEY_RIGHT_BRACE + ALTGR_MASK // 215 × MULTIPLICATION | |||||
#define ISO_8859_1_D8 0 // 216 Ø O STROKE | |||||
#define ISO_8859_1_D9 0 // 217 Ù U GRAVE | |||||
#define ISO_8859_1_DA ACUTE_ACCENT_BITS + KEY_U + SHIFT_MASK // 218 Ú U ACUTE | |||||
#define ISO_8859_1_DB CIRCUMFLEX_BITS + KEY_U + SHIFT_MASK // 219 Û U CIRCUMFLEX | |||||
#define ISO_8859_1_DC DIAERESIS_BITS + KEY_U + SHIFT_MASK // 220 Ü U DIAERESIS | |||||
#define ISO_8859_1_DD ACUTE_ACCENT_BITS + KEY_Z + SHIFT_MASK // 221 Ý Y ACUTE | |||||
#define ISO_8859_1_DE 0 // 222 Þ THORN | |||||
#define ISO_8859_1_DF KEY_QUOTE + ALTGR_MASK // 223 ß SHARP S | |||||
#define ISO_8859_1_E0 0 // 224 à a GRAVE | |||||
#define ISO_8859_1_E1 ACUTE_ACCENT_BITS + KEY_A // 225 á a ACUTE | |||||
#define ISO_8859_1_E2 CIRCUMFLEX_BITS + KEY_A // 226 â a CIRCUMFLEX | |||||
#define ISO_8859_1_E3 0 // 227 ã a TILDE | |||||
#define ISO_8859_1_E4 DIAERESIS_BITS + KEY_A // 228 ä a DIAERESIS | |||||
#define ISO_8859_1_E5 0 // 229 å a RING ABOVE | |||||
#define ISO_8859_1_E6 0 // 230 æ ae | |||||
#define ISO_8859_1_E7 CEDILLA_BITS + KEY_C // 231 ç c CEDILLA | |||||
#define ISO_8859_1_E8 0 // 232 è e GRAVE | |||||
#define ISO_8859_1_E9 ACUTE_ACCENT_BITS + KEY_E // 233 é e ACUTE | |||||
#define ISO_8859_1_EA CIRCUMFLEX_BITS + KEY_E // 234 ê e CIRCUMFLEX | |||||
#define ISO_8859_1_EB DIAERESIS_BITS + KEY_E // 235 ë e DIAERESIS | |||||
#define ISO_8859_1_EC 0 // 236 ì i GRAVE | |||||
#define ISO_8859_1_ED ACUTE_ACCENT_BITS + KEY_I // 237 í i ACUTE | |||||
#define ISO_8859_1_EE CIRCUMFLEX_BITS + KEY_I // 238 î i CIRCUMFLEX | |||||
#define ISO_8859_1_EF DIAERESIS_BITS + KEY_I // 239 ï i DIAERESIS | |||||
#define ISO_8859_1_F0 0 // 240 ð ETH | |||||
#define ISO_8859_1_F1 0 // 241 ñ n TILDE | |||||
#define ISO_8859_1_F2 0 // 242 ò o GRAVE | |||||
#define ISO_8859_1_F3 ACUTE_ACCENT_BITS + KEY_O // 243 ó o ACUTE | |||||
#define ISO_8859_1_F4 CIRCUMFLEX_BITS + KEY_O // 244 ô o CIRCUMFLEX | |||||
#define ISO_8859_1_F5 0 // 245 õ o TILDE | |||||
#define ISO_8859_1_F6 DIAERESIS_BITS + KEY_O // 246 ö o DIAERESIS | |||||
#define ISO_8859_1_F7 KEY_LEFT_BRACE + ALTGR_MASK // 247 ÷ DIVISION | |||||
#define ISO_8859_1_F8 0 // 248 ø o STROKE | |||||
#define ISO_8859_1_F9 0 // 249 ù u GRAVE | |||||
#define ISO_8859_1_FA ACUTE_ACCENT_BITS + KEY_U // 250 ú u ACUTE | |||||
#define ISO_8859_1_FB CIRCUMFLEX_BITS + KEY_U // 251 û u CIRCUMFLEX | |||||
#define ISO_8859_1_FC DIAERESIS_BITS + KEY_U // 252 ü u DIAERESIS | |||||
#define ISO_8859_1_FD ACUTE_ACCENT_BITS + KEY_Z // 253 ý y ACUTE | |||||
#define ISO_8859_1_FE 0 // 254 þ THORN | |||||
#define ISO_8859_1_FF 0 // 255 ÿ y DIAERESIS | |||||
#define UNICODE_20AC KEY_E + ALTGR_MASK // € Euro Sign | |||||
#define UNICODE_EXTRA00 0x0160 // S caron | |||||
#define KEYCODE_EXTRA00 KEY_LEFT_BRACE + SHIFT_MASK | |||||
#define UNICODE_EXTRA01 0x0161 // s caron | |||||
#define KEYCODE_EXTRA01 KEY_LEFT_BRACE | |||||
#define UNICODE_EXTRA02 0x0110 // D with stroke | |||||
#define KEYCODE_EXTRA02 KEY_RIGHT_BRACE + SHIFT_MASK | |||||
#define UNICODE_EXTRA03 0x0111 // d with stroke | |||||
#define KEYCODE_EXTRA03 KEY_RIGHT_BRACE | |||||
#define UNICODE_EXTRA04 0x010C // C with caron | |||||
#define KEYCODE_EXTRA04 KEY_SEMICOLON + SHIFT_MASK | |||||
#define UNICODE_EXTRA05 0x010D // c with caron | |||||
#define KEYCODE_EXTRA05 KEY_SEMICOLON | |||||
#define UNICODE_EXTRA06 0x0106 // C with acute | |||||
#define KEYCODE_EXTRA06 KEY_QUOTE + SHIFT_MASK | |||||
#define UNICODE_EXTRA07 0x0107 // c with acute | |||||
#define KEYCODE_EXTRA07 KEY_QUOTE | |||||
#define UNICODE_EXTRA08 0x017D // Z with caron | |||||
#define KEYCODE_EXTRA08 KEY_BACKSLASH + SHIFT_MASK | |||||
#define UNICODE_EXTRA09 0x017E // z with caron | |||||
#define KEYCODE_EXTRA09 KEY_BACKSLASH | |||||
#define UNICODE_EXTRA10 0x0141 // L with stroke | |||||
#define KEYCODE_EXTRA10 KEY_L + ALTGR_MASK | |||||
#define UNICODE_EXTRA11 0x0142 // l with stroke | |||||
#define KEYCODE_EXTRA11 KEY_K + ALTGR_MASK | |||||
#define UNICODE_EXTRA12 0x010E // D with caron | |||||
#define KEYCODE_EXTRA12 CARON_BITS + KEY_D + SHIFT_MASK | |||||
#define UNICODE_EXTRA13 0x010F // d with caron | |||||
#define KEYCODE_EXTRA13 CARON_BITS + KEY_D | |||||
#define UNICODE_EXTRA14 0x011A // E with caron | |||||
#define KEYCODE_EXTRA14 CARON_BITS + KEY_E + SHIFT_MASK | |||||
#define UNICODE_EXTRA15 0x011B // e with caron | |||||
#define KEYCODE_EXTRA15 CARON_BITS + KEY_E | |||||
#define UNICODE_EXTRA16 0x013D // L with caron | |||||
#define KEYCODE_EXTRA16 CARON_BITS + KEY_L + SHIFT_MASK | |||||
#define UNICODE_EXTRA17 0x013E // l with caron | |||||
#define KEYCODE_EXTRA17 CARON_BITS + KEY_L | |||||
#define UNICODE_EXTRA18 0x0147 // N with caron | |||||
#define KEYCODE_EXTRA18 CARON_BITS + KEY_N + SHIFT_MASK | |||||
#define UNICODE_EXTRA19 0x0148 // n with caron | |||||
#define KEYCODE_EXTRA19 CARON_BITS + KEY_N | |||||
#define UNICODE_EXTRA20 0x0158 // R with caron | |||||
#define KEYCODE_EXTRA20 CARON_BITS + KEY_R + SHIFT_MASK | |||||
#define UNICODE_EXTRA21 0x0159 // r with caron | |||||
#define KEYCODE_EXTRA21 CARON_BITS + KEY_R | |||||
#define UNICODE_EXTRA22 0x0164 // T with caron | |||||
#define KEYCODE_EXTRA22 CARON_BITS + KEY_T + SHIFT_MASK | |||||
#define UNICODE_EXTRA23 0x0165 // t with caron | |||||
#define KEYCODE_EXTRA23 CARON_BITS + KEY_T | |||||
#define UNICODE_EXTRA24 0x0102 // A with breve | |||||
#define KEYCODE_EXTRA24 BREVE_BITS + KEY_A + SHIFT_MASK | |||||
#define UNICODE_EXTRA25 0x0103 // a with breve | |||||
#define KEYCODE_EXTRA25 BREVE_BITS + KEY_A | |||||
#define UNICODE_EXTRA26 0x016E // U with ring above TODO: verify | |||||
#define KEYCODE_EXTRA26 DEADKEY_DEGREE_SIGN + KEY_U + SHIFT_MASK | |||||
#define UNICODE_EXTRA27 0x016F // u with ring above TODO: verify | |||||
#define KEYCODE_EXTRA27 DEADKEY_DEGREE_SIGN + KEY_U | |||||
#define UNICODE_EXTRA28 0x0104 // A with ogonek | |||||
#define KEYCODE_EXTRA28 OGONEK_BITS + KEY_A + SHIFT_MASK | |||||
#define UNICODE_EXTRA29 0x0105 // a with ogonek | |||||
#define KEYCODE_EXTRA29 OGONEK_BITS + KEY_A | |||||
#define UNICODE_EXTRA30 0x0118 // E with ogonek | |||||
#define KEYCODE_EXTRA30 OGONEK_BITS + KEY_E + SHIFT_MASK | |||||
#define UNICODE_EXTRA31 0x0119 // e with ogonek | |||||
#define KEYCODE_EXTRA31 OGONEK_BITS + KEY_E | |||||
#define UNICODE_EXTRA32 0x017B // Z with dot above | |||||
#define KEYCODE_EXTRA32 DEADKEY_DOT_ABOVE + KEY_Z + SHIFT_MASK | |||||
#define UNICODE_EXTRA33 0x017C // z with dot above | |||||
#define KEYCODE_EXTRA33 DEADKEY_DOT_ABOVE + KEY_Z | |||||
#define UNICODE_EXTRA34 0x0139 // L with acute | |||||
#define KEYCODE_EXTRA34 ACUTE_ACCENT_BITS + KEY_L + SHIFT_MASK | |||||
#define UNICODE_EXTRA35 0x013A // l with acute | |||||
#define KEYCODE_EXTRA35 ACUTE_ACCENT_BITS + KEY_L | |||||
#define UNICODE_EXTRA36 0x0143 // N with acute | |||||
#define KEYCODE_EXTRA36 ACUTE_ACCENT_BITS + KEY_N + SHIFT_MASK | |||||
#define UNICODE_EXTRA37 0x0144 // n with acute | |||||
#define KEYCODE_EXTRA37 ACUTE_ACCENT_BITS + KEY_N | |||||
#define UNICODE_EXTRA38 0x0154 // R with acute | |||||
#define KEYCODE_EXTRA38 ACUTE_ACCENT_BITS + KEY_R + SHIFT_MASK | |||||
#define UNICODE_EXTRA39 0x0155 // r with acute | |||||
#define KEYCODE_EXTRA39 ACUTE_ACCENT_BITS + KEY_R | |||||
#define UNICODE_EXTRA40 0x015A // S with acute | |||||
#define KEYCODE_EXTRA40 ACUTE_ACCENT_BITS + KEY_S + SHIFT_MASK | |||||
#define UNICODE_EXTRA41 0x015B // s with acute | |||||
#define KEYCODE_EXTRA41 ACUTE_ACCENT_BITS + KEY_S | |||||
#define UNICODE_EXTRA42 0x0179 // Z with acute | |||||
#define KEYCODE_EXTRA42 ACUTE_ACCENT_BITS + KEY_Z + SHIFT_MASK | |||||
#define UNICODE_EXTRA43 0x017A // z with acute | |||||
#define KEYCODE_EXTRA43 ACUTE_ACCENT_BITS + KEY_Z | |||||
#define UNICODE_EXTRA44 0x0150 // O with double acute | |||||
#define KEYCODE_EXTRA44 DOUBLE_ACUTE_BITS + KEY_O + SHIFT_MASK | |||||
#define UNICODE_EXTRA45 0x0151 // o with double acute | |||||
#define KEYCODE_EXTRA45 DOUBLE_ACUTE_BITS + KEY_O | |||||
#define UNICODE_EXTRA46 0x0170 // U with double acute | |||||
#define KEYCODE_EXTRA46 DOUBLE_ACUTE_BITS + KEY_u + SHIFT_MASK | |||||
#define UNICODE_EXTRA47 0x0171 // u with double acute | |||||
#define KEYCODE_EXTRA47 DOUBLE_ACUTE_BITS + KEY_u | |||||
#define UNICODE_EXTRA48 0x015E // S with cedilla | |||||
#define KEYCODE_EXTRA48 CEDILLA_BITS + KEY_S + SHIFT_MASK | |||||
#define UNICODE_EXTRA49 0x015F // s with cedilla | |||||
#define KEYCODE_EXTRA49 CEDILLA_BITS + KEY_S | |||||
#define UNICODE_EXTRA50 0x201A // single low quote | |||||
#define KEYCODE_EXTRA50 KEY_TILDE | |||||
#define UNICODE_EXTRA51 0x20AC // euro sign | |||||
#define KEYCODE_EXTRA51 KEY_E + ALTGR_MASK | |||||
#endif // LAYOUT_SERBIAN_LATIN_ONLY | |||||
#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) | ||||
{ | { | ||||
#if !defined(ARDUINO) | |||||
#ifdef USING_MAKEFILE | |||||
// To use Teensy 3.0 without Arduino, simply put your code here. | // To use Teensy 3.0 without Arduino, simply put your code here. | ||||
// For example: | // For example: |
/* ---------------------------------------------------------------------- | /* ---------------------------------------------------------------------- | ||||
* 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; | ||||
} | |||||
} | |||||
} | |||||
} | |||||
} | } | ||||
/** | /** |
/* | |||||
* Copyright (c) 2013 ARM Ltd | |||||
* All rights reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* 3. The name of the company may not be used to endorse or promote | |||||
* products derived from this software without specific prior written | |||||
* permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED | |||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||||
* IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | |||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#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 | |||||
*/ | |||||
/* This memcpy routine is optimised for Cortex-M3/M4 cores with/without | |||||
unaligned access. | |||||
If compiled with GCC, this file should be enclosed within following | |||||
pre-processing check: | |||||
if defined (__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) | |||||
Prototype: void *memcpy (void *dst, const void *src, size_t count); | |||||
The job will be done in 5 steps. | |||||
Step 1: Align src/dest pointers, copy mis-aligned if fail to align both | |||||
Step 2: Repeatedly copy big block size of __OPT_BIG_BLOCK_SIZE | |||||
Step 3: Repeatedly copy big block size of __OPT_MID_BLOCK_SIZE | |||||
Step 4: Copy word by word | |||||
Step 5: Copy byte-to-byte | |||||
Tunable options: | |||||
__OPT_BIG_BLOCK_SIZE: Size of big block in words. Default to 64. | |||||
__OPT_MID_BLOCK_SIZE: Size of big block in words. Default to 16. | |||||
*/ | |||||
#ifndef __OPT_BIG_BLOCK_SIZE | |||||
#define __OPT_BIG_BLOCK_SIZE (4 * 16) | |||||
#endif | |||||
#ifndef __OPT_MID_BLOCK_SIZE | |||||
#define __OPT_MID_BLOCK_SIZE (4 * 4) | |||||
#endif | |||||
#if __OPT_BIG_BLOCK_SIZE == 16 | |||||
#define BEGIN_UNROLL_BIG_BLOCK \ | |||||
.irp offset, 0,4,8,12 | |||||
#elif __OPT_BIG_BLOCK_SIZE == 32 | |||||
#define BEGIN_UNROLL_BIG_BLOCK \ | |||||
.irp offset, 0,4,8,12,16,20,24,28 | |||||
#elif __OPT_BIG_BLOCK_SIZE == 64 | |||||
#define BEGIN_UNROLL_BIG_BLOCK \ | |||||
.irp offset, 0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60 | |||||
#else | |||||
#error "Illegal __OPT_BIG_BLOCK_SIZE" | |||||
#endif | |||||
#if __OPT_MID_BLOCK_SIZE == 8 | |||||
#define BEGIN_UNROLL_MID_BLOCK \ | |||||
.irp offset, 0,4 | |||||
#elif __OPT_MID_BLOCK_SIZE == 16 | |||||
#define BEGIN_UNROLL_MID_BLOCK \ | |||||
.irp offset, 0,4,8,12 | |||||
#else | |||||
#error "Illegal __OPT_MID_BLOCK_SIZE" | |||||
#endif | |||||
#define END_UNROLL .endr | |||||
.syntax unified | |||||
.text | |||||
.align 2 | |||||
.global memcpy | |||||
.thumb | |||||
.thumb_func | |||||
.type memcpy, %function | |||||
memcpy: | |||||
@ r0: dst | |||||
@ r1: src | |||||
@ r2: len | |||||
#ifdef __ARM_FEATURE_UNALIGNED | |||||
/* In case of UNALIGNED access supported, ip is not used in | |||||
function body. */ | |||||
mov ip, r0 | |||||
#else | |||||
push {r0} | |||||
#endif | |||||
orr r3, r1, r0 | |||||
ands r3, r3, #3 | |||||
bne .Lmisaligned_copy | |||||
.Lbig_block: | |||||
subs r2, __OPT_BIG_BLOCK_SIZE | |||||
blo .Lmid_block | |||||
/* Kernel loop for big block copy */ | |||||
.align 2 | |||||
.Lbig_block_loop: | |||||
BEGIN_UNROLL_BIG_BLOCK | |||||
#ifdef __ARM_ARCH_7EM__ | |||||
ldr r3, [r1], #4 | |||||
str r3, [r0], #4 | |||||
END_UNROLL | |||||
#else /* __ARM_ARCH_7M__ */ | |||||
ldr r3, [r1, \offset] | |||||
str r3, [r0, \offset] | |||||
END_UNROLL | |||||
adds r0, __OPT_BIG_BLOCK_SIZE | |||||
adds r1, __OPT_BIG_BLOCK_SIZE | |||||
#endif | |||||
subs r2, __OPT_BIG_BLOCK_SIZE | |||||
bhs .Lbig_block_loop | |||||
.Lmid_block: | |||||
adds r2, __OPT_BIG_BLOCK_SIZE - __OPT_MID_BLOCK_SIZE | |||||
blo .Lcopy_word_by_word | |||||
/* Kernel loop for mid-block copy */ | |||||
.align 2 | |||||
.Lmid_block_loop: | |||||
BEGIN_UNROLL_MID_BLOCK | |||||
#ifdef __ARM_ARCH_7EM__ | |||||
ldr r3, [r1], #4 | |||||
str r3, [r0], #4 | |||||
END_UNROLL | |||||
#else /* __ARM_ARCH_7M__ */ | |||||
ldr r3, [r1, \offset] | |||||
str r3, [r0, \offset] | |||||
END_UNROLL | |||||
adds r0, __OPT_MID_BLOCK_SIZE | |||||
adds r1, __OPT_MID_BLOCK_SIZE | |||||
#endif | |||||
subs r2, __OPT_MID_BLOCK_SIZE | |||||
bhs .Lmid_block_loop | |||||
.Lcopy_word_by_word: | |||||
adds r2, __OPT_MID_BLOCK_SIZE - 4 | |||||
blo .Lcopy_less_than_4 | |||||
/* Kernel loop for small block copy */ | |||||
.align 2 | |||||
.Lcopy_word_by_word_loop: | |||||
ldr r3, [r1], #4 | |||||
str r3, [r0], #4 | |||||
subs r2, #4 | |||||
bhs .Lcopy_word_by_word_loop | |||||
.Lcopy_less_than_4: | |||||
adds r2, #4 | |||||
beq .Ldone | |||||
lsls r2, r2, #31 | |||||
itt ne | |||||
ldrbne r3, [r1], #1 | |||||
strbne r3, [r0], #1 | |||||
bcc .Ldone | |||||
#ifdef __ARM_FEATURE_UNALIGNED | |||||
ldrh r3, [r1] | |||||
strh r3, [r0] | |||||
#else | |||||
ldrb r3, [r1] | |||||
strb r3, [r0] | |||||
ldrb r3, [r1, #1] | |||||
strb r3, [r0, #1] | |||||
#endif /* __ARM_FEATURE_UNALIGNED */ | |||||
.Ldone: | |||||
#ifdef __ARM_FEATURE_UNALIGNED | |||||
mov r0, ip | |||||
#else | |||||
pop {r0} | |||||
#endif | |||||
bx lr | |||||
.align 2 | |||||
.Lmisaligned_copy: | |||||
#ifdef __ARM_FEATURE_UNALIGNED | |||||
/* Define label DST_ALIGNED to BIG_BLOCK. It will go to aligned copy | |||||
once destination is adjusted to aligned. */ | |||||
#define Ldst_aligned Lbig_block | |||||
/* Copy word by word using LDR when alignment can be done in hardware, | |||||
i.e., SCTLR.A is set, supporting unaligned access in LDR and STR. */ | |||||
cmp r2, #8 | |||||
blo .Lbyte_copy | |||||
/* if src is aligned, just go to the big block loop. */ | |||||
lsls r3, r1, #30 | |||||
beq .Ldst_aligned | |||||
#else | |||||
/* if len < 12, misalignment adjustment has more overhead than | |||||
just byte-to-byte copy. Also, len must >=8 to guarantee code | |||||
afterward work correctly. */ | |||||
cmp r2, #12 | |||||
blo .Lbyte_copy | |||||
#endif /* __ARM_FEATURE_UNALIGNED */ | |||||
/* Align dst only, not trying to align src. That is the because | |||||
handling of aligned src and misaligned dst need more overhead than | |||||
otherwise. By doing this the worst case is when initial src is aligned, | |||||
additional up to 4 byte additional copy will executed, which is | |||||
acceptable. */ | |||||
ands r3, r0, #3 | |||||
beq .Ldst_aligned | |||||
rsb r3, #4 | |||||
subs r2, r3 | |||||
lsls r3, r3, #31 | |||||
itt ne | |||||
ldrbne r3, [r1], #1 | |||||
strbne r3, [r0], #1 | |||||
bcc .Ldst_aligned | |||||
#ifdef __ARM_FEATURE_UNALIGNED | |||||
ldrh r3, [r1], #2 | |||||
strh r3, [r0], #2 | |||||
b .Ldst_aligned | |||||
#else | |||||
ldrb r3, [r1], #1 | |||||
strb r3, [r0], #1 | |||||
ldrb r3, [r1], #1 | |||||
strb r3, [r0], #1 | |||||
/* Now that dst is aligned */ | |||||
.Ldst_aligned: | |||||
/* if r1 is aligned now, it means r0/r1 has the same misalignment, | |||||
and they are both aligned now. Go aligned copy. */ | |||||
ands r3, r1, #3 | |||||
beq .Lbig_block | |||||
/* dst is aligned, but src isn't. Misaligned copy. */ | |||||
push {r4, r5} | |||||
subs r2, #4 | |||||
/* Backward r1 by misaligned bytes, to make r1 aligned. | |||||
Since we need to restore r1 to unaligned address after the loop, | |||||
we need keep the offset bytes to ip and sub it from r1 afterward. */ | |||||
subs r1, r3 | |||||
rsb ip, r3, #4 | |||||
/* Pre-load on word */ | |||||
ldr r4, [r1], #4 | |||||
cmp r3, #2 | |||||
beq .Lmisaligned_copy_2_2 | |||||
cmp r3, #3 | |||||
beq .Lmisaligned_copy_3_1 | |||||
.macro mis_src_copy shift | |||||
1: | |||||
lsrs r4, r4, \shift | |||||
ldr r3, [r1], #4 | |||||
lsls r5, r3, 32-\shift | |||||
orr r4, r4, r5 | |||||
str r4, [r0], #4 | |||||
mov r4, r3 | |||||
subs r2, #4 | |||||
bhs 1b | |||||
.endm | |||||
.Lmisaligned_copy_1_3: | |||||
mis_src_copy shift=8 | |||||
b .Lsrc_misaligned_tail | |||||
.Lmisaligned_copy_3_1: | |||||
mis_src_copy shift=24 | |||||
b .Lsrc_misaligned_tail | |||||
.Lmisaligned_copy_2_2: | |||||
/* For 2_2 misalignment, ldr is still faster than 2 x ldrh. */ | |||||
mis_src_copy shift=16 | |||||
.Lsrc_misaligned_tail: | |||||
adds r2, #4 | |||||
subs r1, ip | |||||
pop {r4, r5} | |||||
#endif /* __ARM_FEATURE_UNALIGNED */ | |||||
.Lbyte_copy: | |||||
subs r2, #4 | |||||
blo .Lcopy_less_than_4 | |||||
.Lbyte_copy_loop: | |||||
subs r2, #1 | |||||
ldrb r3, [r1], #1 | |||||
strb r3, [r0], #1 | |||||
bhs .Lbyte_copy_loop | |||||
ldrb r3, [r1] | |||||
strb r3, [r0] | |||||
ldrb r3, [r1, #1] | |||||
strb r3, [r0, #1] | |||||
ldrb r3, [r1, #2] | |||||
strb r3, [r0, #2] | |||||
#ifdef __ARM_FEATURE_UNALIGNED | |||||
mov r0, ip | |||||
#else | |||||
pop {r0} | |||||
#endif | |||||
bx lr | |||||
.size memcpy, .-memcpy | |||||
#endif | |||||
#endif // __MK20DX128__ || __MK20DX256__ || __MK66FX1M0__ | |||||
/* | |||||
* Copyright (c) 2014 Travis Geiselbrecht | |||||
* | |||||
* 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. | |||||
*/ | |||||
//#include <asm.h> | |||||
//#include <arch/arm/cores.h> | |||||
#if defined (__OPTIMIZE_SIZE__) | |||||
#if defined (__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) | |||||
.global memset | |||||
.text | |||||
.syntax unified | |||||
.thumb | |||||
.align 2 | |||||
/* void *memset(void *s, int c, size_t n); */ | |||||
.type memset, %function | |||||
.thumb_func | |||||
memset: | |||||
//FUNCTION(memset) | |||||
// save the original pointer | |||||
push { r0, lr } | |||||
// check for zero length | |||||
cbz r2, .L_done | |||||
// short memsets aren't worth optimizing and make sure we have | |||||
// enough headroom to try to do dwordwise move optimization | |||||
cmp r2, #16 | |||||
blt .L_bytewise | |||||
// see how many bytes we need to move to align to dword boundaries | |||||
and r3, r0, #7 | |||||
cbz r3, .L_prepare_dwordwise | |||||
rsb r3, #8 | |||||
subs r2, r3 | |||||
.L_bytewise_align: | |||||
// bytewise to align memset | |||||
subs r3, r3, #1 | |||||
strb r1, [r0], #1 | |||||
bgt .L_bytewise_align | |||||
.L_prepare_dwordwise: | |||||
// fill a pair of 32 bit registers with the 8 bit value | |||||
uxtb r1, r1 | |||||
orr r1, r1, r1, lsl #8 | |||||
orr r1, r1, r1, lsl #16 | |||||
mov r12, r1 | |||||
// load the number of dwords left | |||||
lsrs r3, r2, #3 | |||||
.L_dwordwise: | |||||
// dwordwise memset | |||||
subs r3, r3, #1 | |||||
strd r1, r12, [r0], #8 | |||||
bgt .L_dwordwise | |||||
// remaining bytes | |||||
ands r2, #7 | |||||
beq .L_done | |||||
.L_bytewise: | |||||
// bytewise memset | |||||
subs r2, r2, #1 | |||||
strb r1, [r0], #1 | |||||
bgt .L_bytewise | |||||
.L_done: | |||||
// restore the base pointer as return value | |||||
pop { r0, pc } | |||||
#endif | |||||
#endif |
// 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 | ||||
.bss : { | .bss : { | ||||
. = ALIGN(4); | . = ALIGN(4); | ||||
_sbss = .; | |||||
_sbss = .; | |||||
__bss_start__ = .; | |||||
*(.bss*) | *(.bss*) | ||||
*(COMMON) | *(COMMON) | ||||
. = ALIGN(4); | . = ALIGN(4); | ||||
_ebss = .; | _ebss = .; | ||||
__bss_end = .; | __bss_end = .; | ||||
__bss_end__ = .; | |||||
} > 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. | ||||
} | } | ||||
/* INCLUDE common.ld */ | |||||
/* Teensyduino Core Library | |||||
* http://www.pjrc.com/teensy/ | |||||
* Copyright (c) 2013 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. | |||||
*/ | |||||
SECTIONS | SECTIONS | ||||
{ | { | ||||
.text : { | .text : { | ||||
.bss : { | .bss : { | ||||
. = ALIGN(4); | . = ALIGN(4); | ||||
_sbss = .; | |||||
_sbss = .; | |||||
__bss_start__ = .; | |||||
*(.bss*) | *(.bss*) | ||||
*(COMMON) | *(COMMON) | ||||
. = ALIGN(4); | . = ALIGN(4); | ||||
_ebss = .; | _ebss = .; | ||||
__bss_end = .; | __bss_end = .; | ||||
__bss_end__ = .; | |||||
} > RAM | } > RAM | ||||
_estack = ORIGIN(RAM) + LENGTH(RAM); | _estack = ORIGIN(RAM) + LENGTH(RAM); | ||||
_teensy_model_identifier = 0x21; | |||||
} | } | ||||
/* 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. | |||||
*/ | |||||
MEMORY | |||||
{ | |||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K | |||||
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 262136 | |||||
} | |||||
SECTIONS | |||||
{ | |||||
.text : { | |||||
. = 0; | |||||
KEEP(*(.vectors)) | |||||
*(.startup*) | |||||
/* TODO: does linker detect startup overflow onto flashconfig? */ | |||||
. = 0x400; | |||||
KEEP(*(.flashconfig*)) | |||||
*(.text*) | |||||
*(.rodata*) | |||||
. = ALIGN(4); | |||||
KEEP(*(.init)) | |||||
. = ALIGN(4); | |||||
__preinit_array_start = .; | |||||
KEEP (*(.preinit_array)) | |||||
__preinit_array_end = .; | |||||
__init_array_start = .; | |||||
KEEP (*(SORT(.init_array.*))) | |||||
KEEP (*(.init_array)) | |||||
__init_array_end = .; | |||||
} > FLASH = 0xFF | |||||
.ARM.exidx : { | |||||
__exidx_start = .; | |||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*) | |||||
__exidx_end = .; | |||||
} > FLASH | |||||
_etext = .; | |||||
.usbdescriptortable (NOLOAD) : { | |||||
/* . = ORIGIN(RAM); */ | |||||
. = ALIGN(512); | |||||
*(.usbdescriptortable*) | |||||
} > RAM | |||||
.dmabuffers (NOLOAD) : { | |||||
. = ALIGN(4); | |||||
*(.dmabuffers*) | |||||
} > RAM | |||||
.usbbuffers (NOLOAD) : { | |||||
. = ALIGN(4); | |||||
*(.usbbuffers*) | |||||
} > RAM | |||||
.data : AT (_etext) { | |||||
. = ALIGN(4); | |||||
_sdata = .; | |||||
*(.fastrun*) | |||||
*(.data*) | |||||
. = ALIGN(4); | |||||
_edata = .; | |||||
} > RAM | |||||
.noinit (NOLOAD) : { | |||||
*(.noinit*) | |||||
} > RAM | |||||
.bss : { | |||||
. = ALIGN(4); | |||||
_sbss = .; | |||||
__bss_start__ = .; | |||||
*(.bss*) | |||||
*(COMMON) | |||||
. = ALIGN(4); | |||||
_ebss = .; | |||||
__bss_end = .; | |||||
__bss_end__ = .; | |||||
} > RAM | |||||
_estack = ORIGIN(RAM) + LENGTH(RAM); | |||||
_teensy_model_identifier = 0x1F; | |||||
} | |||||
/* 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. | |||||
*/ | |||||
MEMORY | |||||
{ | |||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 1024K | |||||
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K | |||||
} | |||||
SECTIONS | |||||
{ | |||||
.text : { | |||||
. = 0; | |||||
KEEP(*(.vectors)) | |||||
*(.startup*) | |||||
/* TODO: does linker detect startup overflow onto flashconfig? */ | |||||
. = 0x400; | |||||
KEEP(*(.flashconfig*)) | |||||
*(.text*) | |||||
*(.rodata*) | |||||
. = ALIGN(4); | |||||
KEEP(*(.init)) | |||||
. = ALIGN(4); | |||||
__preinit_array_start = .; | |||||
KEEP (*(.preinit_array)) | |||||
__preinit_array_end = .; | |||||
__init_array_start = .; | |||||
KEEP (*(SORT(.init_array.*))) | |||||
KEEP (*(.init_array)) | |||||
__init_array_end = .; | |||||
} > FLASH = 0xFF | |||||
.ARM.exidx : { | |||||
__exidx_start = .; | |||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*) | |||||
__exidx_end = .; | |||||
} > FLASH | |||||
_etext = .; | |||||
.usbdescriptortable (NOLOAD) : { | |||||
/* . = ORIGIN(RAM); */ | |||||
. = ALIGN(512); | |||||
*(.usbdescriptortable*) | |||||
} > RAM | |||||
.dmabuffers (NOLOAD) : { | |||||
. = ALIGN(4); | |||||
*(.dmabuffers*) | |||||
} > RAM | |||||
.usbbuffers (NOLOAD) : { | |||||
. = ALIGN(4); | |||||
*(.usbbuffers*) | |||||
} > RAM | |||||
.data : AT (_etext) { | |||||
. = ALIGN(4); | |||||
_sdata = .; | |||||
*(.fastrun*) | |||||
*(.data*) | |||||
. = ALIGN(4); | |||||
_edata = .; | |||||
} > RAM | |||||
.noinit (NOLOAD) : { | |||||
*(.noinit*) | |||||
} > RAM | |||||
.bss : { | |||||
. = ALIGN(4); | |||||
_sbss = .; | |||||
__bss_start__ = .; | |||||
*(.bss*) | |||||
*(COMMON) | |||||
. = ALIGN(4); | |||||
_ebss = .; | |||||
__bss_end = .; | |||||
__bss_end__ = .; | |||||
} > RAM | |||||
_estack = ORIGIN(RAM) + LENGTH(RAM); | |||||
_teensy_model_identifier = 0x22; | |||||
} | |||||
/* 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. | |||||
*/ | |||||
MEMORY | |||||
{ | |||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 62K | |||||
RAM (rwx) : ORIGIN = 0x1FFFF800, LENGTH = 8K | |||||
} | |||||
SECTIONS | |||||
{ | |||||
.text : { | |||||
. = 0; | |||||
KEEP(*(.vectors)) | |||||
*(.startup*) | |||||
/* TODO: does linker detect startup overflow onto flashconfig? */ | |||||
. = 0x400; | |||||
KEEP(*(.flashconfig*)) | |||||
*(.text*) | |||||
*(.rodata*) | |||||
. = ALIGN(4); | |||||
KEEP(*(.init)) | |||||
. = ALIGN(4); | |||||
__preinit_array_start = .; | |||||
KEEP (*(.preinit_array)) | |||||
__preinit_array_end = .; | |||||
__init_array_start = .; | |||||
KEEP (*(SORT(.init_array.*))) | |||||
KEEP (*(.init_array)) | |||||
__init_array_end = .; | |||||
} > FLASH = 0xFF | |||||
.ARM.exidx : { | |||||
__exidx_start = .; | |||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*) | |||||
__exidx_end = .; | |||||
} > FLASH | |||||
_etext = .; | |||||
.usbdescriptortable (NOLOAD) : { | |||||
/* . = ORIGIN(RAM); */ | |||||
. = ALIGN(512); | |||||
*(.usbdescriptortable*) | |||||
} > RAM | |||||
.dmabuffers (NOLOAD) : { | |||||
. = ALIGN(4); | |||||
*(.dmabuffers*) | |||||
} > RAM | |||||
.usbbuffers (NOLOAD) : { | |||||
. = ALIGN(4); | |||||
*(.usbbuffers*) | |||||
} > RAM | |||||
.data : AT (_etext) { | |||||
. = ALIGN(4); | |||||
_sdata = .; | |||||
*(.fastrun*) | |||||
*(.data*) | |||||
. = ALIGN(4); | |||||
_edata = .; | |||||
} > RAM | |||||
.noinit (NOLOAD) : { | |||||
*(.noinit*) | |||||
} > RAM | |||||
.bss : { | |||||
. = ALIGN(4); | |||||
_sbss = .; | |||||
__bss_start__ = .; | |||||
*(.bss*) | |||||
*(COMMON) | |||||
. = ALIGN(4); | |||||
_ebss = .; | |||||
__bss_end = .; | |||||
__bss_end__ = .; | |||||
} > 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 <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <math.h> | |||||
size_t strlen(const char *s) | |||||
{ | |||||
size_t n=0; | |||||
while (*s++) n++; | |||||
return n; | |||||
} | |||||
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; | ||||
} | } | ||||
} | } | ||||
// TODO: actually write an efficient dtostrf().... | |||||
#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) | ||||
{ | { | ||||
char format[20]; | |||||
sprintf(format, "%%%d.%df", width, precision); | |||||
sprintf(buf, format, val); | |||||
int decpt, sign, reqd, pad; | |||||
const char *s, *e; | |||||
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); | |||||
// if only 1 digit in output | |||||
if (precision == 0 && decpt == 0) { | |||||
// round and move decimal point | |||||
s = (*s < '5') ? "0" : "1"; | |||||
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++; | |||||
p = buf; | |||||
e = p + reqd; | |||||
pad = width - reqd; | |||||
if (pad > 0) { | |||||
e += pad; | |||||
while (pad-- > 0) *p++ = ' '; | |||||
} | |||||
if (sign) *p++ = '-'; | |||||
if (decpt == 0 && precision > 0) { | |||||
*p++ = '0'; | |||||
*p++ = '.'; | |||||
} | |||||
else if (decpt < 0 && precision > 0) { | |||||
*p++ = '0'; | |||||
*p++ = '.'; | |||||
// print leading zeros | |||||
while ( decpt < 0 ) { | |||||
decpt++; | |||||
*p++ = '0'; | |||||
} | |||||
} | |||||
// print digits | |||||
while (p < e) { | |||||
*p++ = *s++; | |||||
if (p == e) break; | |||||
if (--decpt == 0) *p++ = '.'; | |||||
} | |||||
if (width < 0) { | |||||
pad = (reqd + width) * -1; | |||||
while (pad-- > 0) *p++ = ' '; | |||||
} | |||||
*p = 0; | |||||
//char format[20]; | |||||
//sprintf(format, "%%%d.%df", width, precision); | |||||
//sprintf(buf, format, val); | |||||
return buf; | return buf; | ||||
} | } | ||||
// 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> | ||||
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; | |||||
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; | |||||
// A0-A9 are always digital 14-23, for Arduino compatibility | |||||
#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__) | |||||
#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__) | |||||
#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__) | |||||
#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__) | |||||
#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 | |||||
#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 34 | |||||
#define NUM_ANALOG_INPUTS 14 | |||||
#define analogInputToDigitalPin(p) (((p) < 10) ? (p) + 14 : -1) | |||||
#define digitalPinHasPWM(p) (((p) >= 3 && (p) <= 6) || (p) == 9 || (p) == 10 || ((p) >= 20 && (p) <= 23)) | |||||
#define NUM_DIGITAL_PINS CORE_NUM_DIGITAL | |||||
#define NUM_ANALOG_INPUTS CORE_NUM_ANALOG | |||||
#define NOT_AN_INTERRUPT -1 | #define NOT_AN_INTERRUPT -1 | ||||
#define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1) | |||||
#if defined(__MK20DX128__) | |||||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) <= 13) ? (p) + 24 : -1)) | |||||
#define digitalPinHasPWM(p) (((p) >= 3 && (p) <= 6) || (p) == 9 || (p) == 10 || ((p) >= 20 && (p) <= 23)) | |||||
#define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1) | |||||
#elif defined(__MK20DX256__) | |||||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) <= 13) ? (p) + 24 : (((p) == 14) ? 40 : (((p) <= 20) ? (p) + 11 : -1)))) | |||||
#define digitalPinHasPWM(p) (((p) >= 3 && (p) <= 6) || (p) == 9 || (p) == 10 || ((p) >= 20 && (p) <= 23) || (p) == 25 || (p) == 32) | |||||
#define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1) | |||||
#elif defined(__MKL26Z64__) | |||||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) <= 12) ? (p) + 14 : -1)) | |||||
#define digitalPinHasPWM(p) ((p) == 3 || (p) == 4 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 16 || (p) == 17 || (p) == 20 || (p) == 22 || (p) == 23) | |||||
#define digitalPinToInterrupt(p) ((((p) >= 2 && (p) <= 15) || ((p) >= 20 && (p) <= 23)) ? (p) : -1) | |||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
// TODO analogInputToDigitalPin needs update... | |||||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) >= 12 && (p) <= 20) ? (p) + 19 : -1)) | |||||
#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) | |||||
#endif | |||||
#define digitalPinToPCICR(p) ((volatile uint8_t *)0) | |||||
#define digitalPinToPCICRbit(p) (0) | |||||
#define digitalPinToPCIFR(p) ((volatile uint8_t *)0) | |||||
#define digitalPinToPCIFRbit(p) (0) | |||||
#define digitalPinToPCMSK(p) ((volatile uint8_t *)0) | |||||
#define digitalPinToPCMSKbit(p) (0) | |||||
#if defined(KINETISK) | |||||
struct digital_pin_bitband_and_config_table_struct { | struct digital_pin_bitband_and_config_table_struct { | ||||
volatile uint32_t *reg; | volatile uint32_t *reg; | ||||
volatile uint32_t *config; | volatile uint32_t *config; | ||||
}; | }; | ||||
extern const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[]; | extern const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[]; | ||||
// compatibility macros | // compatibility macros | ||||
#define digitalPinToPort(pin) (pin) | #define digitalPinToPort(pin) (pin) | ||||
#define digitalPinToBitMask(pin) (1) | #define digitalPinToBitMask(pin) (1) | ||||
#define portInputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 128)) | #define portInputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 128)) | ||||
#define portModeRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 160)) | #define portModeRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 160)) | ||||
#define portConfigRegister(pin) ((volatile uint32_t *)(digital_pin_to_info_PGM[(pin)].config)) | #define portConfigRegister(pin) ((volatile uint32_t *)(digital_pin_to_info_PGM[(pin)].config)) | ||||
#define digitalPinToPortReg(pin) (portOutputRegister(pin)) | #define digitalPinToPortReg(pin) (portOutputRegister(pin)) | ||||
#define digitalPinToBit(pin) (1) | #define digitalPinToBit(pin) (1) | ||||
#elif defined(KINETISL) | |||||
struct digital_pin_bitband_and_config_table_struct { | |||||
volatile uint8_t *reg; | |||||
volatile uint32_t *config; | |||||
uint8_t mask; | |||||
}; | |||||
extern const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[]; | |||||
// compatibility macros | |||||
#define digitalPinToPort(pin) (pin) | |||||
#define digitalPinToBitMask(pin) (digital_pin_to_info_PGM[(pin)].mask) | |||||
#define portOutputRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 0)) | |||||
#define portSetRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 4)) | |||||
#define portClearRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 8)) | |||||
#define portToggleRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 12)) | |||||
#define portInputRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 16)) | |||||
#define portModeRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 20)) | |||||
#define portConfigRegister(pin) ((digital_pin_to_info_PGM[(pin)].config)) | |||||
#define digitalPinToPortReg(pin) (portOutputRegister(pin)) | |||||
//#define digitalPinToBit(pin) (1) | |||||
#endif | |||||
#define NOT_ON_TIMER 0 | #define NOT_ON_TIMER 0 | ||||
static inline uint8_t digitalPinToTimer(uint8_t) __attribute__((always_inline, unused)); | static inline uint8_t digitalPinToTimer(uint8_t) __attribute__((always_inline, unused)); | ||||
// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX | // SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX | ||||
// pins are NOT connected to anything by default. | // pins are NOT connected to anything by default. | ||||
// | // | ||||
#if F_CPU >= 20000000 && !defined(USB_DISABLED) | |||||
#define SERIAL_PORT_MONITOR Serial | #define SERIAL_PORT_MONITOR Serial | ||||
#else | |||||
#define SERIAL_PORT_MONITOR Serial1 | |||||
#endif | |||||
#define SERIAL_PORT_USBVIRTUAL Serial | #define SERIAL_PORT_USBVIRTUAL Serial | ||||
#define SERIAL_PORT_HARDWARE Serial1 | #define SERIAL_PORT_HARDWARE Serial1 | ||||
#define SERIAL_PORT_HARDWARE1 Serial2 | #define SERIAL_PORT_HARDWARE1 Serial2 | ||||
#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 | |||||
#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 "kinetis.h" | |||||
#include "ser_print.h" | |||||
#ifdef KINETISL | |||||
// Simple polling-only Serial1 support for Teensy-LC | |||||
// this is really only useful for extremely low-level troubleshooting | |||||
void ser_write(uint8_t c) | |||||
{ | |||||
while ((UART0_S1 & UART_S1_TDRE) == 0) /* wait */ ; | |||||
UART0_D = c; | |||||
} | |||||
void ser_print(const char *p) | |||||
{ | |||||
while (*p) { | |||||
char c = *p++; | |||||
if (c == '\n') ser_write('\r'); | |||||
ser_write(c); | |||||
} | |||||
} | |||||
static void ser_print_hex1(unsigned int n) | |||||
{ | |||||
n &= 15; | |||||
if (n < 10) { | |||||
ser_write('0' + n); | |||||
} else { | |||||
ser_write('A' - 10 + n); | |||||
} | |||||
} | |||||
void ser_print_hex(unsigned int n) | |||||
{ | |||||
ser_print_hex1(n >> 4); | |||||
ser_print_hex1(n); | |||||
} | |||||
void ser_print_hex32(unsigned int n) | |||||
{ | |||||
ser_print_hex(n >> 24); | |||||
ser_print_hex(n >> 16); | |||||
ser_print_hex(n >> 8); | |||||
ser_print_hex(n); | |||||
} | |||||
#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. | |||||
*/ | |||||
#ifdef __cplusplus | |||||
extern "C"{ | |||||
#endif | |||||
void ser_print(const char *p); | |||||
void ser_print_hex(unsigned int n); | |||||
void ser_print_hex32(unsigned int n); | |||||
#ifdef __cplusplus | |||||
} // extern "C" | |||||
#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. | ||||
// 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 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; | ||||
static volatile uint8_t *transmit_pin=NULL; | |||||
#if TX_BUFFER_SIZE > 255 | |||||
#if defined(KINETISK) | |||||
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 | |||||
#elif defined(KINETISL) | |||||
static volatile uint8_t *transmit_pin=NULL; | |||||
static uint8_t transmit_mask=0; | |||||
#define transmit_assert() *(transmit_pin+4) = transmit_mask; | |||||
#define transmit_deassert() *(transmit_pin+8) = transmit_mask; | |||||
static volatile uint8_t *rts_pin=NULL; | |||||
static uint8_t rts_mask=0; | |||||
#define rts_assert() *(rts_pin+8) = rts_mask; | |||||
#define rts_deassert() *(rts_pin+4) = rts_mask; | |||||
#endif | |||||
#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 | ||||
static volatile uint8_t rx_buffer_head = 0; | static volatile uint8_t rx_buffer_head = 0; | ||||
static volatile uint8_t rx_buffer_tail = 0; | static volatile uint8_t rx_buffer_tail = 0; | ||||
#endif | #endif | ||||
static uint8_t rx_pin_num = 0; | |||||
static uint8_t tx_pin_num = 1; | |||||
// 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 | ||||
#ifdef HAS_KINETISK_UART0_FIFO | |||||
#define C2_ENABLE UART_C2_TE | UART_C2_RE | UART_C2_RIE | UART_C2_ILIE | #define C2_ENABLE UART_C2_TE | UART_C2_RE | UART_C2_RIE | UART_C2_ILIE | ||||
#else | |||||
#define C2_ENABLE UART_C2_TE | UART_C2_RE | UART_C2_RIE | |||||
#endif | |||||
#define C2_TX_ACTIVE C2_ENABLE | UART_C2_TIE | #define C2_TX_ACTIVE C2_ENABLE | UART_C2_TIE | ||||
#define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE | #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE | ||||
#define C2_TX_INACTIVE C2_ENABLE | #define C2_TX_INACTIVE C2_ENABLE | ||||
tx_buffer_head = 0; | tx_buffer_head = 0; | ||||
tx_buffer_tail = 0; | tx_buffer_tail = 0; | ||||
transmitting = 0; | transmitting = 0; | ||||
CORE_PIN0_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); | |||||
CORE_PIN1_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); | |||||
switch (rx_pin_num) { | |||||
case 0: CORE_PIN0_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) | |||||
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 | |||||
} | |||||
switch (tx_pin_num) { | |||||
case 1: CORE_PIN1_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) | |||||
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 | |||||
} | |||||
#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_C1 = 0; | |||||
#ifdef HAS_KINETISK_UART0_FIFO | |||||
UART0_C1 = UART_C1_ILT; | UART0_C1 = UART_C1_ILT; | ||||
UART0_TWFIFO = 2; // tx watermark, causes S1_TDRE to set | UART0_TWFIFO = 2; // tx watermark, causes S1_TDRE to set | ||||
UART0_RWFIFO = 4; // rx watermark, causes S1_RDRF to set | UART0_RWFIFO = 4; // rx watermark, causes S1_RDRF to set | ||||
UART0_PFIFO = UART_PFIFO_TXFE | UART_PFIFO_RXFE; | UART0_PFIFO = UART_PFIFO_TXFE | UART_PFIFO_RXFE; | ||||
#else | |||||
UART0_C1 = 0; | |||||
UART0_PFIFO = 0; | |||||
#endif | |||||
#elif defined(HAS_KINETISL_UART0) | |||||
if (divisor < 1) divisor = 1; | |||||
UART0_BDH = (divisor >> 8) & 0x1F; | |||||
UART0_BDL = divisor & 0xFF; | |||||
UART0_C1 = 0; | |||||
#endif | |||||
UART0_C2 = C2_TX_INACTIVE; | UART0_C2 = C2_TX_INACTIVE; | ||||
NVIC_SET_PRIORITY(IRQ_UART0_STATUS, IRQ_PRIORITY); | NVIC_SET_PRIORITY(IRQ_UART0_STATUS, IRQ_PRIORITY); | ||||
NVIC_ENABLE_IRQ(IRQ_UART0_STATUS); | NVIC_ENABLE_IRQ(IRQ_UART0_STATUS); | ||||
void serial_format(uint32_t format) | void serial_format(uint32_t format) | ||||
{ | { | ||||
uint8_t c; | |||||
c = UART0_C1; | |||||
c = (c & ~0x13) | (format & 0x03); // configure parity | |||||
if (format & 0x04) c |= 0x10; // 9 bits (might include parity) | |||||
UART0_C1 = c; | |||||
if ((format & 0x0F) == 0x04) UART0_C3 |= 0x40; // 8N2 is 9 bit with 9th bit always 1 | |||||
c = UART0_S2 & ~0x10; | |||||
if (format & 0x10) c |= 0x10; // rx invert | |||||
UART0_S2 = c; | |||||
c = UART0_C3 & ~0x10; | |||||
if (format & 0x20) c |= 0x10; // tx invert | |||||
UART0_C3 = c; | |||||
uint8_t c; | |||||
c = UART0_C1; | |||||
c = (c & ~0x13) | (format & 0x03); // configure parity | |||||
if (format & 0x04) c |= 0x10; // 9 bits (might include parity) | |||||
UART0_C1 = c; | |||||
if ((format & 0x0F) == 0x04) UART0_C3 |= 0x40; // 8N2 is 9 bit with 9th bit always 1 | |||||
c = UART0_S2 & ~0x10; | |||||
if (format & 0x10) c |= 0x10; // rx invert | |||||
UART0_S2 = c; | |||||
c = UART0_C3 & ~0x10; | |||||
if (format & 0x20) c |= 0x10; // tx invert | |||||
UART0_C3 = c; | |||||
#ifdef SERIAL_9BIT_SUPPORT | #ifdef SERIAL_9BIT_SUPPORT | ||||
c = UART0_C4 & 0x1F; | |||||
if (format & 0x08) c |= 0x20; // 9 bit mode with parity (requires 10 bits) | |||||
UART0_C4 = c; | |||||
use9Bits = format & 0x80; | |||||
c = UART0_C4 & 0x1F; | |||||
if (format & 0x08) c |= 0x20; // 9 bit mode with parity (requires 10 bits) | |||||
UART0_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 = 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 | #endif | ||||
} | } | ||||
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(); | |||||
} | } | ||||
void serial_set_transmit_pin(uint8_t pin) | void serial_set_transmit_pin(uint8_t pin) | ||||
pinMode(pin, OUTPUT); | pinMode(pin, OUTPUT); | ||||
digitalWrite(pin, LOW); | digitalWrite(pin, LOW); | ||||
transmit_pin = portOutputRegister(pin); | transmit_pin = portOutputRegister(pin); | ||||
#if defined(KINETISL) | |||||
transmit_mask = digitalPinToBitMask(pin); | |||||
#endif | |||||
} | |||||
void serial_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_UART0)) { | |||||
switch (tx_pin_num & 127) { | |||||
case 1: CORE_PIN1_CONFIG = 0; break; // PTB17 | |||||
case 5: CORE_PIN5_CONFIG = 0; break; // PTD7 | |||||
#if defined(KINETISL) | |||||
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 | |||||
} | |||||
if (opendrain) { | |||||
cfg = PORT_PCR_DSE | PORT_PCR_ODE; | |||||
} else { | |||||
cfg = PORT_PCR_DSE | PORT_PCR_SRE; | |||||
} | |||||
switch (pin & 127) { | |||||
case 1: CORE_PIN1_CONFIG = cfg | PORT_PCR_MUX(3); break; | |||||
case 5: CORE_PIN5_CONFIG = cfg | PORT_PCR_MUX(3); break; | |||||
#if defined(KINETISL) | |||||
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 | |||||
} | |||||
} | |||||
tx_pin_num = pin; | |||||
} | |||||
void serial_set_rx(uint8_t pin) | |||||
{ | |||||
if (pin == rx_pin_num) return; | |||||
if ((SIM_SCGC4 & SIM_SCGC4_UART0)) { | |||||
switch (rx_pin_num) { | |||||
case 0: CORE_PIN0_CONFIG = 0; break; // PTB16 | |||||
case 21: CORE_PIN21_CONFIG = 0; break; // PTD6 | |||||
#if defined(KINETISL) | |||||
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 | |||||
} | |||||
switch (pin) { | |||||
case 0: CORE_PIN0_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) | |||||
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 | |||||
} | |||||
} | |||||
rx_pin_num = pin; | |||||
} | |||||
int serial_set_rts(uint8_t pin) | |||||
{ | |||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return 0; | |||||
if (pin < CORE_NUM_DIGITAL) { | |||||
rts_pin = portOutputRegister(pin); | |||||
#if defined(KINETISL) | |||||
rts_mask = digitalPinToBitMask(pin); | |||||
#endif | |||||
pinMode(pin, OUTPUT); | |||||
rts_assert(); | |||||
} else { | |||||
rts_pin = NULL; | |||||
return 0; | |||||
} | |||||
/* | |||||
if (pin == 6) { | |||||
CORE_PIN6_CONFIG = PORT_PCR_MUX(3); | |||||
} else if (pin == 19) { | |||||
CORE_PIN19_CONFIG = PORT_PCR_MUX(3); | |||||
} else { | |||||
UART0_MODEM &= ~UART_MODEM_RXRTSE; | |||||
return 0; | |||||
} | |||||
UART0_MODEM |= UART_MODEM_RXRTSE; | |||||
*/ | |||||
return 1; | |||||
} | |||||
int serial_set_cts(uint8_t pin) | |||||
{ | |||||
#if defined(KINETISK) | |||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return 0; | |||||
if (pin == 18) { | |||||
CORE_PIN18_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_PE; // weak pulldown | |||||
} else if (pin == 20) { | |||||
CORE_PIN20_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_PE; // weak pulldown | |||||
} else { | |||||
UART0_MODEM &= ~UART_MODEM_TXCTSE; | |||||
return 0; | |||||
} | |||||
UART0_MODEM |= UART_MODEM_TXCTSE; | |||||
return 1; | |||||
#else | |||||
return 0; | |||||
#endif | |||||
} | } | ||||
void serial_putchar(uint32_t c) | void serial_putchar(uint32_t c) | ||||
uint32_t head, n; | uint32_t head, n; | ||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return; | if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return; | ||||
if (transmit_pin) *transmit_pin = 1; | |||||
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; | ||||
UART0_C2 = C2_TX_ACTIVE; | UART0_C2 = C2_TX_ACTIVE; | ||||
} | } | ||||
#ifdef HAS_KINETISK_UART0_FIFO | |||||
void serial_write(const void *buf, unsigned int count) | void serial_write(const void *buf, unsigned int count) | ||||
{ | { | ||||
const uint8_t *p = (const uint8_t *)buf; | const uint8_t *p = (const uint8_t *)buf; | ||||
const uint8_t *end = p + count; | const uint8_t *end = p + count; | ||||
uint32_t head, n; | |||||
uint32_t head, n; | |||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return; | |||||
if (transmit_pin) *transmit_pin = 1; | |||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return; | |||||
if (transmit_pin) transmit_assert(); | |||||
while (p < end) { | while (p < end) { | ||||
head = tx_buffer_head; | |||||
if (++head >= TX_BUFFER_SIZE) head = 0; | |||||
head = tx_buffer_head; | |||||
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 { | ||||
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; | ||||
} | } | ||||
} while (tx_buffer_tail == head); | } while (tx_buffer_tail == head); | ||||
} | } | ||||
tx_buffer[head] = *p++; | |||||
transmitting = 1; | |||||
tx_buffer_head = head; | |||||
tx_buffer[head] = *p++; | |||||
transmitting = 1; | |||||
tx_buffer_head = head; | |||||
} | } | ||||
UART0_C2 = C2_TX_ACTIVE; | |||||
UART0_C2 = C2_TX_ACTIVE; | |||||
} | } | ||||
#else | |||||
void serial_write(const void *buf, unsigned int count) | |||||
{ | |||||
const uint8_t *p = (const uint8_t *)buf; | |||||
while (count-- > 0) serial_putchar(*p++); | |||||
} | |||||
#endif | |||||
void serial_flush(void) | void serial_flush(void) | ||||
{ | { | ||||
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) { | |||||
int avail; | |||||
if (head >= tail) avail = head - tail; | |||||
else avail = SERIAL1_RX_BUFFER_SIZE + head - tail; | |||||
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]; | ||||
} | } | ||||
void serial_clear(void) | void serial_clear(void) | ||||
{ | { | ||||
#ifdef HAS_KINETISK_UART0_FIFO | |||||
if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return; | if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return; | ||||
UART0_C2 &= ~(UART_C2_RE | UART_C2_RIE | UART_C2_ILIE); | UART0_C2 &= ~(UART_C2_RE | UART_C2_RIE | UART_C2_ILIE); | ||||
UART0_CFIFO = UART_CFIFO_RXFLUSH; | UART0_CFIFO = UART_CFIFO_RXFLUSH; | ||||
UART0_C2 |= (UART_C2_RE | UART_C2_RIE | UART_C2_ILIE); | UART0_C2 |= (UART_C2_RE | UART_C2_RIE | UART_C2_ILIE); | ||||
#endif | |||||
rx_buffer_head = rx_buffer_tail; | rx_buffer_head = rx_buffer_tail; | ||||
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 | |||||
// Idle line UART_S1_IDLE | |||||
// Transmit complete UART_S1_TC | |||||
// Idle line UART_S1_IDLE | |||||
// Receive data above watermark UART_S1_RDRF | // Receive data above watermark UART_S1_RDRF | ||||
// LIN break detect UART_S2_LBKDIF | |||||
// RxD pin active edge UART_S2_RXEDGIF | |||||
// LIN break detect UART_S2_LBKDIF | |||||
// RxD pin active edge UART_S2_RXEDGIF | |||||
void uart0_status_isr(void) | void uart0_status_isr(void) | ||||
{ | { | ||||
uint32_t head, newhead, tail, n; | |||||
uint8_t avail, c; | |||||
uint32_t head, tail, n; | |||||
uint8_t c; | |||||
#ifdef HAS_KINETISK_UART0_FIFO | |||||
uint32_t newhead; | |||||
uint8_t avail; | |||||
if (UART0_S1 & (UART_S1_RDRF | UART_S1_IDLE)) { | if (UART0_S1 & (UART_S1_RDRF | UART_S1_IDLE)) { | ||||
__disable_irq(); | __disable_irq(); | ||||
head = rx_buffer_head; | head = rx_buffer_head; | ||||
tail = rx_buffer_tail; | tail = rx_buffer_tail; | ||||
do { | do { | ||||
n = UART0_D; | |||||
if (use9Bits && (UART0_C3 & 0x80)) n |= 0x100; | |||||
if (use9Bits && (UART0_C3 & 0x80)) { | |||||
n = UART0_D | 0x100; | |||||
} else { | |||||
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; | ||||
} | } | ||||
} while (--avail > 0); | } while (--avail > 0); | ||||
rx_buffer_head = head; | rx_buffer_head = head; | ||||
if (rts_pin) { | |||||
int avail; | |||||
if (head >= tail) avail = head - tail; | |||||
else avail = SERIAL1_RX_BUFFER_SIZE + head - tail; | |||||
if (avail >= RTS_HIGH_WATERMARK) rts_deassert(); | |||||
} | |||||
} | } | ||||
} | } | ||||
c = UART0_C2; | c = UART0_C2; | ||||
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); | ||||
tx_buffer_tail = tail; | tx_buffer_tail = tail; | ||||
if (UART0_S1 & UART_S1_TDRE) UART0_C2 = C2_TX_COMPLETING; | if (UART0_S1 & UART_S1_TDRE) UART0_C2 = C2_TX_COMPLETING; | ||||
} | } | ||||
#else | |||||
if (UART0_S1 & UART_S1_RDRF) { | |||||
if (use9Bits && (UART0_C3 & 0x80)) { | |||||
n = UART0_D | 0x100; | |||||
} else { | |||||
n = UART0_D; | |||||
} | |||||
head = rx_buffer_head + 1; | |||||
if (head >= SERIAL1_RX_BUFFER_SIZE) head = 0; | |||||
if (head != rx_buffer_tail) { | |||||
rx_buffer[head] = n; | |||||
rx_buffer_head = head; | |||||
} | |||||
} | |||||
c = UART0_C2; | |||||
if ((c & UART_C2_TIE) && (UART0_S1 & UART_S1_TDRE)) { | |||||
head = tx_buffer_head; | |||||
tail = tx_buffer_tail; | |||||
if (head == tail) { | |||||
UART0_C2 = C2_TX_COMPLETING; | |||||
} else { | |||||
if (++tail >= SERIAL1_TX_BUFFER_SIZE) tail = 0; | |||||
n = tx_buffer[tail]; | |||||
if (use9Bits) UART0_C3 = (UART0_C3 & ~0x40) | ((n & 0x100) >> 2); | |||||
UART0_D = n; | |||||
tx_buffer_tail = tail; | |||||
} | |||||
} | |||||
#endif | |||||
if ((c & UART_C2_TCIE) && (UART0_S1 & UART_S1_TC)) { | if ((c & UART_C2_TCIE) && (UART0_S1 & UART_S1_TC)) { | ||||
transmitting = 0; | transmitting = 0; | ||||
if (transmit_pin) *transmit_pin = 0; | |||||
if (transmit_pin) transmit_deassert(); | |||||
UART0_C2 = C2_TX_INACTIVE; | UART0_C2 = C2_TX_INACTIVE; | ||||
} | } | ||||
} | } |