diff options
Diffstat (limited to 'cores/arduino')
38 files changed, 788 insertions, 882 deletions
diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h index e12ac82..f1da68d 100644 --- a/cores/arduino/Arduino.h +++ b/cores/arduino/Arduino.h @@ -21,6 +21,7 @@ #define Arduino_h #include <stdlib.h> +#include <stdbool.h> #include <string.h> #include <math.h> @@ -43,9 +44,6 @@ void yield(void); #define OUTPUT 0x1 #define INPUT_PULLUP 0x2 -#define true 0x1 -#define false 0x0 - #define PI 3.1415926535897932384626433832795 #define HALF_PI 1.5707963267948966192313216916398 #define TWO_PI 6.283185307179586476925286766559 @@ -116,10 +114,13 @@ typedef unsigned int word; #define bit(b) (1UL << (b)) -typedef uint8_t boolean; +typedef bool boolean; typedef uint8_t byte; void init(void); +void initVariant(void); + +int atexit(void (*func)()) __attribute__((weak)); void pinMode(uint8_t, uint8_t); void digitalWrite(uint8_t, uint8_t); @@ -133,6 +134,7 @@ unsigned long micros(void); void delay(unsigned long); 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); 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); @@ -196,20 +198,21 @@ extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; #define TIMER0B 2 #define TIMER1A 3 #define TIMER1B 4 -#define TIMER2 5 -#define TIMER2A 6 -#define TIMER2B 7 - -#define TIMER3A 8 -#define TIMER3B 9 -#define TIMER3C 10 -#define TIMER4A 11 -#define TIMER4B 12 -#define TIMER4C 13 -#define TIMER4D 14 -#define TIMER5A 15 -#define TIMER5B 16 -#define TIMER5C 17 +#define TIMER1C 5 +#define TIMER2 6 +#define TIMER2A 7 +#define TIMER2B 8 + +#define TIMER3A 9 +#define TIMER3B 10 +#define TIMER3C 11 +#define TIMER4A 12 +#define TIMER4B 13 +#define TIMER4C 14 +#define TIMER4D 15 +#define TIMER5A 16 +#define TIMER5B 17 +#define TIMER5C 18 #ifdef __cplusplus } // extern "C" @@ -230,6 +233,7 @@ uint16_t makeWord(byte h, byte l); #define word(...) makeWord(__VA_ARGS__) unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); +unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); void noTone(uint8_t _pin); @@ -237,7 +241,7 @@ void noTone(uint8_t _pin); // WMath prototypes long random(long); long random(long, long); -void randomSeed(unsigned int); +void randomSeed(unsigned long); long map(long, long, long, long, long); #endif diff --git a/cores/arduino/CDC.cpp b/cores/arduino/CDC.cpp index a691306..5d4f2a0 100644 --- a/cores/arduino/CDC.cpp +++ b/cores/arduino/CDC.cpp @@ -16,7 +16,6 @@ ** SOFTWARE. */ -#include "Platform.h" #include "USBAPI.h" #include <avr/wdt.h> @@ -80,98 +79,81 @@ bool WEAK CDC_Setup(Setup& setup) if (CDC_SET_LINE_CODING == r) { USB_RecvControl((void*)&_usbLineInfo,7); - return true; } 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 // like servicing endpoints before the sketch ends - if (1200 == _usbLineInfo.dwDTERate) { - // We check DTR state to determine if host port is open (bit 0 of lineState). - if ((_usbLineInfo.lineState & 0x01) == 0) { - *(uint16_t *)0x0800 = 0x7777; - wdt_enable(WDTO_120MS); - } else { - // 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 - // cancel if DTR goes back high. - - wdt_disable(); - wdt_reset(); - *(uint16_t *)0x0800 = 0x0; - } + + // We check DTR state to determine if host port is open (bit 0 of lineState). + if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) + { + *(uint16_t *)0x0800 = 0x7777; + wdt_enable(WDTO_120MS); + } + else + { + // 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 + // cancel if DTR goes back high. + + wdt_disable(); + wdt_reset(); + *(uint16_t *)0x0800 = 0x0; } - return true; } + return true; } return false; } -int _serialPeek = -1; -void Serial_::begin(unsigned long baud_count) +void Serial_::begin(unsigned long /* baud_count */) { + peek_buffer = -1; } -void Serial_::begin(unsigned long baud_count, byte config) +void Serial_::begin(unsigned long /* baud_count */, byte /* config */) { + peek_buffer = -1; } void Serial_::end(void) { } -void Serial_::accept(void) -{ - int i = (unsigned int)(_rx_buffer_head+1) % SERIAL_BUFFER_SIZE; - - // if we should be storing the received character into the location - // just before the tail (meaning that the head would advance to the - // current location of the tail), we're about to overflow the buffer - // and so we don't write the character or advance the head. - - // while we have room to store a byte - while (i != _rx_buffer_tail) { - int c = USB_Recv(CDC_RX); - if (c == -1) - break; // no more data - _rx_buffer[_rx_buffer_head] = c; - _rx_buffer_head = i; - - i = (unsigned int)(_rx_buffer_head+1) % SERIAL_BUFFER_SIZE; - } -} - int Serial_::available(void) { - return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail) % SERIAL_BUFFER_SIZE; + if (peek_buffer >= 0) { + return 1 + USB_Available(CDC_RX); + } + return USB_Available(CDC_RX); } int Serial_::peek(void) { - if (_rx_buffer_head == _rx_buffer_tail) { - return -1; - } else { - return _rx_buffer[_rx_buffer_tail]; - } + if (peek_buffer < 0) + peek_buffer = USB_Recv(CDC_RX); + return peek_buffer; } int Serial_::read(void) { - // if the head isn't ahead of the tail, we don't have any characters - if (_rx_buffer_head == _rx_buffer_tail) { - return -1; - } else { - unsigned char c = _rx_buffer[_rx_buffer_tail]; - _rx_buffer_tail = (unsigned int)(_rx_buffer_tail + 1) % SERIAL_BUFFER_SIZE; + if (peek_buffer >= 0) { + int c = peek_buffer; + peek_buffer = -1; return c; - } + } + return USB_Recv(CDC_RX); } void Serial_::flush(void) @@ -181,6 +163,11 @@ void Serial_::flush(void) size_t Serial_::write(uint8_t c) { + return write(&c, 1); +} + +size_t Serial_::write(const uint8_t *buffer, size_t size) +{ /* only try to send bytes if the high-level CDC connection itself is open (not just the pipe) - the OS should set lineState when the port is opened and clear lineState when the port is closed. @@ -191,7 +178,7 @@ size_t Serial_::write(uint8_t c) // open connection isn't broken cleanly (cable is yanked out, host dies // or locks up, or host virtual serial port hangs) if (_usbLineInfo.lineState > 0) { - int r = USB_Send(CDC_TX,&c,1); + int r = USB_Send(CDC_TX,buffer,size); if (r > 0) { return r; } else { diff --git a/cores/arduino/HID.cpp b/cores/arduino/HID.cpp index ac63608..75c37b2 100644 --- a/cores/arduino/HID.cpp +++ b/cores/arduino/HID.cpp @@ -16,9 +16,7 @@ ** SOFTWARE. */ -#include "Platform.h" #include "USBAPI.h" -#include "USBDesc.h" #if defined(USBCON) #ifdef HID_ENABLED @@ -106,7 +104,7 @@ const u8 _hidReportDescriptor[] = { 0x81, 0x00, // INPUT (Data,Ary,Abs) 0xc0, // END_COLLECTION -#if RAWHID_ENABLED +#ifdef RAWHID_ENABLED // RAW HID 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), // 30 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), @@ -151,7 +149,7 @@ int WEAK HID_GetInterface(u8* interfaceNum) return USB_SendControl(TRANSFER_PGM,&_hidInterface,sizeof(_hidInterface)); } -int WEAK HID_GetDescriptor(int i) +int WEAK HID_GetDescriptor(int /* i */) { return USB_SendControl(TRANSFER_PGM,_hidReportDescriptor,sizeof(_hidReportDescriptor)); } @@ -510,11 +508,11 @@ void Keyboard_::releaseAll(void) size_t Keyboard_::write(uint8_t c) { - uint8_t p = press(c); // Keydown - uint8_t r = release(c); // Keyup - return (p); // just return the result of press() since release() almost always returns 1 + uint8_t p = press(c); // Keydown + release(c); // Keyup + return p; // just return the result of press() since release() almost always returns 1 } #endif -#endif /* if defined(USBCON) */
\ No newline at end of file +#endif /* if defined(USBCON) */ diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index a270ace..a2029a8 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -72,7 +72,7 @@ void serialEventRun(void) if (Serial2_available && serialEvent2 && Serial2_available()) serialEvent2(); #endif #if defined(HAVE_HWSERIAL3) - if (Serial3_available && serialEvent2 && Serial3_available()) serialEvent3(); + if (Serial3_available && serialEvent3 && Serial3_available()) serialEvent3(); #endif } @@ -83,7 +83,7 @@ void HardwareSerial::_tx_udr_empty_irq(void) // If interrupts are enabled, there must be more data in the output // buffer. Send the next byte unsigned char c = _tx_buffer[_tx_buffer_tail]; - _tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_BUFFER_SIZE; + _tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_TX_BUFFER_SIZE; *_udr = c; @@ -117,7 +117,7 @@ void HardwareSerial::begin(unsigned long baud, byte config) baud_setting = (F_CPU / 8 / baud - 1) / 2; } - // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) + // assign the baud_setting, a.k.a. ubrr (USART Baud Rate Register) *_ubrrh = baud_setting >> 8; *_ubrrl = baud_setting; @@ -152,7 +152,7 @@ void HardwareSerial::end() int HardwareSerial::available(void) { - return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail) % SERIAL_BUFFER_SIZE; + return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE; } int HardwareSerial::peek(void) @@ -171,11 +171,26 @@ int HardwareSerial::read(void) return -1; } else { unsigned char c = _rx_buffer[_rx_buffer_tail]; - _rx_buffer_tail = (uint8_t)(_rx_buffer_tail + 1) % SERIAL_BUFFER_SIZE; + _rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE; return c; } } +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 + if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail; + return tail - head - 1; +} + void HardwareSerial::flush() { // If we have never written a byte, no need to flush. This special @@ -198,6 +213,7 @@ void HardwareSerial::flush() size_t HardwareSerial::write(uint8_t c) { + _written = true; // 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 (> @@ -207,7 +223,7 @@ size_t HardwareSerial::write(uint8_t c) sbi(*_ucsra, TXC0); return 1; } - uint8_t i = (_tx_buffer_head + 1) % SERIAL_BUFFER_SIZE; + tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE; // If the output buffer is full, there's nothing for it other than to // wait for the interrupt handler to empty it a bit @@ -228,10 +244,8 @@ size_t HardwareSerial::write(uint8_t c) _tx_buffer_head = i; sbi(*_ucsrb, UDRIE0); - _written = true; return 1; } - #endif // whole file diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h index 226bf57..1beafc5 100644 --- a/cores/arduino/HardwareSerial.h +++ b/cores/arduino/HardwareSerial.h @@ -32,10 +32,36 @@ // using a ring buffer (I think), in which head is the index of the location // to which to write the next incoming character and tail is the index of the // location from which to read. +// NOTE: a "power of 2" buffer size is reccomended to dramatically +// optimize all the modulo operations for ring buffers. +// WARNING: When buffer sizes are increased to > 256, the buffer index +// variables are automatically increased in size, but the extra +// atomicity guards needed for that are not implemented. This will +// often work, but occasionally a race condition can occur that makes +// Serial behave erratically. See https://github.com/arduino/Arduino/issues/2405 +#if !defined(SERIAL_TX_BUFFER_SIZE) #if (RAMEND < 1000) - #define SERIAL_BUFFER_SIZE 16 +#define SERIAL_TX_BUFFER_SIZE 16 #else - #define SERIAL_BUFFER_SIZE 64 +#define SERIAL_TX_BUFFER_SIZE 64 +#endif +#endif +#if !defined(SERIAL_RX_BUFFER_SIZE) +#if (RAMEND < 1000) +#define SERIAL_RX_BUFFER_SIZE 16 +#else +#define SERIAL_RX_BUFFER_SIZE 64 +#endif +#endif +#if (SERIAL_TX_BUFFER_SIZE>256) +typedef uint16_t tx_buffer_index_t; +#else +typedef uint8_t tx_buffer_index_t; +#endif +#if (SERIAL_RX_BUFFER_SIZE>256) +typedef uint16_t rx_buffer_index_t; +#else +typedef uint8_t rx_buffer_index_t; #endif // Define config for Serial.begin(baud, config); @@ -76,16 +102,16 @@ class HardwareSerial : public Stream // Has any byte been written to the UART since begin() bool _written; - volatile uint8_t _rx_buffer_head; - volatile uint8_t _rx_buffer_tail; - volatile uint8_t _tx_buffer_head; - volatile uint8_t _tx_buffer_tail; + volatile rx_buffer_index_t _rx_buffer_head; + volatile rx_buffer_index_t _rx_buffer_tail; + volatile tx_buffer_index_t _tx_buffer_head; + volatile tx_buffer_index_t _tx_buffer_tail; // Don't put any members after these buffers, since only the first // 32 bytes of this struct can be accessed quickly using the ldd // instruction. - unsigned char _rx_buffer[SERIAL_BUFFER_SIZE]; - unsigned char _tx_buffer[SERIAL_BUFFER_SIZE]; + unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE]; + unsigned char _tx_buffer[SERIAL_TX_BUFFER_SIZE]; public: inline HardwareSerial( @@ -98,6 +124,7 @@ class HardwareSerial : public Stream virtual int available(void); virtual int peek(void); virtual int read(void); + int availableForWrite(void); virtual void flush(void); virtual size_t write(uint8_t); inline size_t write(unsigned long n) { return write((uint8_t)n); } diff --git a/cores/arduino/HardwareSerial0.cpp b/cores/arduino/HardwareSerial0.cpp index 67495ad..1146eeb 100644 --- a/cores/arduino/HardwareSerial0.cpp +++ b/cores/arduino/HardwareSerial0.cpp @@ -43,7 +43,7 @@ #elif defined(USART_RXC_vect) ISR(USART_RXC_vect) // ATmega8 #else - #error "Don't know what the Data Received vector is called for the first UART" + #error "Don't know what the Data Received vector is called for Serial" #endif { Serial._rx_complete_irq(); @@ -58,7 +58,7 @@ ISR(USART0_UDRE_vect) #elif defined(USART_UDRE_vect) ISR(USART_UDRE_vect) #else - #error "Don't know what the Data Register Empty vector is called for the first UART" + #error "Don't know what the Data Register Empty vector is called for Serial" #endif { Serial._tx_udr_empty_irq(); diff --git a/cores/arduino/HardwareSerial1.cpp b/cores/arduino/HardwareSerial1.cpp index ec076e7..19625e2 100644 --- a/cores/arduino/HardwareSerial1.cpp +++ b/cores/arduino/HardwareSerial1.cpp @@ -36,39 +36,29 @@ #if defined(HAVE_HWSERIAL1) -#if defined(USART_RX_vect) - ISR(USART_RX_vect) +#if defined(UART1_RX_vect) +ISR(UART1_RX_vect) #elif defined(USART1_RX_vect) - ISR(USART1_RX_vect) -#elif defined(USART_RXC_vect) - ISR(USART_RXC_vect) // ATmega8 +ISR(USART1_RX_vect) #else - #error "Don't know what the Data Received vector is called for the first UART" +#error "Don't know what the Data Register Empty vector is called for Serial1" #endif - { - Serial1._rx_complete_irq(); - } +{ + Serial1._rx_complete_irq(); +} #if defined(UART1_UDRE_vect) ISR(UART1_UDRE_vect) -#elif defined(UART_UDRE_vect) -ISR(UART_UDRE_vect) #elif defined(USART1_UDRE_vect) ISR(USART1_UDRE_vect) -#elif defined(USART_UDRE_vect) -ISR(USART_UDRE_vect) #else - #error "Don't know what the Data Register Empty vector is called for the first UART" +#error "Don't know what the Data Register Empty vector is called for Serial1" #endif { Serial1._tx_udr_empty_irq(); } -#if defined(UBRRH) && defined(UBRRL) - HardwareSerial Serial1(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR); -#else - HardwareSerial Serial1(&UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1); -#endif +HardwareSerial Serial1(&UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1); // Function that can be weakly referenced by serialEventRun to prevent // pulling in this file if it's not otherwise used. diff --git a/cores/arduino/HardwareSerial2.cpp b/cores/arduino/HardwareSerial2.cpp index e700770..fd334ae 100644 --- a/cores/arduino/HardwareSerial2.cpp +++ b/cores/arduino/HardwareSerial2.cpp @@ -36,39 +36,17 @@ #if defined(HAVE_HWSERIAL2) -#if defined(USART_RX_vect) - ISR(USART_RX_vect) -#elif defined(USART2_RX_vect) - ISR(USART2_RX_vect) -#elif defined(USART_RXC_vect) - ISR(USART_RXC_vect) // ATmega8 -#else - #error "Don't know what the Data Received vector is called for the first UART" -#endif - { - Serial2._rx_complete_irq(); - } +ISR(USART2_RX_vect) +{ + Serial2._rx_complete_irq(); +} -#if defined(UART2_UDRE_vect) -ISR(UART2_UDRE_vect) -#elif defined(UART_UDRE_vect) -ISR(UART_UDRE_vect) -#elif defined(USART2_UDRE_vect) ISR(USART2_UDRE_vect) -#elif defined(USART_UDRE_vect) -ISR(USART_UDRE_vect) -#else - #error "Don't know what the Data Register Empty vector is called for the first UART" -#endif { Serial2._tx_udr_empty_irq(); } -#if defined(UBRRH) && defined(UBRRL) - HardwareSerial Serial2(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR); -#else - HardwareSerial Serial2(&UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2); -#endif +HardwareSerial Serial2(&UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2); // Function that can be weakly referenced by serialEventRun to prevent // pulling in this file if it's not otherwise used. diff --git a/cores/arduino/HardwareSerial3.cpp b/cores/arduino/HardwareSerial3.cpp index 300c4bd..a68095b 100644 --- a/cores/arduino/HardwareSerial3.cpp +++ b/cores/arduino/HardwareSerial3.cpp @@ -36,39 +36,17 @@ #if defined(HAVE_HWSERIAL3) -#if defined(USART_RX_vect) - ISR(USART_RX_vect) -#elif defined(USART3_RX_vect) - ISR(USART3_RX_vect) -#elif defined(USART_RXC_vect) - ISR(USART_RXC_vect) // ATmega8 -#else - #error "Don't know what the Data Received vector is called for the first UART" -#endif - { - Serial3._rx_complete_irq(); - } +ISR(USART3_RX_vect) +{ + Serial3._rx_complete_irq(); +} -#if defined(UART3_UDRE_vect) -ISR(UART3_UDRE_vect) -#elif defined(UART_UDRE_vect) -ISR(UART_UDRE_vect) -#elif defined(USART3_UDRE_vect) ISR(USART3_UDRE_vect) -#elif defined(USART_UDRE_vect) -ISR(USART_UDRE_vect) -#else - #error "Don't know what the Data Register Empty vector is called for the first UART" -#endif { Serial3._tx_udr_empty_irq(); } -#if defined(UBRRH) && defined(UBRRL) - HardwareSerial Serial3(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR); -#else - HardwareSerial Serial3(&UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3); -#endif +HardwareSerial Serial3(&UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3); // Function that can be weakly referenced by serialEventRun to prevent // pulling in this file if it's not otherwise used. diff --git a/cores/arduino/HardwareSerial_private.h b/cores/arduino/HardwareSerial_private.h index 915d7a1..761a5e5 100644 --- a/cores/arduino/HardwareSerial_private.h +++ b/cores/arduino/HardwareSerial_private.h @@ -34,6 +34,11 @@ // slower. #if !defined(TXC0) #if defined(TXC) +// Some chips like ATmega8 don't have UPE, only PE. The other bits are +// named as expected. +#if !defined(UPE) && defined(PE) +#define UPE PE +#endif // On ATmega8, the uart and its bits are not numbered, so there is no TXC0 etc. #define TXC0 TXC #define RXEN0 RXEN @@ -99,7 +104,7 @@ void HardwareSerial::_rx_complete_irq(void) // No Parity error, read byte and store it in the buffer if there is // room unsigned char c = *_udr; - int i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_BUFFER_SIZE; + rx_buffer_index_t i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE; // if we should be storing the received character into the location // just before the tail (meaning that the head would advance to the diff --git a/cores/arduino/IPAddress.cpp b/cores/arduino/IPAddress.cpp index 22a0e42..899cbd4 100644 --- a/cores/arduino/IPAddress.cpp +++ b/cores/arduino/IPAddress.cpp @@ -22,42 +22,42 @@ 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) { - _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) { - memcpy(_address, &address, sizeof(_address)); + _address.dword = address; } IPAddress::IPAddress(const uint8_t *address) { - memcpy(_address, address, sizeof(_address)); + memcpy(_address.bytes, address, sizeof(_address.bytes)); } IPAddress& IPAddress::operator=(const uint8_t *address) { - memcpy(_address, address, sizeof(_address)); + memcpy(_address.bytes, address, sizeof(_address.bytes)); return *this; } IPAddress& IPAddress::operator=(uint32_t address) { - memcpy(_address, (const uint8_t *)&address, sizeof(_address)); + _address.dword = address; return *this; } bool IPAddress::operator==(const uint8_t* addr) const { - return memcmp(addr, _address, sizeof(_address)) == 0; + return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; } size_t IPAddress::printTo(Print& p) const @@ -65,10 +65,10 @@ 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(_address.bytes[i], DEC); n += p.print('.'); } - n += p.print(_address[3], DEC); + n += p.print(_address.bytes[3], DEC); return n; } diff --git a/cores/arduino/IPAddress.h b/cores/arduino/IPAddress.h index 6ea8127..94acdc4 100644 --- a/cores/arduino/IPAddress.h +++ b/cores/arduino/IPAddress.h @@ -27,12 +27,16 @@ class IPAddress : public Printable { private: - uint8_t _address[4]; // IPv4 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; }; + uint8_t* raw_address() { return _address.bytes; }; public: // Constructors @@ -43,13 +47,13 @@ public: // 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() const { return *((uint32_t*)_address); }; - bool operator==(const IPAddress& addr) const { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); }; + operator uint32_t() const { return _address.dword; }; + bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; }; bool operator==(const uint8_t* addr) const; // 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 IPAddress& operator=(const uint8_t *address); diff --git a/cores/arduino/Platform.h b/cores/arduino/Platform.h deleted file mode 100644 index 8b8f742..0000000 --- a/cores/arduino/Platform.h +++ /dev/null @@ -1,23 +0,0 @@ - -#ifndef __PLATFORM_H__ -#define __PLATFORM_H__ - -#include <inttypes.h> -#include <avr/pgmspace.h> -#include <avr/eeprom.h> -#include <avr/interrupt.h> -#include <util/delay.h> - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned long u32; - -#include "Arduino.h" - -#if defined(USBCON) - #include "USBDesc.h" - #include "USBCore.h" - #include "USBAPI.h" -#endif /* if defined(USBCON) */ - -#endif diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 5df5630..782d50b 100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -122,9 +122,7 @@ size_t Print::print(const Printable& x) size_t Print::println(void) { - size_t n = print('\r'); - n += print('\n'); - return n; + return write("\r\n"); } size_t Print::println(const String &s) diff --git a/cores/arduino/Printable.h b/cores/arduino/Printable.h index d03c9af..2a1b2e9 100644 --- a/cores/arduino/Printable.h +++ b/cores/arduino/Printable.h @@ -20,7 +20,7 @@ #ifndef Printable_h #define Printable_h -#include <new.h> +#include <stdlib.h> class Print; diff --git a/cores/arduino/Server.h b/cores/arduino/Server.h index 77c415c..69e3e39 100644 --- a/cores/arduino/Server.h +++ b/cores/arduino/Server.h @@ -20,6 +20,8 @@ #ifndef server_h #define server_h +#include "Print.h" + class Server : public Print { public: virtual void begin() =0; diff --git a/cores/arduino/Stream.cpp b/cores/arduino/Stream.cpp index aafb7fc..b31942f 100644 --- a/cores/arduino/Stream.cpp +++ b/cores/arduino/Stream.cpp @@ -18,6 +18,8 @@ Created July 2011 parsing functions based on TextFinder library by Michael Margolis + + findMulti/findUntil routines written by Jim Leonard/Xuth */ #include "Arduino.h" @@ -75,7 +77,7 @@ void Stream::setTimeout(unsigned long timeout) // sets the maximum number of mi // find returns true if the target string is found bool Stream::find(char *target) { - return findUntil(target, NULL); + return findUntil(target, strlen(target), NULL, 0); } // reads data from the stream until the target string of given length is found @@ -96,32 +98,13 @@ bool Stream::findUntil(char *target, char *terminator) // 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) { - size_t index = 0; // maximum target string length is 64k bytes! - size_t termIndex = 0; - int c; - - if( *target == 0) - return true; // return true if target is a null string - while( (c = timedRead()) > 0){ - - if(c != target[index]) - index = 0; // reset index if any char does not match - - if( c == target[index]){ - //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); - if(++index >= targetLen){ // return true if all chars in the target match - return true; - } - } - - if(termLen > 0 && c == terminator[termIndex]){ - if(++termIndex >= termLen) - return false; // return false if terminate string found before target string - } - else - termIndex = 0; + if (terminator == NULL) { + MultiTarget t[1] = {{target, targetLen, 0}}; + return findMulti(t, 1) == 0 ? true : false; + } else { + MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}}; + return findMulti(t, 2) == 0 ? true : false; } - return false; } @@ -137,7 +120,7 @@ long Stream::parseInt() // this allows format characters (typically commas) in values to be ignored long Stream::parseInt(char skipChar) { - boolean isNegative = false; + bool isNegative = false; long value = 0; int c; @@ -173,8 +156,8 @@ float Stream::parseFloat() // as above but the given skipChar is ignored // this allows format characters (typically commas) in values to be ignored float Stream::parseFloat(char skipChar){ - boolean isNegative = false; - boolean isFraction = false; + bool isNegative = false; + bool isFraction = false; long value = 0; char c; float fraction = 1.0; @@ -268,3 +251,67 @@ String Stream::readStringUntil(char terminator) return ret; } +int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) { + // any zero length target string automatically matches and would make + // a mess of the rest of the algorithm. + for (struct MultiTarget *t = targets; t < targets+tCount; ++t) { + if (t->len <= 0) + return t - targets; + } + + while (1) { + int c = timedRead(); + if (c < 0) + return -1; + + for (struct MultiTarget *t = targets; t < targets+tCount; ++t) { + // the simple case is if we match, deal with that first. + if (c == t->str[t->index]) { + if (++t->index == t->len) + return t - targets; + else + continue; + } + + // if not we need to walk back and see if we could have matched further + // down the stream (ie '1112' doesn't match the first position in '11112' + // but it will match the second position so we can't just reset the current + // index to 0 when we find a mismatch. + if (t->index == 0) + continue; + + int origIndex = t->index; + do { + --t->index; + // first check if current char works against the new current index + if (c != t->str[t->index]) + continue; + + // if it's the only char then we're good, nothing more to check + if (t->index == 0) { + t->index++; + break; + } + + // otherwise we need to check the rest of the found string + int diff = origIndex - t->index; + size_t i; + for (i = 0; i < t->index; ++i) { + if (t->str[i] != t->str[i + diff]) + break; + } + + // if we successfully got through the previous loop then our current + // index is good. + if (i == t->index) { + t->index++; + break; + } + + // otherwise we just try the next index + } while (t->index); + } + } + // unreachable + return -1; +} diff --git a/cores/arduino/Stream.h b/cores/arduino/Stream.h index 5cf5ddf..15f6761 100644 --- a/cores/arduino/Stream.h +++ b/cores/arduino/Stream.h @@ -64,6 +64,8 @@ class Stream : public Print bool find(uint8_t *target, size_t length) { return find ((char *)target, length); } // returns true if target string is found, false if timed out + bool find(char target) { return find (&target, 1); } + bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found bool findUntil(uint8_t *target, char *terminator) { return findUntil((char *)target, terminator); } @@ -97,6 +99,17 @@ class Stream : public Print // this allows format characters (typically commas) in values to be ignored float parseFloat(char skipChar); // as above but the given skipChar is ignored + + struct MultiTarget { + const char *str; // string you're searching for + size_t len; // length of string you're searching for + size_t index; // index used by the search routine. + }; + + // This allows you to search for an arbitrary number of strings. + // Returns index of the target that is found first or -1 if timeout occurs. + int findMulti(struct MultiTarget *targets, int tCount); }; + #endif diff --git a/cores/arduino/Tone.cpp b/cores/arduino/Tone.cpp index 9bb6fe7..7216219 100644 --- a/cores/arduino/Tone.cpp +++ b/cores/arduino/Tone.cpp @@ -30,6 +30,8 @@ Version Modified By Date Comments 0006 D Mellis 09/12/29 Replaced objects with functions 0007 M Sproul 10/08/29 Changed #ifdefs from cpu to register 0008 S Kanemoto 12/06/22 Fixed for Leonardo by @maris_HY +0009 J Reucker 15/04/10 Issue #292 Fixed problems with ATmega8 (thanks to Pete62) +0010 jipp 15/04/13 added additional define check #2923 *************************************************/ #include <avr/interrupt.h> @@ -151,7 +153,7 @@ static int8_t toneBegin(uint8_t _pin) // whereas 16 bit timers are set to either ck/1 or ck/64 prescalar switch (_timer) { - #if defined(TCCR0A) && defined(TCCR0B) + #if defined(TCCR0A) && defined(TCCR0B) && defined(WGM01) case 0: // 8 bit timer TCCR0A = 0; @@ -296,13 +298,13 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) #if defined(TCCR0B) if (_timer == 0) { - TCCR0B = prescalarbits; + TCCR0B = (TCCR0B & 0b11111000) | prescalarbits; } else #endif #if defined(TCCR2B) { - TCCR2B = prescalarbits; + TCCR2B = (TCCR2B & 0b11111000) | prescalarbits; } #else { @@ -389,7 +391,7 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) break; #endif -#if defined(TIMSK3) +#if defined(OCR3A) && defined(TIMSK3) && defined(OCIE3A) case 3: OCR3A = ocr; timer3_toggle_count = toggle_count; @@ -397,7 +399,7 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) break; #endif -#if defined(TIMSK4) +#if defined(OCR4A) && defined(TIMSK4) && defined(OCIE4A) case 4: OCR4A = ocr; timer4_toggle_count = toggle_count; @@ -454,21 +456,21 @@ void disableTimer(uint8_t _timer) #endif break; -#if defined(TIMSK3) +#if defined(TIMSK3) && defined(OCIE3A) case 3: - TIMSK3 = 0; + bitWrite(TIMSK3, OCIE3A, 0); break; #endif -#if defined(TIMSK4) +#if defined(TIMSK4) && defined(OCIE4A) case 4: - TIMSK4 = 0; + bitWrite(TIMSK4, OCIE4A, 0); break; #endif -#if defined(TIMSK5) +#if defined(TIMSK5) && defined(OCIE5A) case 5: - TIMSK5 = 0; + bitWrite(TIMSK5, OCIE5A, 0); break; #endif } diff --git a/cores/arduino/USBAPI.h b/cores/arduino/USBAPI.h index 5a33002..5837b3e 100644 --- a/cores/arduino/USBAPI.h +++ b/cores/arduino/USBAPI.h @@ -1,10 +1,42 @@ +/* + USBAPI.h + Copyright (c) 2005-2014 Arduino. 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 +*/ #ifndef __USBAPI__ #define __USBAPI__ +#include <inttypes.h> +#include <avr/pgmspace.h> +#include <avr/eeprom.h> +#include <avr/interrupt.h> +#include <util/delay.h> + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; + +#include "Arduino.h" + #if defined(USBCON) +#include "USBDesc.h" +#include "USBCore.h" + //================================================================================ //================================================================================ // USB @@ -27,25 +59,33 @@ extern USBDevice_ USBDevice; struct ring_buffer; +#ifndef SERIAL_BUFFER_SIZE #if (RAMEND < 1000) #define SERIAL_BUFFER_SIZE 16 #else #define SERIAL_BUFFER_SIZE 64 #endif +#endif +#if (SERIAL_BUFFER_SIZE>256) +#error Please lower the CDC Buffer size +#endif class Serial_ : public Stream { +private: + int peek_buffer; public: + Serial_() { peek_buffer = -1; }; void begin(unsigned long); void begin(unsigned long, uint8_t); void end(void); virtual int available(void); - virtual void accept(void); virtual int peek(void); virtual int read(void); virtual void flush(void); virtual size_t write(uint8_t); + virtual size_t write(const uint8_t*, size_t); using Print::write; // pull in write(str) and write(buf, size) from Print operator bool(); diff --git a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp index c46c75f..b4f7bed 100644 --- a/cores/arduino/USBCore.cpp +++ b/cores/arduino/USBCore.cpp @@ -16,9 +16,7 @@ ** SOFTWARE. */ -#include "Platform.h" #include "USBAPI.h" -#include "USBDesc.h" #if defined(USBCON) @@ -57,12 +55,18 @@ const u16 STRING_LANGUAGE[2] = { const u8 STRING_PRODUCT[] PROGMEM = USB_PRODUCT; #if USB_VID == 0x2341 -#define USB_MANUFACTURER "Arduino LLC" +# if defined(USB_MANUFACTURER) +# undef USB_MANUFACTURER +# endif +# define USB_MANUFACTURER "Arduino LLC" #elif USB_VID == 0x1b4f -#define USB_MANUFACTURER "SparkFun" +# if defined(USB_MANUFACTURER) +# undef USB_MANUFACTURER +# endif +# define USB_MANUFACTURER "SparkFun" #elif !defined(USB_MANUFACTURER) // Fall through to unknown if no manufacturer name was provided in a macro -#define USB_MANUFACTURER "Unknown" +# define USB_MANUFACTURER "Unknown" #endif const u8 STRING_MANUFACTURER[] PROGMEM = USB_MANUFACTURER; @@ -88,7 +92,8 @@ volatile u8 _usbConfiguration = 0; static inline void WaitIN(void) { - while (!(UEINTX & (1<<TXINI))); + while (!(UEINTX & (1<<TXINI))) + ; } static inline void ClearIN(void) @@ -268,7 +273,6 @@ int USB_Send(u8 ep, const void* d, int len) int r = len; const u8* data = (const u8*)d; - u8 zero = ep & TRANSFER_ZERO; u8 timeout = 250; // 250ms timeout on send? TODO while (len) { @@ -283,9 +287,12 @@ int USB_Send(u8 ep, const void* d, int len) if (n > len) n = len; - len -= n; { LockEP lock(ep); + // Frame may have been released by the SOF interrupt handler + if (!ReadWriteAllowed()) + continue; + len -= n; if (ep & TRANSFER_ZERO) { while (n--) @@ -621,8 +628,6 @@ ISR(USB_GEN_vect) { #ifdef CDC_ENABLED USB_Flush(CDC_TX); // Send a tx frame if found - if (USB_Available(CDC_RX)) // Handle received bytes (if any) - Serial.accept(); #endif // check whether the one-shot period has elapsed. if so, turn off the LED diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index d3fbf10..71dd45c 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -223,6 +223,18 @@ void detachInterrupt(uint8_t interruptNum) { #warning detachInterrupt may need some more work for this cpu (case 1) #endif break; + + case 2: + #if defined(EIMSK) && defined(INT2) + EIMSK &= ~(1 << INT2); + #elif defined(GICR) && defined(INT2) + GICR &= ~(1 << INT2); // atmega32 + #elif defined(GIMSK) && defined(INT2) + GIMSK &= ~(1 << INT2); + #elif defined(INT2) + #warning detachInterrupt may need some more work for this cpu (case 2) + #endif + break; #endif } diff --git a/cores/arduino/WMath.cpp b/cores/arduino/WMath.cpp index 2120c4c..214ccdc 100644 --- a/cores/arduino/WMath.cpp +++ b/cores/arduino/WMath.cpp @@ -27,7 +27,7 @@ extern "C" { #include "stdlib.h" } -void randomSeed(unsigned int seed) +void randomSeed(unsigned long seed) { if (seed != 0) { srandom(seed); diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index ed880ce..dcd469d 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -619,7 +619,7 @@ String String::substring(unsigned int left, unsigned int right) const left = temp; } String out; - if (left > len) return out; + if (left >= len) return out; if (right > len) right = len; char temp = buffer[right]; // save the replaced character buffer[right] = '\0'; @@ -684,15 +684,16 @@ void String::replace(const String& find, const String& replace) } void String::remove(unsigned int index){ - if (index >= len) { return; } - int count = len - index; - remove(index, count); + // Pass the biggest integer as the count. The remove method + // below will take care of truncating it at the end of the + // string. + remove(index, (unsigned int)-1); } void String::remove(unsigned int index, unsigned int count){ if (index >= len) { return; } if (count <= 0) { return; } - if (index + count > len) { count = len - index; } + if (count > len - index) { count = len - index; } char *writeTo = buffer + index; len = len - count; strncpy(writeTo, buffer + index + count,len - index); diff --git a/cores/arduino/abi.cpp b/cores/arduino/abi.cpp new file mode 100644 index 0000000..8d719b8 --- /dev/null +++ b/cores/arduino/abi.cpp @@ -0,0 +1,35 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include <stdlib.h> + +extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__)); +extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__)); + +void __cxa_pure_virtual(void) { + // We might want to write some diagnostics to uart in this case + //std::terminate(); + abort(); +} + +void __cxa_deleted_virtual(void) { + // We might want to write some diagnostics to uart in this case + //std::terminate(); + abort(); +} + diff --git a/cores/arduino/avr-libc/malloc.c b/cores/arduino/avr-libc/malloc.c deleted file mode 100644 index 9dcfe21..0000000 --- a/cores/arduino/avr-libc/malloc.c +++ /dev/null @@ -1,267 +0,0 @@ -/* Copyright (c) 2002, 2004, 2010 Joerg Wunsch - Copyright (c) 2010 Gerben van den Broeke - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the copyright holders nor the names of - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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. -*/ - - -/* $Id: malloc.c 2149 2010-06-09 20:45:37Z joerg_wunsch $ */ - -#include <stdlib.h> -#include "sectionname.h" -#include "stdlib_private.h" - -#include <avr/io.h> - -/* - * Exported interface: - * - * When extending the data segment, the allocator will not try to go - * beyond the current stack limit, decreased by __malloc_margin bytes. - * Thus, all possible stack frames of interrupt routines that could - * interrupt the current function, plus all further nested function - * calls must not require more stack space, or they'll risk to collide - * with the data segment. - */ - -/* May be changed by the user only before the first malloc() call. */ - -size_t __malloc_margin = 128; -char *__malloc_heap_start = &__heap_start; -char *__malloc_heap_end = &__heap_end; - -char *__brkval; -struct __freelist *__flp; - -ATTRIBUTE_CLIB_SECTION -void * -malloc(size_t len) -{ - struct __freelist *fp1, *fp2, *sfp1, *sfp2; - char *cp; - size_t s, avail; - - /* - * Our minimum chunk size is the size of a pointer (plus the - * size of the "sz" field, but we don't need to account for - * this), otherwise we could not possibly fit a freelist entry - * into the chunk later. - */ - if (len < sizeof(struct __freelist) - sizeof(size_t)) - len = sizeof(struct __freelist) - sizeof(size_t); - - /* - * First, walk the free list and try finding a chunk that - * would match exactly. If we found one, we are done. While - * walking, note down the smallest chunk we found that would - * still fit the request -- we need it for step 2. - * - */ - for (s = 0, fp1 = __flp, fp2 = 0; - fp1; - fp2 = fp1, fp1 = fp1->nx) { - if (fp1->sz < len) - continue; - if (fp1->sz == len) { - /* - * Found it. Disconnect the chunk from the - * freelist, and return it. - */ - if (fp2) - fp2->nx = fp1->nx; - else - __flp = fp1->nx; - return &(fp1->nx); - } - else { - if (s == 0 || fp1->sz < s) { - /* this is the smallest chunk found so far */ - s = fp1->sz; - sfp1 = fp1; - sfp2 = fp2; - } - } - } - /* - * Step 2: If we found a chunk on the freelist that would fit - * (but was too large), look it up again and use it, since it - * is our closest match now. Since the freelist entry needs - * to be split into two entries then, watch out that the - * difference between the requested size and the size of the - * chunk found is large enough for another freelist entry; if - * not, just enlarge the request size to what we have found, - * and use the entire chunk. - */ - if (s) { - if (s - len < sizeof(struct __freelist)) { - /* Disconnect it from freelist and return it. */ - if (sfp2) - sfp2->nx = sfp1->nx; - else - __flp = sfp1->nx; - return &(sfp1->nx); - } - /* - * Split them up. Note that we leave the first part - * as the new (smaller) freelist entry, and return the - * upper portion to the caller. This saves us the - * work to fix up the freelist chain; we just need to - * fixup the size of the current entry, and note down - * the size of the new chunk before returning it to - * the caller. - */ - cp = (char *)sfp1; - s -= len; - cp += s; - sfp2 = (struct __freelist *)cp; - sfp2->sz = len; - sfp1->sz = s - sizeof(size_t); - return &(sfp2->nx); - } - /* - * Step 3: If the request could not be satisfied from a - * freelist entry, just prepare a new chunk. This means we - * need to obtain more memory first. The largest address just - * not allocated so far is remembered in the brkval variable. - * Under Unix, the "break value" was the end of the data - * segment as dynamically requested from the operating system. - * Since we don't have an operating system, just make sure - * that we don't collide with the stack. - */ - if (__brkval == 0) - __brkval = __malloc_heap_start; - cp = __malloc_heap_end; - if (cp == 0) - cp = STACK_POINTER() - __malloc_margin; - if (cp <= __brkval) - /* - * Memory exhausted. - */ - return 0; - avail = cp - __brkval; - /* - * Both tests below are needed to catch the case len >= 0xfffe. - */ - if (avail >= len && avail >= len + sizeof(size_t)) { - fp1 = (struct __freelist *)__brkval; - __brkval += len + sizeof(size_t); - fp1->sz = len; - return &(fp1->nx); - } - /* - * Step 4: There's no help, just fail. :-/ - */ - return 0; -} - - -ATTRIBUTE_CLIB_SECTION -void -free(void *p) -{ - struct __freelist *fp1, *fp2, *fpnew; - char *cp1, *cp2, *cpnew; - - /* ISO C says free(NULL) must be a no-op */ - if (p == 0) - return; - - cpnew = p; - cpnew -= sizeof(size_t); - fpnew = (struct __freelist *)cpnew; - fpnew->nx = 0; - - /* - * Trivial case first: if there's no freelist yet, our entry - * will be the only one on it. If this is the last entry, we - * can reduce __brkval instead. - */ - if (__flp == 0) { - if ((char *)p + fpnew->sz == __brkval) - __brkval = cpnew; - else - __flp = fpnew; - return; - } - - /* - * Now, find the position where our new entry belongs onto the - * freelist. Try to aggregate the chunk with adjacent chunks - * if possible. - */ - for (fp1 = __flp, fp2 = 0; - fp1; - fp2 = fp1, fp1 = fp1->nx) { - if (fp1 < fpnew) - continue; - cp1 = (char *)fp1; - fpnew->nx = fp1; - if ((char *)&(fpnew->nx) + fpnew->sz == cp1) { - /* upper chunk adjacent, assimilate it */ - fpnew->sz += fp1->sz + sizeof(size_t); - fpnew->nx = fp1->nx; - } - if (fp2 == 0) { - /* new head of freelist */ - __flp = fpnew; - return; - } - break; - } - /* - * Note that we get here either if we hit the "break" above, - * or if we fell off the end of the loop. The latter means - * we've got a new topmost chunk. Either way, try aggregating - * with the lower chunk if possible. - */ - fp2->nx = fpnew; - cp2 = (char *)&(fp2->nx); - if (cp2 + fp2->sz == cpnew) { - /* lower junk adjacent, merge */ - fp2->sz += fpnew->sz + sizeof(size_t); - fp2->nx = fpnew->nx; - } - /* - * If there's a new topmost chunk, lower __brkval instead. - */ - for (fp1 = __flp, fp2 = 0; - fp1->nx != 0; - fp2 = fp1, fp1 = fp1->nx) - /* advance to entry just before end of list */; - cp2 = (char *)&(fp1->nx); - if (cp2 + fp1->sz == __brkval) { - if (fp2 == NULL) - /* Freelist is empty now. */ - __flp = NULL; - else - fp2->nx = NULL; - __brkval = cp2 - sizeof(size_t); - } -} - diff --git a/cores/arduino/avr-libc/realloc.c b/cores/arduino/avr-libc/realloc.c deleted file mode 100644 index b76ce56..0000000 --- a/cores/arduino/avr-libc/realloc.c +++ /dev/null @@ -1,150 +0,0 @@ -/* Copyright (c) 2004, 2010 Joerg Wunsch - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the copyright holders nor the names of - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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. -*/ -/* $Id: realloc.c 2127 2010-06-07 14:49:37Z joerg_wunsch $ */ - -#include <stdlib.h> -#include <string.h> -#include "sectionname.h" -#include "stdlib_private.h" - -#include <avr/io.h> - -ATTRIBUTE_CLIB_SECTION -void * -realloc(void *ptr, size_t len) -{ - struct __freelist *fp1, *fp2, *fp3, *ofp3; - char *cp, *cp1; - void *memp; - size_t s, incr; - - /* Trivial case, required by C standard. */ - if (ptr == 0) - return malloc(len); - - cp1 = (char *)ptr; - cp1 -= sizeof(size_t); - fp1 = (struct __freelist *)cp1; - - cp = (char *)ptr + len; /* new next pointer */ - if (cp < cp1) - /* Pointer wrapped across top of RAM, fail. */ - return 0; - - /* - * See whether we are growing or shrinking. When shrinking, - * we split off a chunk for the released portion, and call - * free() on it. Therefore, we can only shrink if the new - * size is at least sizeof(struct __freelist) smaller than the - * previous size. - */ - if (len <= fp1->sz) { - /* The first test catches a possible unsigned int - * rollover condition. */ - if (fp1->sz <= sizeof(struct __freelist) || - len > fp1->sz - sizeof(struct __freelist)) - return ptr; - fp2 = (struct __freelist *)cp; - fp2->sz = fp1->sz - len - sizeof(size_t); - fp1->sz = len; - free(&(fp2->nx)); - return ptr; - } - - /* - * If we get here, we are growing. First, see whether there - * is space in the free list on top of our current chunk. - */ - incr = len - fp1->sz; - cp = (char *)ptr + fp1->sz; - fp2 = (struct __freelist *)cp; - for (s = 0, ofp3 = 0, fp3 = __flp; - fp3; - ofp3 = fp3, fp3 = fp3->nx) { - if (fp3 == fp2 && fp3->sz + sizeof(size_t) >= incr) { - /* found something that fits */ - if (fp3->sz + sizeof(size_t) - incr > sizeof(struct __freelist)) { - /* split off a new freelist entry */ - cp = (char *)ptr + len; - fp2 = (struct __freelist *)cp; - fp2->nx = fp3->nx; - fp2->sz = fp3->sz - incr; - fp1->sz = len; - } else { - /* it just fits, so use it entirely */ - fp1->sz += fp3->sz + sizeof(size_t); - fp2 = fp3->nx; - } - if (ofp3) - ofp3->nx = fp2; - else - __flp = fp2; - return ptr; - } - /* - * Find the largest chunk on the freelist while - * walking it. - */ - if (fp3->sz > s) - s = fp3->sz; - } - /* - * If we are the topmost chunk in memory, and there was no - * large enough chunk on the freelist that could be re-used - * (by a call to malloc() below), quickly extend the - * allocation area if possible, without need to copy the old - * data. - */ - if (__brkval == (char *)ptr + fp1->sz && len > s) { - cp1 = __malloc_heap_end; - cp = (char *)ptr + len; - if (cp1 == 0) - cp1 = STACK_POINTER() - __malloc_margin; - if (cp < cp1) { - __brkval = cp; - fp1->sz = len; - return ptr; - } - /* If that failed, we are out of luck. */ - return 0; - } - - /* - * Call malloc() for a new chunk, then copy over the data, and - * release the old region. - */ - if ((memp = malloc(len)) == 0) - return 0; - memcpy(memp, ptr, fp1->sz); - free(ptr); - return memp; -} - diff --git a/cores/arduino/avr-libc/sectionname.h b/cores/arduino/avr-libc/sectionname.h deleted file mode 100644 index 8e0f448..0000000 --- a/cores/arduino/avr-libc/sectionname.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (c) 2009 Atmel Corporation - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the copyright holders nor the names of - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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. -*/ - -#ifndef __SECTIONNAME_H__ -#define __SECTIONNAME_H__ - -/* Put all avr-libc functions in a common, unique sub-section name under .text. */ - -#define CLIB_SECTION .text.avr-libc -#define MLIB_SECTION .text.avr-libc.fplib - -#define STR(x) _STR(x) -#define _STR(x) #x - -#define ATTRIBUTE_CLIB_SECTION __attribute__ ((section (STR(CLIB_SECTION)))) -#define ATTRIBUTE_MLIB_SECTION __attribute__ ((section (STR(MLIB_SECTION)))) - -#define ASSEMBLY_CLIB_SECTION .section CLIB_SECTION, "ax", @progbits -#define ASSEMBLY_MLIB_SECTION .section MLIB_SECTION, "ax", @progbits - -#endif diff --git a/cores/arduino/avr-libc/stdlib_private.h b/cores/arduino/avr-libc/stdlib_private.h deleted file mode 100644 index 65c3427..0000000 --- a/cores/arduino/avr-libc/stdlib_private.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright (c) 2004, Joerg Wunsch - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the copyright holders nor the names of - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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. -*/ - -/* $Id: stdlib_private.h 1657 2008-03-24 17:11:08Z arcanum $ */ - -#include <inttypes.h> -#include <stdlib.h> -#include <avr/io.h> - -#if !defined(__DOXYGEN__) - -struct __freelist { - size_t sz; - struct __freelist *nx; -}; - -#endif - -extern char *__brkval; /* first location not yet allocated */ -extern struct __freelist *__flp; /* freelist pointer (head of freelist) */ -extern size_t __malloc_margin; /* user-changeable before the first malloc() */ -extern char *__malloc_heap_start; -extern char *__malloc_heap_end; - -extern char __heap_start; -extern char __heap_end; - -/* Needed for definition of AVR_STACK_POINTER_REG. */ -#include <avr/io.h> - -#define STACK_POINTER() ((char *)AVR_STACK_POINTER_REG) - diff --git a/cores/arduino/main.cpp b/cores/arduino/main.cpp index 0ad6962..72074de 100644 --- a/cores/arduino/main.cpp +++ b/cores/arduino/main.cpp @@ -19,10 +19,20 @@ #include <Arduino.h> +// Declared weak in Arduino.h to allow user redefinitions. +int atexit(void (* /*func*/ )()) { return 0; } + +// Weak empty variant initialization function. +// May be redefined by variant files. +void initVariant() __attribute__((weak)); +void initVariant() { } + int main(void) { init(); + initVariant(); + #if defined(USBCON) USBDevice.attach(); #endif diff --git a/cores/arduino/new.cpp b/cores/arduino/new.cpp index b81031e..cf6f89c 100644 --- a/cores/arduino/new.cpp +++ b/cores/arduino/new.cpp @@ -1,28 +1,36 @@ -#include <new.h> +/* + Copyright (c) 2014 Arduino. All right reserved. -void * operator new(size_t size) -{ + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include <stdlib.h> + +void *operator new(size_t size) { return malloc(size); } -void * operator new[](size_t size) -{ +void *operator new[](size_t size) { return malloc(size); } -void operator delete(void * ptr) -{ +void operator delete(void * ptr) { free(ptr); } -void operator delete[](void * ptr) -{ +void operator delete[](void * ptr) { free(ptr); } -int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);}; -void __cxa_guard_release (__guard *g) {*(char *)g = 1;}; -void __cxa_guard_abort (__guard *) {}; - -void __cxa_pure_virtual(void) {}; - diff --git a/cores/arduino/new.h b/cores/arduino/new.h index 991c86c..6e1b68f 100644 --- a/cores/arduino/new.h +++ b/cores/arduino/new.h @@ -1,6 +1,20 @@ -/* 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 - */ +/* + Copyright (c) 2014 Arduino. 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 +*/ #ifndef NEW_H #define NEW_H @@ -12,13 +26,5 @@ void * operator new[](size_t size); void operator delete(void * ptr); void operator delete[](void * ptr); -__extension__ typedef int __guard __attribute__((mode (__DI__))); - -extern "C" int __cxa_guard_acquire(__guard *); -extern "C" void __cxa_guard_release (__guard *); -extern "C" void __cxa_guard_abort (__guard *); - -extern "C" void __cxa_pure_virtual(void); - #endif diff --git a/cores/arduino/wiring.c b/cores/arduino/wiring.c index 5cbe241..6cb22c0 100644 --- a/cores/arduino/wiring.c +++ b/cores/arduino/wiring.c @@ -92,7 +92,6 @@ unsigned long micros() { #error TIMER 0 not defined #endif - #ifdef TIFR0 if ((TIFR0 & _BV(TOV0)) && (t < 255)) m++; @@ -119,65 +118,118 @@ void delay(unsigned long ms) } } -/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */ +/* Delay for the given number of microseconds. Assumes a 1, 8, 12, 16, 20 or 24 MHz clock. */ void delayMicroseconds(unsigned int us) { + // call = 4 cycles + 2 to 4 cycles to init us(2 for constant delay, 4 for variable) + // calling avrlib's delay_us() function with low values (e.g. 1 or // 2 microseconds) gives delays longer than desired. //delay_us(us); -#if F_CPU >= 20000000L +#if F_CPU >= 24000000L + // for the 24 MHz clock for the aventurous ones, trying to overclock + + // zero delay fix + if (!us) return; // = 3 cycles, (4 when true) + + // the following loop takes a 1/6 of a microsecond (4 cycles) + // per iteration, so execute it six times for each microsecond of + // delay requested. + us *= 6; // x6 us, = 7 cycles + + // account for the time taken in the preceeding commands. + // we just burned 22 (24) cycles above, remove 5, (5*4=20) + // us is at least 6 so we can substract 5 + us -= 5; //=2 cycles + +#elif F_CPU >= 20000000L // for the 20 MHz clock on rare Arduino boards - // for a one-microsecond delay, simply wait 2 cycle and return. The overhead - // of the function call yields a delay of exactly a one microsecond. + // for a one-microsecond delay, simply return. the overhead + // of the function call takes 18 (20) cycles, which is 1us __asm__ __volatile__ ( "nop" "\n\t" - "nop"); //just waiting 2 cycle - if (--us == 0) - return; + "nop" "\n\t" + "nop" "\n\t" + "nop"); //just waiting 4 cycles + if (us <= 1) return; // = 3 cycles, (4 when true) // the following loop takes a 1/5 of a microsecond (4 cycles) // per iteration, so execute it five times for each microsecond of // delay requested. - us = (us<<2) + us; // x5 us + us = (us << 2) + us; // x5 us, = 7 cycles // account for the time taken in the preceeding commands. - us -= 2; + // we just burned 26 (28) cycles above, remove 7, (7*4=28) + // us is at least 10 so we can substract 7 + us -= 7; // 2 cycles #elif F_CPU >= 16000000L // for the 16 MHz clock on most Arduino boards // for a one-microsecond delay, simply return. the overhead - // of the function call yields a delay of approximately 1 1/8 us. - if (--us == 0) - return; + // of the function call takes 14 (16) cycles, which is 1us + if (us <= 1) return; // = 3 cycles, (4 when true) - // the following loop takes a quarter of a microsecond (4 cycles) + // the following loop takes 1/4 of a microsecond (4 cycles) // per iteration, so execute it four times for each microsecond of // delay requested. - us <<= 2; + us <<= 2; // x4 us, = 4 cycles // account for the time taken in the preceeding commands. - us -= 2; -#else - // for the 8 MHz internal clock on the ATmega168 + // we just burned 19 (21) cycles above, remove 5, (5*4=20) + // us is at least 8 so we can substract 5 + us -= 5; // = 2 cycles, + +#elif F_CPU >= 12000000L + // for the 12 MHz clock if somebody is working with USB + + // for a 1 microsecond delay, simply return. the overhead + // of the function call takes 14 (16) cycles, which is 1.5us + if (us <= 1) return; // = 3 cycles, (4 when true) - // for a one- or two-microsecond delay, simply return. the overhead of - // the function calls takes more than two microseconds. can't just - // subtract two, since us is unsigned; we'd overflow. - if (--us == 0) - return; - if (--us == 0) - return; + // the following loop takes 1/3 of a microsecond (4 cycles) + // per iteration, so execute it three times for each microsecond of + // delay requested. + us = (us << 1) + us; // x3 us, = 5 cycles + + // account for the time taken in the preceeding commands. + // we just burned 20 (22) cycles above, remove 5, (5*4=20) + // us is at least 6 so we can substract 5 + us -= 5; //2 cycles + +#elif F_CPU >= 8000000L + // for the 8 MHz internal clock - // the following loop takes half of a microsecond (4 cycles) + // for a 1 and 2 microsecond delay, simply return. the overhead + // of the function call takes 14 (16) cycles, which is 2us + if (us <= 2) return; // = 3 cycles, (4 when true) + + // the following loop takes 1/2 of a microsecond (4 cycles) // per iteration, so execute it twice for each microsecond of // delay requested. - us <<= 1; - - // partially compensate for the time taken by the preceeding commands. - // we can't subtract any more than this or we'd overflow w/ small delays. - us--; + us <<= 1; //x2 us, = 2 cycles + + // account for the time taken in the preceeding commands. + // we just burned 17 (19) cycles above, remove 4, (4*4=16) + // us is at least 6 so we can substract 4 + us -= 4; // = 2 cycles + +#else + // for the 1 MHz internal clock (default settings for common Atmega microcontrollers) + + // the overhead of the function calls is 14 (16) cycles + if (us <= 16) return; //= 3 cycles, (4 when true) + if (us <= 25) return; //= 3 cycles, (4 when true), (must be at least 25 if we want to substract 22) + + // compensate for the time taken by the preceeding and next commands (about 22 cycles) + us -= 22; // = 2 cycles + // the following loop takes 4 microseconds (4 cycles) + // per iteration, so execute it us/4 times + // us is at least 4, divided by 4 gives us 1 (no zero delay bug) + us >>= 2; // us div 4, = 4 cycles + + #endif // busy wait @@ -185,6 +237,7 @@ void delayMicroseconds(unsigned int us) "1: sbiw %0,1" "\n\t" // 2 cycles "brne 1b" : "=w" (us) : "0" (us) // 2 cycles ); + // return = 4 cycles } void init() @@ -199,7 +252,7 @@ void init() #if defined(TCCR0A) && defined(WGM01) sbi(TCCR0A, WGM01); sbi(TCCR0A, WGM00); -#endif +#endif // set timer 0 prescale factor to 64 #if defined(__AVR_ATmega128__) @@ -302,14 +355,32 @@ void init() #endif #if defined(ADCSRA) - // set a2d prescale factor to 128 - // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range. - // XXX: this will not work properly for other clock speeds, and - // this code should use F_CPU to determine the prescale factor. - sbi(ADCSRA, ADPS2); - sbi(ADCSRA, ADPS1); - sbi(ADCSRA, ADPS0); - + // set a2d prescaler so we are inside the desired 50-200 KHz range. + #if F_CPU >= 16000000 // 16 MHz / 128 = 125 KHz + sbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + #elif F_CPU >= 8000000 // 8 MHz / 64 = 125 KHz + sbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + cbi(ADCSRA, ADPS0); + #elif F_CPU >= 4000000 // 4 MHz / 32 = 125 KHz + sbi(ADCSRA, ADPS2); + cbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + #elif F_CPU >= 2000000 // 2 MHz / 16 = 125 KHz + sbi(ADCSRA, ADPS2); + cbi(ADCSRA, ADPS1); + cbi(ADCSRA, ADPS0); + #elif F_CPU >= 1000000 // 1 MHz / 8 = 125 KHz + cbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + #else // 128 kHz / 2 = 64 KHz -> This is the closest you can get, the prescaler is 2 + cbi(ADCSRA, ADPS2); + cbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + #endif // enable a2d conversions sbi(ADCSRA, ADEN); #endif diff --git a/cores/arduino/wiring_analog.c b/cores/arduino/wiring_analog.c index 8feead9..48a9ef5 100644 --- a/cores/arduino/wiring_analog.c +++ b/cores/arduino/wiring_analog.c @@ -160,6 +160,14 @@ void analogWrite(uint8_t pin, int val) break; #endif + #if defined(TCCR1A) && defined(COM1C1) + case TIMER1C: + // connect pwm to pin on timer 1, channel B + sbi(TCCR1A, COM1C1); + OCR1C = val; // set pwm duty + break; + #endif + #if defined(TCCR2) && defined(COM21) case TIMER2: // connect pwm to pin on timer 2 diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index be323b1..df94cc1 100644 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -84,6 +84,9 @@ static void turnOffPWM(uint8_t timer) #if defined(TCCR1A) && defined(COM1B1) case TIMER1B: cbi(TCCR1A, COM1B1); break; #endif + #if defined(TCCR1A) && defined(COM1C1) + case TIMER1C: cbi(TCCR1A, COM1C1); break; + #endif #if defined(TCCR2) && defined(COM21) case TIMER2: cbi(TCCR2, COM21); break; diff --git a/cores/arduino/wiring_private.h b/cores/arduino/wiring_private.h index c366005..3bd2900 100644 --- a/cores/arduino/wiring_private.h +++ b/cores/arduino/wiring_private.h @@ -43,6 +43,8 @@ extern "C"{ #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif +uint32_t countPulseASM(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops); + #define EXTERNAL_INT_0 0 #define EXTERNAL_INT_1 1 #define EXTERNAL_INT_2 2 @@ -52,7 +54,7 @@ extern "C"{ #define EXTERNAL_INT_6 6 #define EXTERNAL_INT_7 7 -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega128RFA1__) || defined(__AVR_ATmega256RFR2__) #define EXTERNAL_NUM_INTERRUPTS 8 #elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) #define EXTERNAL_NUM_INTERRUPTS 3 diff --git a/cores/arduino/wiring_pulse.S b/cores/arduino/wiring_pulse.S new file mode 100644 index 0000000..1dd22e6 --- /dev/null +++ b/cores/arduino/wiring_pulse.S @@ -0,0 +1,178 @@ +/* + wiring_pulse.s - pulseInASM() function in different flavours + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2014 Martino Facchin + + 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 +*/ + +/* + * The following routine was generated by avr-gcc 4.8.3 with the following parameters + * -gstabs -Wa,-ahlmsd=output.lst -dp -fverbose-asm -O2 + * on the original C function + * + * unsigned long pulseInSimpl(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops) + * { + * unsigned long width = 0; + * // wait for any previous pulse to end + * while ((*port & bit) == stateMask) + * if (--maxloops == 0) + * return 0; + * + * // wait for the pulse to start + * while ((*port & bit) != stateMask) + * if (--maxloops == 0) + * return 0; + * + * // wait for the pulse to stop + * while ((*port & bit) == stateMask) { + * if (++width == maxloops) + * return 0; + * } + * return width; + * } + * + * some compiler outputs were removed but the rest of the code is untouched + */ + +#include <avr/io.h> + +.section .text + +.global countPulseASM + +countPulseASM: + +.LM0: +.LFBB1: + push r12 ; ; 130 pushqi1/1 [length = 1] + push r13 ; ; 131 pushqi1/1 [length = 1] + push r14 ; ; 132 pushqi1/1 [length = 1] + push r15 ; ; 133 pushqi1/1 [length = 1] + push r16 ; ; 134 pushqi1/1 [length = 1] + push r17 ; ; 135 pushqi1/1 [length = 1] +/* prologue: function */ +/* frame size = 0 */ +/* stack size = 6 */ +.L__stack_usage = 6 + mov r30,r24 ; port, port ; 2 *movhi/1 [length = 2] + mov r31,r25 ; port, port +/* unsigned long width = 0; +*** // wait for any previous pulse to end +*** while ((*port & bit) == stateMask) +*/ +.LM1: + rjmp .L2 ; ; 181 jump [length = 1] +.L4: +/* if (--maxloops == 0) */ +.LM2: + subi r16,1 ; maxloops, ; 17 addsi3/2 [length = 4] + sbc r17, r1 ; maxloops + sbc r18, r1 ; maxloops + sbc r19, r1 ; maxloops + breq .L13 ; , ; 19 branch [length = 1] +.L2: +/* if (--maxloops == 0) */ +.LM3: + ld r25,Z ; D.1554, *port_7(D) ; 22 movqi_insn/4 [length = 1] + and r25,r22 ; D.1554, bit ; 24 andqi3/1 [length = 1] + cp r25,r20 ; D.1554, stateMask ; 25 *cmpqi/2 [length = 1] + breq .L4 ; , ; 26 branch [length = 1] + rjmp .L6 ; ; 184 jump [length = 1] +.L7: +/* return 0; +*** +*** // wait for the pulse to start +*** while ((*port & bit) != stateMask) +*** if (--maxloops == 0) +*/ +.LM4: + subi r16,1 ; maxloops, ; 31 addsi3/2 [length = 4] + sbc r17, r1 ; maxloops + sbc r18, r1 ; maxloops + sbc r19, r1 ; maxloops + breq .L13 ; , ; 33 branch [length = 1] +.L6: +/* if (--maxloops == 0) */ +.LM5: + ld r25,Z ; D.1554, *port_7(D) ; 41 movqi_insn/4 [length = 1] + and r25,r22 ; D.1554, bit ; 43 andqi3/1 [length = 1] + cpse r25,r20 ; D.1554, stateMask ; 44 enable_interrupt-3 [length = 1] + rjmp .L7 ; + mov r12, r1 ; width ; 7 *movsi/2 [length = 4] + mov r13, r1 ; width + mov r14, r1 ; width + mov r15, r1 ; width + rjmp .L9 ; ; 186 jump [length = 1] +.L10: +/* return 0; +*** +*** // wait for the pulse to stop +*** while ((*port & bit) == stateMask) { +*** if (++width == maxloops) +*/ +.LM6: + ldi r24,-1 ; , ; 50 addsi3/3 [length = 5] + sub r12,r24 ; width, + sbc r13,r24 ; width, + sbc r14,r24 ; width, + sbc r15,r24 ; width, + cp r16,r12 ; maxloops, width ; 51 *cmpsi/2 [length = 4] + cpc r17,r13 ; maxloops, width + cpc r18,r14 ; maxloops, width + cpc r19,r15 ; maxloops, width + breq .L13 ; , ; 52 branch [length = 1] +.L9: +/* if (++width == maxloops) */ +.LM7: + ld r24,Z ; D.1554, *port_7(D) ; 60 movqi_insn/4 [length = 1] + and r24,r22 ; D.1554, bit ; 62 andqi3/1 [length = 1] + cp r24,r20 ; D.1554, stateMask ; 63 *cmpqi/2 [length = 1] + breq .L10 ; , ; 64 branch [length = 1] +/* return 0; +*** } +*** return width; +*/ +.LM8: + mov r22,r12 ; D.1553, width ; 108 movqi_insn/1 [length = 1] + mov r23,r13 ; D.1553, width ; 109 movqi_insn/1 [length = 1] + mov r24,r14 ; D.1553, width ; 110 movqi_insn/1 [length = 1] + mov r25,r15 ; D.1553, width ; 111 movqi_insn/1 [length = 1] +/* epilogue start */ +.LM9: + pop r17 ; ; 171 popqi [length = 1] + pop r16 ; ; 172 popqi [length = 1] + pop r15 ; ; 173 popqi [length = 1] + pop r14 ; ; 174 popqi [length = 1] + pop r13 ; ; 175 popqi [length = 1] + pop r12 ; ; 176 popqi [length = 1] + ret ; 177 return_from_epilogue [length = 1] +.L13: +.LM10: + ldi r22,0 ; D.1553 ; 120 movqi_insn/1 [length = 1] + ldi r23,0 ; D.1553 ; 121 movqi_insn/1 [length = 1] + ldi r24,0 ; D.1553 ; 122 movqi_insn/1 [length = 1] + ldi r25,0 ; D.1553 ; 123 movqi_insn/1 [length = 1] +/* epilogue start */ +.LM11: + pop r17 ; ; 138 popqi [length = 1] + pop r16 ; ; 139 popqi [length = 1] + pop r15 ; ; 140 popqi [length = 1] + pop r14 ; ; 141 popqi [length = 1] + pop r13 ; ; 142 popqi [length = 1] + pop r12 ; ; 143 popqi [length = 1] + ret ; 144 return_from_epilogue [length = 1] diff --git a/cores/arduino/wiring_pulse.c b/cores/arduino/wiring_pulse.c index 0d96886..4c44d1c 100644 --- a/cores/arduino/wiring_pulse.c +++ b/cores/arduino/wiring_pulse.c @@ -28,7 +28,10 @@ /* Measures the length (in microseconds) of a pulse on the pin; state is HIGH * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds * to 3 minutes in length, but must be called at least a few dozen microseconds - * before the start of the pulse. */ + * before the start of the pulse. + * + * This function performs better with short pulses in noInterrupt() context + */ unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) { // cache the port and bit of the pin in order to speed up the @@ -37,33 +40,57 @@ unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) uint8_t bit = digitalPinToBitMask(pin); uint8_t port = digitalPinToPort(pin); uint8_t stateMask = (state ? bit : 0); - unsigned long width = 0; // keep initialization out of time critical area - + + // convert the timeout from microseconds to a number of times through + // the initial loop; it takes approximately 16 clock cycles per iteration + unsigned long maxloops = microsecondsToClockCycles(timeout)/16; + + unsigned long width = countPulseASM(portInputRegister(port), bit, stateMask, maxloops); + + // prevent clockCyclesToMicroseconds to return bogus values if countPulseASM timed out + if (width) + return clockCyclesToMicroseconds(width * 16 + 16); + else + return 0; +} + +/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH + * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds + * to 3 minutes in length, but must be called at least a few dozen microseconds + * before the start of the pulse. + * + * ATTENTION: + * this function relies on micros() so cannot be used in noInterrupt() context + */ +unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout) +{ + // cache the port and bit of the pin in order to speed up the + // pulse width measuring loop and achieve finer resolution. calling + // digitalRead() instead yields much coarser resolution. + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + uint8_t stateMask = (state ? bit : 0); + // convert the timeout from microseconds to a number of times through // the initial loop; it takes 16 clock cycles per iteration. unsigned long numloops = 0; - unsigned long maxloops = microsecondsToClockCycles(timeout) / 16; - + unsigned long maxloops = microsecondsToClockCycles(timeout); + // wait for any previous pulse to end while ((*portInputRegister(port) & bit) == stateMask) if (numloops++ == maxloops) return 0; - + // wait for the pulse to start while ((*portInputRegister(port) & bit) != stateMask) if (numloops++ == maxloops) return 0; - + + unsigned long start = micros(); // wait for the pulse to stop while ((*portInputRegister(port) & bit) == stateMask) { if (numloops++ == maxloops) return 0; - width++; } - - // convert the reading to microseconds. The loop has been determined - // to be 20 clock cycles long and have about 16 clocks between the edge - // and the start of the loop. There will be some error introduced by - // the interrupt handlers. - return clockCyclesToMicroseconds(width * 21 + 16); + return micros() - start; } |