1282 lines
44 KiB
C++
1282 lines
44 KiB
C++
|
#include "Repetier.h"
|
||
|
#include <compat/twi.h>
|
||
|
|
||
|
//extern "C" void __cxa_pure_virtual() { }
|
||
|
|
||
|
HAL::HAL()
|
||
|
{
|
||
|
//ctor
|
||
|
}
|
||
|
|
||
|
HAL::~HAL()
|
||
|
{
|
||
|
//dtor
|
||
|
}
|
||
|
|
||
|
uint16_t HAL::integerSqrt(uint32_t a)
|
||
|
{
|
||
|
// http://www.mikrocontroller.net/articles/AVR_Arithmetik#32_Bit_.2F_32_Bit
|
||
|
//-----------------------------------------------------------
|
||
|
// Fast and short 32 bits AVR sqrt routine, avr-gcc ABI compliant
|
||
|
// R25:R24 = SQRT (R25:R24:R23:R22) rounded to the
|
||
|
// nearest integer (0.5 rounds up)
|
||
|
// Destroys R18-R19,R22-R23,R26-R27
|
||
|
// Cycles incl call & ret = 265-310
|
||
|
// Stack incl call = 2-3
|
||
|
//-----------------------------------------------------------
|
||
|
|
||
|
uint16_t b;
|
||
|
|
||
|
__asm__ __volatile__ (
|
||
|
"ldi R19, 0xc0 \n\t"
|
||
|
"clr R18 \n\t" // rotation mask in R19:R18
|
||
|
"ldi R27, 0x40 \n\t"
|
||
|
"sub R26, R26 \n\t" // developing sqrt in R27:R26, C=0
|
||
|
"1: brcs 2f \n\t" // C --> Bit is always 1
|
||
|
"cp %C1, R26 \n\t"
|
||
|
"cpc %D1, R27 \n\t" // Does test value fit?
|
||
|
"brcs 3f \n\t" // C --> nope, bit is 0
|
||
|
"2: sub %C1, R26 \n\t"
|
||
|
"sbc %D1, R27 \n\t" // Adjust argument for next bit
|
||
|
"or R26, R18 \n\t"
|
||
|
"or R27, R19 \n\t" // Set bit to 1
|
||
|
"3: lsr R19 \n\t"
|
||
|
"ror R18 \n\t" // Shift right mask, C --> end loop
|
||
|
"eor R27, R19 \n\t"
|
||
|
"eor R26, R18 \n\t" // Shift right only test bit in result
|
||
|
"rol %A1 \n\t" // Bit 0 only set if end of loop
|
||
|
"rol %B1 \n\t"
|
||
|
"rol %C1 \n\t"
|
||
|
"rol %D1 \n\t" // Shift left remaining argument (C used at 1:)
|
||
|
"sbrs %A1, 0 \n\t" // Skip if 15 bits developed
|
||
|
"rjmp 1b \n\t" // Develop 15 bits of the sqrt
|
||
|
"brcs 4f \n\t" // C--> Last bits always 1
|
||
|
"cp R26, %C1 \n\t"
|
||
|
"cpc R27, %D1 \n\t" // Test for last bit 1
|
||
|
"brcc 5f \n\t" // NC --> bit is 0
|
||
|
"4: sbc %B1, R19 \n\t" // Subtract C (any value from 1 to 0x7f will do)
|
||
|
"sbc %C1, R26 \n\t"
|
||
|
"sbc %D1, R27 \n\t" // Update argument for test
|
||
|
"inc R26 \n\t" // Last bit is 1
|
||
|
"5: lsl %B1 \n\t" // Only bit 7 matters
|
||
|
"rol %C1 \n\t"
|
||
|
"rol %D1 \n\t" // Remainder * 2 + C
|
||
|
"brcs 6f \n\t" // C --> Always round up
|
||
|
"cp R26, %C1 \n\t"
|
||
|
"cpc R27, %D1 \n\t" // C decides rounding
|
||
|
"6: adc R26, R19 \n\t"
|
||
|
"adc R27, R19 \n\t" // Round up if C (R19=0)
|
||
|
"mov %B0, R27 \n\t" // return in R25:R24 for avr-gcc ABI compliance
|
||
|
"mov %A0, R26 \n\t"
|
||
|
:"=r"(b)
|
||
|
:"r"(a)
|
||
|
:"r18","r19","r27","r26" );
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
const uint16_t fast_div_lut[17] PROGMEM = {0,F_CPU/4096,F_CPU/8192,F_CPU/12288,F_CPU/16384,F_CPU/20480,F_CPU/24576,F_CPU/28672,F_CPU/32768,F_CPU/36864
|
||
|
,F_CPU/40960,F_CPU/45056,F_CPU/49152,F_CPU/53248,F_CPU/57344,F_CPU/61440,F_CPU/65536
|
||
|
};
|
||
|
|
||
|
const uint16_t slow_div_lut[257] PROGMEM = {0,0,0,0,0,0,0,0,F_CPU/256,F_CPU/288,F_CPU/320,F_CPU/352
|
||
|
,F_CPU/384,F_CPU/416,F_CPU/448,F_CPU/480,F_CPU/512,F_CPU/544,F_CPU/576,F_CPU/608,F_CPU/640,F_CPU/672,F_CPU/704,F_CPU/736,F_CPU/768,F_CPU/800,F_CPU/832
|
||
|
,F_CPU/864,F_CPU/896,F_CPU/928,F_CPU/960,F_CPU/992,F_CPU/1024,F_CPU/1056,F_CPU/1088,F_CPU/1120,F_CPU/1152,F_CPU/1184,F_CPU/1216,F_CPU/1248,F_CPU/1280,F_CPU/1312
|
||
|
,F_CPU/1344,F_CPU/1376,F_CPU/1408,F_CPU/1440,F_CPU/1472,F_CPU/1504,F_CPU/1536,F_CPU/1568,F_CPU/1600,F_CPU/1632,F_CPU/1664,F_CPU/1696,F_CPU/1728,F_CPU/1760,F_CPU/1792
|
||
|
,F_CPU/1824,F_CPU/1856,F_CPU/1888,F_CPU/1920,F_CPU/1952,F_CPU/1984,F_CPU/2016
|
||
|
,F_CPU/2048,F_CPU/2080,F_CPU/2112,F_CPU/2144,F_CPU/2176,F_CPU/2208,F_CPU/2240,F_CPU/2272,F_CPU/2304,F_CPU/2336,F_CPU/2368,F_CPU/2400
|
||
|
,F_CPU/2432,F_CPU/2464,F_CPU/2496,F_CPU/2528,F_CPU/2560,F_CPU/2592,F_CPU/2624,F_CPU/2656,F_CPU/2688,F_CPU/2720,F_CPU/2752,F_CPU/2784,F_CPU/2816,F_CPU/2848,F_CPU/2880
|
||
|
,F_CPU/2912,F_CPU/2944,F_CPU/2976,F_CPU/3008,F_CPU/3040,F_CPU/3072,F_CPU/3104,F_CPU/3136,F_CPU/3168,F_CPU/3200,F_CPU/3232,F_CPU/3264,F_CPU/3296,F_CPU/3328,F_CPU/3360
|
||
|
,F_CPU/3392,F_CPU/3424,F_CPU/3456,F_CPU/3488,F_CPU/3520,F_CPU/3552,F_CPU/3584,F_CPU/3616,F_CPU/3648,F_CPU/3680,F_CPU/3712,F_CPU/3744,F_CPU/3776,F_CPU/3808,F_CPU/3840
|
||
|
,F_CPU/3872,F_CPU/3904,F_CPU/3936,F_CPU/3968,F_CPU/4000,F_CPU/4032,F_CPU/4064
|
||
|
,F_CPU/4096,F_CPU/4128,F_CPU/4160,F_CPU/4192,F_CPU/4224,F_CPU/4256,F_CPU/4288,F_CPU/4320,F_CPU/4352,F_CPU/4384,F_CPU/4416,F_CPU/4448,F_CPU/4480,F_CPU/4512,F_CPU/4544
|
||
|
,F_CPU/4576,F_CPU/4608,F_CPU/4640,F_CPU/4672,F_CPU/4704,F_CPU/4736,F_CPU/4768,F_CPU/4800,F_CPU/4832,F_CPU/4864,F_CPU/4896,F_CPU/4928,F_CPU/4960,F_CPU/4992,F_CPU/5024
|
||
|
,F_CPU/5056,F_CPU/5088,F_CPU/5120,F_CPU/5152,F_CPU/5184,F_CPU/5216,F_CPU/5248,F_CPU/5280,F_CPU/5312,F_CPU/5344,F_CPU/5376,F_CPU/5408,F_CPU/5440,F_CPU/5472,F_CPU/5504
|
||
|
,F_CPU/5536,F_CPU/5568,F_CPU/5600,F_CPU/5632,F_CPU/5664,F_CPU/5696,F_CPU/5728,F_CPU/5760,F_CPU/5792,F_CPU/5824,F_CPU/5856,F_CPU/5888,F_CPU/5920,F_CPU/5952,F_CPU/5984
|
||
|
,F_CPU/6016,F_CPU/6048,F_CPU/6080,F_CPU/6112,F_CPU/6144,F_CPU/6176,F_CPU/6208,F_CPU/6240,F_CPU/6272,F_CPU/6304,F_CPU/6336,F_CPU/6368,F_CPU/6400,F_CPU/6432,F_CPU/6464
|
||
|
,F_CPU/6496,F_CPU/6528,F_CPU/6560,F_CPU/6592,F_CPU/6624,F_CPU/6656,F_CPU/6688,F_CPU/6720,F_CPU/6752,F_CPU/6784,F_CPU/6816,F_CPU/6848,F_CPU/6880,F_CPU/6912,F_CPU/6944
|
||
|
,F_CPU/6976,F_CPU/7008,F_CPU/7040,F_CPU/7072,F_CPU/7104,F_CPU/7136,F_CPU/7168,F_CPU/7200,F_CPU/7232,F_CPU/7264,F_CPU/7296,F_CPU/7328,F_CPU/7360,F_CPU/7392,F_CPU/7424
|
||
|
,F_CPU/7456,F_CPU/7488,F_CPU/7520,F_CPU/7552,F_CPU/7584,F_CPU/7616,F_CPU/7648,F_CPU/7680,F_CPU/7712,F_CPU/7744,F_CPU/7776,F_CPU/7808,F_CPU/7840,F_CPU/7872,F_CPU/7904
|
||
|
,F_CPU/7936,F_CPU/7968,F_CPU/8000,F_CPU/8032,F_CPU/8064,F_CPU/8096,F_CPU/8128,F_CPU/8160,F_CPU/8192
|
||
|
};
|
||
|
/** \brief approximates division of F_CPU/divisor
|
||
|
|
||
|
In the stepper interrupt a division is needed, which is a slow operation.
|
||
|
The result is used for timer calculation where small errors are ok. This
|
||
|
function uses lookup tables to find a fast approximation of the result.
|
||
|
|
||
|
*/
|
||
|
int32_t HAL::CPUDivU2(unsigned int divisor)
|
||
|
{
|
||
|
#if CPU_ARCH==ARCH_AVR
|
||
|
int32_t res;
|
||
|
unsigned short table;
|
||
|
if(divisor<8192)
|
||
|
{
|
||
|
if(divisor<512)
|
||
|
{
|
||
|
if(divisor<10) divisor = 10;
|
||
|
return Div4U2U(F_CPU,divisor); // These entries have overflows in lookuptable!
|
||
|
}
|
||
|
table = (unsigned short)&slow_div_lut[0];
|
||
|
__asm__ __volatile__( // needs 64 ticks neu 49 Ticks
|
||
|
"mov r18,%A1 \n\t"
|
||
|
"andi r18,31 \n\t" // divisor & 31 in r18
|
||
|
"lsr %B1 \n\t" // divisor >> 4
|
||
|
"ror %A1 \n\t"
|
||
|
"lsr %B1 \n\t"
|
||
|
"ror %A1 \n\t"
|
||
|
"lsr %B1 \n\t"
|
||
|
"ror %A1 \n\t"
|
||
|
"lsr %B1 \n\t"
|
||
|
"ror %A1 \n\t"
|
||
|
"andi %A1,254 \n\t"
|
||
|
"add %A2,%A1 \n\t" // table+divisor>>3
|
||
|
"adc %B2,%B1 \n\t"
|
||
|
"lpm %A0,Z+ \n\t" // y0 in res
|
||
|
"lpm %B0,Z+ \n\t" // %C0,%D0 are 0
|
||
|
"movw r4,%A0 \n\t" // y0 nach gain (r4-r5)
|
||
|
"lpm r0,Z+ \n\t" // gain = gain-y1
|
||
|
"sub r4,r0 \n\t"
|
||
|
"lpm r0,Z+ \n\t"
|
||
|
"sbc r5,r0 \n\t"
|
||
|
"mul r18,r4 \n\t" // gain*(divisor & 31)
|
||
|
"movw %A1,r0 \n\t" // divisor not needed any more, use for byte 0,1 of result
|
||
|
"mul r18,r5 \n\t"
|
||
|
"add %B1,r0 \n\t"
|
||
|
"mov %A2,r1 \n\t"
|
||
|
"lsl %A1 \n\t"
|
||
|
"rol %B1 \n\t"
|
||
|
"rol %A2 \n\t"
|
||
|
"lsl %A1 \n\t"
|
||
|
"rol %B1 \n\t"
|
||
|
"rol %A2 \n\t"
|
||
|
"lsl %A1 \n\t"
|
||
|
"rol %B1 \n\t"
|
||
|
"rol %A2 \n\t"
|
||
|
"sub %A0,%B1 \n\t"
|
||
|
"sbc %B0,%A2 \n\t"
|
||
|
"clr %C0 \n\t"
|
||
|
"clr %D0 \n\t"
|
||
|
"clr r1 \n\t"
|
||
|
: "=&r" (res),"=&d"(divisor),"=&z"(table) : "1"(divisor),"2"(table) : "r18","r4","r5");
|
||
|
return res;
|
||
|
/*unsigned short adr0 = (unsigned short)&slow_div_lut+(divisor>>4)&1022;
|
||
|
long y0= pgm_read_dword_near(adr0);
|
||
|
long gain = y0-pgm_read_dword_near(adr0+2);
|
||
|
return y0-((gain*(divisor & 31))>>5);*/
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
table = (unsigned short)&fast_div_lut[0];
|
||
|
__asm__ __volatile__( // needs 49 ticks
|
||
|
"movw r18,%A1 \n\t"
|
||
|
"andi r19,15 \n\t" // divisor & 4095 in r18,r19
|
||
|
"lsr %B1 \n\t" // divisor >> 3, then %B1 is 2*(divisor >> 12)
|
||
|
"lsr %B1 \n\t"
|
||
|
"lsr %B1 \n\t"
|
||
|
"andi %B1,254 \n\t"
|
||
|
"add %A2,%B1 \n\t" // table+divisor>>11
|
||
|
"adc %B2,r1 \n\t" //
|
||
|
"lpm %A0,Z+ \n\t" // y0 in res
|
||
|
"lpm %B0,Z+ \n\t"
|
||
|
"movw r4,%A0 \n\t" // y0 to gain (r4-r5)
|
||
|
"lpm r0,Z+ \n\t" // gain = gain-y1
|
||
|
"sub r4,r0 \n\t"
|
||
|
"lpm r0,Z+ \n\t"
|
||
|
"sbc r5,r0 \n\t" // finished - result has max. 16 bit
|
||
|
"mul r18,r4 \n\t" // gain*(divisor & 4095)
|
||
|
"movw %A1,r0 \n\t" // divisor not needed any more, use for byte 0,1 of result
|
||
|
"mul r19,r5 \n\t"
|
||
|
"mov %A2,r0 \n\t" // %A2 = byte 3 of result
|
||
|
"mul r18,r5 \n\t"
|
||
|
"add %B1,r0 \n\t"
|
||
|
"adc %A2,r1 \n\t"
|
||
|
"mul r19,r4 \n\t"
|
||
|
"add %B1,r0 \n\t"
|
||
|
"adc %A2,r1 \n\t"
|
||
|
"andi %B1,240 \n\t" // >> 12
|
||
|
"swap %B1 \n\t"
|
||
|
"swap %A2 \r\n"
|
||
|
"mov %A1,%A2 \r\n"
|
||
|
"andi %A1,240 \r\n"
|
||
|
"or %B1,%A1 \r\n"
|
||
|
"andi %A2,15 \r\n"
|
||
|
"sub %A0,%B1 \n\t"
|
||
|
"sbc %B0,%A2 \n\t"
|
||
|
"clr %C0 \n\t"
|
||
|
"clr %D0 \n\t"
|
||
|
"clr r1 \n\t"
|
||
|
: "=&r" (res),"=&d"(divisor),"=&z"(table) : "1"(divisor),"2"(table) : "r18","r19","r4","r5");
|
||
|
return res;
|
||
|
/*
|
||
|
// The asm mimics the following code
|
||
|
unsigned short adr0 = (unsigned short)&fast_div_lut+(divisor>>11)&254;
|
||
|
unsigned short y0= pgm_read_word_near(adr0);
|
||
|
unsigned short gain = y0-pgm_read_word_near(adr0+2);
|
||
|
return y0-(((long)gain*(divisor & 4095))>>12);*/
|
||
|
}
|
||
|
#else
|
||
|
return F_CPU/divisor;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void HAL::setupTimer()
|
||
|
{
|
||
|
#if USE_ADVANCE
|
||
|
EXTRUDER_TCCR = 0; // need Normal not fastPWM set by arduino init
|
||
|
EXTRUDER_TIMSK |= (1<<EXTRUDER_OCIE); // Activate compa interrupt on timer 0
|
||
|
#endif
|
||
|
PWM_TCCR = 0; // Setup PWM interrupt
|
||
|
PWM_OCR = 64;
|
||
|
PWM_TIMSK |= (1<<PWM_OCIE);
|
||
|
|
||
|
TCCR1A = 0; // Steup timer 1 interrupt to no prescale CTC mode
|
||
|
TCCR1C = 0;
|
||
|
TIMSK1 = 0;
|
||
|
TCCR1B = (_BV(WGM12) | _BV(CS10)); // no prescaler == 0.0625 usec tick | 001 = clk/1
|
||
|
OCR1A=65500; //start off with a slow frequency.
|
||
|
TIMSK1 |= (1<<OCIE1A); // Enable interrupt
|
||
|
#if FEATURE_SERVO
|
||
|
#if SERVO0_PIN>-1
|
||
|
SET_OUTPUT(SERVO0_PIN);
|
||
|
WRITE(SERVO0_PIN,LOW);
|
||
|
#endif
|
||
|
#if SERVO1_PIN>-1
|
||
|
SET_OUTPUT(SERVO1_PIN);
|
||
|
WRITE(SERVO1_PIN,LOW);
|
||
|
#endif
|
||
|
#if SERVO2_PIN>-1
|
||
|
SET_OUTPUT(SERVO2_PIN);
|
||
|
WRITE(SERVO2_PIN,LOW);
|
||
|
#endif
|
||
|
#if SERVO3_PIN>-1
|
||
|
SET_OUTPUT(SERVO3_PIN);
|
||
|
WRITE(SERVO3_PIN,LOW);
|
||
|
#endif
|
||
|
TCCR3A = 0; // normal counting mode
|
||
|
TCCR3B = _BV(CS31); // set prescaler of 8
|
||
|
TCNT3 = 0; // clear the timer count
|
||
|
#if defined(__AVR_ATmega128__)
|
||
|
TIFR |= _BV(OCF3A); // clear any pending interrupts;
|
||
|
ETIMSK |= _BV(OCIE3A); // enable the output compare interrupt
|
||
|
#else
|
||
|
TIFR3 = _BV(OCF3A); // clear any pending interrupts;
|
||
|
TIMSK3 = _BV(OCIE3A) ; // enable the output compare interrupt
|
||
|
#endif
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void HAL::showStartReason()
|
||
|
{
|
||
|
// Check startup - does nothing if bootloader sets MCUSR to 0
|
||
|
uint8_t mcu = MCUSR;
|
||
|
if(mcu & 1) Com::printInfoFLN(Com::tPowerUp);
|
||
|
if(mcu & 2) Com::printInfoFLN(Com::tExternalReset);
|
||
|
if(mcu & 4) Com::printInfoFLN(Com::tBrownOut);
|
||
|
if(mcu & 8) Com::printInfoFLN(Com::tWatchdog);
|
||
|
if(mcu & 32) Com::printInfoFLN(Com::tSoftwareReset);
|
||
|
MCUSR=0;
|
||
|
}
|
||
|
int HAL::getFreeRam()
|
||
|
{
|
||
|
int freeram = 0;
|
||
|
InterruptProtectedBlock noInts;
|
||
|
uint8_t * heapptr, * stackptr;
|
||
|
heapptr = (uint8_t *)malloc(4); // get heap pointer
|
||
|
free(heapptr); // free up the memory again (sets heapptr to 0)
|
||
|
stackptr = (uint8_t *)(SP); // save value of stack pointer
|
||
|
freeram = (int)stackptr-(int)heapptr;
|
||
|
return freeram;
|
||
|
}
|
||
|
|
||
|
void(* resetFunc) (void) = 0; //declare reset function @ address 0
|
||
|
|
||
|
void HAL::resetHardware()
|
||
|
{
|
||
|
resetFunc();
|
||
|
}
|
||
|
|
||
|
void HAL::analogStart()
|
||
|
{
|
||
|
#if ANALOG_INPUTS > 0
|
||
|
ADMUX = ANALOG_REF; // refernce voltage
|
||
|
for(uint8_t i=0; i<ANALOG_INPUTS; i++)
|
||
|
{
|
||
|
osAnalogInputCounter[i] = 0;
|
||
|
osAnalogInputBuildup[i] = 0;
|
||
|
osAnalogInputValues[i] = 0;
|
||
|
}
|
||
|
ADCSRA = _BV(ADEN)|_BV(ADSC)|ANALOG_PRESCALER;
|
||
|
//ADCSRA |= _BV(ADSC); // start ADC-conversion
|
||
|
while (ADCSRA & _BV(ADSC) ) {} // wait for conversion
|
||
|
/* ADCW must be read once, otherwise the next result is wrong. */
|
||
|
uint dummyADCResult;
|
||
|
dummyADCResult = ADCW;
|
||
|
// Enable interrupt driven conversion loop
|
||
|
uint8_t channel = pgm_read_byte(&osAnalogInputChannels[osAnalogInputPos]);
|
||
|
#if defined(ADCSRB) && defined(MUX5)
|
||
|
if(channel & 8) // Reading channel 0-7 or 8-15?
|
||
|
ADCSRB |= _BV(MUX5);
|
||
|
else
|
||
|
ADCSRB &= ~_BV(MUX5);
|
||
|
#endif
|
||
|
ADMUX = (ADMUX & ~(0x1F)) | (channel & 7);
|
||
|
ADCSRA |= _BV(ADSC); // start conversion without interrupt!
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/*************************************************************************
|
||
|
* Title: I2C master library using hardware TWI interface
|
||
|
* Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
|
||
|
* File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $
|
||
|
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
|
||
|
* Target: any AVR device with hardware TWI
|
||
|
* Usage: API compatible with I2C Software Library i2cmaster.h
|
||
|
**************************************************************************/
|
||
|
#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
|
||
|
#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
|
||
|
#endif
|
||
|
|
||
|
#include <avr/io.h>
|
||
|
|
||
|
/*************************************************************************
|
||
|
Initialization of the I2C bus interface. Need to be called only once
|
||
|
*************************************************************************/
|
||
|
void HAL::i2cInit(unsigned long clockSpeedHz)
|
||
|
{
|
||
|
/* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
|
||
|
TWSR = 0; /* no prescaler */
|
||
|
TWBR = ((F_CPU/clockSpeedHz)-16)/2; /* must be > 10 for stable operation */
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************
|
||
|
Issues a start condition and sends address and transfer direction.
|
||
|
return 0 = device accessible, 1= failed to access device
|
||
|
*************************************************************************/
|
||
|
unsigned char HAL::i2cStart(unsigned char address)
|
||
|
{
|
||
|
uint8_t twst;
|
||
|
|
||
|
// send START condition
|
||
|
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
|
||
|
|
||
|
// wait until transmission completed
|
||
|
while(!(TWCR & (1<<TWINT)));
|
||
|
|
||
|
// check value of TWI Status Register. Mask prescaler bits.
|
||
|
twst = TW_STATUS & 0xF8;
|
||
|
if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
|
||
|
|
||
|
// send device address
|
||
|
TWDR = address;
|
||
|
TWCR = (1<<TWINT) | (1<<TWEN);
|
||
|
|
||
|
// wail until transmission completed and ACK/NACK has been received
|
||
|
while(!(TWCR & (1<<TWINT)));
|
||
|
|
||
|
// check value of TWI Status Register. Mask prescaler bits.
|
||
|
twst = TW_STATUS & 0xF8;
|
||
|
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************
|
||
|
Issues a start condition and sends address and transfer direction.
|
||
|
If device is busy, use ack polling to wait until device is ready
|
||
|
|
||
|
Input: address and transfer direction of I2C device
|
||
|
*************************************************************************/
|
||
|
void HAL::i2cStartWait(unsigned char address)
|
||
|
{
|
||
|
uint8_t twst;
|
||
|
while ( 1 )
|
||
|
{
|
||
|
// send START condition
|
||
|
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
|
||
|
|
||
|
// wait until transmission completed
|
||
|
while(!(TWCR & (1<<TWINT)));
|
||
|
|
||
|
// check value of TWI Status Register. Mask prescaler bits.
|
||
|
twst = TW_STATUS & 0xF8;
|
||
|
if ( (twst != TW_START) && (twst != TW_REP_START)) continue;
|
||
|
|
||
|
// send device address
|
||
|
TWDR = address;
|
||
|
TWCR = (1<<TWINT) | (1<<TWEN);
|
||
|
|
||
|
// wail until transmission completed
|
||
|
while(!(TWCR & (1<<TWINT)));
|
||
|
|
||
|
// check value of TWI Status Register. Mask prescaler bits.
|
||
|
twst = TW_STATUS & 0xF8;
|
||
|
if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) )
|
||
|
{
|
||
|
/* device busy, send stop condition to terminate write operation */
|
||
|
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
|
||
|
|
||
|
// wait until stop condition is executed and bus released
|
||
|
while(TWCR & (1<<TWSTO));
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
//if( twst != TW_MT_SLA_ACK) return 1;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************
|
||
|
Terminates the data transfer and releases the I2C bus
|
||
|
*************************************************************************/
|
||
|
void HAL::i2cStop(void)
|
||
|
{
|
||
|
/* send stop condition */
|
||
|
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
|
||
|
// wait until stop condition is executed and bus released
|
||
|
while(TWCR & (1<<TWSTO));
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************
|
||
|
Send one byte to I2C device
|
||
|
|
||
|
Input: byte to be transfered
|
||
|
Return: 0 write successful
|
||
|
1 write failed
|
||
|
*************************************************************************/
|
||
|
unsigned char HAL::i2cWrite( unsigned char data )
|
||
|
{
|
||
|
uint8_t twst;
|
||
|
// send data to the previously addressed device
|
||
|
TWDR = data;
|
||
|
TWCR = (1<<TWINT) | (1<<TWEN);
|
||
|
// wait until transmission completed
|
||
|
while(!(TWCR & (1<<TWINT)));
|
||
|
// check value of TWI Status Register. Mask prescaler bits
|
||
|
twst = TW_STATUS & 0xF8;
|
||
|
if( twst != TW_MT_DATA_ACK) return 1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************
|
||
|
Read one byte from the I2C device, request more data from device
|
||
|
Return: byte read from I2C device
|
||
|
*************************************************************************/
|
||
|
unsigned char HAL::i2cReadAck(void)
|
||
|
{
|
||
|
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
|
||
|
while(!(TWCR & (1<<TWINT)));
|
||
|
return TWDR;
|
||
|
}
|
||
|
|
||
|
/*************************************************************************
|
||
|
Read one byte from the I2C device, read is followed by a stop condition
|
||
|
|
||
|
Return: byte read from I2C device
|
||
|
*************************************************************************/
|
||
|
unsigned char HAL::i2cReadNak(void)
|
||
|
{
|
||
|
TWCR = (1<<TWINT) | (1<<TWEN);
|
||
|
while(!(TWCR & (1<<TWINT)));
|
||
|
return TWDR;
|
||
|
}
|
||
|
|
||
|
#if FEATURE_SERVO
|
||
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || defined(__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
|
||
|
#define SERVO2500US F_CPU/3200
|
||
|
#define SERVO5000US F_CPU/1600
|
||
|
unsigned int HAL::servoTimings[4] = {0,0,0,0};
|
||
|
static uint8_t servoIndex = 0;
|
||
|
void HAL::servoMicroseconds(uint8_t servo,int ms)
|
||
|
{
|
||
|
if(ms<500) ms = 0;
|
||
|
if(ms>2500) ms = 2500;
|
||
|
servoTimings[servo] = (unsigned int)(((F_CPU/1000000)*(long)ms)>>3);
|
||
|
}
|
||
|
SIGNAL (TIMER3_COMPA_vect)
|
||
|
{
|
||
|
switch(servoIndex)
|
||
|
{
|
||
|
case 0:
|
||
|
TCNT3 = 0;
|
||
|
if(HAL::servoTimings[0])
|
||
|
{
|
||
|
#if SERVO0_PIN>-1
|
||
|
WRITE(SERVO0_PIN,HIGH);
|
||
|
#endif
|
||
|
OCR3A = HAL::servoTimings[0];
|
||
|
}
|
||
|
else OCR3A = SERVO2500US;
|
||
|
break;
|
||
|
case 1:
|
||
|
#if SERVO0_PIN>-1
|
||
|
WRITE(SERVO0_PIN,LOW);
|
||
|
#endif
|
||
|
OCR3A = SERVO5000US;
|
||
|
break;
|
||
|
case 2:
|
||
|
TCNT3 = 0;
|
||
|
if(HAL::servoTimings[1])
|
||
|
{
|
||
|
#if SERVO1_PIN>-1
|
||
|
WRITE(SERVO1_PIN,HIGH);
|
||
|
#endif
|
||
|
OCR3A = HAL::servoTimings[1];
|
||
|
}
|
||
|
else OCR3A = SERVO2500US;
|
||
|
break;
|
||
|
case 3:
|
||
|
#if SERVO1_PIN>-1
|
||
|
WRITE(SERVO1_PIN,LOW);
|
||
|
#endif
|
||
|
OCR3A = SERVO5000US;
|
||
|
break;
|
||
|
case 4:
|
||
|
TCNT3 = 0;
|
||
|
if(HAL::servoTimings[2])
|
||
|
{
|
||
|
#if SERVO2_PIN>-1
|
||
|
WRITE(SERVO2_PIN,HIGH);
|
||
|
#endif
|
||
|
OCR3A = HAL::servoTimings[2];
|
||
|
}
|
||
|
else OCR3A = SERVO2500US;
|
||
|
break;
|
||
|
case 5:
|
||
|
#if SERVO2_PIN>-1
|
||
|
WRITE(SERVO2_PIN,LOW);
|
||
|
#endif
|
||
|
OCR3A = SERVO5000US;
|
||
|
break;
|
||
|
case 6:
|
||
|
TCNT3 = 0;
|
||
|
if(HAL::servoTimings[3])
|
||
|
{
|
||
|
#if SERVO3_PIN>-1
|
||
|
WRITE(SERVO3_PIN,HIGH);
|
||
|
#endif
|
||
|
OCR3A = HAL::servoTimings[3];
|
||
|
}
|
||
|
else OCR3A = SERVO2500US;
|
||
|
break;
|
||
|
case 7:
|
||
|
#if SERVO3_PIN>-1
|
||
|
WRITE(SERVO3_PIN,LOW);
|
||
|
#endif
|
||
|
OCR3A = SERVO5000US;
|
||
|
break;
|
||
|
}
|
||
|
servoIndex++;
|
||
|
if(servoIndex>7)
|
||
|
servoIndex = 0;
|
||
|
}
|
||
|
#else
|
||
|
#error No servo support for your board, please diable FEATURE_SERVO
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
// ================== Interrupt handling ======================
|
||
|
|
||
|
/** \brief Sets the timer 1 compare value to delay ticks.
|
||
|
|
||
|
This function sets the OCR1A compare counter to get the next interrupt
|
||
|
at delay ticks measured from the last interrupt. delay must be << 2^24
|
||
|
*/
|
||
|
inline void setTimer(uint32_t delay)
|
||
|
{
|
||
|
__asm__ __volatile__ (
|
||
|
"cli \n\t"
|
||
|
"tst %C[delay] \n\t" //if(delay<65536) {
|
||
|
"brne else%= \n\t"
|
||
|
"cpi %B[delay],255 \n\t"
|
||
|
"breq else%= \n\t" // delay <65280
|
||
|
"sts stepperWait,r1 \n\t" // stepperWait = 0;
|
||
|
"sts stepperWait+1,r1 \n\t"
|
||
|
"sts stepperWait+2,r1 \n\t"
|
||
|
"lds %C[delay],%[time] \n\t" // Read TCNT1
|
||
|
"lds %D[delay],%[time]+1 \n\t"
|
||
|
"ldi r18,100 \n\t" // Add 100 to TCNT1
|
||
|
"add %C[delay],r18 \n\t"
|
||
|
"adc %D[delay],r1 \n\t"
|
||
|
"cp %A[delay],%C[delay] \n\t" // delay<TCNT1+1
|
||
|
"cpc %B[delay],%D[delay] \n\t"
|
||
|
"brcc exact%= \n\t"
|
||
|
"sts %[ocr]+1,%D[delay] \n\t" // OCR1A = TCNT1+100;
|
||
|
"sts %[ocr],%C[delay] \n\t"
|
||
|
"rjmp end%= \n\t"
|
||
|
"exact%=: sts %[ocr]+1,%B[delay] \n\t" // OCR1A = delay;
|
||
|
"sts %[ocr],%A[delay] \n\t"
|
||
|
"rjmp end%= \n\t"
|
||
|
"else%=: subi %B[delay], 0x80 \n\t" //} else { stepperWait = delay-32768;
|
||
|
"sbci %C[delay], 0x00 \n\t"
|
||
|
"sts stepperWait,%A[delay] \n\t"
|
||
|
"sts stepperWait+1,%B[delay] \n\t"
|
||
|
"sts stepperWait+2,%C[delay] \n\t"
|
||
|
"ldi %D[delay], 0x80 \n\t" //OCR1A = 32768;
|
||
|
"sts %[ocr]+1, %D[delay] \n\t"
|
||
|
"sts %[ocr], r1 \n\t"
|
||
|
"end%=: \n\t"
|
||
|
:[delay]"=&d"(delay) // Output
|
||
|
:"0"(delay),[ocr]"i" (_SFR_MEM_ADDR(OCR1A)),[time]"i"(_SFR_MEM_ADDR(TCNT1)) // Input
|
||
|
:"r18" // Clobber
|
||
|
);
|
||
|
/* // Assembler above replaced this code
|
||
|
if(delay<65280) {
|
||
|
stepperWait = 0;
|
||
|
unsigned int count = TCNT1+100;
|
||
|
if(delay<count)
|
||
|
OCR1A = count;
|
||
|
else
|
||
|
OCR1A = delay;
|
||
|
} else {
|
||
|
stepperWait = delay-32768;
|
||
|
OCR1A = 32768;
|
||
|
}*/
|
||
|
}
|
||
|
|
||
|
volatile uint8_t insideTimer1 = 0;
|
||
|
long stepperWait = 0;
|
||
|
/** \brief Timer interrupt routine to drive the stepper motors.
|
||
|
*/
|
||
|
ISR(TIMER1_COMPA_vect)
|
||
|
{
|
||
|
if(insideTimer1) return;
|
||
|
uint8_t doExit;
|
||
|
__asm__ __volatile__ (
|
||
|
"ldi %[ex],0 \n\t"
|
||
|
"lds r23,stepperWait+2 \n\t"
|
||
|
"tst r23 \n\t" //if(stepperWait<65536) {
|
||
|
"brne else%= \n\t" // Still > 65535
|
||
|
"lds r23,stepperWait+1 \n\t"
|
||
|
"tst r23 \n\t"
|
||
|
"brne last%= \n\t" // Still not 0, go ahead
|
||
|
"lds r22,stepperWait \n\t"
|
||
|
"breq end%= \n\t" // stepperWait is 0, do your work
|
||
|
"last%=: \n\t"
|
||
|
"sts %[ocr]+1,r23 \n\t" // OCR1A = stepper wait;
|
||
|
"sts %[ocr],r22 \n\t"
|
||
|
"sts stepperWait,r1 \n\t"
|
||
|
"sts stepperWait+1,r1 \n\t"
|
||
|
"rjmp end1%= \n\t"
|
||
|
"else%=: lds r22,stepperWait+1 \n\t" //} else { stepperWait = stepperWait-32768;
|
||
|
"subi r22, 0x80 \n\t"
|
||
|
"sbci r23, 0x00 \n\t"
|
||
|
"sts stepperWait+1,r22 \n\t" // ocr1a stays 32768
|
||
|
"sts stepperWait+2,r23 \n\t"
|
||
|
"end1%=: ldi %[ex],1 \n\t"
|
||
|
"end%=: \n\t"
|
||
|
:[ex]"=&d"(doExit):[ocr]"i" (_SFR_MEM_ADDR(OCR1A)):"r22","r23" );
|
||
|
if(doExit) return;
|
||
|
insideTimer1 = 1;
|
||
|
OCR1A = 61000;
|
||
|
if(PrintLine::hasLines())
|
||
|
{
|
||
|
setTimer(PrintLine::bresenhamStep());
|
||
|
}
|
||
|
else
|
||
|
if(FEATURE_BABYSTEPPING && Printer::zBabystepsMissing) {
|
||
|
Printer::zBabystep();
|
||
|
setTimer(Printer::interval);
|
||
|
} else
|
||
|
{
|
||
|
if(waitRelax == 0)
|
||
|
{
|
||
|
#if USE_ADVANCE
|
||
|
if(Printer::advanceStepsSet)
|
||
|
{
|
||
|
Printer::extruderStepsNeeded -= Printer::advanceStepsSet;
|
||
|
#if ENABLE_QUADRATIC_ADVANCE
|
||
|
Printer::advanceExecuted = 0;
|
||
|
#endif
|
||
|
Printer::advanceStepsSet = 0;
|
||
|
}
|
||
|
#endif
|
||
|
#if USE_ADVANCE
|
||
|
if(!Printer::extruderStepsNeeded) if(DISABLE_E) Extruder::disableCurrentExtruderMotor();
|
||
|
#else
|
||
|
if(DISABLE_E) Extruder::disableCurrentExtruderMotor();
|
||
|
#endif
|
||
|
}
|
||
|
else waitRelax--;
|
||
|
stepperWait = 0; // Importent becaus of optimization in asm at begin
|
||
|
OCR1A = 65500; // Wait for next move
|
||
|
}
|
||
|
DEBUG_MEMORY;
|
||
|
insideTimer1 = 0;
|
||
|
}
|
||
|
|
||
|
#if !defined(HEATER_PWM_SPEED)
|
||
|
#define HEATER_PWM_SPEED 0
|
||
|
#endif
|
||
|
#if HEATER_PWM_SPEED < 0
|
||
|
#define HEATER_PWM_SPEED 0
|
||
|
#endif
|
||
|
#if HEATER_PWM_SPEED > 3
|
||
|
#define HEATER_PWM_SPEED 3
|
||
|
#endif
|
||
|
|
||
|
#if HEATER_PWM_SPEED == 0
|
||
|
#define HEATER_PWM_STEP 1
|
||
|
#define HEATER_PWM_MASK 255
|
||
|
#elif HEATER_PWM_SPEED == 1
|
||
|
#define HEATER_PWM_STEP 2
|
||
|
#define HEATER_PWM_MASK 254
|
||
|
#elif HEATER_PWM_SPEED == 2
|
||
|
#define HEATER_PWM_STEP 4
|
||
|
#define HEATER_PWM_MASK 252
|
||
|
#else
|
||
|
#define HEATER_PWM_STEP 4
|
||
|
#define HEATER_PWM_MASK 252
|
||
|
#endif
|
||
|
#define pulseDensityModulate( pin, density,error,invert) {uint8_t carry;carry = error + (invert ? 255 - density : density); WRITE(pin, (carry < error)); error = carry;}
|
||
|
/**
|
||
|
This timer is called 3906 timer per second. It is used to update pwm values for heater and some other frequent jobs.
|
||
|
*/
|
||
|
ISR(PWM_TIMER_VECTOR)
|
||
|
{
|
||
|
static uint8_t pwm_count = 0;
|
||
|
static uint8_t pwm_count_heater = 0;
|
||
|
static uint8_t pwm_pos_set[NUM_EXTRUDER + 3];
|
||
|
static uint8_t pwm_cooler_pos_set[NUM_EXTRUDER];
|
||
|
PWM_OCR += 64;
|
||
|
if(pwm_count_heater == 0 && !PDM_FOR_EXTRUDER)
|
||
|
{
|
||
|
#if defined(EXT0_HEATER_PIN) && EXT0_HEATER_PIN > -1
|
||
|
if((pwm_pos_set[0] = (pwm_pos[0] & HEATER_PWM_MASK)) > 0) WRITE(EXT0_HEATER_PIN,!HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
#if defined(EXT1_HEATER_PIN) && EXT1_HEATER_PIN > -1 && NUM_EXTRUDER > 1
|
||
|
if((pwm_pos_set[1] = (pwm_pos[1] & HEATER_PWM_MASK)) > 0) WRITE(EXT1_HEATER_PIN,!HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
#if defined(EXT2_HEATER_PIN) && EXT2_HEATER_PIN > -1 && NUM_EXTRUDER > 2
|
||
|
if((pwm_pos_set[2] = (pwm_pos[2] & HEATER_PWM_MASK)) > 0) WRITE(EXT2_HEATER_PIN,!HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
#if defined(EXT3_HEATER_PIN) && EXT3_HEATER_PIN > -1 && NUM_EXTRUDER > 3
|
||
|
if((pwm_pos_set[3] = (pwm_pos[3] & HEATER_PWM_MASK)) > 0) WRITE(EXT3_HEATER_PIN,!HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
#if defined(EXT4_HEATER_PIN) && EXT4_HEATER_PIN > -1 && NUM_EXTRUDER > 4
|
||
|
if((pwm_pos_set[4] = (pwm_pos[4] & HEATER_PWM_MASK)) > 0) WRITE(EXT4_HEATER_PIN,!HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
#if defined(EXT5_HEATER_PIN) && EXT5_HEATER_PIN > -1 && NUM_EXTRUDER > 5
|
||
|
if((pwm_pos_set[5] = (pwm_pos[5] & HEATER_PWM_MASK)) > 0) WRITE(EXT5_HEATER_PIN,!HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
#if HEATED_BED_HEATER_PIN > -1 && HAVE_HEATED_BED
|
||
|
if((pwm_pos_set[NUM_EXTRUDER] = pwm_pos[NUM_EXTRUDER]) > 0) WRITE(HEATED_BED_HEATER_PIN,!HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
}
|
||
|
if(pwm_count == 0 && !PDM_FOR_COOLER)
|
||
|
{
|
||
|
#if defined(EXT0_HEATER_PIN) && EXT0_HEATER_PIN > -1 && EXT0_EXTRUDER_COOLER_PIN > -1
|
||
|
if((pwm_cooler_pos_set[0] = extruder[0].coolerPWM) > 0) WRITE(EXT0_EXTRUDER_COOLER_PIN, 1);
|
||
|
#endif
|
||
|
#if !SHARED_COOLER && defined(EXT1_HEATER_PIN) && EXT1_HEATER_PIN > -1 && NUM_EXTRUDER > 1
|
||
|
#if EXT1_EXTRUDER_COOLER_PIN > -1 && EXT1_EXTRUDER_COOLER_PIN != EXT0_EXTRUDER_COOLER_PIN
|
||
|
if((pwm_cooler_pos_set[1] = extruder[1].coolerPWM) > 0) WRITE(EXT1_EXTRUDER_COOLER_PIN, 1);
|
||
|
#endif
|
||
|
#endif
|
||
|
#if !SHARED_COOLER && defined(EXT2_HEATER_PIN) && EXT2_HEATER_PIN > -1 && NUM_EXTRUDER > 2
|
||
|
#if EXT2_EXTRUDER_COOLER_PIN > -1
|
||
|
if((pwm_cooler_pos_set[2] = extruder[2].coolerPWM) > 0) WRITE(EXT2_EXTRUDER_COOLER_PIN, 1);
|
||
|
#endif
|
||
|
#endif
|
||
|
#if !SHARED_COOLER && defined(EXT3_HEATER_PIN) && EXT3_HEATER_PIN > -1 && NUM_EXTRUDER > 3
|
||
|
#if EXT3_EXTRUDER_COOLER_PIN > -1
|
||
|
if((pwm_cooler_pos_set[3] = extruder[3].coolerPWM) > 0) WRITE(EXT3_EXTRUDER_COOLER_PIN, 1);
|
||
|
#endif
|
||
|
#endif
|
||
|
#if !SHARED_COOLER && defined(EXT4_HEATER_PIN) && EXT4_HEATER_PIN > -1 && NUM_EXTRUDER > 4
|
||
|
#if EXT4_EXTRUDER_COOLER_PIN > -1
|
||
|
if((pwm_cooler_pos_set[4] = pwm_pos[4].coolerPWM) > 0) WRITE(EXT4_EXTRUDER_COOLER_PIN, 1);
|
||
|
#endif
|
||
|
#endif
|
||
|
#if !SHARED_COOLER && defined(EXT5_HEATER_PIN) && EXT5_HEATER_PIN > -1 && NUM_EXTRUDER > 5
|
||
|
#if EXT5_EXTRUDER_COOLER_PIN > -1
|
||
|
if((pwm_cooler_pos_set[5] = extruder[5].coolerPWM) > 0) WRITE(EXT5_EXTRUDER_COOLER_PIN, 1);
|
||
|
#endif
|
||
|
#endif
|
||
|
#if FAN_BOARD_PIN > -1
|
||
|
if((pwm_pos_set[NUM_EXTRUDER + 1] = pwm_pos[NUM_EXTRUDER + 1]) > 0) WRITE(FAN_BOARD_PIN,1);
|
||
|
#endif
|
||
|
#if FAN_PIN > -1 && FEATURE_FAN_CONTROL
|
||
|
if((pwm_pos_set[NUM_EXTRUDER + 2] = pwm_pos[NUM_EXTRUDER + 2]) > 0) WRITE(FAN_PIN,1);
|
||
|
#endif
|
||
|
}
|
||
|
#if defined(EXT0_HEATER_PIN) && EXT0_HEATER_PIN > -1
|
||
|
#if PDM_FOR_EXTRUDER
|
||
|
pulseDensityModulate(EXT0_HEATER_PIN, pwm_pos[0], pwm_pos_set[0], HEATER_PINS_INVERTED);
|
||
|
#else
|
||
|
if(pwm_pos_set[0] == pwm_count_heater && pwm_pos_set[0] != HEATER_PWM_MASK) WRITE(EXT0_HEATER_PIN,HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
#if EXT0_EXTRUDER_COOLER_PIN > -1
|
||
|
#if PDM_FOR_COOLER
|
||
|
pulseDensityModulate(EXT0_EXTRUDER_COOLER_PIN, extruder[0].coolerPWM, pwm_cooler_pos_set[0], false);
|
||
|
#else
|
||
|
if(pwm_cooler_pos_set[0] == pwm_count && pwm_cooler_pos_set[0] != 255) WRITE(EXT0_EXTRUDER_COOLER_PIN,0);
|
||
|
#endif
|
||
|
#endif
|
||
|
#endif
|
||
|
#if defined(EXT1_HEATER_PIN) && EXT1_HEATER_PIN > -1 && NUM_EXTRUDER > 1
|
||
|
#if PDM_FOR_EXTRUDER
|
||
|
pulseDensityModulate(EXT1_HEATER_PIN, pwm_pos[1], pwm_pos_set[1], HEATER_PINS_INVERTED);
|
||
|
#else
|
||
|
if(pwm_pos_set[1] == pwm_count_heater && pwm_pos_set[1] != HEATER_PWM_MASK) WRITE(EXT1_HEATER_PIN,HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
#if !SHARED_COOLER && defined(EXT1_EXTRUDER_COOLER_PIN) && EXT1_EXTRUDER_COOLER_PIN > -1 && EXT1_EXTRUDER_COOLER_PIN != EXT0_EXTRUDER_COOLER_PIN
|
||
|
#if PDM_FOR_COOLER
|
||
|
pulseDensityModulate(EXT1_EXTRUDER_COOLER_PIN, extruder[1].coolerPWM, pwm_cooler_pos_set[1], false);
|
||
|
#else
|
||
|
if(pwm_cooler_pos_set[1] == pwm_count && pwm_cooler_pos_set[1] != 255) WRITE(EXT1_EXTRUDER_COOLER_PIN,0);
|
||
|
#endif
|
||
|
#endif
|
||
|
#endif
|
||
|
#if defined(EXT2_HEATER_PIN) && EXT2_HEATER_PIN>-1 && NUM_EXTRUDER>2
|
||
|
#if PDM_FOR_EXTRUDER
|
||
|
pulseDensityModulate(EXT2_HEATER_PIN, pwm_pos[2], pwm_pos_set[2], HEATER_PINS_INVERTED);
|
||
|
#else
|
||
|
if(pwm_pos_set[2] == pwm_count_heater && pwm_pos_set[2]!=HEATER_PWM_MASK) WRITE(EXT2_HEATER_PIN,HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
#if !SHARED_COOLER && EXT2_EXTRUDER_COOLER_PIN > -1
|
||
|
#if PDM_FOR_COOLER
|
||
|
pulseDensityModulate(EXT2_EXTRUDER_COOLER_PIN, extruder[2].coolerPWM, pwm_cooler_pos_set[2], false);
|
||
|
#else
|
||
|
if(pwm_cooler_pos_set[2] == pwm_count && pwm_cooler_pos_set[2] != 255) WRITE(EXT2_EXTRUDER_COOLER_PIN,0);
|
||
|
#endif
|
||
|
#endif
|
||
|
#endif
|
||
|
#if defined(EXT3_HEATER_PIN) && EXT3_HEATER_PIN>-1 && NUM_EXTRUDER>3
|
||
|
#if PDM_FOR_EXTRUDER
|
||
|
pulseDensityModulate(EXT3_HEATER_PIN, pwm_pos[3], pwm_pos_set[3], HEATER_PINS_INVERTED);
|
||
|
#else
|
||
|
if(pwm_pos_set[3] == pwm_count_heater && pwm_pos_set[3] != HEATER_PWM_MASK) WRITE(EXT3_HEATER_PIN,HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
#if !SHARED_COOLER && EXT3_EXTRUDER_COOLER_PIN > -1
|
||
|
#if PDM_FOR_COOLER
|
||
|
pulseDensityModulate(EXT3_EXTRUDER_COOLER_PIN, extruder[3].coolerPWM, pwm_cooler_pos_set[3], false);
|
||
|
#else
|
||
|
if(pwm_cooler_pos_set[3] == pwm_count && pwm_cooler_pos_set[3] != 255) WRITE(EXT3_EXTRUDER_COOLER_PIN,0);
|
||
|
#endif
|
||
|
#endif
|
||
|
#endif
|
||
|
#if defined(EXT4_HEATER_PIN) && EXT4_HEATER_PIN>-1 && NUM_EXTRUDER>4
|
||
|
#if PDM_FOR_EXTRUDER
|
||
|
pulseDensityModulate(EXT4_HEATER_PIN, pwm_pos[4], pwm_pos_set[4], HEATER_PINS_INVERTED);
|
||
|
#else
|
||
|
if(pwm_pos_set[4] == pwm_count_heater && pwm_pos_set[4] != HEATER_PWM_MASK) WRITE(EXT4_HEATER_PIN,HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
#if !SHARED_COOLER && EXT4_EXTRUDER_COOLER_PIN > -1
|
||
|
#if PDM_FOR_COOLER
|
||
|
pulseDensityModulate(EXT4_EXTRUDER_COOLER_PIN, extruder[4].coolerPWM, pwm_cooler_pos_set[4], false);
|
||
|
#else
|
||
|
if(pwm_cooler_pos_set[4] == pwm_count && pwm_cooler_pos_set[4]!=255) WRITE(EXT4_EXTRUDER_COOLER_PIN,0);
|
||
|
#endif
|
||
|
#endif
|
||
|
#endif
|
||
|
#if defined(EXT5_HEATER_PIN) && EXT5_HEATER_PIN>-1 && NUM_EXTRUDER>5
|
||
|
#if PDM_FOR_EXTRUDER
|
||
|
pulseDensityModulate(EXT5_HEATER_PIN, pwm_pos[5], pwm_pos_set[5], HEATER_PINS_INVERTED);
|
||
|
#else
|
||
|
if(pwm_pos_set[5] == pwm_count_heater && pwm_pos_set[5] != HEATER_PWM_MASK) WRITE(EXT5_HEATER_PIN,HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
#if !SHARED_COOLER && EXT5_EXTRUDER_COOLER_PIN > -1
|
||
|
#if PDM_FOR_COOLER
|
||
|
pulseDensityModulate(EXT5_EXTRUDER_COOLER_PIN, extruder[5].coolerPWM, pwm_cooler_pos_set[5], false);
|
||
|
#else
|
||
|
if(pwm_cooler_pos_set[5] == pwm_count && pwm_cooler_pos_set[5] != 255) WRITE(EXT5_EXTRUDER_COOLER_PIN,0);
|
||
|
#endif
|
||
|
#endif
|
||
|
#endif
|
||
|
#if FAN_BOARD_PIN > -1
|
||
|
#if PDM_FOR_COOLER
|
||
|
pulseDensityModulate(FAN_BOARD_PIN, pwm_pos[NUM_EXTRUDER + 1], pwm_pos_set[NUM_EXTRUDER + 1], false);
|
||
|
#else
|
||
|
if(pwm_pos_set[NUM_EXTRUDER + 1] == pwm_count && pwm_pos_set[NUM_EXTRUDER + 1] != 255) WRITE(FAN_BOARD_PIN,0);
|
||
|
#endif
|
||
|
#endif
|
||
|
#if FAN_PIN > -1 && FEATURE_FAN_CONTROL
|
||
|
#if PDM_FOR_COOLER
|
||
|
pulseDensityModulate(FAN_PIN, pwm_pos[NUM_EXTRUDER + 2], pwm_pos_set[NUM_EXTRUDER + 2], false);
|
||
|
#else
|
||
|
if(pwm_pos_set[NUM_EXTRUDER + 2] == pwm_count && pwm_pos_set[NUM_EXTRUDER + 2] != 255) WRITE(FAN_PIN,0);
|
||
|
#endif
|
||
|
#endif
|
||
|
#if HEATED_BED_HEATER_PIN > -1 && HAVE_HEATED_BED
|
||
|
#if PDM_FOR_EXTRUDER
|
||
|
pulseDensityModulate(HEATED_BED_HEATER_PIN, pwm_pos[NUM_EXTRUDER], pwm_pos_set[NUM_EXTRUDER], HEATER_PINS_INVERTED);
|
||
|
#else
|
||
|
if(pwm_pos_set[NUM_EXTRUDER] == pwm_count_heater && pwm_pos_set[NUM_EXTRUDER] != HEATER_PWM_MASK) WRITE(HEATED_BED_HEATER_PIN,HEATER_PINS_INVERTED);
|
||
|
#endif
|
||
|
#endif
|
||
|
HAL::allowInterrupts();
|
||
|
counterPeriodical++; // Appxoimate a 100ms timer
|
||
|
if(counterPeriodical >= (int)(F_CPU/40960))
|
||
|
{
|
||
|
counterPeriodical = 0;
|
||
|
executePeriodical = 1;
|
||
|
}
|
||
|
// read analog values
|
||
|
#if ANALOG_INPUTS > 0
|
||
|
if((ADCSRA & _BV(ADSC)) == 0) // Conversion finished?
|
||
|
{
|
||
|
osAnalogInputBuildup[osAnalogInputPos] += ADCW;
|
||
|
if(++osAnalogInputCounter[osAnalogInputPos]>=_BV(ANALOG_INPUT_SAMPLE))
|
||
|
{
|
||
|
#if ANALOG_INPUT_BITS + ANALOG_INPUT_SAMPLE < 12
|
||
|
osAnalogInputValues[osAnalogInputPos] =
|
||
|
osAnalogInputBuildup[osAnalogInputPos] <<
|
||
|
(12-ANALOG_INPUT_BITS-ANALOG_INPUT_SAMPLE);
|
||
|
#endif
|
||
|
#if ANALOG_INPUT_BITS + ANALOG_INPUT_SAMPLE > 12
|
||
|
osAnalogInputValues[osAnalogInputPos] =
|
||
|
osAnalogInputBuildup[osAnalogInputPos] >>
|
||
|
(ANALOG_INPUT_BITS+ANALOG_INPUT_SAMPLE-12);
|
||
|
#endif
|
||
|
#if ANALOG_INPUT_BITS + ANALOG_INPUT_SAMPLE == 12
|
||
|
osAnalogInputValues[osAnalogInputPos] =
|
||
|
osAnalogInputBuildup[osAnalogInputPos];
|
||
|
#endif
|
||
|
osAnalogInputBuildup[osAnalogInputPos] = 0;
|
||
|
osAnalogInputCounter[osAnalogInputPos] = 0;
|
||
|
// Start next conversion
|
||
|
if(++osAnalogInputPos>=ANALOG_INPUTS) osAnalogInputPos = 0;
|
||
|
uint8_t channel = pgm_read_byte(&osAnalogInputChannels[osAnalogInputPos]);
|
||
|
#if defined(ADCSRB) && defined(MUX5)
|
||
|
if(channel & 8) // Reading channel 0-7 or 8-15?
|
||
|
ADCSRB |= _BV(MUX5);
|
||
|
else
|
||
|
ADCSRB &= ~_BV(MUX5);
|
||
|
#endif
|
||
|
ADMUX = (ADMUX & ~(0x1F)) | (channel & 7);
|
||
|
}
|
||
|
ADCSRA |= _BV(ADSC); // start next conversion
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
UI_FAST; // Short timed user interface action
|
||
|
pwm_count++;
|
||
|
pwm_count_heater += HEATER_PWM_STEP;
|
||
|
}
|
||
|
#if USE_ADVANCE
|
||
|
|
||
|
static int8_t extruderLastDirection = 0;
|
||
|
void HAL::resetExtruderDirection() {
|
||
|
extruderLastDirection = 0;
|
||
|
}
|
||
|
/** \brief Timer routine for extruder stepper.
|
||
|
|
||
|
Several methods need to move the extruder. To get a optima result,
|
||
|
all methods update the printer_state.extruderStepsNeeded with the
|
||
|
number of additional steps needed. During this interrupt, one step
|
||
|
is executed. This will keep the extruder moving, until the total
|
||
|
wanted movement is achieved. This will be done with the maximum
|
||
|
allowable speed for the extruder.
|
||
|
*/
|
||
|
ISR(EXTRUDER_TIMER_VECTOR)
|
||
|
{
|
||
|
uint8_t timer = EXTRUDER_OCR;
|
||
|
if(!Printer::isAdvanceActivated()) return; // currently no need
|
||
|
if(Printer::extruderStepsNeeded > 0 && extruderLastDirection != 1)
|
||
|
{
|
||
|
Extruder::setDirection(true);
|
||
|
extruderLastDirection = 1;
|
||
|
timer += 40; // Add some more wait time to prevent blocking
|
||
|
}
|
||
|
else if(Printer::extruderStepsNeeded < 0 && extruderLastDirection != -1)
|
||
|
{
|
||
|
Extruder::setDirection(false);
|
||
|
extruderLastDirection = -1;
|
||
|
timer += 40; // Add some more wait time to prevent blocking
|
||
|
}
|
||
|
else if(Printer::extruderStepsNeeded != 0)
|
||
|
{
|
||
|
Extruder::step();
|
||
|
Printer::extruderStepsNeeded -= extruderLastDirection;
|
||
|
Printer::insertStepperHighDelay();
|
||
|
Extruder::unstep();
|
||
|
}
|
||
|
EXTRUDER_OCR = timer + Printer::maxExtruderSpeed;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifndef EXTERNALSERIAL
|
||
|
// Implement serial communication for one stream only!
|
||
|
/*
|
||
|
HardwareSerial.h - Hardware serial library for Wiring
|
||
|
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
|
||
|
|
||
|
This library is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU Lesser General Public
|
||
|
License as published by the Free Software Foundation; either
|
||
|
version 2.1 of the License, or (at your option) any later version.
|
||
|
|
||
|
This library is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
Lesser General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Lesser General Public
|
||
|
License along with this library; if not, write to the Free Software
|
||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
|
||
|
Modified 28 September 2010 by Mark Sproul
|
||
|
|
||
|
Modified to use only 1 queue with fixed length by Repetier
|
||
|
*/
|
||
|
|
||
|
ring_buffer rx_buffer = { { 0 }, 0, 0};
|
||
|
ring_buffer_tx tx_buffer = { { 0 }, 0, 0};
|
||
|
|
||
|
inline void rf_store_char(unsigned char c, ring_buffer *buffer)
|
||
|
{
|
||
|
uint8_t i = (buffer->head + 1) & SERIAL_BUFFER_MASK;
|
||
|
|
||
|
// 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 != buffer->tail)
|
||
|
{
|
||
|
buffer->buffer[buffer->head] = c;
|
||
|
buffer->head = i;
|
||
|
}
|
||
|
}
|
||
|
#if !defined(USART0_RX_vect) && defined(USART1_RX_vect)
|
||
|
// do nothing - on the 32u4 the first USART is USART1
|
||
|
#else
|
||
|
void rfSerialEvent() __attribute__((weak));
|
||
|
void rfSerialEvent() {}
|
||
|
#define serialEvent_implemented
|
||
|
#if defined(USART_RX_vect)
|
||
|
SIGNAL(USART_RX_vect)
|
||
|
#elif defined(USART0_RX_vect)
|
||
|
SIGNAL(USART0_RX_vect)
|
||
|
#else
|
||
|
#if defined(SIG_USART0_RECV)
|
||
|
SIGNAL(SIG_USART0_RECV)
|
||
|
#elif defined(SIG_UART0_RECV)
|
||
|
SIGNAL(SIG_UART0_RECV)
|
||
|
#elif defined(SIG_UART_RECV)
|
||
|
SIGNAL(SIG_UART_RECV)
|
||
|
#else
|
||
|
#error "Don't know what the Data Received vector is called for the first UART"
|
||
|
#endif
|
||
|
#endif
|
||
|
{
|
||
|
#if defined(UDR0)
|
||
|
unsigned char c = UDR0;
|
||
|
#elif defined(UDR)
|
||
|
unsigned char c = UDR;
|
||
|
#else
|
||
|
#error UDR not defined
|
||
|
#endif
|
||
|
rf_store_char(c, &rx_buffer);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if !defined(USART0_UDRE_vect) && defined(USART1_UDRE_vect)
|
||
|
// do nothing - on the 32u4 the first USART is USART1
|
||
|
#else
|
||
|
#if !defined(UART0_UDRE_vect) && !defined(UART_UDRE_vect) && !defined(USART0_UDRE_vect) && !defined(USART_UDRE_vect)
|
||
|
#error "Don't know what the Data Register Empty vector is called for the first UART"
|
||
|
#else
|
||
|
#if defined(UART0_UDRE_vect)
|
||
|
ISR(UART0_UDRE_vect)
|
||
|
#elif defined(UART_UDRE_vect)
|
||
|
ISR(UART_UDRE_vect)
|
||
|
#elif defined(USART0_UDRE_vect)
|
||
|
ISR(USART0_UDRE_vect)
|
||
|
#elif defined(USART_UDRE_vect)
|
||
|
ISR(USART_UDRE_vect)
|
||
|
#endif
|
||
|
{
|
||
|
if (tx_buffer.head == tx_buffer.tail)
|
||
|
{
|
||
|
// Buffer empty, so disable interrupts
|
||
|
#if defined(UCSR0B)
|
||
|
bit_clear(UCSR0B, UDRIE0);
|
||
|
#else
|
||
|
bit_clear(UCSRB, UDRIE);
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// There is more data in the output buffer. Send the next byte
|
||
|
uint8_t c = tx_buffer.buffer[tx_buffer.tail];
|
||
|
tx_buffer.tail = (tx_buffer.tail + 1) & SERIAL_TX_BUFFER_MASK;
|
||
|
|
||
|
#if defined(UDR0)
|
||
|
UDR0 = c;
|
||
|
#elif defined(UDR)
|
||
|
UDR = c;
|
||
|
#else
|
||
|
#error UDR not defined
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// Constructors ////////////////////////////////////////////////////////////////
|
||
|
|
||
|
RFHardwareSerial::RFHardwareSerial(ring_buffer *rx_buffer, ring_buffer_tx *tx_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 udrie, uint8_t u2x)
|
||
|
{
|
||
|
_rx_buffer = rx_buffer;
|
||
|
_tx_buffer = tx_buffer;
|
||
|
_ubrrh = ubrrh;
|
||
|
_ubrrl = ubrrl;
|
||
|
_ucsra = ucsra;
|
||
|
_ucsrb = ucsrb;
|
||
|
_udr = udr;
|
||
|
_rxen = rxen;
|
||
|
_txen = txen;
|
||
|
_rxcie = rxcie;
|
||
|
_udrie = udrie;
|
||
|
_u2x = u2x;
|
||
|
}
|
||
|
|
||
|
// Public Methods //////////////////////////////////////////////////////////////
|
||
|
|
||
|
void RFHardwareSerial::begin(unsigned long baud)
|
||
|
{
|
||
|
uint16_t baud_setting;
|
||
|
bool use_u2x = true;
|
||
|
|
||
|
#if F_CPU == 16000000UL
|
||
|
// hardcoded exception for compatibility with the bootloader shipped
|
||
|
// with the Duemilanove and previous boards and the firmware on the 8U2
|
||
|
// on the Uno and Mega 2560.
|
||
|
if (baud == 57600)
|
||
|
{
|
||
|
use_u2x = false;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
try_again:
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
if ((baud_setting > 4095) && use_u2x)
|
||
|
{
|
||
|
use_u2x = false;
|
||
|
goto try_again;
|
||
|
}
|
||
|
|
||
|
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
|
||
|
*_ubrrh = baud_setting >> 8;
|
||
|
*_ubrrl = baud_setting;
|
||
|
|
||
|
bit_set(*_ucsrb, _rxen);
|
||
|
bit_set(*_ucsrb, _txen);
|
||
|
bit_set(*_ucsrb, _rxcie);
|
||
|
bit_clear(*_ucsrb, _udrie);
|
||
|
}
|
||
|
|
||
|
void RFHardwareSerial::end()
|
||
|
{
|
||
|
// wait for transmission of outgoing data
|
||
|
while (_tx_buffer->head != _tx_buffer->tail)
|
||
|
;
|
||
|
|
||
|
bit_clear(*_ucsrb, _rxen);
|
||
|
bit_clear(*_ucsrb, _txen);
|
||
|
bit_clear(*_ucsrb, _rxcie);
|
||
|
bit_clear(*_ucsrb, _udrie);
|
||
|
|
||
|
// clear a ny received data
|
||
|
_rx_buffer->head = _rx_buffer->tail;
|
||
|
}
|
||
|
|
||
|
int RFHardwareSerial::available(void)
|
||
|
{
|
||
|
return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) & SERIAL_BUFFER_MASK;
|
||
|
}
|
||
|
int RFHardwareSerial::outputUnused(void)
|
||
|
{
|
||
|
return SERIAL_TX_BUFFER_SIZE-(unsigned int)((SERIAL_TX_BUFFER_SIZE + _tx_buffer->head - _tx_buffer->tail) & SERIAL_TX_BUFFER_MASK);
|
||
|
}
|
||
|
|
||
|
int RFHardwareSerial::peek(void)
|
||
|
{
|
||
|
if (_rx_buffer->head == _rx_buffer->tail)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
return _rx_buffer->buffer[_rx_buffer->tail];
|
||
|
}
|
||
|
|
||
|
int RFHardwareSerial::read(void)
|
||
|
{
|
||
|
// if the head isn't ahead of the tail, we don't have any characters
|
||
|
if (_rx_buffer->head == _rx_buffer->tail)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
|
||
|
_rx_buffer->tail = (_rx_buffer->tail + 1) & SERIAL_BUFFER_MASK;
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
void RFHardwareSerial::flush()
|
||
|
{
|
||
|
while (_tx_buffer->head != _tx_buffer->tail)
|
||
|
;
|
||
|
}
|
||
|
#ifdef COMPAT_PRE1
|
||
|
void
|
||
|
#else
|
||
|
size_t
|
||
|
#endif
|
||
|
RFHardwareSerial::write(uint8_t c)
|
||
|
{
|
||
|
uint8_t i = (_tx_buffer->head + 1) & SERIAL_TX_BUFFER_MASK;
|
||
|
|
||
|
// If the output buffer is full, there's nothing for it other than to
|
||
|
// wait for the interrupt handler to empty it a bit
|
||
|
while (i == _tx_buffer->tail)
|
||
|
;
|
||
|
|
||
|
_tx_buffer->buffer[_tx_buffer->head] = c;
|
||
|
_tx_buffer->head = i;
|
||
|
|
||
|
bit_set(*_ucsrb, _udrie);
|
||
|
#ifndef COMPAT_PRE1
|
||
|
return 1;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Preinstantiate Objects //////////////////////////////////////////////////////
|
||
|
|
||
|
#if defined(UBRRH) && defined(UBRRL)
|
||
|
RFHardwareSerial RFSerial(&rx_buffer, &tx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRIE, U2X);
|
||
|
#elif defined(UBRR0H) && defined(UBRR0L)
|
||
|
RFHardwareSerial RFSerial(&rx_buffer, &tx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRIE0, U2X0);
|
||
|
#elif defined(USBCON)
|
||
|
// do nothing - Serial object and buffers are initialized in CDC code
|
||
|
#else
|
||
|
#error no serial port defined (port 0)
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
|