update arduboy core

updated arduboy optimized core with Arduino core changes
wiring.c: optimized timer ISR by removing power down and button counters for shorter and faster code
This commit is contained in:
Mr.Blinky 2020-06-27 01:29:56 +02:00 committed by GitHub
parent ad6274071a
commit 84d1014b14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 288 additions and 281 deletions

View File

@ -113,7 +113,8 @@ void yield(void);
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
#define bitToggle(value, bit) ((value) ^= (1UL << (bit)))
#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit))
// avr-libc defines _NOP() since 1.6.2
#ifndef _NOP
@ -127,29 +128,22 @@ typedef unsigned int word;
typedef bool boolean;
typedef uint8_t byte;
//volatile unsigned char button_ticks_hold; // millis >> 8 when bootloader/reset combo buttons is pressed
//volatile unsigned char button_ticks_now; // millis >> 12
//volatile unsigned char button_ticks_last; // millis >> 12 of last button pressedd
//volatile unsigned char frame_ticks; // sychronized with millis
void init(void);
void initVariant(void);
int atexit(void (*func)()) __attribute__((weak));
void pinMode(uint8_t, uint8_t);
void digitalWrite(uint8_t, uint8_t);
int digitalRead(uint8_t);
int analogRead(uint8_t);
void pinMode(uint8_t pin, uint8_t mode);
void digitalWrite(uint8_t pin, uint8_t val);
int digitalRead(uint8_t pin);
int analogRead(uint8_t pin);
void analogReference(uint8_t mode);
void analogWrite(uint8_t, int);
void analogWrite(uint8_t pin, int val);
unsigned char buttonsIdleTime(void);
unsigned char millisChar(void);
unsigned long millis(void);
unsigned long micros(void);
void delay(unsigned long);
void delayShort(unsigned short);
void delay(unsigned long ms);
void delayShort(unsigned short ms);
void delayMicroseconds(unsigned int us);
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout);
@ -157,8 +151,8 @@ unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout);
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
void attachInterrupt(uint8_t, void (*)(void), int mode);
void detachInterrupt(uint8_t);
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode);
void detachInterrupt(uint8_t interruptNum);
void setup(void);
void loop(void);

View File

@ -18,7 +18,6 @@
#include "USBAPI.h"
#include <avr/wdt.h>
#include <avr/power.h>
#include <util/atomic.h>
#if defined(USBCON)
@ -35,18 +34,14 @@ typedef struct
static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 };
static volatile int32_t breakValue = -1;
#ifndef ARDUBOY_CORE
static u8 wdtcsr_save;
#else
extern volatile unsigned char bootloader_timer;
#endif
#define WEAK __attribute__ ((weak))
extern const CDCDescriptor _cdcInterface PROGMEM;
const CDCDescriptor _cdcInterface =
{
D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1),
D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0),
// CDC communication interface
D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0),
@ -107,33 +102,31 @@ bool CDC_Setup(USBSetup& setup)
// open at 1200 bps, is closed. this is the signal to start the watchdog
// with a relatively long period so it can finish housekeeping tasks
// like servicing endpoints before the sketch ends
#ifndef ARDUBOY_CORE
uint16_t magic_key_pos = MAGIC_KEY_POS;
// If we don't use the new RAMEND directly, check manually if we have a newer bootloader.
// This is used to keep compatible with the old leonardo bootloaders.
// You are still able to set the magic key position manually to RAMEND-1 to save a few bytes for this check.
#if MAGIC_KEY_POS != (RAMEND-1)
#if MAGIC_KEY_POS != (RAMEND-1)
// For future boards save the key in the inproblematic RAMEND
// Which is reserved for the main() return value (which will never return)
if (isLUFAbootloader()) {
// horray, we got a new bootloader!
magic_key_pos = (RAMEND-1);
}
#endif
#endif
// We check DTR state to determine if host port is open (bit 0 of lineState).
if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0)
#ifndef ARDUBOY_CORE
{
#if MAGIC_KEY_POS != (RAMEND-1)
// Backup ram value if its not a newer bootloader.
#if MAGIC_KEY_POS != (RAMEND-1)
// Backup ram value if its not a newer bootloader and it hasn't already been saved.
// This should avoid memory corruption at least a bit, not fully
if (magic_key_pos != (RAMEND-1) && *(uint16_t *)magic_key_pos != MAGIC_KEY) {
*(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos;
}
#endif
#endif
// Store boot key
*(uint16_t *)magic_key_pos = MAGIC_KEY;
// Save the watchdog state in case the reset is aborted.
@ -153,27 +146,17 @@ bool CDC_Setup(USBSetup& setup)
// Restore the watchdog state in case the sketch was using it.
WDTCSR |= (1<<WDCE) | (1<<WDE);
WDTCSR = wdtcsr_save;
#if MAGIC_KEY_POS != (RAMEND-1)
#if MAGIC_KEY_POS != (RAMEND-1)
// Restore backed up (old bootloader) magic key data
if (magic_key_pos != (RAMEND-1)) {
*(uint16_t *)magic_key_pos = *(uint16_t *)(RAMEND-1);
} else
#endif
#endif
{
// Clean up RAMEND key
*(uint16_t *)magic_key_pos = 0x0000;
}
}
#else
{
bootloader_timer = 120; //ms
power_timer0_enable(); //power timer0 is disabled by flashlight/safemode in older Arduboy2 libraries
}
else
{
bootloader_timer = 0;
}
#endif
}
return true;
}

View File

@ -218,7 +218,6 @@ size_t Stream::readBytes(char *buffer, size_t length)
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
{
if (length < 1) return 0;
size_t index = 0;
while (index < length) {
int c = timedRead();

View File

@ -65,6 +65,8 @@ public:
void detach(); // Serial port goes down too...
void poll();
bool wakeupHost(); // returns false, when wakeup cannot be processed
bool isSuspended();
};
extern USBDevice_ USBDevice;

View File

@ -496,14 +496,13 @@ bool SendConfiguration(int maxlen)
static
bool SendDescriptor(USBSetup& setup)
{
int ret;
u8 t = setup.wValueH;
if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t)
return SendConfiguration(setup.wLength);
InitControl(setup.wLength);
#ifdef PLUGGABLE_USB_ENABLED
ret = PluggableUSB().getDescriptor(setup);
int ret = PluggableUSB().getDescriptor(setup);
if (ret != 0) {
return (ret > 0 ? true : false);
}
@ -855,4 +854,10 @@ bool USBDevice_::wakeupHost()
return false;
}
bool USBDevice_::isSuspended()
{
return (_usbSuspendState & (1 << SUSPI));
}
#endif /* if defined(USBCON) */

View File

@ -97,6 +97,9 @@
// bMaxPower in Configuration Descriptor
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
#ifndef USB_CONFIG_POWER
#define USB_CONFIG_POWER (500)
#endif
// bEndpointAddress in Endpoint Descriptor
#define USB_ENDPOINT_DIRECTION_MASK 0x80
@ -267,7 +270,7 @@ typedef struct
{ 18, 1, USB_VERSION, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs }
#define D_CONFIG(_totalLength,_interfaces) \
{ 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED | USB_CONFIG_REMOTE_WAKEUP, USB_CONFIG_POWER_MA(500) }
{ 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED | USB_CONFIG_REMOTE_WAKEUP, USB_CONFIG_POWER_MA(USB_CONFIG_POWER) }
#define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \
{ 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 }

View File

@ -65,7 +65,6 @@ static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = {
nothing,
#endif
};
// volatile static voidFuncPtr twiIntFunc;
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
@ -103,6 +102,39 @@ void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
EICRB = (EICRB & ~((1<<ISC60) | (1<<ISC61))) | (mode << ISC60);
EIMSK |= (1<<INT6);
break;
#elif defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__)
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;
case 2:
EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
EIMSK |= (1 << INT2);
break;
case 3:
EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
EIMSK |= (1 << INT3);
break;
case 4:
EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40);
EIMSK |= (1 << INT4);
break;
case 5:
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;
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
case 2:
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
@ -205,7 +237,32 @@ void detachInterrupt(uint8_t interruptNum) {
break;
case 4:
EIMSK &= ~(1<<INT6);
break;
break;
#elif defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__)
case 0:
EIMSK &= ~(1 << INT0);
break;
case 1:
EIMSK &= ~(1 << INT1);
break;
case 2:
EIMSK &= ~(1 << INT2);
break;
case 3:
EIMSK &= ~(1 << INT3);
break;
case 4:
EIMSK &= ~(1 << INT4);
break;
case 5:
EIMSK &= ~(1 << INT5);
break;
case 6:
EIMSK &= ~(1 << INT6);
break;
case 7:
EIMSK &= ~(1 << INT7);
break;
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
case 2:
EIMSK &= ~(1 << INT0);
@ -274,11 +331,6 @@ void detachInterrupt(uint8_t interruptNum) {
}
}
/*
void attachInterruptTwi(void (*userFunc)(void) ) {
twiIntFunc = userFunc;
}
*/
#define IMPLEMENT_ISR(vect, interrupt) \
ISR(vect) { \
@ -293,6 +345,17 @@ IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_2)
IMPLEMENT_ISR(INT3_vect, EXTERNAL_INT_3)
IMPLEMENT_ISR(INT6_vect, EXTERNAL_INT_4)
#elif defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__)
IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_0)
IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_1)
IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_2)
IMPLEMENT_ISR(INT3_vect, EXTERNAL_INT_3)
IMPLEMENT_ISR(INT4_vect, EXTERNAL_INT_4)
IMPLEMENT_ISR(INT5_vect, EXTERNAL_INT_5)
IMPLEMENT_ISR(INT6_vect, EXTERNAL_INT_6)
IMPLEMENT_ISR(INT7_vect, EXTERNAL_INT_7)
#elif defined(EICRA) && defined(EICRB)
IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_2)
@ -314,11 +377,3 @@ IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_2)
#endif
#endif
/*
ISR(TWI_vect) {
if(twiIntFunc)
twiIntFunc();
}
*/

View File

@ -121,7 +121,7 @@ String::String(double value, unsigned char decimalPlaces)
String::~String()
{
free(buffer);
if (buffer) free(buffer);
}
/*********************************************/

View File

@ -18,8 +18,8 @@
#include <stdlib.h>
extern "C" void __cxa_pure_virtual(void) __attribute__ ((__naked__));
extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__naked__));
extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__));
extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__));
void __cxa_pure_virtual(void) {
// We might want to write some diagnostics to uart in this case

View File

@ -26,6 +26,11 @@ void *operator new[](size_t size) {
return malloc(size);
}
void * operator new(size_t size, void * ptr) noexcept {
(void)size;
return ptr;
}
void operator delete(void * ptr) {
free(ptr);
}

View File

@ -23,6 +23,7 @@
void * operator new(size_t size);
void * operator new[](size_t size);
void * operator new(size_t size, void * ptr) noexcept;
void operator delete(void * ptr);
void operator delete[](void * ptr);

View File

@ -20,8 +20,6 @@
Boston, MA 02111-1307 USA
*/
#define ARDUBOY_CORE_WIRING_C
#include "wiring_private.h"
// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
@ -42,191 +40,150 @@ volatile unsigned long timer0_millis = 0;
static unsigned char timer0_fract = 0;
volatile unsigned char button_ticks_hold = 0;
volatile unsigned char button_ticks_now = 0;
volatile unsigned char button_ticks_last = 0;
volatile unsigned char bootloader_timer = 0;
#if defined(TIM0_OVF_vect)
ISR(TIM0_OVF_vect)
ISR(TIM0_OVF_vect, ISR_NAKED)
#else
ISR(TIMER0_OVF_vect, ISR_NAKED)
#endif
{
// 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;
/*
// 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;
}
m += MILLIS_INC;
f += FRACT_INC;
if (f >= FRACT_MAX) {
f -= FRACT_MAX;
m += 1;
}
timer0_fract = f;
timer0_millis = m;
timer0_overflow_count++;
assembly optimisation saves 46 bytes compared to compiled C++ version
by adding arduboy button combo code takes 8 bytes more than C++ version
3 bytes ram saved (1 byte used extra for button_ticks_hold but 4 bytes
saved due to less stack pushes)
*/
asm volatile(
// save registers and SREG before 12622 after 12576 (saving 46 bytes)
" push r0 \n"
" in r0, __SREG__ \n"
" push r24 \n"
" push r25 \n"
" push r30 \n"
" push r31 \n"
" ldi r25, - %[millis_inc] \n" // millis_inc = MILLIS_INC;
" lds r24, %[fract] \n" // f= timer0_fract;
" subi r24, - %[fract_inc] \n" // f += FRACT_INC;
" cpi r24, %[fract_max] \n" // if (f >= FRACT_MAX)
" brcs 1f \n" // {
timer0_fract = f;
timer0_millis = m;
timer0_overflow_count++;
*/
// save registers and SREG
asm volatile(
" push r16 \n\t"
" in r16, __SREG__ \n\t"
" push r16 \n\t" //use as more functional temp reg
" push r1 \n\t"
" clr r1 \n\t" //zero reg
" push r24 \n\t"
" push r25 \n\t"
" push r30 \n\t"
" push r31 \n\t"
);
asm volatile(
" lds r24, %[fract] \n\t" // f= timer0_fract;
" ldi r25, %[millis_inc] \n\t" // millis_inc = MILLIS_INC;
" subi r24, %[fract_inc] \n\t" // f += FRACT_INC;
" cpi r24, %[fract_max] \n\t" // if (f >= FRACT_MAX) {
" brcs 1f \n\t"
" subi r24, %[fract_max] \n\t" // f -= FRACT_MAX;
" inc r25 \n\t" // millis_inc++ }
"1: \n\t"
" sts %[fract], r24 \n\t" // timer0_fract = f;
" ld r24, z \n\t" //timer0_millis += millis_inc
" add r24, r25 \n\t"
" st z, r24 \n\t"
" ldd r25, z+1 \n\t"
" adc r25, r1 \n\t"
" std z+1, r25 \n\t" // r25 = (millis >>8)
" ldd r16, z+2 \n\t"
" adc r16, r1 \n\t"
" std z+2, r16 \n\t" // r16 = (millis >>16)
" ldd r24, z+3 \n\t"
" adc r24, r1 \n\t"
" std z+3, r24 \n\t"
" eor r16, r25 \n\t" //button_ticks_now = (millis >> 12)
" andi r16, 0x0F \n\t"
" eor r16, r25 \n\t"
" swap r16 \n\t"
" sts %[buttons_now], r16 \n\t"
:
: [millis] "z" (&timer0_millis),
[fract] "" (&timer0_fract),
[buttons_now] "" (&button_ticks_now),
[millis_inc] "M" (MILLIS_INC),
[fract_inc] "M" (256 - FRACT_INC), // negated for subi instruction
[fract_max] "M" (FRACT_MAX)
:
);
//Arduboy bootloader and reset button feature
asm volatile (
" rcall scan_buttons \n\t"
" cpse r24, r1 \n\t" //if (buttons) button_ticks_last = (uint8_t)(Millis >> 12)
" sts %[apd], r16 \n\t"
#ifdef AB_DEVKIT
" cpi r24, 0x50 \n\t" // test DevKit UP+DOWN for bootloader
#else
" cpi r24, 0x90 \n\t" // test arduboy UP+DOWN for bootloader
#endif
" brne 5f \n\t"
"2: lds r16, %[hold] \n\t"
" sub r25, r16 \n\t" // (uint8_t)(timer0_millis >> 8) - button_ticks_last
" cpi r25, 6 \n\t"
" brcs 6f \n\t" // if ((millis - hold) >= 6) {
"3: ldi r24, 0x77 \n\t"
" sts 0x800, r24 \n\t"
" sts 0x801, r24 \n\t"
" ldi r24, %[value1] \n\t"
" ldi r25, %[value2] \n\t"
" sts %[wdtcsr], r24 \n\t"
" sts %[wdtcsr], r25 \n\t"
" rjmp .-2 \n\t" // }
"5: \n\t"
" sts %[hold], r25 \n\t" //button_ticks_hold = (uint8_t)(Millis >> 8)
"6: \n\t"
" lds r24, %[btimer] \n\t" //if (bootloader_timer--) {
" subi r24, 1 \n\t"
" brcs 7f \n\t"
" sts %[btimer],r24 \n\t"
" breq 3b \n\t" // if (bootloader_timer == 0) runBootLoader;
"7: \n\t" //}
" subi r24, %[fract_max] \n" // f -= FRACT_MAX;
" dec r25 \n" // millis_inc++
"1: \n" // }
" sts %[fract], r24 \n" // timer0_fract = f;
// timer0_millis += millis_inc (addition by substracting negative value)
" ldi r30, lo8(%[millis]) \n"
" ldi r31, hi8(%[millis]) \n"
" ld r24, z \n"
" sub r24, r25 \n"
" st z, r24 \n"
" ldd r25, z+1 \n"
" sbci r25, 0xFF \n" // save (uint8_t)(timer0_millis >> 8) in 25
" std z+1, r25 \n"
" ldd r24, z+2 \n"
" sbci r24, 0xFF \n"
" std z+2, r24 \n"
" ldd r24, z+3 \n"
" sbci r24, 0xFF \n"
" std z+3, r24 \n"
//timer0_overflow_count++;
" ldi r30, lo8(%[count]) \n"
" ldi r31, hi8(%[count]) \n"
" ld r24, z \n"
" subi r24, 0xFF \n" // ++ (addition by substracting negative value)
" st z, r24 \n"
" ldd r24, z+1 \n"
" sbci r24, 0xFF \n"
" std z+1, r24 \n"
" ldd r24, z+2 \n"
" sbci r24, 0xFF \n"
" std z+2, r24 \n"
" ldd r24, z+3 \n"
" sbci r24, 0xFF \n"
" std z+3, r24 \n"
//read Arduboy buttons
#ifdef AB_DEVKIT
" in r24, %[pinb] \n" // down, left, up buttons
" andi r24, 0x8F \n"
" sbis %[pinc], 6 \n" // right button
" andi r24, 0xFB \n"
" sbis %[pinf], 7 \n" // A button
" andi r24, 0xFD \n"
" sbis %[pinf], 6 \n" // B button
" andi r24, 0xFE \n"
" cpi r24, 0xAF \n" // test DevKit UP+DOWN for bootloader
#else
" in r24, %[pinf] \n" // directional buttons
" ori r24, 0x0F \n"
" sbis %[pine], 6 \n" // A button
" andi r24, 0xF7 \n"
" sbis %[pinb], 4 \n" // B button
" andi r24, 0xFB \n"
" cpi r24, 0x6F \n" // test arduboy UP+DOWN for bootloader
#endif
" brne 5f \n" // skip button combo not pressed
// test button combo hold long enough
"2: lds r24, %[hold] \n"
" sub r25, r24 \n" // (uint8_t)(timer0_millis >> 8) - button_ticks_hold
" cpi r25, 6 \n" // 1536ms >> 8
" brcs 6f \n" // skip not long enough
//button combo pressed long enough: trigger bootloader mode
".global exit_to_bootloader \n"
"exit_to_bootloader: \n"
"3: ldi r24, 0x77 \n" // set bootloader MAGIC KEY
" sts 0x800, r24 \n"
" sts 0x801, r24 \n"
" ldi r24, %[value1] \n" // set watchdog timer
" ldi r25, %[value2] \n"
" sts %[wdtcsr], r24 \n"
" sts %[wdtcsr], r25 \n"
" rjmp .-2 \n" // infinite loop will trigger watchdog reset
"5: \n" // }
// reset button_ticks_hold
" sts %[hold], r25 \n" // button_ticks_hold = (uint8_t)(Millis >> 8)
"6: \n"
//restore registers and return from interrupt
" pop r31 \n"
" pop r30 \n"
" pop r25 \n"
" pop r24 \n"
" out __SREG__, r0 \n"
" pop r0 \n"
" reti \n"
:
: [hold] "" (&button_ticks_hold),
[apd] "" (&button_ticks_last),
[btimer] "" (&bootloader_timer),
: [millis] "" (&timer0_millis),
[fract] "" (&timer0_fract),
[millis_inc] "M" (MILLIS_INC),
[fract_inc] "M" (FRACT_INC),
[fract_max] "M" (FRACT_MAX),
[count] "" (&timer0_overflow_count),
[hold] "" (&button_ticks_hold),
[pinf] "I" (_SFR_IO_ADDR(PINF)),
[pine] "I" (_SFR_IO_ADDR(PINE)),
[pinc] "I" (_SFR_IO_ADDR(PINC)),
[pinb] "I" (_SFR_IO_ADDR(PINB)),
[value1] "M" ((uint8_t)(_BV(WDCE) | _BV(WDE))),
[value2] "M" ((uint8_t)(_BV(WDE))),
[wdtcsr] "M" (_SFR_MEM_ADDR(WDTCSR))
:
);
//timer0_overflow_count++;
asm volatile (
" ld r24, z \n\t"
" ldd r25, z+1 \n\t"
" adiw r24, 1 \n\t"
" st z, r24 \n\t"
" std z+1, r25 \n\t"
" ldd r24, z+2 \n\t"
" ldd r25, z+3 \n\t"
" adc r24, r1 \n\t"
" adc r25, r1 \n\t"
" std z+2, r24 \n\t"
" std z+3, r25 \n\t"
:
: "z" (&timer0_overflow_count)
);
//restore registers and retirn from interrupt
asm volatile (
" pop r31 \n\t"
" pop r30 \n\t"
" pop r25 \n\t"
" pop r24 \n\t"
" pop r1 \n\t"
" pop r16 \n\t"
" out __SREG__, r16 \n\t"
" pop r16 \n\t"
" reti \n\t"
".global scan_buttons \n\t"
"scan_buttons: \n\t"
#ifdef AB_DEVKIT
" in r24, %[pinb] \n\t" // down, left, up buttons
" com r24 \n\t"
" andi r24, 0x70 \n\t"
" sbis %[pinc], 6 \n\t" // right button
" ori r24, 0x04 \n\t"
" sbis %[pinf], 7 \n\t" // A button
" ori r24, 0x02 \n\t"
" sbis %[pinf], 6 \n\t" // B button
" ori r24, 0x01 \n\t"
#else
" in r24, %[pinf] \n\t" // directional buttons
" com r24 \n\t"
" andi r24, 0xF0 \n\t"
" sbis %[pine], 6 \n\t" // A button
" ori r24, 0x08 \n\t"
" sbis %[pinb], 4 \n\t" // B button
" ori r24, 0x04 \n\t"
#endif
" ret \n\t" // Z flag set from AND when no button is pressed
:
: [pinf] "I" (_SFR_IO_ADDR(PINF)),
[pine] "I" (_SFR_IO_ADDR(PINE)),
[pinc] "I" (_SFR_IO_ADDR(PINC)),
[pinb] "I" (_SFR_IO_ADDR(PINB))
);
}
unsigned char buttonsIdleTime()
{
return button_ticks_now - button_ticks_last;
}
unsigned char millisChar()
{
return *(unsigned char*)&timer0_millis;
}
unsigned long millis()
{
unsigned long m;
@ -428,9 +385,9 @@ void delayMicroseconds(unsigned int us)
// for a one-microsecond delay, simply return. the overhead
// of the function call takes 18 (20) cycles, which is 1us
__asm__ __volatile__ (
"nop" "\n\t"
"nop" "\n\t"
"nop" "\n\t"
"nop" "\n"
"nop" "\n"
"nop" "\n"
"nop"); //just waiting 4 cycles
if (us <= 1) return; // = 3 cycles, (4 when true)
@ -514,7 +471,7 @@ void delayMicroseconds(unsigned int us)
// busy wait
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t" // 2 cycles
"1: sbiw %0,1" "\n" // 2 cycles
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
);
// return = 4 cycles
@ -533,8 +490,8 @@ void init() //assembly optimized by 68 bytes
//sbi(TCCR0A, WGM01);
//sbi(TCCR0A, WGM00);
asm volatile(
" ldi r24, %[value] \n\t"
" out %[tccr0a], r24 \n\t"
" ldi r24, %[value] \n"
" out %[tccr0a], r24 \n"
:
: [tccr0a] "I" (_SFR_IO_ADDR(TCCR0A)),
[value] "M" (_BV(WGM01) | _BV(WGM00))
@ -555,8 +512,8 @@ void init() //assembly optimized by 68 bytes
//sbi(TCCR0B, CS01);
//sbi(TCCR0B, CS00);
asm volatile(
" ldi r24, %[value] \n\t"
" out %[tccr0b], r24 \n\t"
" ldi r24, %[value] \n"
" out %[tccr0b], r24 \n"
:
: [tccr0b] "I" (_SFR_IO_ADDR(TCCR0B)),
[value] "M" (_BV(CS01) | _BV(CS00))
@ -593,10 +550,10 @@ void init() //assembly optimized by 68 bytes
//sbi(TCCR1B, CS10);
//#endif
asm volatile(
" ldi r30, %[tccr1b] \n\t"
" ldi r31, 0x00 \n\t"
" ldi r24, %[value] \n\t"
" st z, r24 \n\t"
" ldi r30, %[tccr1b] \n"
" ldi r31, 0x00 \n"
" ldi r24, %[value] \n"
" st z, r24 \n"
:
: [tccr1b] "M" (_SFR_MEM_ADDR(TCCR1B)),
#if F_CPU >= 8000000L
@ -617,9 +574,9 @@ void init() //assembly optimized by 68 bytes
#if defined(TCCR1A) && defined(WGM10)
//sbi(TCCR1A, WGM10);
asm volatile(
" ldi r30, %[tccr1a] \n\t"
" ldi r24, %[wgm10] \n\t"
" st z, r24 \n\t"
" ldi r30, %[tccr1a] \n"
" ldi r24, %[wgm10] \n"
" st z, r24 \n"
:
: [tccr1a] "M" (_SFR_MEM_ADDR(TCCR1A)),
[wgm10] "M" (_BV(WGM10))
@ -649,9 +606,9 @@ void init() //assembly optimized by 68 bytes
//sbi(TCCR3B, CS31); // set timer 3 prescale factor to 64
//sbi(TCCR3B, CS30);
asm volatile(
" ldi r30, %[tccr3b] \n\t"
" ldi r24, %[value] \n\t"
" st z, r24 \n\t"
" ldi r30, %[tccr3b] \n"
" ldi r24, %[value] \n"
" st z, r24 \n"
:
: [tccr3b] "M" (_SFR_MEM_ADDR(TCCR3B)),
[value] "M" (_BV(CS31) | _BV(CS30))
@ -659,9 +616,9 @@ void init() //assembly optimized by 68 bytes
);
//sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode
asm volatile(
" ldi r30, %[tccr3a] \n\t"
" ldi r24, %[wgm30] \n\t"
" st z, r24 \n\t"
" ldi r30, %[tccr3a] \n"
" ldi r24, %[wgm30] \n"
" st z, r24 \n"
:
: [tccr3a] "M" (_SFR_MEM_ADDR(TCCR3A)),
[wgm30] "M" (_BV(WGM30))
@ -674,9 +631,9 @@ void init() //assembly optimized by 68 bytes
//sbi(TCCR4B, CS41);
//sbi(TCCR4B, CS40);
asm volatile(
" ldi r30, %[tccr4b] \n\t"
" ldi r24, %[value] \n\t"
" st z, r24 \n\t"
" ldi r30, %[tccr4b] \n"
" ldi r24, %[value] \n"
" st z, r24 \n"
:
: [tccr4b] "M" (_SFR_MEM_ADDR(TCCR4B)),
[value] "M" (_BV(CS42) | _BV(CS41) | _BV(CS40))
@ -684,9 +641,9 @@ void init() //assembly optimized by 68 bytes
);
//sbi(TCCR4D, WGM40); // put timer 4 in phase- and frequency-correct PWM mode
asm volatile(
" ldi r30, %[tccr4d] \n\t"
" ldi r24, %[wgm40] \n\t"
" st z, r24 \n\t"
" ldi r30, %[tccr4d] \n"
" ldi r24, %[wgm40] \n"
" st z, r24 \n"
:
: [tccr4d] "M" (_SFR_MEM_ADDR(TCCR4D)),
[wgm40] "M" (_BV(WGM40))
@ -694,9 +651,9 @@ void init() //assembly optimized by 68 bytes
);
//sbi(TCCR4A, PWM4A); // enable PWM mode for comparator OCR4A
asm volatile(
" ldi r30, %[tccr4a] \n\t"
" ldi r24, %[pwm4a] \n\t"
" st z, r24 \n\t"
" ldi r30, %[tccr4a] \n"
" ldi r24, %[pwm4a] \n"
" st z, r24 \n"
:
: [tccr4a] "M" (_SFR_MEM_ADDR(TCCR4A)),
[pwm4a] "M" (_BV(PWM4A))
@ -704,9 +661,9 @@ void init() //assembly optimized by 68 bytes
);
//sbi(TCCR4C, PWM4D); // enable PWM mode for comparator OCR4D
asm volatile(
" ldi r30, %[tccr4c] \n\t"
" ldi r24, %[value] \n\t"
" st z, r24 \n\t"
" ldi r30, %[tccr4c] \n"
" ldi r24, %[value] \n"
" st z, r24 \n"
:
: [tccr4c] "M" (_SFR_MEM_ADDR(TCCR4C)),
[value] "M" (_BV(PWM4D))
@ -733,9 +690,9 @@ void init() //assembly optimized by 68 bytes
//sbi(ADCSRA, ADPS1);
//sbi(ADCSRA, ADPS0);
asm volatile(
" ldi r30, %[adcsra] \n\t"
" ldi r24, %[value] \n\t"
" st z, r24 \n\t"
" ldi r30, %[adcsra] \n"
" ldi r24, %[value] \n"
" st z, r24 \n"
:
: [adcsra] "M" (_SFR_MEM_ADDR(ADCSRA)),
[value] "M" (_BV(ADPS2) |_BV(ADPS1) | _BV(ADPS0))
@ -746,9 +703,9 @@ void init() //assembly optimized by 68 bytes
//sbi(ADCSRA, ADPS1);
//cbi(ADCSRA, ADPS0);
asm volatile(
" ldi r30, %[adcsra] \n\t"
" ldi r24, %[value] \n\t"
" st z, r24 \n\t"
" ldi r30, %[adcsra] \n"
" ldi r24, %[value] \n"
" st z, r24 \n"
:
: [adcsra] "M" (_SFR_MEM_ADDR(ADCSRA)),
[value] "M" (_BV(ADPS2) | _BV(ADPS1))
@ -774,14 +731,14 @@ void init() //assembly optimized by 68 bytes
// enable a2d conversions
//sbi(ADCSRA, ADEN);
asm volatile(
" ori r24, %[aden] \n\t"
" st z, r24 \n\t"
" ori r24, %[aden] \n"
" st z, r24 \n"
:
: [aden] "M" (_BV(ADEN))
: "r24", "r30", "r31"
);
#endif
//(below not relevant for atmega32u4)
// 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()

View File

@ -42,10 +42,13 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
uint8_t i;
for (i = 0; i < 8; i++) {
if (bitOrder == LSBFIRST)
digitalWrite(dataPin, !!(val & (1 << i)));
else
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
if (bitOrder == LSBFIRST) {
digitalWrite(dataPin, val & 1);
val >>= 1;
} else {
digitalWrite(dataPin, (val & 128) != 0);
val <<= 1;
}
digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW);