mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-22 08:22:04 +03:00
Adding support for the Arduino Mega (ATmega1280) to the core and bootloader.
This commit is contained in:
@ -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 <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
|
||||
|
||||
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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
} else {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
else
|
||||
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;
|
||||
}
|
||||
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user