922 wiersze
27 KiB
C++
922 wiersze
27 KiB
C++
/*
|
|
This file is part of Repetier-Firmware.
|
|
|
|
Repetier-Firmware is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Repetier-Firmware 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Repetier-Firmware. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
This firmware is a nearly complete rewrite of the sprinter firmware
|
|
by kliment (https://github.com/kliment/Sprinter)
|
|
which based on Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware.
|
|
|
|
|
|
Main author: repetier
|
|
|
|
Initial port of HAL to Arduino Due: John Silvia
|
|
*/
|
|
|
|
/**
|
|
This is the main Hardware Abstraction Layer (HAL).
|
|
To make the firmware work with different processors and toolchains,
|
|
all hardware related code should be packed into the hal files.
|
|
*/
|
|
|
|
// You can set different sizes if you want, but with binary mode it does not get faster
|
|
#ifndef SERIAL_RX_BUFFER_SIZE
|
|
#define SERIAL_RX_BUFFER_SIZE 128
|
|
#endif
|
|
|
|
#ifndef HAL_H
|
|
#define HAL_H
|
|
|
|
#include <inttypes.h>
|
|
#include "pins.h"
|
|
#include "Print.h"
|
|
#include "fastio.h"
|
|
|
|
// Hack to make 84 MHz Due clock work without changes to pre-existing code
|
|
// which would otherwise have problems with int overflow.
|
|
#undef F_CPU
|
|
#define F_CPU 21000000 // should be factor of F_CPU_TRUE
|
|
#define F_CPU_TRUE 84000000 // actual CPU clock frequency
|
|
#define EEPROM_BYTES 4096 // bytes of eeprom we simulate
|
|
#define SUPPORT_64_BIT_MATH // Gives better results with high resultion deltas
|
|
|
|
// another hack to keep AVR code happy (i.e. SdFat.cpp)
|
|
#define SPR0 0
|
|
#define SPR1 1
|
|
|
|
// force SdFat to use HAL (whether or not using SW spi)
|
|
#undef SOFTWARE_SPI
|
|
#define TIMER0_PRESCALE 128
|
|
|
|
// Some structures assume no padding, need to add this attribute on ARM
|
|
#define PACK __attribute__ ((packed))
|
|
|
|
#define INLINE __attribute__((always_inline))
|
|
|
|
// do not use program space memory with Due
|
|
#define PROGMEM
|
|
#define PGM_P const char *
|
|
typedef char prog_char;
|
|
#undef PSTR
|
|
#define PSTR(s) s
|
|
#undef pgm_read_byte_near
|
|
#define pgm_read_byte_near(x) (*(int8_t*)x)
|
|
#undef pgm_read_byte
|
|
#define pgm_read_byte(x) (*(int8_t*)x)
|
|
#undef pgm_read_float
|
|
#define pgm_read_float(addr) (*(const float *)(addr))
|
|
#undef pgm_read_word
|
|
//#define pgm_read_word(addr) (*(const unsigned int *)(addr))
|
|
#define pgm_read_word(addr) (*(addr))
|
|
#undef pgm_read_word_near
|
|
#define pgm_read_word_near(addr) pgm_read_word(addr)
|
|
#undef pgm_read_dword
|
|
#define pgm_read_dword(addr) (*(addr))
|
|
//#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
|
|
#undef pgm_read_dword_near
|
|
#define pgm_read_dword_near(addr) pgm_read_dword(addr)
|
|
#define _BV(x) (1 << (x))
|
|
|
|
#define FSTRINGVALUE(var,value) const char var[] PROGMEM = value;
|
|
#define FSTRINGVAR(var) static const char var[] PROGMEM;
|
|
#define FSTRINGPARAM(var) PGM_P var
|
|
|
|
|
|
#define EXTRUDER_TIMER TC0
|
|
#define EXTRUDER_TIMER_CHANNEL 0
|
|
#define EXTRUDER_TIMER_IRQ ID_TC0
|
|
#define EXTRUDER_TIMER_VECTOR TC0_Handler
|
|
#define PWM_TIMER TC0
|
|
#define PWM_TIMER_CHANNEL 1
|
|
#define PWM_TIMER_IRQ ID_TC1
|
|
#define PWM_TIMER_VECTOR TC1_Handler
|
|
#define TIMER1_TIMER TC2
|
|
#define TIMER1_TIMER_CHANNEL 2
|
|
#define TIMER1_TIMER_IRQ ID_TC8
|
|
#define TIMER1_COMPA_VECTOR TC8_Handler
|
|
#define SERVO_TIMER TC2
|
|
#define SERVO_TIMER_CHANNEL 0
|
|
#define SERVO_TIMER_IRQ ID_TC6
|
|
#define SERVO_COMPA_VECTOR TC6_Handler
|
|
#define BEEPER_TIMER TC1
|
|
#define BEEPER_TIMER_CHANNEL 0
|
|
#define BEEPER_TIMER_IRQ ID_TC3
|
|
#define BEEPER_TIMER_VECTOR TC3_Handler
|
|
#define DELAY_TIMER TC1
|
|
#define DELAY_TIMER_CHANNEL 1
|
|
#define DELAY_TIMER_IRQ ID_TC4 // IRQ not really used, needed for pmc id
|
|
#define DELAY_TIMER_CLOCK TC_CMR_TCCLKS_TIMER_CLOCK2
|
|
#define DELAY_TIMER_PRESCALE 8
|
|
|
|
//#define SERIAL_BUFFER_SIZE 1024
|
|
//#define SERIAL_PORT UART
|
|
//#define SERIAL_IRQ ID_UART
|
|
//#define SERIAL_PORT_VECTOR UART_Handler
|
|
|
|
// TWI1 if SDA pin = 20 TWI0 for pin = 70
|
|
#define TWI_INTERFACE TWI1
|
|
#define TWI_ID ID_TWI1
|
|
|
|
|
|
#define EXTRUDER_CLOCK_FREQ 60000 // extruder stepper interrupt frequency
|
|
#define PWM_CLOCK_FREQ 3906
|
|
#define TIMER1_CLOCK_FREQ 244
|
|
#define TIMER1_PRESCALE 2
|
|
|
|
|
|
#define SERVO_CLOCK_FREQ 1000
|
|
#define SERVO_PRESCALE 2 // Using TCLOCK1 therefore 2
|
|
#define SERVO2500US (((F_CPU_TRUE / SERVO_PRESCALE) / 1000000) * 2500)
|
|
#define SERVO5000US (((F_CPU_TRUE / SERVO_PRESCALE) / 1000000) * 5000)
|
|
|
|
#define AD_PRESCALE_FACTOR 84 // 500 kHz ADC clock
|
|
#define AD_TRACKING_CYCLES 4 // 0 - 15 + 1 adc clock cycles
|
|
#define AD_TRANSFER_CYCLES 1 // 0 - 3 * 2 + 3 adc clock cycles
|
|
|
|
#define ADC_ISR_EOC(channel) (0x1u << channel)
|
|
#define ENABLED_ADC_CHANNELS {TEMP_0_PIN, TEMP_1_PIN, TEMP_2_PIN}
|
|
|
|
#define PULLUP(IO,v) {pinMode(IO, (v!=LOW ? INPUT_PULLUP : INPUT)); }
|
|
|
|
// INTERVAL / (32Khz/128) = seconds
|
|
#define WATCHDOG_INTERVAL 1024u // 8sec (~16 seconds max)
|
|
|
|
|
|
|
|
#if defined(ARDUINO) && ARDUINO >= 100
|
|
#include "Arduino.h"
|
|
#else
|
|
#include "WProgram.h"
|
|
#define COMPAT_PRE1
|
|
#endif
|
|
|
|
//#define READ(pin) PIO_Get(g_APinDescription[pin].pPort, PIO_INPUT, g_APinDescription[pin].ulPin)
|
|
#define READ_VAR(pin) (g_APinDescription[pin].pPort->PIO_PDSR & g_APinDescription[pin].ulPin ? 1 : 0) // does return 0 or pin value
|
|
#define _READ(pin) (DIO ## pin ## _PORT->PIO_PDSR & DIO ## pin ## _PIN ? 1 : 0) // does return 0 or pin value
|
|
#define READ(pin) _READ(pin)
|
|
//#define WRITE_VAR(pin, v) PIO_SetOutput(g_APinDescription[pin].pPort, g_APinDescription[pin].ulPin, v, 0, PIO_PULLUP)
|
|
#define WRITE_VAR(pin, v) do{if(v) {g_APinDescription[pin].pPort->PIO_SODR = g_APinDescription[pin].ulPin;} else {g_APinDescription[pin].pPort->PIO_CODR = g_APinDescription[pin].ulPin; }}while(0)
|
|
#define _WRITE(port, v) do { if (v) {DIO ## port ## _PORT -> PIO_SODR = DIO ## port ## _PIN; } else {DIO ## port ## _PORT->PIO_CODR = DIO ## port ## _PIN; }; } while (0)
|
|
#define WRITE(pin,v) _WRITE(pin,v)
|
|
|
|
#define SET_INPUT(pin) pmc_enable_periph_clk(g_APinDescription[pin].ulPeripheralId); \
|
|
PIO_Configure(g_APinDescription[pin].pPort, PIO_INPUT, g_APinDescription[pin].ulPin, 0)
|
|
#define SET_OUTPUT(pin) PIO_Configure(g_APinDescription[pin].pPort, PIO_OUTPUT_1, \
|
|
g_APinDescription[pin].ulPin, g_APinDescription[pin].ulPinConfiguration)
|
|
#define TOGGLE(pin) WRITE(pin,!READ(pin))
|
|
#define TOGGLE_VAR(pin) HAL::digitalWrite(pin,!HAL::digitalRead(pin))
|
|
#undef LOW
|
|
#define LOW 0
|
|
#undef HIGH
|
|
#define HIGH 1
|
|
|
|
// Protects a variable scope for interrupts. Uses RAII to force clearance of
|
|
// Interrupt block at the end resp. sets them to previous state.
|
|
// Uses ABSEPRI to allow higher level interrupts then the one changing firmware data
|
|
#if 1
|
|
class InterruptProtectedBlock {
|
|
public:
|
|
INLINE void protect() {
|
|
__disable_irq();
|
|
}
|
|
|
|
INLINE void unprotect() {
|
|
__enable_irq();
|
|
}
|
|
|
|
INLINE InterruptProtectedBlock(bool later = false) {
|
|
if (!later)
|
|
__disable_irq();
|
|
}
|
|
|
|
INLINE ~InterruptProtectedBlock() {
|
|
__enable_irq();
|
|
}
|
|
};
|
|
#else
|
|
class InterruptProtectedBlock {
|
|
uint32_t mask;
|
|
public:
|
|
inline void protect() {
|
|
mask = __get_PRIMASK();;
|
|
__disable_irq();
|
|
}
|
|
|
|
inline void unprotect() {
|
|
__set_PRIMASK(mask);
|
|
}
|
|
|
|
inline InterruptProtectedBlock(bool later = false) {
|
|
mask = __get_PRIMASK();
|
|
if (!later)
|
|
__disable_irq();
|
|
}
|
|
|
|
inline ~InterruptProtectedBlock() {
|
|
__set_PRIMASK(mask);
|
|
}
|
|
};
|
|
#endif
|
|
|
|
#define EEPROM_OFFSET 0
|
|
#define SECONDS_TO_TICKS(s) (unsigned long)(s*(float)F_CPU)
|
|
#define ANALOG_INPUT_SAMPLE 6
|
|
#define ANALOG_INPUT_MEDIAN 10
|
|
|
|
// Bits of the ADC converter
|
|
#define ANALOG_INPUT_BITS 12
|
|
#define ANALOG_REDUCE_BITS 0
|
|
#define ANALOG_REDUCE_FACTOR 1
|
|
|
|
// maximum available RAM
|
|
#define MAX_RAM 98303
|
|
|
|
#define bit_clear(x,y) x&= ~(1<<y) //cbi(x,y)
|
|
#define bit_set(x,y) x|= (1<<y)//sbi(x,y)
|
|
|
|
/** defines the data direction (reading from I2C device) in i2cStart(),i2cRepStart() */
|
|
#define I2C_READ 1
|
|
/** defines the data direction (writing to I2C device) in i2cStart(),i2cRepStart() */
|
|
#define I2C_WRITE 0
|
|
|
|
#ifndef DUE_SOFTWARE_SPI
|
|
extern int spiDueDividors[];
|
|
#endif
|
|
|
|
static uint32_t tone_pin;
|
|
|
|
/** Set max. frequency to 500000 Hz */
|
|
#define LIMIT_INTERVAL (F_CPU/500000)
|
|
|
|
|
|
typedef unsigned int speed_t;
|
|
typedef unsigned long ticks_t;
|
|
typedef unsigned long millis_t;
|
|
typedef unsigned int flag8_t;
|
|
typedef int fast8_t;
|
|
typedef unsigned int ufast8_t;
|
|
|
|
#ifndef RFSERIAL
|
|
#define RFSERIAL Serial // Programming port of the due
|
|
//#define RFSERIAL SerialUSB // Native USB Port of the due
|
|
#endif
|
|
|
|
#if defined(BLUETOOTH_SERIAL) && BLUETOOTH_SERIAL > 0
|
|
#if BLUETOOTH_SERIAL == 1
|
|
#define BT_SERIAL Serial1
|
|
#elif BLUETOOTH_SERIAL == 2
|
|
#define BT_SERIAL Serial2
|
|
#elif BLUETOOTH_SERIAL == 3
|
|
#define BT_SERIAL Serial3
|
|
#elif BLUETOOTH_SERIAL == 100
|
|
#define BT_SERIAL Serial
|
|
#elif BLUETOOTH_SERIAL == 101
|
|
#define BT_SERIAL SerialUSB
|
|
#endif
|
|
|
|
class RFDoubleSerial : public Print
|
|
{
|
|
public:
|
|
RFDoubleSerial();
|
|
void begin(unsigned long);
|
|
void end();
|
|
virtual int available(void);
|
|
virtual int peek(void);
|
|
virtual int read(void);
|
|
virtual void flush(void);
|
|
virtual size_t write(uint8_t);
|
|
using Print::write; // pull in write(str) and write(buf, size) from Print
|
|
};
|
|
extern RFDoubleSerial BTAdapter;
|
|
|
|
#endif
|
|
|
|
|
|
#define OUT_P_I(p,i) //Com::printF(PSTR(p),(int)(i))
|
|
#define OUT_P_I_LN(p,i) //Com::printFLN(PSTR(p),(int)(i))
|
|
#define OUT_P_L(p,i) //Com::printF(PSTR(p),(long)(i))
|
|
#define OUT_P_L_LN(p,i) //Com::printFLN(PSTR(p),(long)(i))
|
|
#define OUT_P_F(p,i) //Com::printF(PSTR(p),(float)(i))
|
|
#define OUT_P_F_LN(p,i) //Com::printFLN(PSTR(p),(float)(i))
|
|
#define OUT_P_FX(p,i,x) //Com::printF(PSTR(p),(float)(i),x)
|
|
#define OUT_P_FX_LN(p,i,x) //Com::printFLN(PSTR(p),(float)(i),x)
|
|
#define OUT_P(p) //Com::printF(PSTR(p))
|
|
#define OUT_P_LN(p) //Com::printFLN(PSTR(p))
|
|
#define OUT_ERROR_P(p) //Com::printErrorF(PSTR(p))
|
|
#define OUT_ERROR_P_LN(p) {//Com::printErrorF(PSTR(p));//Com::println();}
|
|
#define OUT(v) //Com::print(v)
|
|
#define OUT_LN //Com::println()
|
|
|
|
union eeval_t {
|
|
uint8_t b[4];
|
|
float f;
|
|
uint32_t i;
|
|
uint16_t s;
|
|
long l;
|
|
} PACK;
|
|
|
|
#if EEPROM_AVAILABLE == EEPROM_SDCARD
|
|
extern millis_t eprSyncTime;
|
|
#endif
|
|
|
|
class HAL
|
|
{
|
|
public:
|
|
// we use ram instead of eeprom, so reads are faster and safer. Writes store in real eeprom as well
|
|
// as long as hal eeprom functions are used.
|
|
static char virtualEeprom[EEPROM_BYTES];
|
|
static bool wdPinged;
|
|
|
|
HAL();
|
|
virtual ~HAL();
|
|
|
|
//Davinci Specific
|
|
#if FEATURE_BEEPER
|
|
static bool enablesound;
|
|
#endif //FEATURE_BEEPER
|
|
#if ENABLE_WIFI
|
|
static bool bwifion;
|
|
#endif //wifi feature
|
|
|
|
// do any hardware-specific initialization here
|
|
static inline void hwSetup(void)
|
|
{
|
|
#if !FEATURE_WATCHDOG
|
|
// Disable watchdog
|
|
WDT_Disable(WDT);
|
|
#endif
|
|
|
|
#if EEPROM_AVAILABLE == EEPROM_I2C || UI_DISPLAY_TYPE == 3 //init i2c when EEprom installed or using i2c display
|
|
HAL::i2cInit(TWI_CLOCK_FREQ);
|
|
#endif
|
|
// make debugging startup easier
|
|
//Serial.begin(115200);
|
|
TimeTick_Configure(F_CPU_TRUE);
|
|
|
|
// setup microsecond delay timer
|
|
pmc_enable_periph_clk(DELAY_TIMER_IRQ);
|
|
TC_Configure(DELAY_TIMER, DELAY_TIMER_CHANNEL, TC_CMR_WAVSEL_UP |
|
|
TC_CMR_WAVE | DELAY_TIMER_CLOCK);
|
|
TC_Start(DELAY_TIMER, DELAY_TIMER_CHANNEL);
|
|
#if EEPROM_AVAILABLE && EEPROM_MODE != EEPROM_NONE
|
|
// Copy eeprom to ram for faster access
|
|
int i;
|
|
for (i = 0; i < EEPROM_BYTES; i += 4) {
|
|
eeval_t v = eprGetValue(i, 4);
|
|
memcopy4(&virtualEeprom[i],&v.i);
|
|
}
|
|
#else
|
|
int i,n = 0;
|
|
for (i = 0; i < EEPROM_BYTES; i += 4) {
|
|
memcopy4(&virtualEeprom[i],&n);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static uint32_t integer64Sqrt(uint64_t a);
|
|
// return val'val
|
|
static inline unsigned long U16SquaredToU32(unsigned int val)
|
|
{
|
|
return (unsigned long) val * (unsigned long) val;
|
|
}
|
|
static inline unsigned int ComputeV(long timer, long accel)
|
|
{
|
|
return static_cast<unsigned int>((static_cast<int64_t>(timer) * static_cast<int64_t>(accel)) >> 18);
|
|
//return ((timer>>8)*accel)>>10;
|
|
}
|
|
// Multiply two 16 bit values and return 32 bit result
|
|
static inline unsigned long mulu16xu16to32(unsigned int a, unsigned int b)
|
|
{
|
|
return (unsigned long) a * (unsigned long) b;
|
|
}
|
|
// Multiply two 16 bit values and return 32 bit result
|
|
static inline unsigned int mulu6xu16shift16(unsigned int a, unsigned int b)
|
|
{
|
|
return ((unsigned long)a * (unsigned long)b) >> 16;
|
|
}
|
|
static inline unsigned int Div4U2U(unsigned long a, unsigned int b)
|
|
{
|
|
return ((unsigned long)a / (unsigned long)b);
|
|
}
|
|
static inline void digitalWrite(uint8_t pin, uint8_t value)
|
|
{
|
|
WRITE_VAR(pin, value);
|
|
}
|
|
static inline uint8_t digitalRead(uint8_t pin)
|
|
{
|
|
return READ_VAR(pin);
|
|
}
|
|
static inline void pinMode(uint8_t pin, uint8_t mode)
|
|
{
|
|
if (mode == INPUT) {
|
|
SET_INPUT(pin);
|
|
}
|
|
else SET_OUTPUT(pin);
|
|
}
|
|
static long CPUDivU2(speed_t divisor) {
|
|
return F_CPU / divisor;
|
|
}
|
|
static INLINE void delayMicroseconds(uint32_t usec)
|
|
{ //usec += 3;
|
|
uint32_t n = usec * (F_CPU_TRUE / 3000000);
|
|
asm volatile(
|
|
"L2_%=_delayMicroseconds:" "\n\t"
|
|
"subs %0, #1" "\n\t"
|
|
"bge L2_%=_delayMicroseconds" "\n"
|
|
: "+r" (n) :
|
|
);
|
|
}
|
|
static inline void delayMilliseconds(unsigned int delayMs)
|
|
{
|
|
unsigned int del;
|
|
while (delayMs > 0) {
|
|
del = delayMs > 100 ? 100 : delayMs;
|
|
delay(del);
|
|
delayMs -= del;
|
|
#if FEATURE_WATCHDOG
|
|
HAL::pingWatchdog();
|
|
#endif
|
|
}
|
|
}
|
|
static inline void tone(uint8_t pin, int frequency) {
|
|
// set up timer counter 1 channel 0 to generate interrupts for
|
|
// toggling output pin.
|
|
//Davinci Specific
|
|
#if FEATURE_BEEPER
|
|
if (!enablesound)return;
|
|
#endif
|
|
SET_OUTPUT(pin);
|
|
tone_pin = pin;
|
|
pmc_set_writeprotect(false);
|
|
pmc_enable_periph_clk((uint32_t)BEEPER_TIMER_IRQ);
|
|
// set interrupt to lowest possible priority
|
|
NVIC_SetPriority((IRQn_Type)BEEPER_TIMER_IRQ, NVIC_EncodePriority(4, 6, 3));
|
|
TC_Configure(BEEPER_TIMER, BEEPER_TIMER_CHANNEL, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC |
|
|
TC_CMR_TCCLKS_TIMER_CLOCK4); // TIMER_CLOCK4 -> 128 divisor
|
|
uint32_t rc = VARIANT_MCK / 128 / frequency;
|
|
TC_SetRA(BEEPER_TIMER, BEEPER_TIMER_CHANNEL, rc / 2); // 50% duty cycle
|
|
TC_SetRC(BEEPER_TIMER, BEEPER_TIMER_CHANNEL, rc);
|
|
TC_Start(BEEPER_TIMER, BEEPER_TIMER_CHANNEL);
|
|
BEEPER_TIMER->TC_CHANNEL[BEEPER_TIMER_CHANNEL].TC_IER = TC_IER_CPCS;
|
|
BEEPER_TIMER->TC_CHANNEL[BEEPER_TIMER_CHANNEL].TC_IDR = ~TC_IER_CPCS;
|
|
NVIC_EnableIRQ((IRQn_Type)BEEPER_TIMER_IRQ);
|
|
}
|
|
static inline void noTone(uint8_t pin) {
|
|
TC_Stop(TC1, 0);
|
|
WRITE_VAR(pin, LOW);
|
|
}
|
|
|
|
#if EEPROM_AVAILABLE == EEPROM_SDCARD
|
|
static void syncEEPROM(); // store to disk if changed
|
|
static void importEEPROM();
|
|
#endif
|
|
|
|
static inline void eprSetByte(unsigned int pos, uint8_t value)
|
|
{
|
|
eeval_t v;
|
|
v.b[0] = value;
|
|
eprBurnValue(pos, 1, v);
|
|
*(uint8_t*)&virtualEeprom[pos] = value;
|
|
}
|
|
static inline void eprSetInt16(unsigned int pos, int16_t value)
|
|
{
|
|
eeval_t v;
|
|
v.s = value;
|
|
eprBurnValue(pos, 2, v);
|
|
memcopy2(&virtualEeprom[pos],&value);
|
|
}
|
|
static inline void eprSetInt32(unsigned int pos, int32_t value)
|
|
{
|
|
eeval_t v;
|
|
v.i = value;
|
|
eprBurnValue(pos, 4, v);
|
|
memcopy4(&virtualEeprom[pos],&value);
|
|
}
|
|
static inline void eprSetLong(unsigned int pos, long value)
|
|
{
|
|
eeval_t v;
|
|
v.l = value;
|
|
eprBurnValue(pos, sizeof(long), v);
|
|
memcopy4(&virtualEeprom[pos],&value);
|
|
}
|
|
static inline void eprSetFloat(unsigned int pos, float value)
|
|
{
|
|
eeval_t v;
|
|
v.f = value;
|
|
eprBurnValue(pos, sizeof(float), v);
|
|
memcopy4(&virtualEeprom[pos],&value);
|
|
}
|
|
static inline uint8_t eprGetByte(unsigned int pos)
|
|
{
|
|
return *(uint8_t*)&virtualEeprom[pos];
|
|
}
|
|
static inline int16_t eprGetInt16(unsigned int pos)
|
|
{
|
|
int16_t v;
|
|
memcopy2(&v,&virtualEeprom[pos]);
|
|
return v;
|
|
}
|
|
static inline int32_t eprGetInt32(unsigned int pos)
|
|
{
|
|
int32_t v;
|
|
memcopy4(&v,&virtualEeprom[pos]);
|
|
return v;
|
|
}
|
|
static inline long eprGetLong(unsigned int pos)
|
|
{
|
|
int32_t v;
|
|
memcopy4(&v,&virtualEeprom[pos]);
|
|
return v;
|
|
}
|
|
static inline float eprGetFloat(unsigned int pos) {
|
|
float v;
|
|
memcopy4(&v,&virtualEeprom[pos]);
|
|
return v;
|
|
}
|
|
|
|
// Write any data type to EEPROM
|
|
static inline void eprBurnValue(unsigned int pos, int size, union eeval_t newvalue)
|
|
{
|
|
#if EEPROM_AVAILABLE == EEPROM_SPI_ALLIGATOR
|
|
uint8_t eeprom_temp[3];
|
|
|
|
/*write enable*/
|
|
eeprom_temp[0] = 6;//WREN
|
|
WRITE( SPI_EEPROM1_CS , LOW );
|
|
spiSend(SPI_CHAN_EEPROM1 , eeprom_temp , 1);
|
|
WRITE( SPI_EEPROM1_CS , HIGH );
|
|
delayMilliseconds(1);
|
|
|
|
/*write addr*/
|
|
eeprom_temp[0] = 2;//WRITE
|
|
eeprom_temp[1] = ((pos >> 8) & 0xFF); //addrH
|
|
eeprom_temp[2] = (pos & 0xFF); //addrL
|
|
WRITE( SPI_EEPROM1_CS , LOW );
|
|
spiSend(SPI_CHAN_EEPROM1 , eeprom_temp , 3);
|
|
|
|
spiSend(SPI_CHAN_EEPROM1 , &(newvalue.b[0]) , 1);
|
|
for (int i = 1; i < size; i++) {
|
|
pos++;
|
|
// writes cannot cross page boundary
|
|
if ((pos % EEPROM_PAGE_SIZE) == 0) {
|
|
// burn current page then address next one
|
|
WRITE( SPI_EEPROM1_CS , HIGH );
|
|
delayMilliseconds(EEPROM_PAGE_WRITE_TIME);
|
|
|
|
/*write enable*/
|
|
eeprom_temp[0] = 6;//WREN
|
|
WRITE( SPI_EEPROM1_CS , LOW );
|
|
spiSend(SPI_CHAN_EEPROM1 , eeprom_temp , 1);
|
|
WRITE( SPI_EEPROM1_CS , HIGH );
|
|
|
|
eeprom_temp[0] = 2;//WRITE
|
|
eeprom_temp[1] = ((pos >> 8) & 0xFF); //addrH
|
|
eeprom_temp[2] = (pos & 0xFF); //addrL
|
|
WRITE( SPI_EEPROM1_CS , LOW );
|
|
spiSend(SPI_CHAN_EEPROM1 , eeprom_temp , 3);
|
|
}
|
|
spiSend(SPI_CHAN_EEPROM1 , &(newvalue.b[i]) , 1);
|
|
}
|
|
WRITE( SPI_EEPROM1_CS , HIGH );
|
|
delayMilliseconds(EEPROM_PAGE_WRITE_TIME); // wait for page write to complete
|
|
#elif EEPROM_AVAILABLE == EEPROM_I2C
|
|
i2cStartAddr(EEPROM_SERIAL_ADDR << 1 | I2C_WRITE, pos);
|
|
i2cWrite(newvalue.b[0]); // write first byte
|
|
for (int i = 1; i < size; i++) {
|
|
pos++;
|
|
// writes cannot cross page boundary
|
|
if ((pos % EEPROM_PAGE_SIZE) == 0) {
|
|
// burn current page then address next one
|
|
i2cStop();
|
|
delayMilliseconds(EEPROM_PAGE_WRITE_TIME);
|
|
i2cStartAddr(EEPROM_SERIAL_ADDR << 1, pos);
|
|
} else {
|
|
while ( (TWI_INTERFACE->TWI_SR & TWI_SR_TXRDY) != TWI_SR_TXRDY);// wait for transmission register to empty
|
|
}
|
|
i2cWrite(newvalue.b[i]);
|
|
}
|
|
i2cStop(); // signal end of transaction
|
|
delayMilliseconds(EEPROM_PAGE_WRITE_TIME); // wait for page write to complete
|
|
#elif EEPROM_AVAILABLE == EEPROM_SDCARD
|
|
eprSyncTime = HAL::timeInMilliseconds() | 1UL;
|
|
#endif
|
|
}
|
|
|
|
// Read any data type from EEPROM that was previously written by eprBurnValue
|
|
static inline union eeval_t eprGetValue(unsigned int pos, int size)
|
|
{
|
|
#if EEPROM_AVAILABLE == EEPROM_SPI_ALLIGATOR
|
|
int i = 0;
|
|
eeval_t v;
|
|
uint8_t eeprom_temp[3];
|
|
size--;
|
|
|
|
eeprom_temp[0] = 3;//READ
|
|
eeprom_temp[1] = ((pos >> 8) & 0xFF); //addrH
|
|
eeprom_temp[2] = (pos & 0xFF); //addrL
|
|
WRITE( SPI_EEPROM1_CS , HIGH );
|
|
WRITE( SPI_EEPROM1_CS , LOW );
|
|
|
|
spiSend(SPI_CHAN_EEPROM1 , eeprom_temp , 3);
|
|
|
|
for (i = 0; i < size; i++) {
|
|
// read an incomming byte
|
|
v.b[i] = spiReceive(SPI_CHAN_EEPROM1);
|
|
}
|
|
// read last byte
|
|
v.b[i] = spiReceive(SPI_CHAN_EEPROM1);
|
|
WRITE( SPI_EEPROM1_CS , HIGH );
|
|
return v;
|
|
#elif EEPROM_AVAILABLE == EEPROM_I2C
|
|
int i;
|
|
eeval_t v;
|
|
|
|
size--;
|
|
// set read location
|
|
i2cStartAddr(EEPROM_SERIAL_ADDR << 1 | I2C_READ, pos);
|
|
for (i = 0; i < size; i++) {
|
|
// read an incomming byte
|
|
v.b[i] = i2cReadAck();
|
|
}
|
|
// read last byte
|
|
v.b[i] = i2cReadNak();
|
|
return v;
|
|
#else
|
|
eeval_t v;
|
|
int i;
|
|
for (i = 0; i < size; i++) {
|
|
// read an incomming byte
|
|
v.b[i] = 0;
|
|
}
|
|
return v;
|
|
#endif //(MOTHERBOARD==500) || (MOTHERBOARD==501)
|
|
}
|
|
|
|
static inline void allowInterrupts()
|
|
{
|
|
//__enable_irq();
|
|
}
|
|
static inline void forbidInterrupts()
|
|
{
|
|
//__disable_irq();
|
|
}
|
|
static inline unsigned long timeInMilliseconds()
|
|
{
|
|
return millis();
|
|
}
|
|
static inline char readFlashByte(PGM_P ptr)
|
|
{
|
|
return pgm_read_byte(ptr);
|
|
}
|
|
static inline void serialSetBaudrate(long baud)
|
|
{
|
|
Serial.setInterruptPriority(1);
|
|
#if defined(BLUETOOTH_SERIAL) && BLUETOOTH_SERIAL > 0
|
|
BTAdapter.begin(baud);
|
|
#else
|
|
//ESP8266 Specific
|
|
#if ENABLE_WIFI
|
|
WIFI_SERIAL.begin(baud);
|
|
#endif
|
|
RFSERIAL.begin(baud);
|
|
#endif
|
|
}
|
|
static inline bool serialByteAvailable()
|
|
{
|
|
#if defined(BLUETOOTH_SERIAL) && BLUETOOTH_SERIAL > 0
|
|
return BTAdapter.available();
|
|
#else
|
|
//ESP8266 Specific
|
|
#if ENABLE_WIFI
|
|
if(HAL::bwifion) return WIFI_SERIAL.available();
|
|
else
|
|
#endif
|
|
return RFSERIAL.available();
|
|
#endif
|
|
}
|
|
static inline uint8_t serialReadByte()
|
|
{
|
|
#if defined(BLUETOOTH_SERIAL) && BLUETOOTH_SERIAL > 0
|
|
return BTAdapter.read();
|
|
#else
|
|
//ESP8266 Specific
|
|
#if ENABLE_WIFI
|
|
if(HAL::bwifion) return WIFI_SERIAL.read();
|
|
else
|
|
#endif
|
|
return RFSERIAL.read();
|
|
#endif
|
|
}
|
|
static inline void serialWriteByte(char b)
|
|
{
|
|
#if defined(BLUETOOTH_SERIAL) && BLUETOOTH_SERIAL > 0
|
|
BTAdapter.write(b);
|
|
#else
|
|
//ESP8266 Specific
|
|
#if ENABLE_WIFI
|
|
if (HAL::bwifion)
|
|
{
|
|
WIFI_SERIAL.write(b);
|
|
if (b=='\n')
|
|
{
|
|
HAL::delayMilliseconds(DELAY_BY_LINE);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
RFSERIAL.write(b);
|
|
#endif
|
|
}
|
|
static inline void serialFlush()
|
|
{
|
|
#if defined(BLUETOOTH_SERIAL) && BLUETOOTH_SERIAL > 0
|
|
BTAdapter.flush();
|
|
#else
|
|
//ESP8266 Specific
|
|
#if ENABLE_WIFI
|
|
if(HAL::bwifion) WIFI_SERIAL.flush();
|
|
else
|
|
#endif
|
|
RFSERIAL.flush();
|
|
#endif
|
|
}
|
|
static void setupTimer();
|
|
static void showStartReason();
|
|
static int getFreeRam();
|
|
static void resetHardware();
|
|
|
|
// SPI related functions
|
|
|
|
#ifdef DUE_SOFTWARE_SPI
|
|
// bitbanging transfer
|
|
// run at ~100KHz (necessary for init)
|
|
static uint8_t spiTransfer(uint8_t b) // using Mode 0
|
|
{
|
|
for (int bits = 0; bits < 8; bits++) {
|
|
if (b & 0x80) {
|
|
WRITE(MOSI_PIN, HIGH);
|
|
} else {
|
|
WRITE(MOSI_PIN, LOW);
|
|
}
|
|
b <<= 1;
|
|
|
|
WRITE(SCK_PIN, HIGH);
|
|
delayMicroseconds(5);
|
|
|
|
if (READ(MISO_PIN)) {
|
|
b |= 1;
|
|
}
|
|
WRITE(SCK_PIN, LOW);
|
|
delayMicroseconds(5);
|
|
}
|
|
return b;
|
|
}
|
|
static inline void spiBegin()
|
|
{
|
|
SET_OUTPUT(SDSS);
|
|
WRITE(SDSS, HIGH);
|
|
SET_OUTPUT(SCK_PIN);
|
|
SET_INPUT(MISO_PIN);
|
|
SET_OUTPUT(MOSI_PIN);
|
|
}
|
|
|
|
static inline void spiInit(uint8_t spiClock)
|
|
{
|
|
WRITE(SDSS, HIGH);
|
|
WRITE(MOSI_PIN, HIGH);
|
|
WRITE(SCK_PIN, LOW);
|
|
}
|
|
static inline uint8_t spiReceive()
|
|
{
|
|
WRITE(SDSS, LOW);
|
|
uint8_t b = spiTransfer(0xff);
|
|
WRITE(SDSS, HIGH);
|
|
return b;
|
|
}
|
|
static inline void spiReadBlock(uint8_t*buf, uint16_t nbyte)
|
|
{
|
|
if (nbyte == 0) return;
|
|
WRITE(SDSS, LOW);
|
|
for (int i = 0; i < nbyte; i++)
|
|
{
|
|
buf[i] = spiTransfer(0xff);
|
|
}
|
|
WRITE(SDSS, HIGH);
|
|
|
|
}
|
|
static inline void spiSend(uint8_t b) {
|
|
WRITE(SDSS, LOW);
|
|
uint8_t response = spiTransfer(b);
|
|
WRITE(SDSS, HIGH);
|
|
}
|
|
|
|
static inline void spiSend(const uint8_t* buf , size_t n)
|
|
{
|
|
if (n == 0) return;
|
|
WRITE(SDSS, LOW);
|
|
for (uint16_t i = 0; i < n; i++) {
|
|
spiTransfer(buf[i]);
|
|
}
|
|
WRITE(SDSS, HIGH);
|
|
}
|
|
|
|
inline __attribute__((always_inline))
|
|
static void spiSendBlock(uint8_t token, const uint8_t* buf)
|
|
{
|
|
WRITE(SDSS, LOW);
|
|
spiTransfer(token);
|
|
|
|
for (uint16_t i = 0; i < 512; i++)
|
|
{
|
|
spiTransfer(buf[i]);
|
|
}
|
|
WRITE(SDSS, HIGH);
|
|
}
|
|
|
|
#else
|
|
|
|
// hardware SPI
|
|
static void spiBegin();
|
|
// spiClock is 0 to 6, relecting AVR clock dividers 2,4,8,16,32,64,128
|
|
// Due can only go as slow as AVR divider 32 -- slowest Due clock is 329,412 Hz
|
|
static void spiInit(uint8_t spiClock);
|
|
// Write single byte to SPI
|
|
static void spiSend(byte b);
|
|
static void spiSend(const uint8_t* buf , size_t n);
|
|
#if MOTHERBOARD == 500 || MOTHERBOARD == 501
|
|
static void spiSend(uint32_t chan , const uint8_t* buf , size_t n);
|
|
static void spiSend(uint32_t chan, byte b);
|
|
static uint8_t spiReceive(uint32_t chan);
|
|
#endif
|
|
// Read single byte from SPI
|
|
static uint8_t spiReceive();
|
|
// Read from SPI into buffer
|
|
static void spiReadBlock(uint8_t*buf, uint16_t nbyte);
|
|
|
|
// Write from buffer to SPI
|
|
|
|
static void spiSendBlock(uint8_t token, const uint8_t* buf);
|
|
#endif /*DUE_SOFTWARE_SPI*/
|
|
|
|
// I2C Support
|
|
static void i2cSetClockspeed(uint32_t clockSpeedHz);
|
|
static void i2cInit(unsigned long clockSpeedHz);
|
|
static void i2cStartWait(unsigned char address);
|
|
static uint8_t i2cStart(unsigned char address);
|
|
static void i2cStartAddr(unsigned char address, unsigned int pos);
|
|
static void i2cStop(void);
|
|
static void i2cStartBit(void);
|
|
static void i2cCompleted (void);
|
|
static void i2cTxFinished(void);
|
|
static void i2cWrite( uint8_t data );
|
|
static uint8_t i2cReadAck(void);
|
|
static uint8_t i2cReadNak(void);
|
|
|
|
|
|
// Watchdog support
|
|
inline static void startWatchdog() {
|
|
//Davinci Specific
|
|
#if FEATURE_WATCHDOG
|
|
uint32_t timeout = 8000 * 256 / 1000; //8000ms = 8s
|
|
if (timeout == 0) timeout = 1;
|
|
else if (timeout > 0xFFF) timeout = 0xFFF;
|
|
timeout = WDT_MR_WDRSTEN | WDT_MR_WDV(timeout) | WDT_MR_WDD(timeout);
|
|
WDT_Enable (WDT, timeout);
|
|
#endif
|
|
}
|
|
inline static void stopWatchdog() {WDT_Disable (WDT);}
|
|
|
|
inline static void pingWatchdog() {
|
|
#if FEATURE_WATCHDOG
|
|
wdPinged = true;
|
|
#endif
|
|
};
|
|
|
|
inline static float maxExtruderTimerFrequency() {
|
|
return (float)F_CPU_TRUE/32;
|
|
}
|
|
#if FEATURE_SERVO
|
|
static unsigned int servoTimings[4];
|
|
static void servoMicroseconds(uint8_t servo, int ms, uint16_t autoOff);
|
|
#endif
|
|
|
|
static void analogStart(void);
|
|
#if USE_ADVANCE
|
|
static void resetExtruderDirection();
|
|
#endif
|
|
static volatile uint8_t insideTimer1;
|
|
};
|
|
|
|
#endif // HAL_H
|