diff options
Diffstat (limited to 'cores/arduino')
-rw-r--r-- | cores/arduino/Arduino.h | 19 | ||||
-rw-r--r-- | cores/arduino/CDC.cpp | 30 | ||||
-rw-r--r-- | cores/arduino/HardwareSerial.cpp | 63 | ||||
-rw-r--r-- | cores/arduino/Stream.cpp | 1 | ||||
-rw-r--r-- | cores/arduino/USBAPI.h | 2 | ||||
-rw-r--r-- | cores/arduino/USBCore.cpp | 16 | ||||
-rw-r--r-- | cores/arduino/USBCore.h | 3 | ||||
-rw-r--r-- | cores/arduino/WInterrupts.c | 14 | ||||
-rw-r--r-- | cores/arduino/WString.cpp | 2 | ||||
-rw-r--r-- | cores/arduino/new.cpp | 5 | ||||
-rw-r--r-- | cores/arduino/new.h | 1 | ||||
-rw-r--r-- | cores/arduino/wiring.c | 2 | ||||
-rw-r--r-- | cores/arduino/wiring_shift.c | 11 |
13 files changed, 101 insertions, 68 deletions
diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h index 09c1448..91eeb16 100644 --- a/cores/arduino/Arduino.h +++ b/cores/arduino/Arduino.h @@ -111,7 +111,8 @@ void yield(void); #define bitRead(value, bit) (((value) >> (bit)) & 0x01) #define bitSet(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 bitToggle(value, bit) ((value) ^= (1UL << (bit))) +#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit)) // avr-libc defines _NOP() since 1.6.2 #ifndef _NOP @@ -130,16 +131,16 @@ void initVariant(void); int atexit(void (*func)()) __attribute__((weak)); -void pinMode(uint8_t, uint8_t); -void digitalWrite(uint8_t, uint8_t); -int digitalRead(uint8_t); -int analogRead(uint8_t); +void pinMode(uint8_t pin, uint8_t mode); +void digitalWrite(uint8_t pin, uint8_t val); +int digitalRead(uint8_t pin); +int analogRead(uint8_t pin); void analogReference(uint8_t mode); -void analogWrite(uint8_t, int); +void analogWrite(uint8_t pin, int val); unsigned long millis(void); unsigned long micros(void); -void delay(unsigned long); +void delay(unsigned long ms); void delayMicroseconds(unsigned int us); unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout); @@ -147,8 +148,8 @@ unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout); void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); -void attachInterrupt(uint8_t, void (*)(void), int mode); -void detachInterrupt(uint8_t); +void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode); +void detachInterrupt(uint8_t interruptNum); void setup(void); void loop(void); diff --git a/cores/arduino/CDC.cpp b/cores/arduino/CDC.cpp index 0a743e1..4ff6b9b 100644 --- a/cores/arduino/CDC.cpp +++ b/cores/arduino/CDC.cpp @@ -34,14 +34,14 @@ typedef struct static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 }; static volatile int32_t breakValue = -1; -bool _updatedLUFAbootloader = false; +static u8 wdtcsr_save; #define WEAK __attribute__ ((weak)) extern const CDCDescriptor _cdcInterface PROGMEM; const CDCDescriptor _cdcInterface = { - D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1), + D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), // CDC communication interface D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), @@ -57,6 +57,11 @@ const CDCDescriptor _cdcInterface = D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0) }; +bool isLUFAbootloader() +{ + return pgm_read_word(FLASHEND - 1) == NEW_LUFA_SIGNATURE; +} + int CDC_GetInterface(u8* interfaceNum) { interfaceNum[0] += 2; // uses 2 @@ -92,10 +97,7 @@ bool CDC_Setup(USBSetup& setup) if (CDC_SET_CONTROL_LINE_STATE == r) { _usbLineInfo.lineState = setup.wValueL; - } - if (CDC_SET_LINE_CODING == r || CDC_SET_CONTROL_LINE_STATE == r) - { // auto-reset into the bootloader is triggered when the port, already // open at 1200 bps, is closed. this is the signal to start the watchdog // with a relatively long period so it can finish housekeeping tasks @@ -109,7 +111,7 @@ bool CDC_Setup(USBSetup& setup) #if MAGIC_KEY_POS != (RAMEND-1) // For future boards save the key in the inproblematic RAMEND // Which is reserved for the main() return value (which will never return) - if (_updatedLUFAbootloader) { + if (isLUFAbootloader()) { // horray, we got a new bootloader! magic_key_pos = (RAMEND-1); } @@ -119,25 +121,31 @@ bool CDC_Setup(USBSetup& setup) if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) { #if MAGIC_KEY_POS != (RAMEND-1) - // Backup ram value if its not a newer bootloader. + // Backup ram value if its not a newer bootloader and it hasn't already been saved. // This should avoid memory corruption at least a bit, not fully - if (magic_key_pos != (RAMEND-1)) { + if (magic_key_pos != (RAMEND-1) && *(uint16_t *)magic_key_pos != MAGIC_KEY) { *(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos; } #endif // Store boot key *(uint16_t *)magic_key_pos = MAGIC_KEY; + // Save the watchdog state in case the reset is aborted. + wdtcsr_save = WDTCSR; wdt_enable(WDTO_120MS); } - else + else if (*(uint16_t *)magic_key_pos == MAGIC_KEY) { // Most OSs do some intermediate steps when configuring ports and DTR can // twiggle more than once before stabilizing. - // To avoid spurious resets we set the watchdog to 250ms and eventually + // To avoid spurious resets we set the watchdog to 120ms and eventually // cancel if DTR goes back high. + // Cancellation is only done if an auto-reset was started, which is + // indicated by the magic key having been set. - wdt_disable(); wdt_reset(); + // Restore the watchdog state in case the sketch was using it. + WDTCSR |= (1<<WDCE) | (1<<WDE); + WDTCSR = wdtcsr_save; #if MAGIC_KEY_POS != (RAMEND-1) // Restore backed up (old bootloader) magic key data if (magic_key_pos != (RAMEND-1)) { diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index 5cd89e5..e99d503 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -26,6 +26,7 @@ #include <stdio.h> #include <string.h> #include <inttypes.h> +#include <util/atomic.h> #include "Arduino.h" #include "HardwareSerial.h" @@ -76,6 +77,13 @@ void serialEventRun(void) #endif } +// macro to guard critical sections when needed for large TX buffer sizes +#if (SERIAL_TX_BUFFER_SIZE>256) +#define TX_BUFFER_ATOMIC ATOMIC_BLOCK(ATOMIC_RESTORESTATE) +#else +#define TX_BUFFER_ATOMIC +#endif + // Actual interrupt handlers ////////////////////////////////////////////////////////////// void HardwareSerial::_tx_udr_empty_irq(void) @@ -89,8 +97,14 @@ void HardwareSerial::_tx_udr_empty_irq(void) // clear the TXC bit -- "can be cleared by writing a one to its bit // location". This makes sure flush() won't return until the bytes - // actually got written - sbi(*_ucsra, TXC0); + // actually got written. Other r/w bits are preserved, and zeroes + // written to the rest. + +#ifdef MPCM0 + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0); +#else + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << TXC0))); +#endif if (_tx_buffer_head == _tx_buffer_tail) { // Buffer empty, so disable interrupts @@ -177,15 +191,13 @@ int HardwareSerial::read(void) int HardwareSerial::availableForWrite(void) { -#if (SERIAL_TX_BUFFER_SIZE>256) - uint8_t oldSREG = SREG; - cli(); -#endif - tx_buffer_index_t head = _tx_buffer_head; - tx_buffer_index_t tail = _tx_buffer_tail; -#if (SERIAL_TX_BUFFER_SIZE>256) - SREG = oldSREG; -#endif + tx_buffer_index_t head; + tx_buffer_index_t tail; + + TX_BUFFER_ATOMIC { + head = _tx_buffer_head; + tail = _tx_buffer_tail; + } if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail; return tail - head - 1; } @@ -218,8 +230,22 @@ size_t HardwareSerial::write(uint8_t c) // significantly improve the effective datarate at high (> // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) { - *_udr = c; - sbi(*_ucsra, TXC0); + // If TXC is cleared before writing UDR and the previous byte + // completes before writing to UDR, TXC will be set but a byte + // is still being transmitted causing flush() to return too soon. + // So writing UDR must happen first. + // Writing UDR and clearing TC must be done atomically, otherwise + // interrupts might delay the TXC clear so the byte written to UDR + // is transmitted (setting TXC) before clearing TXC. Then TXC will + // be cleared when no bytes are left, causing flush() to hang + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + *_udr = c; +#ifdef MPCM0 + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0); +#else + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << TXC0))); +#endif + } return 1; } tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE; @@ -240,9 +266,14 @@ size_t HardwareSerial::write(uint8_t c) } _tx_buffer[_tx_buffer_head] = c; - _tx_buffer_head = i; - - sbi(*_ucsrb, UDRIE0); + + // make atomic to prevent execution of ISR between setting the + // head pointer and setting the interrupt flag resulting in buffer + // retransmission + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + _tx_buffer_head = i; + sbi(*_ucsrb, UDRIE0); + } return 1; } diff --git a/cores/arduino/Stream.cpp b/cores/arduino/Stream.cpp index d284631..9eff663 100644 --- a/cores/arduino/Stream.cpp +++ b/cores/arduino/Stream.cpp @@ -218,7 +218,6 @@ size_t Stream::readBytes(char *buffer, size_t length) size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) { - if (length < 1) return 0; size_t index = 0; while (index < length) { int c = timedRead(); diff --git a/cores/arduino/USBAPI.h b/cores/arduino/USBAPI.h index 479ced9..701a14f 100644 --- a/cores/arduino/USBAPI.h +++ b/cores/arduino/USBAPI.h @@ -65,6 +65,8 @@ public: void detach(); // Serial port goes down too... void poll(); bool wakeupHost(); // returns false, when wakeup cannot be processed + + bool isSuspended(); }; extern USBDevice_ USBDevice; diff --git a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp index e00fb02..dc6bc38 100644 --- a/cores/arduino/USBCore.cpp +++ b/cores/arduino/USBCore.cpp @@ -35,7 +35,6 @@ extern const u16 STRING_LANGUAGE[] PROGMEM; extern const u8 STRING_PRODUCT[] PROGMEM; extern const u8 STRING_MANUFACTURER[] PROGMEM; extern const DeviceDescriptor USB_DeviceDescriptorIAD PROGMEM; -extern bool _updatedLUFAbootloader; const u16 STRING_LANGUAGE[2] = { (3<<8) | (2+2), @@ -497,14 +496,13 @@ bool SendConfiguration(int maxlen) static bool SendDescriptor(USBSetup& setup) { - int ret; u8 t = setup.wValueH; if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) return SendConfiguration(setup.wLength); InitControl(setup.wLength); #ifdef PLUGGABLE_USB_ENABLED - ret = PluggableUSB().getDescriptor(setup); + int ret = PluggableUSB().getDescriptor(setup); if (ret != 0) { return (ret > 0 ? true : false); } @@ -819,12 +817,6 @@ void USBDevice_::attach() UDIEN = (1<<EORSTE) | (1<<SOFE) | (1<<SUSPE); // Enable interrupts for EOR (End of Reset), SOF (start of frame) and SUSPEND TX_RX_LED_INIT; - -#if MAGIC_KEY_POS != (RAMEND-1) - if (pgm_read_word(FLASHEND - 1) == NEW_LUFA_SIGNATURE) { - _updatedLUFAbootloader = true; - } -#endif } void USBDevice_::detach() @@ -862,4 +854,10 @@ bool USBDevice_::wakeupHost() return false; } +bool USBDevice_::isSuspended() +{ + return (_usbSuspendState & (1 << SUSPI)); +} + + #endif /* if defined(USBCON) */ diff --git a/cores/arduino/USBCore.h b/cores/arduino/USBCore.h index 5e0c7b3..0c63c2b 100644 --- a/cores/arduino/USBCore.h +++ b/cores/arduino/USBCore.h @@ -288,8 +288,7 @@ typedef struct // Old Caterina bootloader places the MAGIC key into unsafe RAM locations (it can be rewritten // by the running sketch before to actual reboot). // Newer bootloaders, recognizable by the LUFA "signature" at the end of the flash, can handle both -// the usafe and the safe location. Check once (in USBCore.cpp) if the bootloader in new, then set the global -// _updatedLUFAbootloader variable to true/false and place the magic key consequently +// the usafe and the safe location. #ifndef MAGIC_KEY #define MAGIC_KEY 0x7777 #endif diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index cef1106..ac72dda 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -65,7 +65,6 @@ static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = { nothing, #endif }; -// volatile static voidFuncPtr twiIntFunc; void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) { if(interruptNum < EXTERNAL_NUM_INTERRUPTS) { @@ -274,11 +273,6 @@ void detachInterrupt(uint8_t interruptNum) { } } -/* -void attachInterruptTwi(void (*userFunc)(void) ) { - twiIntFunc = userFunc; -} -*/ #define IMPLEMENT_ISR(vect, interrupt) \ ISR(vect) { \ @@ -314,11 +308,3 @@ IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_2) #endif #endif - -/* -ISR(TWI_vect) { - if(twiIntFunc) - twiIntFunc(); -} -*/ - diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index f2572d6..043fda7 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -121,7 +121,7 @@ String::String(double value, unsigned char decimalPlaces) String::~String() { - free(buffer); + if (buffer) free(buffer); } /*********************************************/ diff --git a/cores/arduino/new.cpp b/cores/arduino/new.cpp index cf6f89c..fc30cf8 100644 --- a/cores/arduino/new.cpp +++ b/cores/arduino/new.cpp @@ -26,6 +26,11 @@ void *operator new[](size_t size) { return malloc(size); } +void * operator new(size_t size, void * ptr) noexcept { + (void)size; + return ptr; +} + void operator delete(void * ptr) { free(ptr); } diff --git a/cores/arduino/new.h b/cores/arduino/new.h index 6e1b68f..763f5cc 100644 --- a/cores/arduino/new.h +++ b/cores/arduino/new.h @@ -23,6 +23,7 @@ void * operator new(size_t size); void * operator new[](size_t size); +void * operator new(size_t size, void * ptr) noexcept; void operator delete(void * ptr); void operator delete[](void * ptr); diff --git a/cores/arduino/wiring.c b/cores/arduino/wiring.c index b956f78..9727135 100644 --- a/cores/arduino/wiring.c +++ b/cores/arduino/wiring.c @@ -39,7 +39,7 @@ volatile unsigned long timer0_overflow_count = 0; volatile unsigned long timer0_millis = 0; static unsigned char timer0_fract = 0; -#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) +#if defined(TIM0_OVF_vect) ISR(TIM0_OVF_vect) #else ISR(TIMER0_OVF_vect) diff --git a/cores/arduino/wiring_shift.c b/cores/arduino/wiring_shift.c index 2b6f7a8..a9b3be5 100644 --- a/cores/arduino/wiring_shift.c +++ b/cores/arduino/wiring_shift.c @@ -42,10 +42,13 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) uint8_t i; for (i = 0; i < 8; i++) { - if (bitOrder == LSBFIRST) - digitalWrite(dataPin, !!(val & (1 << i))); - else - digitalWrite(dataPin, !!(val & (1 << (7 - i)))); + if (bitOrder == LSBFIRST) { + digitalWrite(dataPin, val & 1); + val >>= 1; + } else { + digitalWrite(dataPin, (val & 128) != 0); + val <<= 1; + } digitalWrite(clockPin, HIGH); digitalWrite(clockPin, LOW); |