Browse Source

Sanguino core update

cathedrow 15 years ago
parent
commit
a9f28b5f31

+ 166 - 15
optiboot/cores/sanguino/HardwareSerial.cpp

@@ -1,5 +1,5 @@
 /*
-  HarwareSerial.cpp - Hardware serial library for Wiring
+  HardwareSerial.cpp - Hardware serial library for Wiring
   Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
 
   This library is free software; you can redistribute it and/or
@@ -17,51 +17,202 @@
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   
   Modified 23 November 2006 by David A. Mellis
-  Modified 29 January 2009, Marius Kintel for Sanguino - http://www.sanguino.cc/
 */
 
-#include "WProgram.h"
-
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
 #include "wiring.h"
+#include "wiring_private.h"
+
 #include "HardwareSerial.h"
 
+// Define constants and variables for buffering incoming serial data.  We're
+// using a ring buffer (I think), in which rx_buffer_head is the index of the
+// location to which to write the next incoming character and rx_buffer_tail
+// is the index of the location from which to read.
+#define RX_BUFFER_SIZE 128
+
+struct ring_buffer {
+  unsigned char buffer[RX_BUFFER_SIZE];
+  int head;
+  int tail;
+};
+
+ring_buffer rx_buffer = { { 0 }, 0, 0 };
+
+
+#if defined(__AVR_ATmega1280__)
+ring_buffer rx_buffer1 = { { 0 }, 0, 0 };
+ring_buffer rx_buffer2 = { { 0 }, 0, 0 };
+ring_buffer rx_buffer3 = { { 0 }, 0, 0 };
+#endif
+
+#if defined(__AVR_ATmega644P__)
+ring_buffer rx_buffer1 = { { 0 }, 0, 0 };
+#endif
+
+inline void store_char(unsigned char c, ring_buffer *rx_buffer)
+{
+  int i = (rx_buffer->head + 1) % 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
+  // current location of the tail), we're about to overflow the buffer
+  // and so we don't write the character or advance the head.
+  if (i != rx_buffer->tail) {
+    rx_buffer->buffer[rx_buffer->head] = c;
+    rx_buffer->head = i;
+  }
+}
+
+#if defined(__AVR_ATmega644P__)
+
+
+SIGNAL(SIG_USART0_RECV)
+{
+  unsigned char c = UDR0;
+  store_char(c, &rx_buffer);
+}
+
+SIGNAL(SIG_USART1_RECV)
+{
+  unsigned char c = UDR1;
+  store_char(c, &rx_buffer1);
+}
+
+#else
+
+#if defined(__AVR_ATmega8__)
+SIGNAL(SIG_UART_RECV)
+#else
+SIGNAL(USART_RX_vect)
+#endif
+{
+#if defined(__AVR_ATmega8__)
+  unsigned char c = UDR;
+#else
+  unsigned char c = UDR0;
+#endif
+  store_char(c, &rx_buffer);
+}
+
+#endif
+
 // Constructors ////////////////////////////////////////////////////////////////
 
-HardwareSerial::HardwareSerial(uint8_t uart)
-  :_uart(uart)
+HardwareSerial::HardwareSerial(ring_buffer *rx_buffer,
+  volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
+  volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
+  volatile uint8_t *udr,
+  uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x)
 {
+  _rx_buffer = rx_buffer;
+  _ubrrh = ubrrh;
+  _ubrrl = ubrrl;
+  _ucsra = ucsra;
+  _ucsrb = ucsrb;
+  _udr = udr;
+  _rxen = rxen;
+  _txen = txen;
+  _rxcie = rxcie;
+  _udre = udre;
+  _u2x = u2x;
 }
 
 // Public Methods //////////////////////////////////////////////////////////////
 
-void HardwareSerial::begin(long speed)
+void HardwareSerial::begin(long baud)
 {
-  beginSerial(_uart, speed);
+  uint16_t baud_setting;
+  bool use_u2x;
+
+  // U2X mode is needed for baud rates higher than (CPU Hz / 16)
+  if (baud > F_CPU / 16) {
+    use_u2x = true;
+  } else {
+    // figure out if U2X mode would allow for a better connection
+    
+    // calculate the percent difference between the baud-rate specified and
+    // the real baud rate for both U2X and non-U2X mode (0-255 error percent)
+    uint8_t nonu2x_baud_error = abs((int)(255-((F_CPU/(16*(((F_CPU/8/baud-1)/2)+1))*255)/baud)));
+    uint8_t u2x_baud_error = abs((int)(255-((F_CPU/(8*(((F_CPU/4/baud-1)/2)+1))*255)/baud)));
+    
+    // prefer non-U2X mode because it handles clock skew better
+    use_u2x = (nonu2x_baud_error > u2x_baud_error);
+  }
+  
+  if (use_u2x) {
+    *_ucsra = 1 << _u2x;
+    baud_setting = (F_CPU / 4 / baud - 1) / 2;
+  } else {
+    *_ucsra = 0;
+    baud_setting = (F_CPU / 8 / baud - 1) / 2;
+  }
+
+  // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
+  *_ubrrh = baud_setting >> 8;
+  *_ubrrl = baud_setting;
+
+  sbi(*_ucsrb, _rxen);
+  sbi(*_ucsrb, _txen);
+  sbi(*_ucsrb, _rxcie);
+}
+
+void HardwareSerial::end()
+{
+  cbi(*_ucsrb, _rxen);
+  cbi(*_ucsrb, _txen);
+  cbi(*_ucsrb, _rxcie);  
 }
 
 uint8_t HardwareSerial::available(void)
 {
-  return serialAvailable(_uart);
+  return (RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE;
 }
 
 int HardwareSerial::read(void)
 {
-  return serialRead(_uart);
+  // 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->buffer[_rx_buffer->tail];
+    _rx_buffer->tail = (_rx_buffer->tail + 1) % RX_BUFFER_SIZE;
+    return c;
+  }
 }
 
 void HardwareSerial::flush()
 {
-  serialFlush(_uart);
+  // don't reverse this or there may be problems if the RX interrupt
+  // occurs after reading the value of rx_buffer_head but before writing
+  // the value to rx_buffer_tail; the previous value of rx_buffer_head
+  // may be written to rx_buffer_tail, making it appear as if the buffer
+  // don't reverse this or there may be problems if the RX interrupt
+  // occurs after reading the value of rx_buffer_head but before writing
+  // the value to rx_buffer_tail; the previous value of rx_buffer_head
+  // may be written to rx_buffer_tail, making it appear as if the buffer
+  // were full, not empty.
+  _rx_buffer->head = _rx_buffer->tail;
 }
 
-void HardwareSerial::write(uint8_t b) {
-  serialWrite(_uart, b);
+void HardwareSerial::write(uint8_t c)
+{
+  while (!((*_ucsra) & (1 << _udre)))
+    ;
+
+  *_udr = c;
 }
 
 // Preinstantiate Objects //////////////////////////////////////////////////////
 
-HardwareSerial Serial = HardwareSerial(0);
+#if defined(__AVR_ATmega8__)
+HardwareSerial Serial(&rx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRE, U2X);
+#else
+HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0, U2X0);
+#endif
 
 #if defined(__AVR_ATmega644P__)
-HardwareSerial Serial1 = HardwareSerial(1);
+HardwareSerial Serial1(&rx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1, U2X1);
 #endif

+ 28 - 10
optiboot/cores/sanguino/HardwareSerial.h

@@ -1,7 +1,6 @@
 /*
   HardwareSerial.h - Hardware serial library for Wiring
   Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
-  Modified 29 January 2009, Marius Kintel for Sanguino - http://www.sanguino.cc/
 
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -25,23 +24,42 @@
 
 #include "Print.h"
 
+struct ring_buffer;
+
 class HardwareSerial : public Print
 {
- private:
-  uint8_t _uart;
- public:
-  HardwareSerial(uint8_t uart);
-  void begin(long);
-  uint8_t available(void);
-  int read(void);
-  void flush(void);
-  virtual void write(uint8_t);
+  private:
+    ring_buffer *_rx_buffer;
+    volatile uint8_t *_ubrrh;
+    volatile uint8_t *_ubrrl;
+    volatile uint8_t *_ucsra;
+    volatile uint8_t *_ucsrb;
+    volatile uint8_t *_udr;
+    uint8_t _rxen;
+    uint8_t _txen;
+    uint8_t _rxcie;
+    uint8_t _udre;
+    uint8_t _u2x;
+  public:
+    HardwareSerial(ring_buffer *rx_buffer,
+      volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
+      volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
+      volatile uint8_t *udr,
+      uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x);
+    void begin(long);
+    void end();
+    uint8_t available(void);
+    int read(void);
+    void flush(void);
+    virtual void write(uint8_t);
+    using Print::write; // pull in write(str) and write(buf, size) from Print
 };
 
 extern HardwareSerial Serial;
 
 #if defined(__AVR_ATmega644P__)
 extern HardwareSerial Serial1;
+
 #endif
 
 #endif

+ 51 - 48
optiboot/cores/sanguino/Print.cpp

@@ -21,7 +21,6 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <inttypes.h>
 #include <math.h>
 #include "wiring.h"
 
@@ -29,71 +28,75 @@
 
 // Public Methods //////////////////////////////////////////////////////////////
 
-void Print::print(uint8_t b)
+/* default implementation: may be overridden */
+void Print::write(const char *str)
 {
-  this->write(b);
+  while (*str)
+    write(*str++);
 }
 
-void Print::print(char c)
+/* default implementation: may be overridden */
+void Print::write(const uint8_t *buffer, size_t size)
 {
-  print((byte) c);
+  while (size--)
+    write(*buffer++);
 }
 
-void Print::print(const char c[])
+void Print::print(const char str[])
 {
-  while (*c)
-    print(*c++);
+  write(str);
 }
 
-void Print::print(int n)
+void Print::print(char c, int base)
 {
-  print((long) n);
+  print((long) c, base);
 }
 
-void Print::print(unsigned int n)
+void Print::print(unsigned char b, int base)
 {
-  print((unsigned long) n);
+  print((unsigned long) b, base);
 }
 
-void Print::print(long n)
+void Print::print(int n, int base)
 {
-  if (n < 0) {
-    print('-');
-    n = -n;
-  }
-  printNumber(n, 10);
+  print((long) n, base);
 }
 
-void Print::print(unsigned long n)
+void Print::print(unsigned int n, int base)
 {
-  printNumber(n, 10);
+  print((unsigned long) n, base);
 }
 
 void Print::print(long n, int base)
 {
-  if (base == 0)
-    print((char) n);
-  else if (base == 10)
-    print(n);
-  else
+  if (base == 0) {
+    write(n);
+  } else if (base == 10) {
+    if (n < 0) {
+      print('-');
+      n = -n;
+    }
+    printNumber(n, 10);
+  } else {
     printNumber(n, base);
+  }
 }
 
-void Print::print(double n)
+void Print::print(unsigned long n, int base)
 {
-  printFloat(n, 2);
+  if (base == 0) write(n);
+  else printNumber(n, base);
 }
 
-void Print::println(void)
+void Print::print(double n, int digits)
 {
-  print('\r');
-  print('\n');  
+  printFloat(n, digits);
 }
 
-void Print::println(char c)
+void Print::println(void)
 {
-  print(c);
-  println();  
+  print('\r');
+  print('\n');  
 }
 
 void Print::println(const char c[])
@@ -102,45 +105,45 @@ void Print::println(const char c[])
   println();
 }
 
-void Print::println(uint8_t b)
+void Print::println(char c, int base)
 {
-  print(b);
+  print(c, base);
   println();
 }
 
-void Print::println(int n)
+void Print::println(unsigned char b, int base)
 {
-  print(n);
+  print(b, base);
   println();
 }
 
-void Print::println(unsigned int n)
+void Print::println(int n, int base)
 {
-  print(n);
+  print(n, base);
   println();
 }
 
-void Print::println(long n)
+void Print::println(unsigned int n, int base)
 {
-  print(n);
-  println();  
+  print(n, base);
+  println();
 }
 
-void Print::println(unsigned long n)
+void Print::println(long n, int base)
 {
-  print(n);
-  println();  
+  print(n, base);
+  println();
 }
 
-void Print::println(long n, int base)
+void Print::println(unsigned long n, int base)
 {
   print(n, base);
   println();
 }
 
-void Print::println(double n)
+void Print::println(double n, int digits)
 {
-  print(n);
+  print(n, digits);
   println();
 }
 

+ 21 - 18
optiboot/cores/sanguino/Print.h

@@ -21,6 +21,7 @@
 #define Print_h
 
 #include <inttypes.h>
+#include <stdio.h> // for size_t
 
 #define DEC 10
 #define HEX 16
@@ -34,26 +35,28 @@ class Print
     void printNumber(unsigned long, uint8_t);
     void printFloat(double, uint8_t);
   public:
-    virtual void write(uint8_t);
-    void print(char);
+    virtual void write(uint8_t) = 0;
+    virtual void write(const char *str);
+    virtual void write(const uint8_t *buffer, size_t size);
+
     void print(const char[]);
-    void print(uint8_t);
-    void print(int);
-    void print(unsigned int);
-    void print(long);
-    void print(unsigned long);
-    void print(long, int);
-    void print(double);
-    void println(void);
-    void println(char);
+    void print(char, int = BYTE);
+    void print(unsigned char, int = BYTE);
+    void print(int, int = DEC);
+    void print(unsigned int, int = DEC);
+    void print(long, int = DEC);
+    void print(unsigned long, int = DEC);
+    void print(double, int = 2);
+
     void println(const char[]);
-    void println(uint8_t);
-    void println(int);
-    void println(unsigned int);
-    void println(long);
-    void println(unsigned long);
-    void println(long, int);
-    void println(double);
+    void println(char, int = BYTE);
+    void println(unsigned char, int = BYTE);
+    void println(int, int = DEC);
+    void println(unsigned int, int = DEC);
+    void println(long, int = DEC);
+    void println(unsigned long, int = DEC);
+    void println(double, int = 2);
+    void println(void);
 };
 
 #endif

+ 153 - 25
optiboot/cores/sanguino/WInterrupts.c

@@ -35,49 +35,177 @@
 volatile static voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS];
 // volatile static voidFuncPtr twiIntFunc;
 
-void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)
-{
-	if(interruptNum < EXTERNAL_NUM_INTERRUPTS)
-	{
-		intFunc[interruptNum] = userFunc;
+#if defined(__AVR_ATmega8__)
+#define EICRA MCUCR
+#define EIMSK GICR
+#endif
+
+void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
+  if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
+    intFunc[interruptNum] = userFunc;
+    
+    // Configure the interrupt mode (trigger on low input, any change, rising
+    // edge, or falling edge).  The mode constants were chosen to correspond
+    // to the configuration bits in the hardware register, so we simply shift
+    // the mode into place.
+      
+    // Enable the interrupt.
+      
+    switch (interruptNum) {
+#if defined(__AVR_ATmega1280__)
+    case 2:
+      EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
+      EIMSK |= (1 << INT0);
+      break;
+    case 3:
+      EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
+      EIMSK |= (1 << INT1);
+      break;
+    case 4:
+      EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
+      EIMSK |= (1 << INT2);
+      break;
+    case 5:
+      EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
+      EIMSK |= (1 << INT3);
+      break;
+    case 0:
+      EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40);
+      EIMSK |= (1 << INT4);
+      break;
+    case 1:
+      EICRB = (EICRB & ~((1 << ISC50) | (1 << ISC51))) | (mode << ISC50);
+      EIMSK |= (1 << INT5);
+      break;
+    case 6:
+      EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60);
+      EIMSK |= (1 << INT6);
+      break;
+    case 7:
+      EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70);
+      EIMSK |= (1 << INT7);
+      break;
+#else
+    case 0:
+      EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
+      EIMSK |= (1 << INT0);
+      break;
+    case 1:
+      EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
+      EIMSK |= (1 << INT1);
+      break;
+#endif
+    }
+  }
+}
 
-		//clear the config for the change settings
-		EICRA &= ~(B00000011 << (interruptNum * 2));
+void detachInterrupt(uint8_t interruptNum) {
+  if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
+    // Disable the interrupt.  (We can't assume that interruptNum is equal
+    // to the number of the EIMSK bit to clear, as this isn't true on the 
+    // ATmega8.  There, INT0 is 6 and INT1 is 7.)
+    switch (interruptNum) {
+#if defined(__AVR_ATmega1280__)
+    case 2:
+      EIMSK &= ~(1 << INT0);
+      break;
+    case 3:
+      EIMSK &= ~(1 << INT1);
+      break;
+    case 4:
+      EIMSK &= ~(1 << INT2);
+      break;
+    case 5:
+      EIMSK &= ~(1 << INT3);
+      break;
+    case 0:
+      EIMSK &= ~(1 << INT4);
+      break;
+    case 1:
+      EIMSK &= ~(1 << INT5);
+      break;
+    case 6:
+      EIMSK &= ~(1 << INT6);
+      break;
+    case 7:
+      EIMSK &= ~(1 << INT7);
+      break;
+#else
+    case 0:
+      EIMSK &= ~(1 << INT0);
+      break;
+    case 1:
+      EIMSK &= ~(1 << INT1);
+      break;
+#endif
+    }
+      
+    intFunc[interruptNum] = 0;
+  }
+}
 
-		//set our mode.
-		EICRA |= (mode << (interruptNum * 2));
+/*
+void attachInterruptTwi(void (*userFunc)(void) ) {
+  twiIntFunc = userFunc;
+}
+*/
+
+#if defined(__AVR_ATmega1280__)
 
-		// Enable the interrupt.
-		EIMSK |= (1 << interruptNum);
-	}
+SIGNAL(INT0_vect) {
+  if(intFunc[EXTERNAL_INT_2])
+    intFunc[EXTERNAL_INT_2]();
+}
+
+SIGNAL(INT1_vect) {
+  if(intFunc[EXTERNAL_INT_3])
+    intFunc[EXTERNAL_INT_3]();
 }
 
-void detachInterrupt(uint8_t interruptNum)
-{
-	if(interruptNum < EXTERNAL_NUM_INTERRUPTS)
-	{
-		// Disable the interrupt.
-		EIMSK &= ~(1 << interruptNum);
+SIGNAL(INT2_vect) {
+  if(intFunc[EXTERNAL_INT_4])
+    intFunc[EXTERNAL_INT_4]();
+}
 
-		intFunc[interruptNum] = 0;
-	}
+SIGNAL(INT3_vect) {
+  if(intFunc[EXTERNAL_INT_5])
+    intFunc[EXTERNAL_INT_5]();
 }
 
-ISR(INT0_vect) {
+SIGNAL(INT4_vect) {
   if(intFunc[EXTERNAL_INT_0])
     intFunc[EXTERNAL_INT_0]();
 }
 
-ISR(INT1_vect) {
+SIGNAL(INT5_vect) {
   if(intFunc[EXTERNAL_INT_1])
     intFunc[EXTERNAL_INT_1]();
 }
 
-ISR(INT2_vect) {
-  if(intFunc[EXTERNAL_INT_2])
-    intFunc[EXTERNAL_INT_2]();
+SIGNAL(INT6_vect) {
+  if(intFunc[EXTERNAL_INT_6])
+    intFunc[EXTERNAL_INT_6]();
 }
 
+SIGNAL(INT7_vect) {
+  if(intFunc[EXTERNAL_INT_7])
+    intFunc[EXTERNAL_INT_7]();
+}
+
+#else
+
+SIGNAL(INT0_vect) {
+  if(intFunc[EXTERNAL_INT_0])
+    intFunc[EXTERNAL_INT_0]();
+}
+
+SIGNAL(INT1_vect) {
+  if(intFunc[EXTERNAL_INT_1])
+    intFunc[EXTERNAL_INT_1]();
+}
+
+#endif
+
 /*
 SIGNAL(SIG_2WIRE_SERIAL) {
   if(twiIntFunc)

+ 2 - 2
optiboot/cores/sanguino/WMath.cpp

@@ -29,7 +29,7 @@ extern "C" {
 
 void randomSeed(unsigned int seed)
 {
-  if (seed != 0){
+  if (seed != 0) {
     srandom(seed);
   }
 }
@@ -57,4 +57,4 @@ long map(long x, long in_min, long in_max, long out_min, long out_max)
 }
 
 unsigned int makeWord(unsigned int w) { return w; }
-unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }
+unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }

+ 4 - 1
optiboot/cores/sanguino/WProgram.h

@@ -19,6 +19,9 @@ uint16_t makeWord(byte h, byte l);
 
 unsigned long pulseIn(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);
+
 // WMath prototypes
 long random(long);
 long random(long, long);
@@ -26,4 +29,4 @@ void randomSeed(unsigned int);
 long map(long, long, long, long, long);
 #endif
 
-#endif
+#endif

+ 77 - 42
optiboot/cores/sanguino/wiring.c

@@ -19,56 +19,77 @@
   Free Software Foundation, Inc., 59 Temple Place, Suite 330,
   Boston, MA  02111-1307  USA
 
-  $Id: wiring.c 388 2008-03-08 22:05:23Z mellis $
+  $Id: wiring.c 808 2009-12-18 17:44:08Z dmellis $
 */
 
 #include "wiring_private.h"
 
+// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
+// the overflow handler is called every 256 ticks.
+#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
+
+// the whole number of milliseconds per timer0 overflow
+#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
+
+// the fractional number of milliseconds per timer0 overflow. we shift right
+// by three to fit these numbers into a byte. (for the clock speeds we care
+// about - 8 and 16 MHz - this doesn't lose precision.)
+#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
+#define FRACT_MAX (1000 >> 3)
+
 volatile unsigned long timer0_overflow_count = 0;
-volatile unsigned long timer0_clock_cycles = 0;
 volatile unsigned long timer0_millis = 0;
+static unsigned char timer0_fract = 0;
 
 SIGNAL(TIMER0_OVF_vect)
 {
-	timer0_overflow_count++;
-	// timer 0 prescale factor is 64 and the timer overflows at 256
-	timer0_clock_cycles += 64UL * 256UL;
-	while (timer0_clock_cycles > clockCyclesPerMicrosecond() * 1000UL) {
-		timer0_clock_cycles -= clockCyclesPerMicrosecond() * 1000UL;
-		timer0_millis++;
+	// copy these to local variables so they can be stored in registers
+	// (volatile variables must be read from memory on every access)
+	unsigned long m = timer0_millis;
+	unsigned char f = timer0_fract;
+
+	m += MILLIS_INC;
+	f += FRACT_INC;
+	if (f >= FRACT_MAX) {
+		f -= FRACT_MAX;
+		m += 1;
 	}
+
+	timer0_fract = f;
+	timer0_millis = m;
+	timer0_overflow_count++;
 }
 
 unsigned long millis()
 {
 	unsigned long m;
 	uint8_t oldSREG = SREG;
-	
+
 	// disable interrupts while we read timer0_millis or we might get an
-	// inconsistent value (e.g. in the middle of the timer0_millis++)
+	// inconsistent value (e.g. in the middle of a write to timer0_millis)
 	cli();
 	m = timer0_millis;
 	SREG = oldSREG;
-	
+
 	return m;
 }
 
 unsigned long micros() {
-	unsigned long m, t;
-	uint8_t oldSREG = SREG;
+	unsigned long m;
+	uint8_t oldSREG = SREG, t;
 	
-	cli();	
+	cli();
+	m = timer0_overflow_count;
 	t = TCNT0;
   
 #ifdef TIFR0
-	if ((TIFR0 & _BV(TOV0)) && (t == 0))
-		t = 256;
+	if ((TIFR0 & _BV(TOV0)) && (t < 255))
+		m++;
 #else
-	if ((TIFR & _BV(TOV0)) && (t == 0))
-		t = 256;
+	if ((TIFR & _BV(TOV0)) && (t < 255))
+		m++;
 #endif
 
-	m = timer0_overflow_count;
 	SREG = oldSREG;
 	
 	return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
@@ -82,13 +103,9 @@ void delay(unsigned long ms)
 		;
 }
 
-/* Delay for the given number of microseconds.  Assumes a 8 or 16 MHz clock. 
- * Disables interrupts, which will disrupt the millis() function if used
- * too frequently. */
+/* Delay for the given number of microseconds.  Assumes a 8 or 16 MHz clock. */
 void delayMicroseconds(unsigned int us)
 {
-	uint8_t oldSREG;
-
 	// calling avrlib's delay_us() function with low values (e.g. 1 or
 	// 2 microseconds) gives delays longer than desired.
 	//delay_us(us);
@@ -123,25 +140,17 @@ void delayMicroseconds(unsigned int us)
 	// 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--;
 #endif
 
-	// disable interrupts, otherwise the timer 0 overflow interrupt that
-	// tracks milliseconds will make us delay longer than we want.
-	oldSREG = SREG;
-	cli();
-
 	// busy wait
 	__asm__ __volatile__ (
 		"1: sbiw %0,1" "\n\t" // 2 cycles
 		"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
 	);
-
-	// reenable interrupts.
-	SREG = oldSREG;
 }
 
 void init()
@@ -153,15 +162,24 @@ void init()
 	// on the ATmega168, timer 0 is also used for fast hardware pwm
 	// (using phase-correct PWM would mean that timer 0 overflowed half as often
 	// resulting in different millis() behavior on the ATmega8 and ATmega168)
+#if !defined(__AVR_ATmega8__)
 	sbi(TCCR0A, WGM01);
 	sbi(TCCR0A, WGM00);
-
+#endif  
 	// set timer 0 prescale factor to 64
+#if defined(__AVR_ATmega8__)
+	sbi(TCCR0, CS01);
+	sbi(TCCR0, CS00);
+#else
 	sbi(TCCR0B, CS01);
 	sbi(TCCR0B, CS00);
-
+#endif
 	// enable timer 0 overflow interrupt
+#if defined(__AVR_ATmega8__)
+	sbi(TIMSK, TOIE0);
+#else
 	sbi(TIMSK0, TOIE0);
+#endif
 
 	// timers 1 and 2 are used for phase-correct hardware pwm
 	// this is better for motors as it ensures an even waveform
@@ -171,15 +189,32 @@ void init()
 	// set timer 1 prescale factor to 64
 	sbi(TCCR1B, CS11);
 	sbi(TCCR1B, CS10);
-
 	// put timer 1 in 8-bit phase correct pwm mode
 	sbi(TCCR1A, WGM10);
 
 	// set timer 2 prescale factor to 64
+#if defined(__AVR_ATmega8__)
+	sbi(TCCR2, CS22);
+#else
 	sbi(TCCR2B, CS22);
-
+#endif
 	// configure timer 2 for phase correct pwm (8-bit)
+#if defined(__AVR_ATmega8__)
+	sbi(TCCR2, WGM20);
+#else
 	sbi(TCCR2A, WGM20);
+#endif
+
+#if defined(__AVR_ATmega1280__)
+	// set timer 3, 4, 5 prescale factor to 64
+	sbi(TCCR3B, CS31);	sbi(TCCR3B, CS30);
+	sbi(TCCR4B, CS41);	sbi(TCCR4B, CS40);
+	sbi(TCCR5B, CS51);	sbi(TCCR5B, CS50);
+	// put timer 3, 4, 5 in 8-bit phase correct pwm mode
+	sbi(TCCR3A, WGM30);
+	sbi(TCCR4A, WGM40);
+	sbi(TCCR5A, WGM50);
+#endif
 
 	// set a2d prescale factor to 128
 	// 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
@@ -195,9 +230,9 @@ void init()
 	// the bootloader connects pins 0 and 1 to the USART; disconnect them
 	// here so they can be used as normal digital i/o; they will be
 	// reconnected in Serial.begin()
+#if defined(__AVR_ATmega8__)
+	UCSRB = 0;
+#else
 	UCSR0B = 0;
-	#if defined(__AVR_ATmega644P__)
-	//TODO: test to see if disabling this helps?
-	//UCSR1B = 0;
-	#endif
-}
+#endif
+}

+ 14 - 14
optiboot/cores/sanguino/wiring.h

@@ -19,7 +19,7 @@
   Free Software Foundation, Inc., 59 Temple Place, Suite 330,
   Boston, MA  02111-1307  USA
 
-  $Id: wiring.h 387 2008-03-08 21:30:00Z mellis $
+  $Id: wiring.h 804 2009-12-18 16:05:52Z dmellis $
 */
 
 #ifndef Wiring_h
@@ -41,11 +41,11 @@ extern "C"{
 #define true 0x1
 #define false 0x0
 
-#define PI 3.14159265
-#define HALF_PI 1.57079
-#define TWO_PI 6.283185
-#define DEG_TO_RAD 0.01745329
-#define RAD_TO_DEG 57.2957786
+#define PI 3.1415926535897932384626433832795
+#define HALF_PI 1.5707963267948966192313216916398
+#define TWO_PI 6.283185307179586476925286766559
+#define DEG_TO_RAD 0.017453292519943295769236907684886
+#define RAD_TO_DEG 57.295779513082320876798154814105
 
 #define SERIAL  0x0
 #define DISPLAY 0x1
@@ -82,8 +82,8 @@ extern "C"{
 #define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
 #define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
 
-#define lowByte(w) ((w) & 0xff)
-#define highByte(w) ((w) >> 8)
+#define lowByte(w) ((uint8_t) ((w) & 0xff))
+#define highByte(w) ((uint8_t) ((w) >> 8))
 
 #define bitRead(value, bit) (((value) >> (bit)) & 0x01)
 #define bitSet(value, bit) ((value) |= (1UL << (bit)))
@@ -92,7 +92,7 @@ extern "C"{
 
 typedef unsigned int word;
 
-#define bit(b) (1 << (b))
+#define bit(b) (1UL << (b))
 
 typedef uint8_t boolean;
 typedef uint8_t byte;
@@ -106,11 +106,11 @@ int analogRead(uint8_t);
 void analogReference(uint8_t mode);
 void analogWrite(uint8_t, int);
 
-void beginSerial(uint8_t, long);
-void serialWrite(uint8_t, unsigned char);
-int serialAvailable(uint8_t);
-int serialRead(uint8_t);
-void serialFlush(uint8_t);
+void beginSerial(long);
+void serialWrite(unsigned char);
+int serialAvailable(void);
+int serialRead(void);
+void serialFlush(void);
 
 unsigned long millis(void);
 unsigned long micros(void);

+ 75 - 12
optiboot/cores/sanguino/wiring_analog.c

@@ -37,13 +37,18 @@ void analogReference(uint8_t mode)
 
 int analogRead(uint8_t pin)
 {
-	uint8_t low, high, ch = analogInPinToBit(pin);
+	uint8_t low, high;
 
 	// set the analog reference (high two bits of ADMUX) and select the
 	// channel (low 4 bits).  this also sets ADLAR (left-adjust result)
 	// to 0 (the default).
-	// the final AND is to clear the pos/neg reference bits
-	ADMUX = ((analog_reference << 6) | (pin & 0x0f)) & B11000111;
+	ADMUX = (analog_reference << 6) | (pin & 0x07);
+  
+#if defined(__AVR_ATmega1280__)
+	// the MUX5 bit of ADCSRB selects whether we're reading from channels
+	// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
+	ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
+#endif
 
 	// without a delay, we seem to read from the wrong channel
 	//delay(1);
@@ -88,16 +93,31 @@ void analogWrite(uint8_t pin, int val)
 		sbi(TCCR1A, COM1B1);
 		// set pwm duty
 		OCR1B = val;
-	} else if (digitalPinToTimer(pin) == TIMER0A) {
-		// connect pwm to pin on timer 0, channel A
-		sbi(TCCR0A, COM0A1);
+#if defined(__AVR_ATmega8__)
+	} else if (digitalPinToTimer(pin) == TIMER2) {
+		// connect pwm to pin on timer 2, channel B
+		sbi(TCCR2, COM21);
 		// set pwm duty
-		OCR0A = val;	
+		OCR2 = val;
+#else
+	} else if (digitalPinToTimer(pin) == TIMER0A) {
+		if (val == 0) {
+			digitalWrite(pin, LOW);
+		} else {
+			// connect pwm to pin on timer 0, channel A
+			sbi(TCCR0A, COM0A1);
+			// set pwm duty
+			OCR0A = val;      
+		}
 	} else if (digitalPinToTimer(pin) == TIMER0B) {
-		// connect pwm to pin on timer 0, channel B
-		sbi(TCCR0A, COM0B1);
-		// set pwm duty
-		OCR0B = val;
+		if (val == 0) {
+			digitalWrite(pin, LOW);
+		} else {
+			// connect pwm to pin on timer 0, channel B
+			sbi(TCCR0A, COM0B1);
+			// set pwm duty
+			OCR0B = val;
+		}
 	} else if (digitalPinToTimer(pin) == TIMER2A) {
 		// connect pwm to pin on timer 2, channel A
 		sbi(TCCR2A, COM2A1);
@@ -108,8 +128,51 @@ void analogWrite(uint8_t pin, int val)
 		sbi(TCCR2A, COM2B1);
 		// set pwm duty
 		OCR2B = val;
+#endif
+#if defined(__AVR_ATmega1280__)
+	// XXX: need to handle other timers here
+	} else if (digitalPinToTimer(pin) == TIMER3A) {
+		// connect pwm to pin on timer 3, channel A
+		sbi(TCCR3A, COM3A1);
+		// set pwm duty
+		OCR3A = val;
+	} else if (digitalPinToTimer(pin) == TIMER3B) {
+		// connect pwm to pin on timer 3, channel B
+		sbi(TCCR3A, COM3B1);
+		// set pwm duty
+		OCR3B = val;
+	} else if (digitalPinToTimer(pin) == TIMER3C) {
+		// connect pwm to pin on timer 3, channel C
+		sbi(TCCR3A, COM3C1);
+		// set pwm duty
+		OCR3C = val;
+	} else if (digitalPinToTimer(pin) == TIMER4A) {
+		// connect pwm to pin on timer 4, channel A
+		sbi(TCCR4A, COM4A1);
+		// set pwm duty
+		OCR4A = val;
+	} else if (digitalPinToTimer(pin) == TIMER4B) {
+		// connect pwm to pin on timer 4, channel B
+		sbi(TCCR4A, COM4B1);
+		// set pwm duty
+		OCR4B = val;
+	} else if (digitalPinToTimer(pin) == TIMER4C) {
+		// connect pwm to pin on timer 4, channel C
+		sbi(TCCR4A, COM4C1);
+		// set pwm duty
+		OCR4C = val;
+	} else if (digitalPinToTimer(pin) == TIMER5A) {
+		// connect pwm to pin on timer 5, channel A
+		sbi(TCCR5A, COM5A1);
+		// set pwm duty
+		OCR5A = val;
+	} else if (digitalPinToTimer(pin) == TIMER5B) {
+		// connect pwm to pin on timer 5, channel B
+		sbi(TCCR5A, COM5B1);
+		// set pwm duty
+		OCR5B = val;
+#endif
 	} else if (val < 128)
-	//fail semi-intelligently
 		digitalWrite(pin, LOW);
 	else
 		digitalWrite(pin, HIGH);

+ 19 - 3
optiboot/cores/sanguino/wiring_digital.c

@@ -50,12 +50,29 @@ void pinMode(uint8_t pin, uint8_t mode)
 static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
 static inline void turnOffPWM(uint8_t timer)
 {
-	if (timer == TIMER0A) cbi(TCCR0A, COM0A1);
-	if (timer == TIMER0B) cbi(TCCR0A, COM0B1);
 	if (timer == TIMER1A) cbi(TCCR1A, COM1A1);
 	if (timer == TIMER1B) cbi(TCCR1A, COM1B1);
+
+#if defined(__AVR_ATmega8__)
+	if (timer == TIMER2) cbi(TCCR2, COM21);
+#else
+	if (timer == TIMER0A) cbi(TCCR0A, COM0A1);
+	if (timer == TIMER0B) cbi(TCCR0A, COM0B1);
 	if (timer == TIMER2A) cbi(TCCR2A, COM2A1);
 	if (timer == TIMER2B) cbi(TCCR2A, COM2B1);
+#endif
+
+#if defined(__AVR_ATmega1280__)
+	if (timer == TIMER3A) cbi(TCCR3A, COM3A1);
+	if (timer == TIMER3B) cbi(TCCR3A, COM3B1);
+	if (timer == TIMER3C) cbi(TCCR3A, COM3C1);
+	if (timer == TIMER4A) cbi(TCCR4A, COM4A1);
+	if (timer == TIMER4B) cbi(TCCR4A, COM4B1);
+	if (timer == TIMER4C) cbi(TCCR4A, COM4C1);
+	if (timer == TIMER5A) cbi(TCCR5A, COM5A1);
+	if (timer == TIMER5B) cbi(TCCR5A, COM5B1);
+	if (timer == TIMER5C) cbi(TCCR5A, COM5C1);
+#endif
 }
 
 void digitalWrite(uint8_t pin, uint8_t val)
@@ -90,6 +107,5 @@ int digitalRead(uint8_t pin)
 	if (timer != NOT_ON_TIMER) turnOffPWM(timer);
 
 	if (*portInputRegister(port) & bit) return HIGH;
-	
 	return LOW;
 }

+ 10 - 2
optiboot/cores/sanguino/wiring_private.h

@@ -27,7 +27,6 @@
 
 #include <avr/io.h>
 #include <avr/interrupt.h>
-#include <avr/signal.h>
 #include <avr/delay.h>
 #include <stdio.h>
 #include <stdarg.h>
@@ -48,8 +47,17 @@ extern "C"{
 #define EXTERNAL_INT_0 0
 #define EXTERNAL_INT_1 1
 #define EXTERNAL_INT_2 2
+#define EXTERNAL_INT_3 3
+#define EXTERNAL_INT_4 4
+#define EXTERNAL_INT_5 5
+#define EXTERNAL_INT_6 6
+#define EXTERNAL_INT_7 7
 
-#define EXTERNAL_NUM_INTERRUPTS 3
+#if defined(__AVR_ATmega1280__)
+#define EXTERNAL_NUM_INTERRUPTS 8
+#else
+#define EXTERNAL_NUM_INTERRUPTS 2
+#endif
 
 typedef void (*voidFuncPtr)(void);