From a42326aba2fd9696a4b2e1239a5a222014056ff5 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Wed, 25 Mar 2009 10:50:00 +0000 Subject: Adding support for the Arduino Mega (ATmega1280) to the core and bootloader. --- cores/arduino/HardwareSerial.cpp | 149 ++++++++++++++++++- cores/arduino/HardwareSerial.h | 24 +++ cores/arduino/WInterrupts.c | 140 ++++++++++++++++-- cores/arduino/pins_arduino.c | 308 ++++++++++++++++++++++++++++++++++++++- cores/arduino/pins_arduino.h | 27 +++- cores/arduino/wiring.c | 11 ++ cores/arduino/wiring_analog.c | 85 ++++++++--- cores/arduino/wiring_digital.c | 12 ++ cores/arduino/wiring_private.h | 10 ++ 9 files changed, 717 insertions(+), 49 deletions(-) (limited to 'cores') diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index aab7fc5..f8a959a 100755 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/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 @@ -23,36 +23,169 @@ #include #include #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 + +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_ATmega1280__) + +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); +} + +SIGNAL(SIG_USART2_RECV) +{ + unsigned char c = UDR2; + store_char(c, &rx_buffer2); +} + +SIGNAL(SIG_USART3_RECV) +{ + unsigned char c = UDR3; + store_char(c, &rx_buffer3); +} + +#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(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) +{ + _rx_buffer = rx_buffer; + _ubrrh = ubrrh; + _ubrrl = ubrrl; + _ucsra = ucsra; + _ucsrb = ucsrb; + _udr = udr; + _rxen = rxen; + _txen = txen; + _rxcie = rxcie; + _udre = udre; +} + // Public Methods ////////////////////////////////////////////////////////////// void HardwareSerial::begin(long speed) { - beginSerial(speed); + *_ubrrh = ((F_CPU / 16 + speed / 2) / speed - 1) >> 8; + *_ubrrl = ((F_CPU / 16 + speed / 2) / speed - 1); + sbi(*_ucsrb, _rxen); + sbi(*_ucsrb, _txen); + sbi(*_ucsrb, _rxcie); } uint8_t HardwareSerial::available(void) { - return serialAvailable(); + return (RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE; } int HardwareSerial::read(void) { - return serialRead(); + // 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(); + // 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(b); +void HardwareSerial::write(uint8_t c) +{ + while (!((*_ucsra) & (1 << _udre))) + ; + + *_udr = c; } // Preinstantiate Objects ////////////////////////////////////////////////////// -HardwareSerial Serial = HardwareSerial(); +#if defined(__AVR_ATmega8__) +HardwareSerial Serial(&rx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRE); +#else +HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0); +#endif + +#if defined(__AVR_ATmega1280__) +HardwareSerial Serial1(&rx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1); +HardwareSerial Serial2(&rx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRE2); +HardwareSerial Serial3(&rx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRE3); +#endif diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h index e4cb969..55abf07 100755 --- a/cores/arduino/HardwareSerial.h +++ b/cores/arduino/HardwareSerial.h @@ -24,9 +24,27 @@ #include "Print.h" +struct ring_buffer; + class HardwareSerial : public Print { + 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; 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); void begin(long); uint8_t available(void); int read(void); @@ -36,5 +54,11 @@ class HardwareSerial : public Print extern HardwareSerial Serial; +#if defined(__AVR_ATmega1280__) +extern HardwareSerial Serial1; +extern HardwareSerial Serial2; +extern HardwareSerial Serial3; +#endif + #endif diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index 8b9003f..69a78b0 100755 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -44,29 +44,101 @@ void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) { if(interruptNum < EXTERNAL_NUM_INTERRUPTS) { intFunc[interruptNum] = userFunc; - if (interruptNum == 0) { - // 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. - EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00); + // 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. - // 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); - } else { + break; + case 1: EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10); EIMSK |= (1 << INT1); + break; +#endif } } } void detachInterrupt(uint8_t interruptNum) { if(interruptNum < EXTERNAL_NUM_INTERRUPTS) { - if (interruptNum == 0) - // Disable the interrupt. + // 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); - else + break; + case 1: EIMSK &= ~(1 << INT1); + break; +#endif + } intFunc[interruptNum] = 0; } @@ -78,6 +150,50 @@ void attachInterruptTwi(void (*userFunc)(void) ) { } */ +#if defined(__AVR_ATmega1280__) + +SIGNAL(INT0_vect) { + if(intFunc[EXTERNAL_INT_2]) + intFunc[EXTERNAL_INT_2](); +} + +SIGNAL(INT1_vect) { + if(intFunc[EXTERNAL_INT_3]) + intFunc[EXTERNAL_INT_3](); +} + +SIGNAL(INT2_vect) { + if(intFunc[EXTERNAL_INT_4]) + intFunc[EXTERNAL_INT_4](); +} + +SIGNAL(INT3_vect) { + if(intFunc[EXTERNAL_INT_5]) + intFunc[EXTERNAL_INT_5](); +} + +SIGNAL(INT4_vect) { + if(intFunc[EXTERNAL_INT_0]) + intFunc[EXTERNAL_INT_0](); +} + +SIGNAL(INT5_vect) { + if(intFunc[EXTERNAL_INT_1]) + intFunc[EXTERNAL_INT_1](); +} + +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](); @@ -88,6 +204,8 @@ SIGNAL(INT1_vect) { intFunc[EXTERNAL_INT_1](); } +#endif + /* SIGNAL(SIG_2WIRE_SERIAL) { if(twiIntFunc) diff --git a/cores/arduino/pins_arduino.c b/cores/arduino/pins_arduino.c index ef3f168..1c1c088 100755 --- a/cores/arduino/pins_arduino.c +++ b/cores/arduino/pins_arduino.c @@ -51,15 +51,315 @@ // // (PWM+ indicates the additional PWM pins on the ATmega168.) +// ATMEL ATMEGA1280 / ARDUINO +// +// 0-7 PE0-PE7 works +// 8-13 PB0-PB5 works +// 14-21 PA0-PA7 works +// 22-29 PH0-PH7 works +// 30-35 PG5-PG0 works +// 36-43 PC7-PC0 works +// 44-51 PJ7-PJ0 works +// 52-59 PL7-PL0 works +// 60-67 PD7-PD0 works +// A0-A7 PF0-PF7 +// A8-A15 PK0-PK7 +#define PA 1 #define PB 2 #define PC 3 #define PD 4 +#define PE 5 +#define PF 6 +#define PG 7 +#define PH 8 +#define PJ 10 +#define PK 11 +#define PL 12 + +#define REPEAT8(x) x, x, x, x, x, x, x, x +#define BV0TO7 _BV(0), _BV(1), _BV(2), _BV(3), _BV(4), _BV(5), _BV(6), _BV(7) +#define BV7TO0 _BV(7), _BV(6), _BV(5), _BV(4), _BV(3), _BV(2), _BV(1), _BV(0) + + +#if defined(__AVR_ATmega1280__) +const uint16_t PROGMEM port_to_mode_PGM[] = { + NOT_A_PORT, + &DDRA, + &DDRB, + &DDRC, + &DDRD, + &DDRE, + &DDRF, + &DDRG, + &DDRH, + NOT_A_PORT, + &DDRJ, + &DDRK, + &DDRL, +}; + +const uint16_t PROGMEM port_to_output_PGM[] = { + NOT_A_PORT, + &PORTA, + &PORTB, + &PORTC, + &PORTD, + &PORTE, + &PORTF, + &PORTG, + &PORTH, + NOT_A_PORT, + &PORTJ, + &PORTK, + &PORTL, +}; +const uint16_t PROGMEM port_to_input_PGM[] = { + NOT_A_PIN, + &PINA, + &PINB, + &PINC, + &PIND, + &PINE, + &PINF, + &PING, + &PINH, + NOT_A_PIN, + &PINJ, + &PINK, + &PINL, +}; + +const uint8_t PROGMEM digital_pin_to_port_PGM[] = { + // PORTLIST + // ------------------------------------------- + PE , // PE 0 ** 0 ** USART0_RX + PE , // PE 1 ** 1 ** USART0_TX + PE , // PE 4 ** 2 ** PWM2 + PE , // PE 5 ** 3 ** PWM3 + PG , // PG 5 ** 4 ** PWM4 + PE , // PE 3 ** 5 ** PWM5 + PH , // PH 3 ** 6 ** PWM6 + PH , // PH 4 ** 7 ** PWM7 + PH , // PH 5 ** 8 ** PWM8 + PH , // PH 6 ** 9 ** PWM9 + PB , // PB 4 ** 10 ** PWM10 + PB , // PB 5 ** 11 ** PWM11 + PB , // PB 6 ** 12 ** PWM12 + PB , // PB 7 ** 13 ** PWM13 + PJ , // PJ 1 ** 14 ** USART3_TX + PJ , // PJ 0 ** 15 ** USART3_RX + PH , // PH 1 ** 16 ** USART2_TX + PH , // PH 0 ** 17 ** USART2_RX + PD , // PD 3 ** 18 ** USART1_TX + PD , // PD 2 ** 19 ** USART1_RX + PD , // PD 1 ** 20 ** I2C_SDA + PD , // PD 0 ** 21 ** I2C_SCL + PA , // PA 0 ** 22 ** D22 + PA , // PA 1 ** 23 ** D23 + PA , // PA 2 ** 24 ** D24 + PA , // PA 3 ** 25 ** D25 + PA , // PA 4 ** 26 ** D26 + PA , // PA 5 ** 27 ** D27 + PA , // PA 6 ** 28 ** D28 + PA , // PA 7 ** 29 ** D29 + PC , // PC 7 ** 30 ** D30 + PC , // PC 6 ** 31 ** D31 + PC , // PC 5 ** 32 ** D32 + PC , // PC 4 ** 33 ** D33 + PC , // PC 3 ** 34 ** D34 + PC , // PC 2 ** 35 ** D35 + PC , // PC 1 ** 36 ** D36 + PC , // PC 0 ** 37 ** D37 + PD , // PD 7 ** 38 ** D38 + PG , // PG 2 ** 39 ** D39 + PG , // PG 1 ** 40 ** D40 + PG , // PG 0 ** 41 ** D41 + PL , // PL 7 ** 42 ** D42 + PL , // PL 6 ** 43 ** D43 + PL , // PL 5 ** 44 ** D44 + PL , // PL 4 ** 45 ** D45 + PL , // PL 3 ** 46 ** D46 + PL , // PL 2 ** 47 ** D47 + PL , // PL 1 ** 48 ** D48 + PL , // PL 0 ** 49 ** D49 + PB , // PB 3 ** 50 ** SPI_MISO + PB , // PB 2 ** 51 ** SPI_MOSI + PB , // PB 1 ** 52 ** SPI_SCK + PB , // PB 0 ** 53 ** SPI_SS + PF , // PF 0 ** 54 ** A0 + PF , // PF 1 ** 55 ** A1 + PF , // PF 2 ** 56 ** A2 + PF , // PF 3 ** 57 ** A3 + PF , // PF 4 ** 58 ** A4 + PF , // PF 5 ** 59 ** A5 + PF , // PF 6 ** 60 ** A6 + PF , // PF 7 ** 61 ** A7 + PK , // PK 0 ** 62 ** A8 + PK , // PK 1 ** 63 ** A9 + PK , // PK 2 ** 64 ** A10 + PK , // PK 3 ** 65 ** A11 + PK , // PK 4 ** 66 ** A12 + PK , // PK 5 ** 67 ** A13 + PK , // PK 6 ** 68 ** A14 + PK , // PK 7 ** 69 ** A15 +}; + +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { + // PIN IN PORT + // ------------------------------------------- + _BV( 0 ) , // PE 0 ** 0 ** USART0_RX + _BV( 1 ) , // PE 1 ** 1 ** USART0_TX + _BV( 4 ) , // PE 4 ** 2 ** PWM2 + _BV( 5 ) , // PE 5 ** 3 ** PWM3 + _BV( 5 ) , // PG 5 ** 4 ** PWM4 + _BV( 3 ) , // PE 3 ** 5 ** PWM5 + _BV( 3 ) , // PH 3 ** 6 ** PWM6 + _BV( 4 ) , // PH 4 ** 7 ** PWM7 + _BV( 5 ) , // PH 5 ** 8 ** PWM8 + _BV( 6 ) , // PH 6 ** 9 ** PWM9 + _BV( 4 ) , // PB 4 ** 10 ** PWM10 + _BV( 5 ) , // PB 5 ** 11 ** PWM11 + _BV( 6 ) , // PB 6 ** 12 ** PWM12 + _BV( 7 ) , // PB 7 ** 13 ** PWM13 + _BV( 1 ) , // PJ 1 ** 14 ** USART3_TX + _BV( 0 ) , // PJ 0 ** 15 ** USART3_RX + _BV( 1 ) , // PH 1 ** 16 ** USART2_TX + _BV( 0 ) , // PH 0 ** 17 ** USART2_RX + _BV( 3 ) , // PD 3 ** 18 ** USART1_TX + _BV( 2 ) , // PD 2 ** 19 ** USART1_RX + _BV( 1 ) , // PD 1 ** 20 ** I2C_SDA + _BV( 0 ) , // PD 0 ** 21 ** I2C_SCL + _BV( 0 ) , // PA 0 ** 22 ** D22 + _BV( 1 ) , // PA 1 ** 23 ** D23 + _BV( 2 ) , // PA 2 ** 24 ** D24 + _BV( 3 ) , // PA 3 ** 25 ** D25 + _BV( 4 ) , // PA 4 ** 26 ** D26 + _BV( 5 ) , // PA 5 ** 27 ** D27 + _BV( 6 ) , // PA 6 ** 28 ** D28 + _BV( 7 ) , // PA 7 ** 29 ** D29 + _BV( 7 ) , // PC 7 ** 30 ** D30 + _BV( 6 ) , // PC 6 ** 31 ** D31 + _BV( 5 ) , // PC 5 ** 32 ** D32 + _BV( 4 ) , // PC 4 ** 33 ** D33 + _BV( 3 ) , // PC 3 ** 34 ** D34 + _BV( 2 ) , // PC 2 ** 35 ** D35 + _BV( 1 ) , // PC 1 ** 36 ** D36 + _BV( 0 ) , // PC 0 ** 37 ** D37 + _BV( 7 ) , // PD 7 ** 38 ** D38 + _BV( 2 ) , // PG 2 ** 39 ** D39 + _BV( 1 ) , // PG 1 ** 40 ** D40 + _BV( 0 ) , // PG 0 ** 41 ** D41 + _BV( 7 ) , // PL 7 ** 42 ** D42 + _BV( 6 ) , // PL 6 ** 43 ** D43 + _BV( 5 ) , // PL 5 ** 44 ** D44 + _BV( 4 ) , // PL 4 ** 45 ** D45 + _BV( 3 ) , // PL 3 ** 46 ** D46 + _BV( 2 ) , // PL 2 ** 47 ** D47 + _BV( 1 ) , // PL 1 ** 48 ** D48 + _BV( 0 ) , // PL 0 ** 49 ** D49 + _BV( 3 ) , // PB 3 ** 50 ** SPI_MISO + _BV( 2 ) , // PB 2 ** 51 ** SPI_MOSI + _BV( 1 ) , // PB 1 ** 52 ** SPI_SCK + _BV( 0 ) , // PB 0 ** 53 ** SPI_SS + _BV( 0 ) , // PF 0 ** 54 ** A0 + _BV( 1 ) , // PF 1 ** 55 ** A1 + _BV( 2 ) , // PF 2 ** 56 ** A2 + _BV( 3 ) , // PF 3 ** 57 ** A3 + _BV( 4 ) , // PF 4 ** 58 ** A4 + _BV( 5 ) , // PF 5 ** 59 ** A5 + _BV( 6 ) , // PF 6 ** 60 ** A6 + _BV( 7 ) , // PF 7 ** 61 ** A7 + _BV( 0 ) , // PK 0 ** 62 ** A8 + _BV( 1 ) , // PK 1 ** 63 ** A9 + _BV( 2 ) , // PK 2 ** 64 ** A10 + _BV( 3 ) , // PK 3 ** 65 ** A11 + _BV( 4 ) , // PK 4 ** 66 ** A12 + _BV( 5 ) , // PK 5 ** 67 ** A13 + _BV( 6 ) , // PK 6 ** 68 ** A14 + _BV( 7 ) , // PK 7 ** 69 ** A15 +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { + // TIMERS + // ------------------------------------------- + NOT_ON_TIMER , // PE 0 ** 0 ** USART0_RX + NOT_ON_TIMER , // PE 1 ** 1 ** USART0_TX + TIMER3B , // PE 4 ** 2 ** PWM2 + TIMER3C , // PE 5 ** 3 ** PWM3 + TIMER0B , // PG 5 ** 4 ** PWM4 + TIMER3A , // PE 3 ** 5 ** PWM5 + TIMER4A , // PH 3 ** 6 ** PWM6 + TIMER4B , // PH 4 ** 7 ** PWM7 + TIMER4C , // PH 5 ** 8 ** PWM8 + TIMER2B , // PH 6 ** 9 ** PWM9 + TIMER2A , // PB 4 ** 10 ** PWM10 + TIMER1A , // PB 5 ** 11 ** PWM11 + TIMER1B , // PB 6 ** 12 ** PWM12 + TIMER0A , // PB 7 ** 13 ** PWM13 + NOT_ON_TIMER , // PJ 1 ** 14 ** USART3_TX + NOT_ON_TIMER , // PJ 0 ** 15 ** USART3_RX + NOT_ON_TIMER , // PH 1 ** 16 ** USART2_TX + NOT_ON_TIMER , // PH 0 ** 17 ** USART2_RX + NOT_ON_TIMER , // PD 3 ** 18 ** USART1_TX + NOT_ON_TIMER , // PD 2 ** 19 ** USART1_RX + NOT_ON_TIMER , // PD 1 ** 20 ** I2C_SDA + NOT_ON_TIMER , // PD 0 ** 21 ** I2C_SCL + NOT_ON_TIMER , // PA 0 ** 22 ** D22 + NOT_ON_TIMER , // PA 1 ** 23 ** D23 + NOT_ON_TIMER , // PA 2 ** 24 ** D24 + NOT_ON_TIMER , // PA 3 ** 25 ** D25 + NOT_ON_TIMER , // PA 4 ** 26 ** D26 + NOT_ON_TIMER , // PA 5 ** 27 ** D27 + NOT_ON_TIMER , // PA 6 ** 28 ** D28 + NOT_ON_TIMER , // PA 7 ** 29 ** D29 + NOT_ON_TIMER , // PC 7 ** 30 ** D30 + NOT_ON_TIMER , // PC 6 ** 31 ** D31 + NOT_ON_TIMER , // PC 5 ** 32 ** D32 + NOT_ON_TIMER , // PC 4 ** 33 ** D33 + NOT_ON_TIMER , // PC 3 ** 34 ** D34 + NOT_ON_TIMER , // PC 2 ** 35 ** D35 + NOT_ON_TIMER , // PC 1 ** 36 ** D36 + NOT_ON_TIMER , // PC 0 ** 37 ** D37 + NOT_ON_TIMER , // PD 7 ** 38 ** D38 + NOT_ON_TIMER , // PG 2 ** 39 ** D39 + NOT_ON_TIMER , // PG 1 ** 40 ** D40 + NOT_ON_TIMER , // PG 0 ** 41 ** D41 + NOT_ON_TIMER , // PL 7 ** 42 ** D42 + NOT_ON_TIMER , // PL 6 ** 43 ** D43 + TIMER5C , // PL 5 ** 44 ** D44 + TIMER5B , // PL 4 ** 45 ** D45 + TIMER5A , // PL 3 ** 46 ** D46 + NOT_ON_TIMER , // PL 2 ** 47 ** D47 + NOT_ON_TIMER , // PL 1 ** 48 ** D48 + NOT_ON_TIMER , // PL 0 ** 49 ** D49 + NOT_ON_TIMER , // PB 3 ** 50 ** SPI_MISO + NOT_ON_TIMER , // PB 2 ** 51 ** SPI_MOSI + NOT_ON_TIMER , // PB 1 ** 52 ** SPI_SCK + NOT_ON_TIMER , // PB 0 ** 53 ** SPI_SS + NOT_ON_TIMER , // PF 0 ** 54 ** A0 + NOT_ON_TIMER , // PF 1 ** 55 ** A1 + NOT_ON_TIMER , // PF 2 ** 56 ** A2 + NOT_ON_TIMER , // PF 3 ** 57 ** A3 + NOT_ON_TIMER , // PF 4 ** 58 ** A4 + NOT_ON_TIMER , // PF 5 ** 59 ** A5 + NOT_ON_TIMER , // PF 6 ** 60 ** A6 + NOT_ON_TIMER , // PF 7 ** 61 ** A7 + NOT_ON_TIMER , // PK 0 ** 62 ** A8 + NOT_ON_TIMER , // PK 1 ** 63 ** A9 + NOT_ON_TIMER , // PK 2 ** 64 ** A10 + NOT_ON_TIMER , // PK 3 ** 65 ** A11 + NOT_ON_TIMER , // PK 4 ** 66 ** A12 + NOT_ON_TIMER , // PK 5 ** 67 ** A13 + NOT_ON_TIMER , // PK 6 ** 68 ** A14 + NOT_ON_TIMER , // PK 7 ** 69 ** A15 +}; +#else // these arrays map port names (e.g. port B) to the // appropriate addresses for various functions (e.g. reading // and writing) -const uint8_t PROGMEM port_to_mode_PGM[] = { +const uint16_t PROGMEM port_to_mode_PGM[] = { NOT_A_PORT, NOT_A_PORT, &DDRB, @@ -67,7 +367,7 @@ const uint8_t PROGMEM port_to_mode_PGM[] = { &DDRD, }; -const uint8_t PROGMEM port_to_output_PGM[] = { +const uint16_t PROGMEM port_to_output_PGM[] = { NOT_A_PORT, NOT_A_PORT, &PORTB, @@ -75,7 +375,7 @@ const uint8_t PROGMEM port_to_output_PGM[] = { &PORTD, }; -const uint8_t PROGMEM port_to_input_PGM[] = { +const uint16_t PROGMEM port_to_input_PGM[] = { NOT_A_PORT, NOT_A_PORT, &PINB, @@ -166,4 +466,4 @@ const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { NOT_ON_TIMER, NOT_ON_TIMER, }; - +#endif diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h index e0b7add..c7e40fd 100644 --- a/cores/arduino/pins_arduino.h +++ b/cores/arduino/pins_arduino.h @@ -39,14 +39,25 @@ #define TIMER2A 6 #define TIMER2B 7 -extern const uint8_t PROGMEM port_to_mode_PGM[]; -extern const uint8_t PROGMEM port_to_input_PGM[]; -extern const uint8_t PROGMEM port_to_output_PGM[]; +#define TIMER3A 8 +#define TIMER3B 9 +#define TIMER3C 10 +#define TIMER4A 11 +#define TIMER4B 12 +#define TIMER4C 13 +#define TIMER5A 14 +#define TIMER5B 15 +#define TIMER5C 16 + +// On the ATmega1280, the addresses of some of the port registers are +// greater than 255, so we can't store them in uint8_t's. +extern const uint16_t PROGMEM port_to_mode_PGM[]; +extern const uint16_t PROGMEM port_to_input_PGM[]; +extern const uint16_t PROGMEM port_to_output_PGM[]; extern const uint8_t PROGMEM digital_pin_to_port_PGM[]; -extern const uint8_t PROGMEM digital_pin_to_bit_PGM[]; +// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[]; extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[]; - extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; // Get the bit location within the hardware port of the given virtual pin. @@ -58,8 +69,8 @@ extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; #define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) ) #define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) ) #define analogInPinToBit(P) (P) -#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_output_PGM + (P))) ) -#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_input_PGM + (P))) ) -#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_mode_PGM + (P))) ) +#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) ) +#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) +#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) ) #endif diff --git a/cores/arduino/wiring.c b/cores/arduino/wiring.c index aaf7b86..73c26f2 100755 --- a/cores/arduino/wiring.c +++ b/cores/arduino/wiring.c @@ -196,6 +196,17 @@ void init() 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. // XXX: this will not work properly for other clock speeds, and diff --git a/cores/arduino/wiring_analog.c b/cores/arduino/wiring_analog.c index f3767d2..529ad52 100755 --- a/cores/arduino/wiring_analog.c +++ b/cores/arduino/wiring_analog.c @@ -37,12 +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). - ADMUX = (analog_reference << 6) | (pin & 0x0f); + 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); @@ -95,23 +101,23 @@ void analogWrite(uint8_t pin, int 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; - } + 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) { - if (val == 0) { - digitalWrite(pin, LOW); - } else { - // 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); @@ -122,6 +128,49 @@ 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) digitalWrite(pin, LOW); diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index 3044e18..1cdbf6c 100755 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -61,6 +61,18 @@ static inline void turnOffPWM(uint8_t timer) 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) diff --git a/cores/arduino/wiring_private.h b/cores/arduino/wiring_private.h index b30c1f0..2dfe552 100755 --- a/cores/arduino/wiring_private.h +++ b/cores/arduino/wiring_private.h @@ -46,8 +46,18 @@ 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 +#if defined(__AVR_ATmega1280__) +#define EXTERNAL_NUM_INTERRUPTS 8 +#else #define EXTERNAL_NUM_INTERRUPTS 2 +#endif typedef void (*voidFuncPtr)(void); -- cgit v1.2.3-18-g5258